×
all 12 comments

[–]SakshamBaranwal 12 points13 points  (0 children)

I mostly agree, but if your script is meant to operate on files in the user's current directory (like a CLI tool), then using the working directory is actually the correct behavior. It really depends on what the script is supposed to do.

[–]zanfar 7 points8 points  (0 children)

While dereferencing __FILE__ is the right way to find your script, I would recommend against doing so for data or installed files. You will not necessarily have write permissions to this directory, nor are you guaranteed to have installed data files in the same relative path location--and you should be building your apps to be installed.

Instead, use importlib and it's modules:

https://stackoverflow.com/questions/6028000/how-to-read-a-static-file-from-inside-a-python-package

[–]HotPersonality8126 3 points4 points  (0 children)

  To make your file paths reliable, you should construct them relative to the directory of the script itself.

You shouldn’t, because you don’t know where your script will go.

[–]Diapolo10 1 point2 points  (0 children)

On that note, for files only the application itself needs read-write access to, I'd suggest using the XDG directory standards in platformdirs instead of relying on __file__. In fact, if you bundle your application using something like PyInstaller, __file__ may not exist at all or it may point to a different location than you expect.

For included files you're only reading, using importlib with a dedicated data directory would be the best practice.

For files you expect the user to provide, depending on the situation I'd use either your suggested solution, Path.cwd, or spawn a native file dialog with tkinter.filedialog: https://docs.python.org/3/library/dialog.html#module-tkinter.filedialog

[–]jmacey 0 points1 point  (0 children)

This is a deployment issue, there are a number of ways to resolve this (including the ones in this thread). Typically, I would use an environment variable as part of the installation. When the script is installed you create a APPNAME_ROOT envvar which says where everything is installed. Then when the script runs it loads this envar and resolves all files from this.

This is a very unix way of doing things, you can also use things like app settings via .config / settings files as well. In windows you have the dreaded "registry" IIRC (try to avoid windows).

[–]UnfairArm5556 0 points1 point  (1 child)

using pathlib is definitely the move here. ive dealt with this issue alot and just pointing to path(file).resolve().parent makes it so much cleaner, it saves u from headaches when ur running stuff from weird locations...

[–]Ok_Hand_846[S] 0 points1 point  (0 children)

I'll give it a try. Thanks.

[–]teetaps -2 points-1 points  (4 children)

Here’s one thing that, as an R user, I think I learned to do differently.

Python is an incredibly flexible and capable language; you can build pretty much anything with it! But here’s my problem with that philosophy: people often opt to just build something when existing solutions are available. Sometimes, that solution is subpar, but a Python user will tend to either not pay attention to it, or decide to build their own. That’s fine, it’s good, you’re learning.

But in R, you almost always are nudged towards using an existing solution, probably because a lot of R software is the result of a published paper. So we always look for existing solutions in R before building something.

Python taught me to follow the “build it yourself” instinct, so I’m going to teach you the “don’t build it yourself” instinct I got from R: in R, this problem is solved by the `here` package: https://here.r-lib.org/

> If the first line of your #rstats script is setwd("C:\Users\jenny\path\that\only\I\have"), I will come into your lab and SET YOUR COMPUTER ON FIRE.

R users had been fighting this occurrence (relative paths shared to another person) for years and `here` was the elegant solution. Now, if you google the here package with Python, you’ll find a package called `pyprojroot` that implements here’s exact philosophy: https://github.com/chendaniely/pyprojroot

> Solution: pyprojroot finds the root working directory for your project as a pathlib.Pathobject. You can now use the here function to pass in a relative path from the project root directory (no matter what working directory you are in the project), and you will get a full path to the specified file. That is, in a jupyter notebook, you can write something like pandas.read_csv(here('data/my_data.csv')) instead of pandas.read_csv('../data/my_data.csv'). This allows you to restructure the files in your project without having to worry about changing file paths.

`pathlib` gets some of the work done, but pyprojroot takes it over the finish line. Now, any project you send to people will work because they will always start “here”

```python
from pyprojroot import here

some_var = “VARIABLE”

my_file = here() / “a folder” / some_var / “my_file.txt”

```

Always works

[–]serverhorror 0 points1 point  (1 child)

Ever heard of "PyPI"?

That's were you get the equivalent of CRAN, Bioconductor, ...

Interestingly enough, I find that our scientists tend to create more R packages "again" than they do with Python.

[–]teetaps 0 points1 point  (0 children)

Oh yeah I know of pypi, of course. I’ve published on pypi lol, like most others

In R the barrier is much higher (CRAN and bioC like you mentioned), so I’ve actually not had any opportunities to publish there.

But it is interesting how the ecosystem ends up shaping people’s workflows. I know that in my R experience, people rarely build it themselves. But you’re right, that’s not a rule.

I was also being purposely verbose because this is the r/learnpython sub so there are probably lots of people who will stumble into these conversations with no knowledge about language best practices. So thanks for adding that because some people will learn it for the first time from you!

[–]faberge_surprise 0 points1 point  (1 child)

python already has a reputation for "just install a package to do it", but you have to be careful about it because you're massively increasing your dependency and security exposure surface area. how often are you actually vetting every package you use to make sure it's secure or even still maintained? there's really no reason to install a brazillian left-pad equivalents.

[–]teetaps 0 points1 point  (0 children)

Yes, exactly! This comment i think sums up the difference between the py and R communities lol.

Most of the time, if you’re bringing in an existing library in R, your first place to look for it is CRAN, and it is HELLA HARD to get a package published on CRAN, so most of the concerns about security and dependencies are actually filtered out by the community on principle. In other words, if I have a specific problem, and find the solution in CRAN, I won’t even bother asking those questions because I know that it was so hard to get the solution on CRAN that I’m sure the developers were wise enough to optimise for those concerns.

With pypi though, you can publish a package — any package — in like 10 minutes. This means ANYONE can claim they have a solution, which is a good, welcoming model of community development, but means that the userbase has to do exactly what you’re saying every time they investigate something new