I created a standalone python script to export my atlas layouts. Everything is working great except that the SVG symbols that I am using from the Resource Sharing plugin are just question marks, assuming that it is having trouble locating them. However, if I run the script via the startup.py in the QGIS3 folder everything works like expected. I would really like to avoid using this method though as it prevents you from using QGIS until the script finishes, which takes about 2 hours. I am hoping that I just need to add a simple environmental variable to my .bat file so that it can locate the Resource Sharing plugin. Thanks in advance for any help!
.bat file
#ECHO off
set OSGEO4W_ROOT=C:\OSGeo4W64
call "%OSGEO4W_ROOT%\bin\o4w_env.bat"
call "%OSGEO4W_ROOT%\bin\qt5_env.bat"
call "%OSGEO4W_ROOT%\bin\py3_env.bat"
path %OSGEO4W_ROOT%\apps\qgis\bin;%PATH%
set QGIS_PREFIX_PATH=%OSGEO4W_ROOT%\apps\qgis
set GDAL_FILENAME_IS_UTF8=YES
set VSI_CACHE=TRUE
set VSI_CACHE_SIZE=1000000
set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\qgis\qtplugins;%OSGEO4W_ROOT%\apps\qt5\plugins
SET PYCHARM="C:\Program Files\JetBrains\PyCharm 2019.2.3\bin\pycharm64.exe"
set PYTHONPATH=%OSGEO4W_ROOT%\apps\qgis\python
set PYTHONHOME=%OSGEO4W_ROOT%\apps\Python37
set PYTHONPATH=%OSGEO4W_ROOT%\apps\Python37\lib\site-packages;%PYTHONPATH%
set QT_QPA_PLATFORM_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\Qt5\plugins\platforms
set QGIS_PREFIX_PATH=%OSGEO4W_ROOT%\apps\qgis
start "PyCharm aware of QGIS" /B %PYCHARM% %*
Python Script
from qgis.core import QgsApplication, QgsProject, QgsLayoutExporter
import os
import sys
def export_atlas(qgs_project_path, layout_name, outputs_folder):
# Open existing project
project = QgsProject.instance()
project.read(qgs_project_path)
print(f'Project in "{project.fileName()} loaded successfully')
# Open prepared layout that as atlas enabled and set
layout = project.layoutManager().layoutByName(layout_name)
# Export atlas
exporter = QgsLayoutExporter(layout)
settings = QgsLayoutExporter.PdfExportSettings()
exporter.exportToPdfs(layout.atlas(), outputs_folder, settings)
def run():
# Start a QGIS application without GUI
QgsApplication.setPrefixPath(r"C:\\OSGeo4W64\\apps\\qgis", True)
qgs = QgsApplication([], False)
qgs.initQgis()
sys.path.append(r'C:\OSGeo4W64\apps\qgis\python\plugins')
project_path = [project_path]
output_folder = [export_location]
layout_name_portrait = [portrait layout name]
layout_name_landscape = [landscape laytout name]
export_atlas(project_path, layout_name_portrait, output_folder)
export_atlas(project_path, layout_name_landscape, output_folder)
# Close the QGIS application
qgs.exitQgis()
run()
I guess that it might have something to do with the setting svg/searchPathsForSVG.
QgsSettings().setValue('svg/searchPathsForSVG', <your path>)
I'm trying to package a python application for Nix, but I'm finding that the majority of the documentation assumes that I want to package a library.
In order to do this, I looked at Rednotebook example (not for any particular reason other than I happened to know it was written in python), which can be found in python-packages, but as that file is so huge, here is the relevant part:
redNotebook = buildPythonPackage rec {
name = "rednotebook-1.8.1";
src = pkgs.fetchurl {
url = "mirror://sourceforge/rednotebook/${name}.tar.gz";
sha256 = "00b7s4xpqpxsbzjvjx9qsx5d84m9pvn383c5di1nsfh35pig0rzn";
};
# no tests available
doCheck = false;
propagatedBuildInputs = with self; [ pygtk pywebkitgtk pyyaml chardet ];
meta = {
homepage = http://rednotebook.sourceforge.net/index.html;
description = "A modern journal that includes a calendar navigation, customizable templates, export functionality and word clouds";
license = licenses.gpl2;
maintainers = with maintainers; [ tstrobel ];
};
};
My derivation looks like this:
{ pkgs ? import <nixpkgs> {} }:
let
requirements = import ./nix/requirements.nix { inherit pkgs; };
in
pkgs.python35Packages.buildPythonPackage rec {
name = "package-name";
version = "1.0.0";
namePrefix = "";
src = ./.;
doCheck = false;
propagatedBuildInputs = builtins.attrValues requirements.packages;
}
requirements.nix was the output of pypi2nix and requirements.packages has type "list of derivations". Despite this when I cd into the resulting store path for Rednotebook there is a /bin directory with some wrapper scripts. The store path for my app there is just a lib an no /bin
How do I tell Nixpkgs that I have an application?
There are buildPythonPackage and buildPythonApplication functions, but at the end of the day, they both call mkPythonDerivation.
A Python application with a simple Nix package you can reference is Ranger; which uses buildPythonApplication. The resulting derivation contains a wrapper in /nix/store/PACKAGE/bin/
Was experimenting with building and installing a sample service written in Python.
Ended up using buildPythonApplication in my installer
Important points
If you are leveraging setuptools to distribute your app you need to have the entry_points value in your setup call:
from distutils.core import setup
setup(
...
entry_points = {
'console_scripts': ['sample_module = src.app:main']
}
src - source code folder
app - entry point module name
main - name of the entry point function
My whole build configuration was:
# sample.nix
with (import <nixpkgs> {});
python37.pkgs.buildPythonApplication rec {
pname = "sample_service";
version = "0.0.3";
src = ./sample_package;
meta = with lib; {
homepage = "https://www.example.com";
description = "Sample Python Service";
};
}
sample_package was the folder that contained 'src' folder and 'setup.py' located at the same level as above 'sample.nix' file.
At this point, if you run nix-build sample.nix it will build and install the package for you. However, to make it available on the path you will need to capture the resulting path in the nix store and run:
nix-env -i <nix_store_path>
buildPythonPackage is to be used for libraries, that is, when you want it to expose its modules in site-packages. buildPythonApplication is for applications that just happen to be written in Python. In that case, when you include such a derivation in another derivation, you don't want to expose the libraries.
This separation is important because it may happen that a Python 3 environment calls a tool that is written in Python 2 and vice versa.
Note that at the time of writing this issue hasn't been completely solved yet, but at least python.buildEnv or python.withPackages will not include applications along with their dependencies.
I am trying to convert a python game (made with pygame) into a exe file for windows, and I did using cx_Freeze. No problems there.
The thing is that when I launch myGame.exe, it opens the normal Pygame window and a console window(which I do not want).
Is there a way to remove the console window? I read most of the documentation, but I saw nothing really (except base, but I don't get what that is).
BTW, here is my setup file:
import cx_Freeze
exe = [cx_Freeze.Executable("myGame.py")]
cx_Freeze.setup(
name = "GameName",
version = "1.0",
options = {"build_exe": {"packages": ["pygame", "random", "ConfigParser", "sys"], "include_files": [
"images", "settings.ini", "arialbd.ttf"]}},
executables = exe
)
Here's a screen shot of what happens when I launch the exe:
So what was wrong, was that the setup.py file was missing a parameter.
What you need to add is base = "Win32GUI" to declare that you do not need a console window upon launch of the application.
Here's the code:
import cx_Freeze
exe = [cx_Freeze.Executable("myGame.py", base = "Win32GUI")] # <-- HERE
cx_Freeze.setup(
name = "GameName",
version = "1.0",
options = {"build_exe": {"packages": ["pygame", "random", "ConfigParser", "sys"],
"include_files": ["images", "settings.ini", "arialbd.ttf"]}},
executables = exe
)
The parameter can be passed also by the shell if you are making a quick executable
like this:
cxfreeze my_program.py --base-name=WIN32GUI
I want to build a cross-platform application ,I used a windows API called SHOpenFolderAndSelectItems(). Although I found example called it by pywin32,but pywin32 is not available on Linux , I don't want to call a Windows API on linux,just don't want to make another code version for Linux,so I wonder how to access it by ctypes? yes,this API cannot be called on Linux ,I just want to make it silent in the code so that I can freeze the Python scripts into executables by cx_Freeze without pywin32 module-missing error happend .
from win32com.shell import shell, shellcon
import os
def launch_file_explorer(path, files):
'''
Given a absolute base path and names of its children (no path), open
up one File Explorer window with all the child files selected
'''
folder_pidl = shell.SHILCreateFromPath(path,0)[0]
desktop = shell.SHGetDesktopFolder()
shell_folder = desktop.BindToObject(folder_pidl, None,shell.IID_IShellFolder)
name_to_item_mapping = dict([(desktop.GetDisplayNameOf(item, shellcon.SHGDN_FORPARSING|shellcon.SHGDN_INFOLDER), item) for item in shell_folder])
print(name_to_item_mapping)
to_show = []
for file in files:
if file in name_to_item_mapping:
to_show.append(name_to_item_mapping[file])
# else:
# raise Exception('File: "%s" not found in "%s"' % (file, path))
shell.SHOpenFolderAndSelectItems(folder_pidl, to_show, 0)
p=r'E:\aa'
print(os.listdir(p))
launch_file_explorer(p, os.listdir(p))
Installed docx on Windows 7 here:
D:\Program Files (x86)\Python27\Lib\site-packages as shown below:
Installed docx on OS X at /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/docx-0.0.2-py2.7.egg-info as shown below:
Following is the sample script (named as docx_example.py), which runs absolutely fine on the python interpreter:
#!/usr/bin/env python
'''
This file makes an docx (Office 2007) file from scratch, showing off most of python-docx's features.
If you need to make documents from scratch, use this file as a basis for your work.
Part of Python's docx module - http://github.com/mikemaccana/python-docx
See LICENSE for licensing information.
'''
from docx import *
if __name__ == '__main__':
# Default set of relationshipships - these are the minimum components of a document
relationships = relationshiplist()
# Make a new document tree - this is the main part of a Word document
document = newdocument()
# This xpath location is where most interesting content lives
docbody = document.xpath('/w:document/w:body', namespaces=nsprefixes)[0]
# Append two headings and a paragraph
docbody.append(heading('''Welcome to Python's docx module''',1) )
docbody.append(heading('Make and edit docx in 200 lines of pure Python',2))
docbody.append(paragraph('The module was created when I was looking for a Python support for MS Word .doc files on PyPI and Stackoverflow. Unfortunately, the only solutions I could find used:'))
# Add a numbered list
for point in ['''COM automation''','''.net or Java''','''Automating OpenOffice or MS Office''']:
docbody.append(paragraph(point,style='ListNumber'))
docbody.append(paragraph('''For those of us who prefer something simpler, I made docx.'''))
docbody.append(heading('Making documents',2))
docbody.append(paragraph('''The docx module has the following features:'''))
# Add some bullets
for point in ['Paragraphs','Bullets','Numbered lists','Multiple levels of headings','Tables','Document Properties']:
docbody.append(paragraph(point,style='ListBullet'))
docbody.append(paragraph('Tables are just lists of lists, like this:'))
# Append a table
docbody.append(table([['A1','A2','A3'],['B1','B2','B3'],['C1','C2','C3']]))
docbody.append(heading('Editing documents',2))
docbody.append(paragraph('Thanks to the awesomeness of the lxml module, we can:'))
for point in ['Search and replace','Extract plain text of document','Add and delete items anywhere within the document']:
docbody.append(paragraph(point,style='ListBullet'))
# Search and replace
print 'Searching for something in a paragraph ...',
if search(docbody, 'the awesomeness'): print 'found it!'
else: print 'nope.'
print 'Searching for something in a heading ...',
if search(docbody, '200 lines'): print 'found it!'
else: print 'nope.'
print 'Replacing ...',
docbody = replace(docbody,'the awesomeness','the goshdarned awesomeness')
print 'done.'
# Add a pagebreak
docbody.append(pagebreak(type='page', orient='portrait'))
docbody.append(heading('Ideas? Questions? Want to contribute?',2))
docbody.append(paragraph('''Email <python.docx#librelist.com>'''))
# Create our properties, contenttypes, and other support files
coreprops = coreproperties(title='Python docx demo',subject='A practical example of making docx from Python',creator='Mike MacCana',keywords=['python','Office Open XML','Word'])
appprops = appproperties()
contenttypes = contenttypes()
websettings = websettings()
wordrelationships = wordrelationships(relationships)
# Save our document
savedocx(document,coreprops,appprops,contenttypes,websettings,wordrelationships,'docx_example.docx')
Following is the setup script (named as docx_setup.py) to create the standalone (.app in Mac OSX and .exe in Windows 7):
import sys,os
# Globals: START
main_script='docx_example'
dist_dir_main_path=os.path.abspath('./docx-bin')
compression_level=2
optimization_level=2
bundle_parameter=1
skip_archive_parameter=False
emulation_parameter=False
module_cross_reference_parameter=False
ascii_parameter=False
includes_list=['lxml.etree','lxml._elementpath','gzip']
# Globals: STOP
# Global Functions: START
def isDarwin():
return sys.platform=='darwin'
def isLinux():
return sys.platform=='linux2'
def isWindows():
return os.name=='nt'
# Global Functions: STOP
if isDarwin():
from setuptools import setup
# Setup distribution directory: START
dist_dir=os.path.abspath('%s/osx' %(dist_dir_main_path))
if os.path.exists(dist_dir):
os.system('rm -rf %s' %(dist_dir))
os.system('mkdir -p %s' %(dist_dir))
# Setup distribution directory: STOP
APP = ['%s.py' %(main_script)]
OPTIONS={'argv_emulation': False,
'dist_dir': dist_dir,
'includes': includes_list
}
print 'Creating standalone now...'
setup(app=APP,options={'py2app': OPTIONS},setup_requires=['py2app'])
os.system('rm -rf build')
os.system('tar -C %s -czf %s/%s.tgz %s.app' %(dist_dir,dist_dir,main_script,main_script))
os.system('rm -rf %s/%s.app' %(dist_dir,main_script))
print 'Re-distributable Standalone file(s) created at %s/%s.zip. Unzip and start using!!!' %(dist_dir,main_script)
elif isWindows():
from distutils.core import setup
import py2exe
# Setup distribution directory: START
dist_dir=os.path.abspath('%s/win' %(dist_dir_main_path))
if os.path.exists(dist_dir):
os.system('rmdir /S /Q %s' %(dist_dir))
os.system('mkdir %s' %(dist_dir))
# Setup distribution directory: STOP
OPTIONS={'compressed': compression_level,
'optimize': optimization_level,
'bundle_files': bundle_parameter,
'dist_dir': dist_dir,
'xref': module_cross_reference_parameter,
'skip_archive': skip_archive_parameter,
'ascii': ascii_parameter,
'custom_boot_script': '',
'includes': includes_list
}
print 'Creating standalone now...'
setup(options = {'py2exe': OPTIONS},zipfile = None,windows=[{'script': '%s.py' %(main_script)}])
print 'Re-distributable Standalone file(s) created in the following location: %s' %(dist_dir)
os.system('rmdir /S /Q build')
Now comes the real problem.
Following is the error posted on Mac OS X console after trying to use the docx_example.app, created using the command python docx_setup.py py2app:
docx_example: Searching for something in a paragraph ... found it!
docx_example: Searching for something in a heading ... found it!
docx_example: Replacing ... done.
docx_example: Traceback (most recent call last):
docx_example: File "/Users/admin/docx-bin/osx/docx_example.app/Contents/Resources/__boot__.py", line 64, in <module>
docx_example: _run('docx_example.py')
docx_example: File "/Users/admin/docx-bin/osx/docx_example.app/Contents/Resources/__boot__.py", line 36, in _run
docx_example: execfile(path, globals(), globals())
docx_example: File "/Users/admin/docx-bin/osx/docx_example.app/Contents/Resources/docx_example.py", line 75, in <module>
docx_example: savedocx(document,coreprops,appprops,contenttypes,websettings,wordrelationships,'docx_example.docx')
docx_example: File "docx.pyc", line 849, in savedocx
docx_example: AssertionError
docx_example: docx_example Error
docx_example Exited with code: 255
Following is the error posted in docx_example.exe.log file in Windows 7 after trying to use the docx_example.exe, created using the command python docx_setup.py py2exe:
Traceback (most recent call last):
File "docx_example.py", line 75, in <module>
File "docx.pyo", line 854, in savedocx
WindowsError: [Error 3] The system cannot find the path specified: 'D:\\docx_example\\docx_example.exe\\template'
As you can see, both OS X and Windows 7 are referring to something similar here. Please help.
i have found a solution
in api.py
From
_thisdir = os.path.split(__file__)[0]
To
_thisdir = 'C:\Python27\Lib\site-packages\docx'
Or whatever your docx file is
What's going on (at least for py2exe) is something similar to this question.
The documentation on data_files is here.
What you basically have to do is change
setup(options = {'py2exe': OPTIONS},zipfile = None,windows=[{'script': '%s.py' %(main_script)}])
to
data_files = [
('template', 'D:/Program Files (x86)/Python27/Lib/site-packages/docx-template/*'),
]
setup(
options={'py2exe': OPTIONS},
zipfile=None,
windows=[{'script': '%s.py' %(main_script)}],
data_files=data_files
)
The exact place where the template files are may be wrong above, so you might need to adjust it.
But there may be several other sets of data_files you need to include. You may want to go about retrieving them programatically with an os.listdir or os.walk type of command.
As mentioned in the other post, you will also have to change
bundle_parameter=1
to
bundle_parameter=2
at the top of the file.
You can solve the entire problem by using this API which is based in python-docx. The advantage of the API is that this one doesnt have the savedoc function so you will not have any other AssertionError.
For the WindowsError: [Error 3] The system cannot find the path specified: 'D:\\docx_example\\docx_example.exe\\template' error you need to edit the api.py file of docx egg folder which is located in the Python folder of the system (in my computer: C:\Python27\Lib\site-packages\python_docx-0.3.0a5-py2.7.egg\docx)
Changing this:
_thisdir = os.path.split(__file__)[0]
_default_docx_path = os.path.join(_thisdir, 'templates', 'default.docx')
To this:
thisdir = os.getcwd()
_default_docx_path = os.path.join(thisdir, 'templates', 'default.docx')
The first one was taking the actual running program and adding it to the path to locate the templates folder.
C:\myfiles\myprogram.exe\templates\default.docx
The solution takes only the path, not the running program.
C:\myfiles\templates\default.docx
Hope it helps!
Instead of changing some library file, I find it easier and cleaner to tell python-docx explicitly where to look for the template, i.e.:
document = Document('whatever/path/you/choose/to/some.docx')
This effectively solves the py2exe and docx path problem.