Change output directory in setup.py - python

I'm using setup from setuptools to create a setup.py, and I was wondering if it's possible to change the output directory programmatically to change it from dist/.
I'm aware that you can do this from the command line using the --dist-dir flag, but I want to be able to do from within the setup.py file instead.
Anyone have any ideas?

You need to override code that set the default name:
from distutils.command.bdist import bdist as _bdist
from distutils.command.sdist import sdist as _sdist
dist_dir = 'my-dist-dir'
class bdist(_bdist):
def finalize_options(self):
_bdist.finalize_options(self)
self.dist_dir = dist_dir
class sdist(_sdist):
def finalize_options(self):
_sdist.finalize_options(self)
self.dist_dir = dist_dir
setup(
cmdclass={
'bdist': bdist,
'sdist': sdist,
},
…
)
Other bdist_* commands copy the value from bdist.

Related

How to make a executable using Panda3D and Pyinstaller in Python?

I'm trying to make an executable with this code(only for testing):
from panda3d.core import loadPrcFile
from direct.showbase.ShowBase import ShowBase
class Game(ShowBase):
def __init__(self):
ShowBase.__init__(self)
def main() -> None:
loadPrcFile('file.prc')
Game().run()
if __name__ == '__main__':
main()
when I try to make it up with pyinstaller I get this:
Warning: unable to auto-locate config files in directory named by "<auto>etc".
Don't use pyinstaller, Panda3D is configured for setuptools.
Create a requirements.txt file, in this file add: Panda3D
Than create a setup.py file, in this file add the following code:
from setuptools import setup
setup(
name="tester",
options = {
'build_apps': {
'include_patterns': [
'**/*.png',
'**/*.jpg',
'**/*.egg',
],
'gui_apps': {
'tester': 'main.py',
},
'log_append': False,
'plugins': [
'pandagl',
'p3openal_audio',
],
'platforms':['win_amd64']
}
}
)
Both files the requirements.txt and the setup.py should be in the folder where your Panda3D files are.
Don't forget to change tester: to_your_file_name.py in setup.py file.
Open a cmd window in the folder where the setup.py file is.
Run this command in your cmd:
python setup.py build_apps
This will create a windows 64 bit executable from yor Panda3D application in the build folder. There you will find the tester.exe file.
If you are using 3D models with textures, make sure they are also copied next to the executable file.
If you want to learn more check out the docs: https://docs.panda3d.org/1.10/python/distribution/index

reading "--plat-name" argument in setup.py

The setuptools bdist_wheel/bdist_egg commands have a --plat-name argument that allows for overriding the host platform name. This value gets tacked onto the name of the resulting file, e.g., mypackage-1.2.3-py2.py3-none-manylinux1_x86_64.whl.
How can I read this value in setup.py? Note I'm not asking for the host platform the script is running on, e.g., platform.system(). I want the platform name that setuptools is using.
In bdist_egg (and only it; bdist_wheel just runs bdist_egg) --plat-name argument is stored in self.plat_name. So you can override bdist_egg with your custom class and use self.plat_name:
from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
from setuptools import setup
class bdist_egg(_bdist_egg):
def run(self):
# Use self.plat_name before building an egg…
_bdist_egg.run(self)
# …or after
setup(
…
cmdclass={
'bdist_egg': bdist_egg,
},
…
)

Generating files for sdist

I'm looking for a way to generate and include a file into the package created by sdist/wheel.
Is there some way to hook into the process to create a new file that will be picked up during the build.
To build a file during build phase override cmdclass. See https://stackoverflow.com/a/43728788/7976758:
import distutils.command.build
# Override build command
class BuildCommand(distutils.command.build.build):
def run(self):
# Run the original build command
distutils.command.build.build.run(self)
# Custom build stuff goes here
# Replace the build command with ours
setup(...,
cmdclass={"build": BuildCommand})
To include a non-code file in a sdist list in in MANIFEST or MANIFEST.in. See https://docs.python.org/3/distutils/sourcedist.html#specifying-the-files-to-distribute
To include a non-code file in a wheel list it as package_data in your setup.py. See https://docs.python.org/3/distutils/setupscript.html#installing-package-data:
setup(...,
packages=['mypkg'],
package_data={'mypkg': ['*.dat']},
)

How to include (script-built) libraries with package installation?

I am making a Python package that has a C++-extension module and someone else's shared library that it requires. I want everything installable via pip. My current setup.py file works when I use pip install -e . but when I don't use develop mode (e.i. omit the -e) I get "cannot open shared object file" when importing the module in Python. I believe the reason is that setuptools doesn't consider the shared library to be part of my package, so the relative link to the library is broken during installation when files are copied to the install directory.
Here is what my setup.py file looks like:
from setuptools import setup, Extension, Command
import setuptools.command.develop
import setuptools.command.build_ext
import setuptools.command.install
import distutils.command.build
import subprocess
import sys
import os
# This function downloads and builds the shared-library
def run_clib_install_script():
build_clib_cmd = ['bash', 'clib_install.sh']
if subprocess.call(build_clib_cmd) != 0:
sys.exit("Failed to build C++ dependencies")
# I make a new command that will build the shared-library
class build_clib(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
run_clib_install_script()
# I subclass install so that it will call my new command
class install(setuptools.command.install.install):
def run(self):
self.run_command('build_clib')
setuptools.command.install.install.run(self)
# I do the same for build...
class build(distutils.command.build.build):
sub_commands = [
('build_clib', lambda self: True),
] + distutils.command.build.build.sub_commands
# ...and the same for develop
class develop(setuptools.command.develop.develop):
def run(self):
self.run_command('build_clib')
setuptools.command.develop.develop.run(self)
# These are my includes...
# note that /clib/include only exists after calling clib_install.sh
cwd = os.path.dirname(os.path.abspath(__file__))
include_dirs = [
cwd,
cwd + '/clib/include',
cwd + '/common',
]
# These are my arguments for the compiler to my shared-library
lib_path = os.path.join(cwd, "clib", "lib")
library_dirs = [lib_path]
link_args = [os.path.join(lib_path, "libclib.so")]
# My extension module gets these arguments so it can link to clib
mygen_module = Extension('mygen',
language="c++14",
sources=["common/mygen.cpp"],
libraries=['clib'],
extra_compile_args=['-std=c++14'],
include_dirs=include_dirs,
library_dirs=library_dirs,
extra_link_args=link_args
+ ['-Wl,-rpath,$ORIGIN/../clib/lib'])
# I use cmdclass to override the default setuptool commands
setup(name='mypack',
cmdclass = {'install': install,
'build_clib': build_clib, 'build': build,
'develop': develop},
packages=['mypack'],
ext_package='mypack',
ext_modules=[mygen_module],
# package_dir={'mypack': '.'},
# package_data={'mypack': ['docs/*md']},
include_package_data=True)
I subclass some of the setuptools commands in order to build the shared-library before it compiles the extension. clib_install.sh is a bash script that locally downloads and builds the shared library in /clib, creating the headers (in /clib/include) and .so file (in /clib/lib). To solve problems with linking to shared-library dependencies I used $ORIGIN/../clib/lib as a link argument so that the absolute path to clib isn't needed.
Unfortunately, the /clib directory doesn't get copied to the install location. I tried tinkering with package_data but it didn't copy my directory over. In fact, I don't even know what pip/setuptools does with /clib after the script is called, I guess it is made in some temporary build directory and gets deleted after. I am not sure how to get /clib to where it needs to be after it is made.
package_data={
'mypack': [
'clib/include/*.h',
'clib/lib/*.so',
'docs/*md',
]
},

Running custom setuptools build during install

I've tried to implement Compass compiling during setuptools' build, but the following code runs compilation during explicit build command and doesn't runs during install.
#!/usr/bin/env python
import os
import setuptools
from distutils.command.build import build
SETUP_DIR = os.path.dirname(os.path.abspath(__file__))
class BuildCSS(setuptools.Command):
description = 'build CSS from SCSS'
user_options = []
def initialize_options(self):
pass
def run(self):
os.chdir(os.path.join(SETUP_DIR, 'django_project_dir', 'compass_project_dir'))
import platform
if 'Windows' == platform.system():
command = 'compass.bat compile'
else:
command = 'compass compile'
import subprocess
try:
subprocess.check_call(command.split())
except (subprocess.CalledProcessError, OSError):
print 'ERROR: problems with compiling Sass. Is Compass installed?'
raise SystemExit
os.chdir(SETUP_DIR)
def finalize_options(self):
pass
class Build(build):
sub_commands = build.sub_commands + [('build_css', None)]
setuptools.setup(
# Custom attrs here.
cmdclass={
'build': Build,
'build_css': BuildCSS,
},
)
Any custom instructions at Build.run (e.g. some printing) doesn't apply during install too, but dist instance contains in commands attribute only my build command implementation instances. Incredible! But I think the trouble is in complex relations between setuptools and distutils. Does anybody knows how to make custom building run during install on Python 2.7?
Update: Found that install definitely doesn't calls build command, but it calls bdist_egg which runs build_ext. Seems like I should implement "Compass" build extension.
Unfortunatelly, I haven't found the answer. Seems like the ability to run post-install scripts correctly there's only at Distutils 2. Now you can use this work-around:
Update: Because of setuptools' stack checks, we should override install.do_egg_install, not run method:
from setuptools.command.install import install
class Install(install):
def do_egg_install(self):
self.run_command('build_css')
install.do_egg_install(self)
Update2: easy_install runs exactly bdist_egg command which is used by install too, so the most correct way (espetially if you want to make easy_install work) is to override bdist_egg command. Whole code:
#!/usr/bin/env python
import setuptools
from distutils.command.build import build as _build
from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
class bdist_egg(_bdist_egg):
def run(self):
self.run_command('build_css')
_bdist_egg.run(self)
class build_css(setuptools.Command):
description = 'build CSS from SCSS'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
pass # Here goes CSS compilation.
class build(_build):
sub_commands = _build.sub_commands + [('build_css', None)]
setuptools.setup(
# Here your setup args.
cmdclass={
'bdist_egg': bdist_egg,
'build': build,
'build_css': build_css,
},
)
You may see how I've used this here.

Categories