I would like to install my Python module in development mode. As I have seen in many examples python setup.py develop is supposed to do that. But the develop command does not exist for my setup.py file:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
import os
src = ["_NetworKit.pyx"] # list of source files
modules = [Extension("_NetworKit",
src,
language = "c++",
extra_compile_args=["-fopenmp", "-std=c++11", "-O3", "-DNOGTEST"],
extra_link_args=["-fopenmp", "-std=c++11"],
libraries=["NetworKit-Core-O"],
library_dirs=["../"])]
for e in modules:
e.cython_directives = {"embedsignature" : True}
setup(name="_NetworKit",
cmdclass={"build_ext": build_ext},
ext_modules=modules,
py_modules = ["NetworKit.py"])
(Note the Cython extension module).
What am I missing? Do I need to modify the setup.py?
The develop command is a part of setuptools. Install setuptools and replace the first line in setup.py with this:
from setuptools import setup
Related
With the move to the new pyproject.toml system, I was wondering whether there was a way to install packages in editable mode while compiling extensions (which pip install -e . does not do).
So I want pip to:
run the build_ext I configured for Cython and generate my .so files
put them in the local folder
do the rest of the normal editable install
I found some mentions of build_wheel_for_editable on the pip documentation but I could not find any actual example of where this hook should be implemented and what it should look like. (to be honest, I'm not even completely sure this is what I'm looking for)
So would anyone know how to do that?
I'd also happy about any additional explanation as to why pip install . runs build_ext but the editable command does not.
Details:
I don't have a setup.py file anymore; the pyproject.toml uses setuptools and contains
[build-system]
requires = ["setuptools>=61.0", "numpy>=1.17", "cython>=0.18"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
package-dir = {"" = "."}
[tool.setuptools.packages]
find = {}
[tool.setuptools.cmdclass]
build_ext = "_custom_build.build_ext"
The custom build_ext looks like
from setuptools import Extension
from setuptools.command.build_ext import build_ext as _build_ext
from Cython.Build import cythonize
class build_ext(_build_ext):
def initialize_options(self):
super().initialize_options()
if self.distribution.ext_modules is None:
self.distribution.ext_modules = []
extensions = Extension(...)
self.distribution.ext_modules.extend(cythonize(extensions))
def build_extensions(self):
...
super().build_extensions()
It builds a .pyx into .cpp, then adds it with another cpp into a .so.
I created a module that looks like this:
$ tree .
.
├── pyproject.toml
├── setup.py
└── test
└── helloworld.pyx
1 directory, 3 files
My pyproject.toml looks like:
[build-system]
requires = ["setuptools>=61.0", "numpy>=1.17", "cython>=0.18"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
py-modules = ["test"]
[project]
name = "test"
version = "0.0.1"%
My setup.py:
from setuptools import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("test/helloworld.pyx"))
And helloworld.pyx just contains print("Hello world").
When I do pip install -e ., it builds the cython file as expected.
If you really don't want to have a setup.py at all, I think you'll need to override build_py instead of build_ext, but IMO just having the simple setup.py file isn't a big deal.
I use Cython.Distutils to create my Cython package, a wheel file is created.
But installing the wheel, I found my built package is installed directly under site-package director. e.g., venv3/lib/python3.9/site-packages
I wish to install the package under the package name like venv3/lib/python3.9/site-packages/my_package
My command: python setup.py bdist_wheel
setup.py:
from Cython.Distutils import build_ext
from setuptools import setup
from Cython.Build import cythonize
from pathlib import Path
this_dir = Path(__file__).parent
setup(
name='MY PKG',
cmdclass={'build_ext': build_ext},
ext_modules=cythonize("src/*.py"),
install_requires=[
'numpy>=1.19.2',
'Cython>=0.29.28'
],
version="0.1.1")
Is there a way that I can copy the installed *.so files under a directory?
Such that I won't have to move the *.so files like
mkdir my_package && mv *.so my_package/
is it possible to detect if current python code is running from package?
if yes - is it possible to get package metadata (name, version, description)?
package is created with this kind of setup.py
import os
from setuptools import setup, find_packages
setup(
name='my-pack-name',
description='my description ' + os.getenv('GIT_COMMIT', '*')[:7],
version=os.getenv('BUILD_VERSION', '0.0.0dev'),
packages=find_packages(),
)
build: python3 setup.py bdist_wheel -d ./artifact
install on target: pip3 install "my-pack-name-x.x.x.whl" --upgrade
now from my_pack_name/app.py that was inside my-pack-name-x.x.x.whl i want to detect that i'm running from installed package
and if so then get package metadata defined during setup.py execution
For Python >=3.8
https://docs.python.org/es/3.10/library/importlib.metadata.html
You can get the metadata for a package by:
from importlib.metadata import metadata
md = metadata("your package name")
author = md["Author"]
# etc ...
For Python <3.8
This is just an idea (not tested).
What about having the package metadata in a different module, and try relative import it in the app.py module?
# metadata.py
name='my-pack-name',
description='my description ' + os.getenv('GIT_COMMIT', '*')[:7],
version=os.getenv('BUILD_VERSION', '0.0.0dev')
In setup.py you could reuse that:
# setup.py
import os
from setuptools import setup, find_packages
import .metadata as md
setup(
name=md.name,
description=md.description + os.getenv('GIT_COMMIT', '*')[:7],
version=md.version,
packages=find_packages(),
)
And the in app.py
def get_metadata():
try:
import .metadata as md
except ImportError:
return None
else:
# return metadata here
That way if get_metadata returns None, you were not able to import the module, so you're not executing the app.py in your package, otherwise, you are in your package and as a bonus you got your metadata.
For the test if python code is running from an installed package (vs. from a development location), I use
if 'site-packages' in __file__:
...
I don't know if that's a good approach; seems to work thus far.
I have a setup.py as follows (other source files are available too)
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [
Extension("fastsim",
["src/fastsim.pyx", "src/selection.c"],
libraries=["m"],)
]
setup(
name="fastsimlib",
cmdclass={"build_ext": build_ext},
ext_modules=ext_modules
)
This works fine as long as there is cython installed in the target machine. I am wondering if I can get rid of the cython dependency by creating an egg file so that I only to run easy_install or pip.
To clarify, I want to create a distribution package so that I can install the library in a machine that does not have cython installed. Or even better, can I only distribute the binary .so file (so that no cython or c code in the package)? The OS and other information of the target machine is given(Ubuntu).
There is a Python package with a setup.py that reads thusly:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
name = 'fastahack',
ext_modules=[
Extension("fastahack.cfastahack",
sources=["fastahack/cfastahack.pyx", "lib/Fasta.cpp", "lib/split.cpp"],
libraries=["stdc++"],
include_dirs=["lib/"],
language="c++"),
],
package_data = {'lib': ['*.pyx', "*.c", "*.h", "README.rst"]},
package_dir = {"fastahack": "fastahack"},
cmdclass = {'build_ext': build_ext},
packages = ['fastahack', 'fastahack.tests'],
author = "Brent Pedersen",
author_email="bpederse#gmail.com",
#test_suite='nose.collector'
)
This setup.py can't be imported if Cython is not installed. As far as I know, importing setup.py is how tools like pip figure out the dependencies of a package. I want to set up this package so that it could be uploaded to PyPI, with the fact that it depends on Cython noted, so that Cython will be downloaded and installed when you try to "pip install fastahack", or when you try to "pip install" directly from the Git repository.
How would I package this module so that it installs correctly from the Internet when Cython is not installed? Always using the latest version of Cython would be a plus.
You can specify Cython as a build dependency using PEP-518 project specification.
In the file pyproject.toml (in the same directory as setup.py) insert:
[build-system]
requires = ["setuptools", "wheel", "Cython"]
Cython will then be installed before building your package.
Note that (currently) you need to pass --no-use-pep517 to pip install if you are installing your package locally as editable (ie with --editable or -e) setuptools v64 supports editable installs with pyproject.toml builds
My standard template for setup.py:
have_cython = False
try:
from Cython.Distutils import build_ext as _build_ext
have_cython = True
except ImportError:
from distutils.command.build_ext import build_ext as _build_ext
if have_cython:
foo = Extension('foo', ['src/foo.pyx'])
else:
foo = Extension('foo', ['src/foo.c'])
setup (
...
ext_modules=[foo],
cmdclass={'build_ext': build_ext}
And don't forget to provide extention .c files with package - that will allow users to build module without installing cython.
Use a try and except for the Cython import and modify your setup based on whether or not your import succeeds. Look at the setup.py of Pandas for an example