I recently downloaded the VSL compiler developed by Matthieu Amiguet (http://www.matthieuamiguet.ch/pages/compilateurs) to learn how to compile with Python PLY. In the README it says to type python setup install. I readapted the code to work in python 3. Here is what I got as an error:
Here is setup.py
import sys, os, shutil
def install():
print ('Installing...')
if not os.path.exists(vsldir): os.mkdir(vsldir)
pyfiles = [f for f in os.listdir('VDK/src/') if not os.path.isdir(f) and f.endswith('.py')]
for p in pyfiles:
shutil.copy('VDK/src/'+p,vsldir)
shutil.copy('VDK/bin/vslc',INSTALLDIR)
shutil.copy('VRE/vsl',INSTALLDIR)
shutil.copy('VRE/vsl',INSTALLDIR)
shutil.copy('vmake/vmake',INSTALLDIR)
os.chmod(INSTALLDIR+'vslc',111)
os.chmod(INSTALLDIR+'vsl',111)
os.chmod(INSTALLDIR+'vmake',111)
print ('Installed!')
def uninstall():
print ('Desinstalling...')
if os.path.exists(vsldir): os.system('rm -R '+vsldir)
if os.path.exists(INSTALLDIR+'vslc'): os.system('rm '+INSTALLDIR+'vslc')
if os.path.exists(INSTALLDIR+'vsl'): os.system('rm '+INSTALLDIR+'vsl')
if os.path.exists(INSTALLDIR+'vsl'): os.system('rm '+INSTALLDIR+'vmake')
print ('Desinstalled!')
def printHelp():
print ('''usage : python setup.py COMMANDE
- install : installation of the compiler and runtime environement
- uninstall : uninstall the compiler et the runtime environement
(this two last command need root password)''')
if __name__ == '__main__':
pythonpath = [path for path in sys.path if path.find('python')!=-1 and path.find('site-packages')!=-1]
print ('========================================'.center(80))
print ('===== VSL Compiler ====='.center(80))
print ('===== David Jacod , Anthony Mougin ====='.center(80))
print ('========================================'.center(80))
if len(pythonpath)==0:
print (' * No python path found. Installation failed')
sys.exit(-1)
if os.name=='posix': INSTALLDIR = '/usr/local/bin/'
elif os.name=='nt': INSTALLDIR = 'c:/VSLCompiler/'
pythonpath=pythonpath[0]
vsldir = pythonpath+'/vslcomp/'
if len(sys.argv)<=2:
if sys.argv[1]=='install': install()
elif sys.argv[1]=='uninstall': uninstall()
else: printHelp()
else:
printHelp()
I am planning a command line Python application that I intend to distribute through PyPi.
When the application is installed with pip, I want to create a user-editable configuration file in the appropriate location on the user's filesystem.
For example, in Ubuntu, the file would be something like ~/.config/foo/config.ini
On installation I want to create the file (if possible) and be able to specify another config file to use instead with a command line parameter.
What is the usual scheme for getting this done?
I think appdirs package on PyPI is what you need, isn’t it?
You should use the appdirs module for this as it reliably handles differences across different platforms:
>>> from appdirs import user_config_dir
>>> appname = "SuperApp"
>>> appauthor = "Acme"
>>> user_config_dir(appname)
'/home/trentm/.config/SuperApp'
A project such as platformdirs can help with such a task. It implements Freedesktop's "XDG Base Directory Specification".
Don't create the file at installation time though. It is preferable to create the file when it is actually needed, this might be during the first run of the application for example.
Something like the following should get you started with the configuration directory:
>>> import platformdirs
>>> platformdirs.user_config_dir('foo')
'/home/sinoroc/.config/foo'
Or without external dependency, it could roughly look like this:
#!/usr/bin/env python3
import argparse
import os
import pathlib
import platform
def get_config_file_path(project_name, file_name):
path = None
config_path = None
platform_system = platform.system()
if platform_system == 'Windows':
if 'APPDATA' in os.environ:
config_path = pathlib.Path(os.environ['APPDATA'])
else:
config_path = pathlib.Path.home().joinpath('AppData', 'Roaming')
elif platform_system == 'Linux':
if 'XDG_CONFIG_HOME' in os.environ:
config_path = pathlib.Path(os.environ['XDG_CONFIG_HOME'])
else:
config_path = pathlib.Path.home().joinpath('.config')
if config_path:
path = config_path.joinpath(project_name, file_name)
return path
def main():
default_config_file_path = get_config_file_path('foo', 'config.ini')
args_parser = argparse.ArgumentParser()
args_parser.add_argument(
'--config', '-c',
default=str(default_config_file_path),
type=argparse.FileType('r'),
)
args = args_parser.parse_args()
if __name__ == '__main__':
main()
I am trying to figure out what is causing this file called builder.py to not run on mac even though it runs on windows. Code:
import cffi
import glob
import platform
# relative to build dir
LIB_BASE = '../libs/'
# compiling libraries statically to get a single binary
EXTRA_SRC = [LIB_BASE + 'subhook/subhook.c']
pltsysname = {'Windows': 'win32', 'Darwin': 'osx', 'Linux': 'elf'}
pltsrc = pltsysname[platform.system()]
pltsrc = LIB_BASE + 'plthook/plthook_{}.c'.format(pltsrc)
# EXTRA_SRC.append(pltsrc) # disabled until it is actually useful
LIBDIRS = []
if platform.system() == 'Windows':
LIBDIRS.append('../libs/SDL/lib/x86/')
CDEFS = 'generated internals SDL XDL subhook xternPython'.split()
def readfile(name):
with open(name, 'r') as f:
content = f.read()
return content
def build():
ffibuilder = cffi.FFI()
for fname in CDEFS:
ffibuilder.cdef(readfile('cdefs/{}.h'.format(fname)))
ffibuilder.embedding_api('uint32_t kickstart();')
ffibuilder.embedding_init_code(readfile('remote.py'))
ffibuilder.set_source(
'_remote', readfile('cdefs/remote.c'), sources=EXTRA_SRC,
libraries=['SDL2'], library_dirs=LIBDIRS,
define_macros=[('SUBHOOK_STATIC', None)])
ffibuilder.compile(tmpdir='build', target='remote.bin')
if __name__ == '__main__':
build()
When ever I run it I expect it to run but instead it comes up with the following error:
Traceback (most recent call last):
File "/Users/alexanderlee/Desktop/sbpe-1.6.1/builder.py", line 1, in <module>
import cffi
ModuleNotFoundError: No module named 'cffi'
>>>
How do I fix it?
It's probably because you only installed cffi on your Windows, so you probably need to install it on your Mac also.
You can follow rules on the docs:
pip install cffi
cffi is a third-party module. It's installed on your Windows computer but not on your Mac.
I got this error when run test.py
C:\Python32>python.exe test.py
Traceback (most recent call last):
File "test.py", line 5, in <module>
import httplib
ImportError: No module named httplib
How to correct it?
Code block for test.py:
#!/usr/local/bin/python
import httplib
import sys
import re
from HTMLParser import HTMLParser
class miniHTMLParser( HTMLParser ):
viewedQueue = []
instQueue = []
def get_next_link( self ):
if self.instQueue == []:
return ''
else:
return self.instQueue.pop(0)
def gethtmlfile( self, site, page ):
try:
httpconn = httplib.HTTPConnection(site)
httpconn.request("GET", page)
resp = httpconn.getresponse()
resppage = resp.read()
except:
resppage = ""
return resppage
def handle_starttag( self, tag, attrs ):
if tag == 'a':
newstr = str(attrs[0][1])
if re.search('http', newstr) == None:
if re.search('mailto', newstr) == None:
if re.search('htm', newstr) != None:
if (newstr in self.viewedQueue) == False:
print (" adding", newstr)
self.instQueue.append( newstr )
self.viewedQueue.append( newstr )
else:
print (" ignoring", newstr)
else:
print (" ignoring", newstr)
else:
print (" ignoring", newstr)
def main():
if sys.argv[1] == '':
print ("usage is ./minispider.py site link")
sys.exit(2)
mySpider = miniHTMLParser()
link = sys.argv[2]
while link != '':
print ("\nChecking link ", link)
# Get the file from the site and link
retfile = mySpider.gethtmlfile( sys.argv[1], link )
# Feed the file into the HTML parser
mySpider.feed(retfile)
# Search the retfile here
# Get the next link in level traversal order
link = mySpider.get_next_link()
mySpider.close()
print ("\ndone\n")
if __name__ == "__main__":
main()
You are running Python 2 code on Python 3. In Python 3, the module has been renamed to http.client.
You could try to run the 2to3 tool on your code, and try to have it translated automatically. References to httplib will automatically be rewritten to use http.client instead.
you can just import http.client and rename it to httplib with this code :
import http.client as httplib
If you use PyCharm, please change you 'Project Interpreter' to '2.7.x'
I had this issue when I was trying to make my Docker container smaller. It was because I'd installed Python 2.7 with:
apt-get install -y --no-install-recommends python
And I should not have included the --no-install-recommends flag:
apt-get install -y python
I want to create a start menu or Desktop shortcut for my Python windows installer package. I am trying to follow https://docs.python.org/3.4/distutils/builtdist.html#the-postinstallation-script
Here is my script;
import sys
from os.path import dirname, join, expanduser
pyw_executable = sys.executable.replace('python.exe','pythonw.exe')
script_file = join(dirname(pyw_executable), 'Scripts', 'tklsystem-script.py')
w_dir = expanduser(join('~','lsf_files'))
print(sys.argv)
if sys.argv[1] == '-install':
print('Creating Shortcut')
create_shortcut(
target=pyw_executable,
description='A program to work with L-System Equations',
filename='L-System Tool',
arguments=script_file,
workdir=wdir
)
I also specified this script in scripts setup option, as indicated by aforementioned docs.
Here is the command I use to create my installer;
python setup.py bdist_wininst --install-script tklsystem-post-install.py
After I install my package using created windows installer, I can't find where my shorcut is created, nor I can confirm whether my script run or not?
How can I make setuptools generated windows installer to create desktop or start menu shortcuts?
Like others have commented here and elsewhere the support functions don't seem to work at all (at least not with setuptools). After a good day's worth of searching through various resources I found a way to create at least the Desktop shortcut. I'm sharing my solution (basically an amalgam of code I found here and here). I should add that my case is slightly different from yasar's, because it creates a shortcut to an installed package (i.e. an .exe file in Python's Scripts directory) instead of a script.
In short, I added a post_install function to my setup.py, and then used the Python extensions for Windows to create the shortcut. The location of the Desktop folder is read from the Windows registry (there are other methods for this, but they can be unreliable if the Desktop is at a non-standard location).
#!/usr/bin/env python
import os
import sys
import sysconfig
if sys.platform == 'win32':
from win32com.client import Dispatch
import winreg
def get_reg(name,path):
# Read variable from Windows Registry
# From https://stackoverflow.com/a/35286642
try:
registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0,
winreg.KEY_READ)
value, regtype = winreg.QueryValueEx(registry_key, name)
winreg.CloseKey(registry_key)
return value
except WindowsError:
return None
def post_install():
# Creates a Desktop shortcut to the installed software
# Package name
packageName = 'mypackage'
# Scripts directory (location of launcher script)
scriptsDir = sysconfig.get_path('scripts')
# Target of shortcut
target = os.path.join(scriptsDir, packageName + '.exe')
# Name of link file
linkName = packageName + '.lnk'
# Read location of Windows desktop folder from registry
regName = 'Desktop'
regPath = r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders'
desktopFolder = os.path.normpath(get_reg(regName,regPath))
# Path to location of link file
pathLink = os.path.join(desktopFolder, linkName)
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(pathLink)
shortcut.Targetpath = target
shortcut.WorkingDirectory = scriptsDir
shortcut.IconLocation = target
shortcut.save()
setup(name='mypackage',
...,
...)
if sys.argv[1] == 'install' and sys.platform == 'win32':
post_install()
Here's a link to a full setup script in which I used this:
https://github.com/KBNLresearch/iromlab/blob/master/setup.py
If you want to confirm whether the script is running or not, you can print to a file instead of the console. Looks like text you print to console in the post-install script won't show up.
Try this:
import sys
from os.path import expanduser, join
pyw_executable = join(sys.prefix, "pythonw.exe")
shortcut_filename = "L-System Toolsss.lnk"
working_dir = expanduser(join('~','lsf_files'))
script_path = join(sys.prefix, "Scripts", "tklsystem-script.py")
if sys.argv[1] == '-install':
# Log output to a file (for test)
f = open(r"C:\test.txt",'w')
print('Creating Shortcut', file=f)
# Get paths to the desktop and start menu
desktop_path = get_special_folder_path("CSIDL_COMMON_DESKTOPDIRECTORY")
startmenu_path = get_special_folder_path("CSIDL_COMMON_STARTMENU")
# Create shortcuts.
for path in [desktop_path, startmenu_path]:
create_shortcut(pyw_executable,
"A program to work with L-System Equations",
join(path, shortcut_filename),
script_path,
working_dir)
At least with Python 3.6.5, 32bit on Windows, setuptools does work for this. But based on the accepted answer, by trial and error I found some issues that may have caused your script to fail to do what you wanted.
create_shortcut does not accept keyword arguments, only positional, so its usage in your code is invalid
You must add a .lnk extension for Windows to recognise the shortcut
I found sys.executable will be the name of the installer executable, not the python executable
As mentioned, you can't see stdout or stderr so you might want to log to a text file. I would suggest also redirecting sys.stdout and sys.stderr to the log file.
(Maybe not relevant) as mentioned in this question there appears to be a bug with the version string generated by bdist_wininst. I used the hexediting hack from an answer there to work around this. The location in the answer is not the same, you have to find the -32 yourself.
Full example script:
import sys
import os
import datetime
global datadir
datadir = os.path.join(get_special_folder_path("CSIDL_APPDATA"), "mymodule")
def main(argv):
if "-install" in argv:
desktop = get_special_folder_path("CSIDL_DESKTOPDIRECTORY")
print("Desktop path: %s" % repr(desktop))
if not os.path.exists(datadir):
os.makedirs(datadir)
dir_created(datadir)
print("Created data directory: %s" % repr(datadir))
else:
print("Data directory already existed at %s" % repr(datadir))
shortcut = os.path.join(desktop, "MyModule.lnk")
if os.path.exists(shortcut):
print("Remove existing shortcut at %s" % repr(shortcut))
os.unlink(shortcut)
print("Creating shortcut at %s...\n" % shortcut)
create_shortcut(
r'C:\Python36\python.exe',
"MyModuleScript",
shortcut,
"",
datadir)
file_created(shortcut)
print("Successfull!")
elif "-remove" in sys.argv:
print("Removing...")
pass
if __name__ == "__main__":
logfile = r'C:\mymodule_install.log' # Fallback location
if os.path.exists(datadir):
logfile = os.path.join(datadir, "install.log")
elif os.environ.get("TEMP") and os.path.exists(os.environ.get("TEMP"),""):
logfile = os.path.join(os.environ.get("TEMP"), "mymodule_install.log")
with open(logfile, 'a+') as f:
f.write("Opened\r\n")
f.write("Ran %s %s at %s" % (sys.executable, " ".join(sys.argv), datetime.datetime.now().isoformat()))
sys.stdout = f
sys.stderr = f
try:
main(sys.argv)
except Exception as e:
raise
f.close()
sys.exit(0)
UPD: on an off chance that the client machine has pywin32 installed, we try in-process creation first. Somewhat cleaner that way.
Here is another take. This assumes the package is called myapp, and that also becomes the executable that you want a shortcut to. Substitute your own package name and your own shortcut text.
Uses a Windows Scripting Host COM class - in process if possible, inside a Powershell command line as a subprocess if not. Tested on Python 3.6+.
from setuptools import setup
from setuptools.command.install import install
import platform, sys, os, site
from os import path, environ
def create_shortcut_under(root, exepath):
# Root is an env variable name -
# either ALLUSERSPROFILE for the all users' Start menu,
# or APPDATA for the current user specific one
profile = environ[root]
linkpath = path.join(profile, "Microsoft", "Windows", "Start Menu", "Programs", "My Python app.lnk")
try:
from win32com.client import Dispatch
from pywintypes import com_error
try:
sh = Dispatch('WScript.Shell')
link = sh.CreateShortcut(linkpath)
link.TargetPath = exepath
link.Save()
return True
except com_error:
return False
except ImportError:
import subprocess
s = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + linkpath + "');$s.TargetPath='" + exepath + "';$s.Save()"
return subprocess.call(['powershell', s], stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) == 0
def create_shortcut(inst):
try:
exepath = path.join(path.dirname(sys.executable), "Scripts", "myapp.exe")
if not path.exists(exepath):
# Support for "pip install --user"
exepath = path.join(path.dirname(site.getusersitepackages()), "Scripts", "myapp.exe")
# If can't modify the global menu, fall back to the
# current user's one
if not create_shortcut_under('ALLUSERSPROFILE', exepath):
create_shortcut_under('APPDATA', exepath)
except:
pass
class my_install(install):
def run(self):
install.run(self)
if platform.system() == 'Windows':
create_shortcut(self)
#...
setup(
#...
cmdclass={'install': my_install},
entry_points={"gui_scripts": ["myapp = myapp.__main__:main"]},