python - compiled calling config file - python

I'm compiling a python application using pyinstaller.
The structure is like so -
d:\app\myprog.exe
d:\app\config\settings.conf
If I run myprog.exe --switch value from d:\app it runs fine, if I try to run from anywhere else like c:\windows it's not finding my settings.conf file complaining with the message:
Traceback (most recent call last):
File "<string>", line 284, in <module>
File "<string>", line 218, in main
File "ConfigParser.py", line 330, in get
ConfigParser.NoSectionError: No section: 'database'
myApp returned -1
database being the first line in the config file I'm trying to reference.
I'm referencing the BASE_DIR from the app here -
# Global Path and Config Info
try:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
except NameError: # We are the main py2exe script, not a module
BASE_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
So that I can get the config file like this -
config = RawConfigParser()
config.read(os.path.join(BASE_DIR, 'config/settings.conf'))
But I guess BASE_DIR is whatever folder I'm running the EXE from (like c:\windows, not the location of the EXE (which is d:\app)?

As mentioned in PyInstaller documentation (in How the One-File Program Works section) when a single executable file (created by PyInstaller) is executed, what happens is that a directory structure of the required library modules (Python VM, libraries and packages, etc.) are extracted from that single executable to a temporary directory, and then the application is started from there.
This means that __file__ in your Python code is not going to be the path to the single executable file, and that's the reason for this issue.
I'd write my app to accept the path to the configuration file from command line arguments, fall back to using an environment variable if available, and then a hard coded default value based on the platform (as most multi platform applications do to reach to their configurations).
Another approach is to use the one-directory output from PyInstaller and include the configuration file in the same directory.
Then to help make it easier to distribute the software to end users, use another tool to create a single Windows installer file from that directory structure. This way you'll be distributing the Windows installer, so users can run to install the application. But when the app runs, it runs from the directory where the configuration file resides.

Related

How to access python scripts from Windows service

The problem: we wish to run an Azure Devops pipeline which contains a step that runs a python command "mkdocs" to generate documentation. However, the pipeline does not have access to this script.
How are you supposed to access python scripts inside a Windows Service?
Environment
The pipeline runs on a self hosted Windows agent (more info). This pipeline runs as a Windows Service, with a "Network Service" account. Important to note is that this account does not have access to the AppData folder, because it is not a user.
mkdocs is a python package installed using pip, which comes with a mkdocs.exe which we attempt to run in the pipeline. This package is normally installed under the user's AppData folder.
Attempt 1:
Simply adding C:\Users\[REDACTED]\AppData\Roaming\Python\Python310\Scripts to PATH. This gives the following expected output in the logs of the pipeline:
##[error]'mkdocs' is not recognized as an internal or external command, operable program or batch file.
This is not surprising since the pipeline does not have access to the [REDACTED] user's AppData folder.
Attempt 2:
Changing the installation directory of pip packages using either --target=c:/PythonScripts, or with the C:\Users\[REDACTED]\AppData\Roaming\pip\pip.ini file:
[global]
target = c:\PythonScripts
When running pip install mkdocs, it successfully installs it into c:/PythonScripts. We add the folder c:/PythonScripts/bin to the PATH. Now when we try to run mkdocs from the command line, we get the following error:
C:\Users\[REDACTED]>mkdocs
Traceback (most recent call last):
File "C:\Program Files\Python310\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Program Files\Python310\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "C:\PythonScripts\bin\mkdocs.exe\__main__.py", line 4, in <module>
ModuleNotFoundError: No module named 'mkdocs'
Somehow it does find the mkdocs.exe because it is on the path, but it cannot load the module mkdocs because that's installed in another directory?
Attempt 3:
Simply installing in the AppData folder and copying the contents. This also didn't work since the module was again not found.
Attempt 4:
Running the service as the user. This is really really undesirable, but it works. I would like to know a proper solution to this problem.

py2exe PackageNotFoundError

I'm currently trying to package a Tkinter app into a .exe file using py2exe. The packaging works fine, and up until a point, the program functions. When I call a certain function, though, running the .exe file logs the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "Tkinter.pyc", line 1532, in __call__
File "/Users/Gordon/Gordon's Files/AutoFormatter/lib\formatterApp.py", line 58, in go
File "formatter.pyc", line 72, in take
File "docx\api.pyc", line 25, in Document
File "docx\opc\package.pyc", line 116, in open
File "docx\opc\pkgreader.pyc", line 32, in from_file
File "docx\opc\phys_pkg.pyc", line 31, in __new__
PackageNotFoundError: Package not found at 'C:\Users\Gordon\Gordon's Files\AutoFormatter\dist\library.zip\docx\templates\default.docx'
Upon originally running py2exe, I checked the \docx\ folder and found that py2exe hadn't actually copied over the \templates\ folder. After manually unzipping the library.zip, adding in the \templates\ folder in the right place, and then manually re-zipping, however, I get the same error.
My setup.py is as follows:
from distutils.core import setup
import py2exe
setup(
windows=[{'script': 'AutoFormatter.py'}],
options={
'py2exe':
{
'includes': ['lxml.etree', 'lxml._elementpath', 'gzip', 'docx'],
}
}
)
I'm running the program on a Windows 7 computer using Python 2.7.8 and py2exe 0.6.9.
This might be too late but I have been having the same troubles as well. I don't know if python-docx was made to be compiled into a single executable yet, none the less I have found solution.
I am on pyinstaller with python2.7, essentially the same thing. I hope that you are freezing into one directory rather than one file. This won't work if you're freezing to one file
Download this here(Mediafire link)
Place it in
C:\Users\Gordon\Gordon's Files\AutoFormatter\dist\library.zip\docx\templates\default.docx
basically wherever your .exe is in.
Hopefully that does the trick
Based off of me scouring through my own directories and the docx module, when you create a document:
doc = Document()
doc.save('hello.docx')
It pulls a template for you to use, if you do not create your own, it will use the default template offered by python-docx itself.
Don't quote me on this, but I believe python-docx looks through its own directories to find the default.docx template when executing it through python.
Since we compiled the script, the path changed to the directory in which the .exe is placed, however pyinstaller (or in your case py2exe) does not include the template with the dist folder, and this creates the PackageNotFoundError

Google App Engine Local Host Issue

I'm new to Google App Engine and I followed multiple video tutorials (One from Udacity) and for some reason I am unable to get it to run on the local host with the simple "Hello World" program.
I do have the Python SDK installed as well as the Google App Engine program installed. I did modify the YAML file so that it matches with my application (it did by default). When I click "run" in the Google App Engine launcher, it shows a yellow triangle caution sign next to the program I'm attempting to run.
When I type the localhost:8080 in the search bar it says:
This webpage is not available
I've also tried reinstalling both Python 2.7.9 and the Google App Engine and to no avail. In short I would like to understand why the program shows no content when I attempt to run it. Here are the log files if it's any help:
2015-03-14 18:36:21 Running command: "['E:\\Python\\pythonw.exe', 'C:\\Program Files (x86)\\Google\\google_appengine\\dev_appserver.py', '--skip_sdk_update_check=yes', '--port=8080', '--admin_port=8000', 'C:\\Program Files (x86)\\Google\\google_appengine\\new_project_template']"
Traceback (most recent call last):
File "C:\Program Files (x86)\Google\google_appengine\dev_appserver.py", line 83, in <module>
_run_file(__file__, globals())
File "C:\Program Files (x86)\Google\google_appengine\dev_appserver.py", line 79, in _run_file
execfile(_PATHS.script_file(script_name), globals_)
NameError: name 'execfile' is not defined
2015-03-14 18:36:21 (Process exited with code 1)
It looks like the default pythonw on your system (E:\Python\pythonw.exe) is some version of Python 3. That's where execfile is indeed not defined (and the GAE launcher's incompatible with Py3 in other ways, anyway, at this time).
To verify, run E:\Python\python.exe at a cmd prompt -- it should greet you with a version banner which I bet will mention Python 3.something.
Where did you (re-)install 2.7.9? How's your PATH environment variable? Likely with E:\Python before wherever 2.7.9 is installed.
Simplest might be to change your PATH so that wherever 2.7.9 is installed comes before E:\Python...!

Py2exe isn't copying webdriver_prefs.json into builds

I'm using py2exe to compile a Python 2.7 script that uses Selenium 2.39.0 to open up Firefox windows and carry out some routines. In the past, I've been able to compile the code without any issue. Today though, after updating from Selenium 2.35 to 2.39, I'm running into trouble. When I try to run the .exe generated by the compiled code, I get the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "Tkinter.pyo", line 1410, in __call__
File "literatureonlineapi2.5.5.py", line 321, in startapi
File "selenium\webdriver\firefox\webdriver.pyo", line 43, in __init__
File "selenium\webdriver\firefox\firefox_profile.pyo", line 58, in __init__
IOError: [Errno 2] No such file or directory: 'C:\\Text\\Professional\\Digital H
umanities\\Programming Languages\\Python\\Query Literature Online\\LION 1.0\\2.5
\\2.5.5\\dist\\.\\selenium\\webdriver\\firefox\\webdriver_prefs.json'
Here we go!
Exception in Tkinter callback
Traceback (most recent call last):
File "Tkinter.pyo", line 1410, in __call__
File "literatureonlineapi2.5.5.py", line 321, in startapi
File "selenium\webdriver\firefox\webdriver.pyo", line 43, in __init__
File "selenium\webdriver\firefox\firefox_profile.pyo", line 58, in __init__
IOError: [Errno 2] No such file or directory: 'C:\\Text\\Professional\\Digital H
umanities\\Programming Languages\\Python\\Query Literature Online\\LION 1.0\\2.5
\\2.5.5\\dist\\.\\selenium\\webdriver\\firefox\\webdriver_prefs.json'
(This error does not appear when I run the uncompiled code.)
I came across a google code page that led me to believe newer versions of Selenium have had trouble with this missing webdriver_prefs.json file, but that didn't help me sort out the problem.
Does anyone know how I might manually provide the missing file? I would be grateful for any help others can offer.
I found a solution, and thought I would post it in case others have a similar problem. I found the missing webdriver_prefs.json file tucked away in
C:\Python27\Lib\site-packages\selenium-2.39.0-py2.7.egg\selenium\webdriver\firefox\
After I had navigated to that directory, I grabbed the webdriver_prefs.json file and the webdriver.xpi file. I then copied both of those files into
dist\selenium\webdriver\firefox\
created by py2exe, and was able to run the compiled code as expected. God save the queen.
I did the following to fix the problem:
Create a sub-folder \selenium\webdriver\firefox\ under dist.
Under command DOS prompt, enter python.exe setup_firefox.py
You could either running the executable under dist or copy all the files under "dist" to your own directory and run the executable from there.
Here is my setup_firefox.py:
from distutils.core import setup
import py2exe,sys,os
sys.argv.append('py2exe')
setup(
console=[{'script':"test.py"}],
options={
"py2exe":{
"skip_archive": True,
"unbuffered": True,
"optimize": 2
},
}
)
I had a related issue for which I have found a work round...
My issue
I was trying to run a python script that uses Selenium 2.48.0 and worked fine on the development machine but failed to open Firefox when py2exe'ed with the error message:
[Errno 2] No such file or directory:'C:\test\dist\library.zip\selenium\webdriver\firefox\webdriver_prefs.json'
Cause
I traced the problem to the following file in the selenium package
C:\Python27\Lib\site-packages\selenium\webdriver\firefox\firefox_profile.py
It was trying to open webdriver_prefs.json and webdriver.xpifrom the same parent directory
This works fine when running on the development machine but when the script is run through py2exe firefox_profile.pyc is added to library.zip but webdriver_prefs.json and webdriver.xpi aren't.
Even if you manual add these files to appropriate location in the zip file you will still get the 'file not found' message.
I think this is because the Selenium file can't cope with opening files from within the zip file.
Work Round
My work round was to get py2exe to copy the two missing files to the dist directory and then modify firefox_profile.py to check the directory string.
If it contained .zip modify the string to look in the parent directory
webdriver_prefs.json
class FirefoxProfile(object):
def __init__(self, profile_directory=None):
if not FirefoxProfile.DEFAULT_PREFERENCES:
'''
The next couple of lines attempt to WEBDRIVER_PREFERENCES json file from the directory
that this file is located.
However if the calling script has been converted to an exe using py2exe this file will
now live within a zip file which will cause the open line to fail with a 'file not found'
message. I think this is because open can't cope with opening a file from within a zip file.
As a work round in our application py2exe will copy the preference to the parent directory
of the zip file and attempt to load it from there
'''
if '.zip' in os.path.join(os.path.dirname(__file__)) :
# find the parent dir that contains the zipfile
parentDir = __file__.split('.zip')[0]
configFile = os.path.join(os.path.dirname(parentDir), WEBDRIVER_PREFERENCES)
print "Running from within a zip file, using [%s]" % configFile
else:
configFile = os.path.join(os.path.dirname(__file__), WEBDRIVER_PREFERENCES)
with open(configFile) as default_prefs:
FirefoxProfile.DEFAULT_PREFERENCES = json.load(default_prefs)
webdriver.xpi
def _install_extension(self, addon, unpack=True):
if addon == WEBDRIVER_EXT:
addon = os.path.join(os.path.dirname(__file__), WEBDRIVER_EXT)
tmpdir = None
xpifile = None
'''
The next couple of lines attempt to install the webdriver xpi from the directory
that this file is located.
However if the calling script has been converted to an exe using py2exe this file will
now live within a zip file which will cause the script to fail with a 'file not found'
message. I think this is because it can't cope with opening a file from within a zip file.
As a work round in our application py2exe will copy the .xpi to the parent directory
of the zip file and attempt to load it from there
'''
if '.zip' in addon :
# find the parent dir that contains the zipfile
parentDir = os.path.dirname(addon.split('.zip')[0])
addon = os.path.join(parentDir, os.path.basename(addon))
print "Running from within a zip file, using [%s]" % addon
if addon.endswith('.xpi'):
tmpdir = tempfile.mkdtemp(suffix='.' + os.path.split(addon)[-1])
compressed_file = zipfile.ZipFile(addon, 'r')
for name in compressed_file.namelist():
if name.endswith('/'):
if not os.path.isdir(os.path.join(tmpdir, name)):
os.makedirs(os.path.join(tmpdir, name))
else:
if not os.path.isdir(os.path.dirname(os.path.join(tmpdir, name))):
os.makedirs(os.path.dirname(os.path.join(tmpdir, name)))
data = compressed_file.read(name)
with open(os.path.join(tmpdir, name), 'wb') as f:
f.write(data)
xpifile = addon
addon = tmpdir
I found the sulution, the py2exe can't open zip file. So after copy the webdriver_prefs.json and webdriver.xpi, decompression the library.zip into a folder named "library.zip"

Pygame breaks outside of Pydev.

Me and a team of friends created this game which I am now trying to run in linux,
We developed it using python 2.7 and Pygame in windows using Aptana studio and the code fully work when running through there.
When downloading it to linux It wouldn't load saying that it could not find files. I then tried running it via CMD in windows and there is the same error.
the error so far is
Traceback (most recent call last):
File "/home/user/Desktop/Raspberroids/mainmenu.py", line 144, in <module>
showMenu()
File "/home/user/Desktop/Raspberroids/mainmenu.py", line 107, in showMenu
menu.init(['Start','About','Quit'], surface)
File "/home/user/Desktop/Raspberroids/mainmenu.py", line 52, in init
self.create_strukture()
File "/home/user/Desktop/Raspberroids/mainmenu.py", line 73, in create_strukture
self.font = pygame.font.Font(self.font_path, self.fontsize)
IOError: unable to read font filename
And the source is at:
https://github.com/ryanteck/RasPiThon/tree/master/Raspberroids/Source%20Code
Happens on both 2.7 and 2.6
Can anyone help?
Your font path data/coders_crux/coders_crux.ttf is relative.
When you start your game from another directory than your source directory, pygame can't find the font.
A simple fix is to add the following lines to the top of your script (mainmenu.py):
import os
os.chdir(os.path.dirname(os.path.realpath(__file__)))
os.path.realpath(\__file__) will get the path to your script, and with os.chdir and os.path.dirname you change the current working directory to the directory of your script.
This way, the relative paths you use will work.
PyDev sets working directory and PYTHONPATH variable for your programs. It can also set console encoding to something different than OS defaults.
Add a print self.font_path statement before creating your Font object and see if path is OK. If it's relative path, you could also use os.path.abspath (see os.path docs for details) to get better understanding of what's going on.

Categories