Python imports confusion - python

I've got a strange issue with importing a module. I've got a virtualenv setup and one module is available in {env}/lib/python2.6/site-packages/pkgname. There is a __init__.py file and pkgname.py inside.
Now, if I run {env}/bin/python and execute import pkgname.pkgname, it works just fine. But if I create a script in {env}/bin/pkgname.py with contents:
#!{env}/bin/python
import pkgname.pkgname
if __name__ == "__main__":
pkgname.pkgname.run()
this fails trying to import the same file again (since the package and the file have the same name). How can I disable looking in the same directory? Or how can I force the import to first look at the global packages?
Alternatively, what's the "proper" way of doing this? Just for consistency, I'd rather call my startup script the same as the actual package it's trying to run.

Call it pkgname. Done. OK, then it won't start if you doubleclick in it WIndows, but that's usually not a problem.

You can modify sys.path. It's just a list of paths to search and the current folder should be the first entry. Your file should run if you move the current folder to the end of the list. But I general I would not do something like that without a VERY good reason. Isn't it possible to rename your file name.py, runpkgname.py or something like that?

Related

Auto-compile other .py files imported as packages?

I have two .py files I wrote that I've imported into a third .py file to use:
(The top of driver.py)
import wafer_diagram
import LightIV
wafer_diagram.py and LightIV.py contain functions that I'm using in driver.py. However, whenever I have a cleared/restarted kernel, I have to run each individual .py file, otherwise they aren't defined in driver.py. Is there a way to automatically do this when I run driver.py? I am using Spyder with python 3.8. Thanks!
Edit: To clarify, after running wafer diagram.py and LightIV.py, I am able to use the functions in driver.py without issue. However, if I restart my kernel, and then try running driver.py, an error will throw that the two modules do not exist.
I was being very silly! Although I imported my other files, I was not calling on their functions correctly. For example, for the function print_struct() from LightIV.py, I would write in driver.py:
import LightIV
print_struct()
Instead, I should have written:
import LightIV
LightIV.print_struct()
The reason that I was able to get away with this for so long was likely due to how Spyder saves variables. I would run LightIV.py and wafer_diagram.py, "saving" their functions, and then using them later on instead of properly importing them.

Is there a more elegant way to refer to script's current directory?

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
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):
Use os.getcwd() and __file__, as you already suggested.
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.
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).
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.

Is it possible to access the launching shortcut directory from a Python executalbe?

I currently have a Python scrip that runs through all Excel files in the current directory and generates a PDF report.
It works fine now but I don't want the users to be anywhere near frozen Python scripts. I created an MSI with cxFreeze which puts the EXE and scripts in the Program Files directory.
What I would like to be able to do is create a shortcut to this executable and pass the directory the shortcut was run from to the Python program so that can be set as the working directory. This would allow the user to move the shortcut to any folder of Excel files and generate a report there.
Does Windows send the location of a opened shortcut to the executable and is there a way to access it from Python?
When you launch a shortcut, Windows changes the working directory to the directory specified in the shortcut, in the Start in field. At this point, Windows has no memory of where the shortcut was stored.
You could change the Start in field to point to the directory that the shortcut is in. But you'd have to do that for every single shortcut, and never make a mistake.
The better approach is to use a script, rather than a shortcut. Place your actual Python script (which we'll call doit.py for sake of example) somewhere in your PYTHONPATH. Then create a single-line Python script that imports it:
import doit
Save it (but don't name it doit.py) and copy it to each directory from which you want to be able to invoke the main script. In doit.py you can use os.getcwd() to find out what directory you're being invoked from.
You could also do it with a batch file. This is a little more flexible in that you can specify the exact name of the script and which Python interpreter should be used, and don't need to store the script in a directory in PYTHONPATH. Also, you don't need to worry about the file's name clashing with the name of a Python module. Simply put this line in a file:
C:\path\to\your\python.exe C:\path\to\your\script.py
Save it as (e.g.) doit.bat and copy it into the directories from which you want to invoke it. As before, your Python script can call os.getcwd() to get the directory. Or you can write it so your Python script accepts it as the first argument, and write your batch file like:
C:\path\to\your\python.exe C:\path\to\your\script.py %cd%
Another thing you can do with the batch file approach is add a pause command to the end so that the user is asked to press a key after the script runs, giving them the opportunity to read any output generated by the script. You could even make this conditional so that it only happens if an error occurs (which requires returning a proper exit code from the script). I'll leave that as an exercise. :-)
Is there a problem with modifying the script to take the directory to process as a command line argument?
You could then configure the different shortcuts to pass in the appropriate directory.
Type the following into a batch file (i.e. script.bat):
python \absolute\path\to\your\script.py %~dp0
pause
Then add these imports at the top of your python file script.py (if not already included):
import os
import sys
And add this to the bottom of the python file (or combine it with a similar statement):
if __name__ == "__main__":
# set current working directory:
if len(sys.argv) > 1:
os.chdir(sys.argv[1])
main()
replace main() with whatever function you want to call or code you want to run.
The following is how I came to my answer:
I tried using kindall's answer and had the following issues:
The first suggestion of storing the script somewhere in PYTHONPATH could not be applied to my situation because my script will be used on a server and needs to be independent of the client computer's python environment (besides having the required pip installations).
I tried calling my python script from a Windows Batch File which could be moved to a different location. Instead of the batch file's location being used as the current working directory, it was C:\Windows.
I tried passing %cd% as an argument to my python script, then setting that to be my CWD. This still resulted in a CWD of C:\Windows.
After reviewing the comments, I tried Eryk Sun's suggestion of instead passing %~dp0 as an argument to the python script. This resulted in the CWD being correctly set to the batch file's location.
I hope this helps others facing similar difficulties.

How create some kind of "main" class in Python

I am beginner in python. I created project with three .py files and one database file in PyCharm. But don`t understand how run my project via cmd console or something else. Do I need to create start class like "main" or what to do? How can I sent my project to another people that they may run it?
On the screen I tried run .py file via cmd Windows console
Python program does not require "main function" as entry point, each line of a .py file will be executed sequentially. All you need is to type: python yourprogram.py in your console.
But on the other hand, many people choose to have a "main function" in their python program and only invoke this function when python program is run as a stand-alone script as opposed to being loaded as a module.
def main():
# do something
if __name__ == "__main__":
main()
Your code ran.
The error seems to suggest that it's running from the src folder and trying to open a src subdirectory with a database.
Without giving absolute paths, all file references are relative to the executed script. So, just connect to the database name, not src/Contacts.db
Each of your .py file is an executable. Depending on how you have coded, these files might be inter-dependent. In that case, there might be a main file(with any name, need not name it main.py, could be hello.py). So, you can run that file with python <filename>. As far as the language is concerned, there is no need to create a special class like main. Though you are free to do that.
General style it to include a statement in the end of the main file like suppose you have three files hello.py, bye.py, work.py, where
from work import *
from bye import *
def hello():
print "Hello"
if __name__ == "__main__":
hello()
You can run python hello.py
For sharing, you can create a zip of the folder and share that zip or you can create a git hub repository and share the github link.
The error is in opening the file. please check for spelling errors and the location of the db file

Where is the huey consumer configuration?

I'm trying to get running the Huey task queue for python (it's a Celery alternative) and I'm stuck with starting the consumer with main.Configuration (as it's written in the tutorial). I know the huey_consumer is looking for the configfile somewhere in the python, but I cannot get it working according to the tutorial and I don't know why I should write a config file and load it as a module (instead of a file).
When I run huey_consumer.py main.Configuration it returns Unable to import "main".
Huey have this issue written in their common pitalls too, but it's not really helping either.
If there is somebody using Huey, please help me.
I had the same problem and solved it by adding the directory containing main.py to the PYTHONPATH. There was no need to copy huey_consumer.py
So the way this works is it tries to import the module "main". It would be equivalent to opening up a python shell and running:
>>> from main import Configuration
Perhaps you can reply with more information about your environment, the layout of your files, what you're running, etc.
I think you need to add an __init__.py file to the folder that contains main.py, ... else you cannot import anything as python will not consider this folder as a module.
What's the difference between a Python module and a Python package?
See comment by giulio-piancastelli

Categories

Resources