how to reference metadata in a pyproject.toml file? - python

I was previously using setup.py to package my Python libs. As it seems pyproject.toml is the future way of setuptools I decided to migrate before my next releases.
In setup.py I was using the following string to define the link to the downloadable tarball:
setup(
version = "2.13.4"
download_url = "https://github.com/xx/xx/archive/v${metadata:version}.tar.gz"
)
My objective is to set up the version number just once. Is it still possible in pyproject.toml and if yes how ?
I tried the following but it's not included the version parameter in the url:
[project]
version = "2.13.4"
[project.urls]
Download = "https://github.com/xx/xx/archive/v${metadata:version}.tar.gz"

Related

Make python script executable via pip using pyproject.toml [duplicate]

I'm trying to add a pyproject.toml to a project that's been using setup.py in order to enable support by pipx. I'd like to specify the command line scripts the project includes in pyproject.toml, but all the guides I can find give instructions for use with poetry, which I am not using.
I also don't want to specify entry points to modules - I already have working command line scripts and just want to specify those.
Is there a proper place in pyproject.toml to specify command line scripts?
Not sure it matters, but the package in question is cutlet.
Update July 2022: if your TOML file uses setuptools as its build system, setuptools will happily create and install a console script. For example, my pyproject.toml file starts like this:
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
Extend your pyproject.toml file with an entry like this, naming the package, module and entry-point function names:
[project.scripts]
my-client = "my_package.my_module:main_cli"
Then run the install sequence:
pip3 install .
And setuptools will install a shell script named my-client somewhere appropriate, for me in my Py3.9 virtual environment 's bin directory (~/.virtualenvs/py39/bin).
I was doing a similar thing, upgrading a package that had a setup.py, altho I had no existing scripts. With the rewrite to using pyproject.toml I dropped the old setup.py file entirely.
FWIW I realize the OP asked for a way to install existing scripts, which I didn't provide. This answer tells setuptools to create and install new scripts.
Update Feb 2023: thanks for all the votes. If you're cutting corners to meet arbitrary management deadlines, just copy-paste this short pyproject.toml file and adjust:
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "my_client"
version = "1.2.3"
authors = [{name="Ubr Programmer", email="ubr#gmailington.com" }]
description = "Client for my awesome system"
readme = "README.md"
dependencies = ["cachetools","requests"]
requires-python = ">=3.9"
[project.scripts]
my-client = "my_package.my_module:main_cli"
[project.urls]
"Homepage" = "https://github.com/your_name_here/something"
"Bug Tracker" = "https://github.com/your_name_here/something/issues"
Is there a proper place in pyproject.toml to specify command line scripts?
PEP566 (Metadata 2.1) only defines Core metadata specifications. Thus, the answer depends on your build system (Note: PEP518 defines build system concept).
If you use the existing build tools such as setuptools, poetry, and flit, you only can consider adding such options in pyproject.toml if that tool supports command line scripts (console_scripts) in pyproject.toml. Surely, if you have your own build tool, you need to implement a parser to parse the command line scripts in pyproject.toml.
Lastly, you can check below list to know which major build system supports command line scripts (console_scripts) in pyproject.toml (2020/Oct):
setuptools: not implemented yet according to PEP621
poetry: yes, here's part of the implementation.
flit: yes.

How to configure os specific dependencies in a pyproject.toml file [Maturin]

I have a rust and python project that I am building using Maturin(https://github.com/PyO3/maturin). It says that it requires a pyproject.toml file for the python dependencies.
I have a dependency of uvloop, which is not supported on windows and arm devices. I have added the code that conditionally imports these packages. However, I do not know how to conditionally install these packages. Right now, these packages are getting installed by default on every OS.
Here is the pyproject.toml file.
[project]
name = "robyn"
dependencies = [
"watchdog>=2.1.3,<3",
"uvloop>=0.16.0,<0.16.1",
"multiprocess>=0.70.12.2,<0.70.12.3"
]
And the github link, jic anyone is interested: https://github.com/sansyrox/robyn/pull/94/files#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711R21
If you don't want to install on windows, specify like this:
# assuming you're using poetry
uvloop = {version = "^0.16.0", markers = 'sys_platform != "win32"'}
As wim indicated in their comment, https://peps.python.org/pep-0508/ specifies how to write constraints on package requirements.
In addition to restricting the package to a range of versions, you can restrict package installations based on various markers, such as sys_platform for the OS, separated from your other requirements with a semicolon.
I haven't tested this with pyproject.toml, but the following works in setup.cfg:
[options]
install_requires =
uvloop ; sys_platform != "win32"

How to include local Python dependency in setup.cfg

A similar question has been asked before, but this time I am asking for the newer setuptools config file — setup.cfg.
Consider my use case, where I have a project with multiple Python packages that depends on each other. For simplicity let's say mypkg1 depends on mypkg2:
mypkg1/
mypkg1/
setup.cfg
mypkg2/
mypkg2/
setup.cfg
How do I write the setup.cfg file for mypkg1 such that it depends on a local copy of mypkg2?
[metadata]
name = mypkg1
version = 0.0.1
[options]
packages = find:
python_requires = >= 3.7
install_requires =
../mypkg2 # Does not work
The answer cannot be to distribute mypkg2 to a package repository (e.g., PyPI) or some VCS release (e.g., GitHub Release) as these solutions makes the package external and no local.
Related Questions
How to include and install local dependencies in setup.py in Python?
This question is for setup.py which does not work for setup.cfg.
https://github.com/pypa/setuptools/issues/1951
The discussion does not indicate any support for this nor any plans for this to be a feature.
Direct references still work. Looks like this:
install_requires =
my_package # file:///home/code/my_package
Note the triple-slash in file:/// - the first two are the usual schema://, the third one is what separates the empty <host> (defaults to localhost) from the path.

Install sphinx compilated doc from setup.py

I want to install some HTML on-line doc that is made (understand compiled from rSt) using sphinx along with the python code into the site-package. I want to to this using setup.py.
To be more specific, I want to complile my *.rst files to HTML and then copy then into site-package from the setup.py file when the user types python setup.py install.
Does someone know how to do this ? I look into sphinx and setuptools doc but was not able to find the info.
The reason I want to do it, is that my package is a GUI tool and the HTML is the on-line help of it. It is displayed into GUI's internal browser.
As already noted you'll need a MANIFEST.in file to include the docs directory:
recursive-include docs *
Now in your setup.py you could programmatically generate the sphinx documentation from your *.rst files.
Here's an example on how to do that automatically when python setup.py install is run:
from distutils.core import setup
# set dependencies, we need sphinx to build doc
dependencies = ['sphinx']
setup(
name='my_package'
# rest of your setup
)
# auto-generate documentation
import sphinx
# automatically build html documentation
# For example:
# format = 'html'
# sphinx-src-dir = './doc'
# sphinx-build-dir = './doc/build'
sphinx.build_main(['setup.py', '-b', '<format>', '<sphinx-src-dir>', '<sphinx-build-dir>'])
Like this you can run sphinx-build as needed (Documentation).
Note: It might be a good idea to add a Custom command to your setup.py for separating documentation generation (f.e. python setup.py make_doc [params]) and install routine (python setup.py install). This way the user could easily supply parameters format, sphinx-src-dir and sphinx-build-dir.
You can add them into your MANIFEST.in and then build the package
recursive-include docs *
Then it will be distributed with your egg

Let sphinx use version from setup.py

If I do sphinx-quickstart I get asked about the version of the project.
I want to avoid to have two places for the version of my project.
How to do this in the python packing world?
The easiest (and probably cleanest) way is to define __version__ for the __init__.py of your top-level package, and then import that package and read the version in both setup.py and your Sphinx project's conf.py.
So lets say your project is called myproject.
Move your current version out of setup.py, and make it a variable in myproject/__init__.py instead:
myproject/__init__.py:
# import foo
# ...
__version__ = '1.5'
Import myproject in your project's setup.py, and replace the hardcoded version with myproject.__version__:
setup.py:
from setuptools import setup
from myproject import __version__
project = "myproject"
setup(
name=project,
version=__version__,
# ...
)
In your Sphinx project's conf.py, do the same. So edit the generated conf.py along these lines:
docs/conf.py:
from myproject import __version__
# ...
# The short X.Y version.
version = __version__
# The full version, including alpha/beta/rc tags.
release = version
For an example of a library that does this pretty much exactly like this, have a look at the requests module (__init__.py | setup.py | conf.py).
This will take care of the auto-generated texts where the project version is used (like the links to the front page of the documentation). If you want to use your version in specific custom places, you can use the rst_epilog directive to dynamically insert configuration values defined in conf.py.
Maybe an even cleaner option is to actually build sphinx from the setup.py command as described in http://www.sphinx-doc.org/en/master/setuptools.html:
setup.py
# this is only necessary when not using setuptools/distribute
from sphinx.setup_command import BuildDoc
cmdclass = {'build_sphinx': BuildDoc}
name = 'My project'
version = '1.2'
release = '1.2.0'
setup(
name=name,
author='Bernard Montgomery',
version=release,
cmdclass=cmdclass,
# these are optional and override conf.py settings
command_options={
'build_sphinx': {
'project': ('setup.py', name),
'version': ('setup.py', version),
'release': ('setup.py', release),
'source_dir': ('setup.py', 'doc')}},
)
Then build documentation using
$ python setup.py build_sphinx
Benefits:
Makes setup.py the single source of version number
Avoids having to make packages out of your project folders unnecessarily
You could have a look at bumpversion module:
"A small command line tool to simplify releasing software by updating all version strings in your source code by the correct increment"
You may use a configuration file .bumpversion.cfg for complex multi-file operations.
Another way is integrating setuptools_scm in your project. This way you can
from setuptools_scm import get_version
version = get_version()
in your conf.py
Here is a straightforward solution, ironically from the setuptools_scm PyPI page:
# contents of docs/conf.py
from importlib.metadata import version
release = version('myproject')
# for example take major/minor
version = '.'.join(release.split('.')[:2])
Here is their explanation why it is discouraged to use their package from Sphinx:
The underlying reason is, that services like Read the Docs sometimes change the working directory for good reasons and using the installed metadata prevents using needless volatile data there.
Extract Information from pyproject.toml
If you use a pyproject.toml you could also parse it in the conf.py with tomli or use the equivalent tomllib when you are on python ^3.11.
Like this you can extract the information from the pyproject.toml and use it in your sphinx documentation configuration.
Here a short incomplete example using tomli, assuming conf.py
is located at <project-root>/docs/source/conf.py:
# conf.py
import tomli
with open("../../pyproject.toml", "rb") as f:
toml = tomli.load(f)
# -- Project information -----------------------------------------------------
pyproject = toml["tool"]["poetry"]
project = pyproject["name"]
version = pyproject["version"]
release = pyproject["version"]
copyright = ...
author = ...
# and the rest of the configuration

Categories