0

I have dev environment and production for running various Python scripts used in crontab.

In dev environment, I usually test scripts from commandline in script directory such as "python myscript.py". Now, some scripts load config from JSON files in the same or subdirectory of script directory. In dev, I can therefore refer to file just like that:

printconf = Config('printing.json')

However, once the script is ready for production, it is put in crontab, and crontab calls scripts from root, therefore breaking the above line.

Additionally, dev and production are obviously in different places in the filesystem, so I can't even use absolute paths, because they won't be the same.

As described in How can I find script's directory with Python?, I can use various methods to find the file current directory. They mean, however, extra processing and I was wondering, if any Python version might have (or might have planned) any additional built-in way to tell that the file must be found relatively to running script's directory? Something like __location__?

In essence, something that would work for file references like importing modules already does.

In addition, I have tried to add a global __location__ variable via sitecustomize.py, but that doesn't even work.

sitecustomize.py:

if '__file__' in globals():
    import os
    _location_ = os.path.join(os.getcwd(), os.path.dirname(__file__))

But that doesn't work either, because: - __location__ is not passed to the script, - and __file__ refers to sitecustomize.py

Ralf
  • 13,322
  • 4
  • 31
  • 55
Gnudiff
  • 3,909
  • 1
  • 22
  • 25
  • `__file__` is built-in predefined variable the running script and you can extract the directory portion of that. – martineau Feb 14 '19 at 09:49

2 Answers2

0

First and foremost, your Dev and Prod environments should not differ too much. This means that for consistency's sake you should use the same setup (filesystem, libraries etc.) for both. This way most of your issues will vanish. If you do this, than it's safe to use a hardcoded path.

Other options (that inevitably involve some processing, but it should not be deal breakers):

  1. Use os.getcwd() and __file__, as you already suggested.
  2. Use a specific argument when running your scripts (e.g.: $SCRIPT_PATH/myscript.py PROD) and choose your paths based on this inside the script.
  3. Use a dedicated config file just for script init, put it in the same place both on DEV and PROD (I would suggest in /etc/$PROJECT_NAME) and run the script with a specific argument (like mentioned above).

None of the above methods will prevent other issues related to consistency, which makes me underline that you should look into using Docker or Vagrant for your Dev setup (and/or Prod, if possible).

Mihai
  • 1,844
  • 1
  • 11
  • 16
  • Well, my setup is somewhat particular. Docker and Vagrant seem to be *way* overkill for a dozen of crontab scripts. I think I will just add creation of __location__ variable to some site customization, so it is avaiable in any script I run. Perhaps you could possible update your answer's 3d point with a pointer to where I should put it? – Gnudiff Feb 14 '19 at 10:08
  • You could create a $PROJECT_NAME dir in /etc or just add it directly there. – Mihai Feb 14 '19 at 11:46
0

As I reviewed this question, it became clear that I provided probably too much of wrong context and too little of relevant one. As I tested the actual solution, I decided against rewriting the question, and instead put the right context in the answer.

Most of the problems were due to fact that I wanted to determine path of file B, relative to script A, when the actual CALL to use file B used a system-wide module C (called from script A) which was in completely different place, like this:

#module C (system-wide in /usr.../site-packages
import os
class Config()
   ...
   def load(file_name):
    # needs to be relative to calling script's dir, not module's!
    real_file_name=os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),file_name)
    ...

#script-A.py ( in /var/scripts/projectA )
from C import Config
conf=Config()
conf.load('file-in-projectA-dir.json')
# finds /var/scripts/projectA/file-in-projectA-dir.json
# regardless of cwd

So this works both for:

cd /
python3 /var/scripts/projectA/script-A.py
#and:
cd /var/scripts/projectA/
python3 script-A.py
#etc

As you can see, this only works due to fact that script-A is called from command line as first parameter. However, that is my main use case. Not sure, what could work otherwise.

Gnudiff
  • 3,909
  • 1
  • 22
  • 25