7

I have a python project with a pyproject.toml file. Typically I store the project's version number in pyproject.toml like this:

% grep version pyproject.toml 
version = "0.0.2"
%

I want to get that version number into a Makefile variable regardless of how many spaces wind up around the version terms.

What should I do to extract the pyproject.toml version string into a Makefile environment variable called VERSION?

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174

4 Answers4

5

This seemed to work out the best... I put this in my Makefile

# grep the version from pyproject.toml, squeeze multiple spaces, delete double
#   and single quotes, get 3rd val. This command tolerates 
#   multiple whitespace sequences around the version number
VERSION := $(shell grep -m 1 version pyproject.toml | tr -s ' ' | tr -d '"' | tr -d "'" | cut -d' ' -f3)

Special thanks to @charl-botha for the -m 1 grep argument... both gnu and bsd grep support -m in this context.

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
  • 4
    This will break if there are multiple "version =" statements in the file, e.g. in additional dependency version constraints further down. Use `-m 1` argument to grep to use only the first occurrence. – Charl Botha Jun 08 '22 at 11:55
  • 1
    I just ran into this: `uvicorn = {extras = ["standard"], version = "^0.17.6"}` -- which necessitated the `-m 1` in our case. HTH? – Charl Botha Jun 08 '22 at 12:10
  • The `-m 1` option also ONLY works if the first occurence is the correct one. If you have a comment or anything else mentioning "version" before the actual version this approach still fails. – Mausy5043 Jun 07 '23 at 06:31
3

If you have a Python available with the tomli package installed, or you're on Python 3.11 with toml built-in (in which case you would import tomllib instead of tomli), and your pyproject.toml follows poetry convention, something like the following would work well:

VERSION := $(shell python -c 'import tomli; print(tomli.load(open("pyproject.toml", "rb"))["tool"]["poetry"]["version"])')

Test on command-line with simply:

python -c 'import tomli; print(tomli.load(open("pyproject.toml", "rb"))["tool"]["poetry"]["version"])'

Obviously you can easily adapt the location of the desired version entry in the case of other pyproject.toml conventions.

BTW, tomllib is in fact tomli, see https://peps.python.org/pep-0680/#rationale

Charl Botha
  • 4,373
  • 34
  • 53
1

If that's all that file really contains, that's sufficiently close to makefile syntax that you can just include it as a makefile:

include pyproject.toml
all: ; echo 'version = $(version)'

$ make
echo 'version = "0.0.2"'
version = "0.0.2"

If you don't want to, or can't, do that, I'd use sed for it:

VERSION := $(shell sed -n 's/^ *version.*=.*"\([^"]*\)".*/\1/p' pyproject.toml)
all: ; echo 'version = $(VERSION)'

$ make
echo 'version = 0.0.2'
version = 0.0.2
MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thanks! I thought that include was a slick way to get `pyproject.toml` variables into a `Makefile`, but `make` choked when it hit this line: `[tool.poetry]`... it dumped me into the `bash` prompt. I think grepping the version out is probably better. – Mike Pennington Mar 23 '22 at 18:26
  • As I said, if that line you quoted is the ONLY line in the file, then it will work. If there's other lines in the file, that don't match makefile syntax (such as `[tool.poetry]`) then include won't work. – MadScientist Mar 23 '22 at 19:05
  • I wasn’t completely sure what you meant at the time, but please understand that ‘pyproject.toml’ requires section headings in brackets… the config is useless without section headers. – Mike Pennington Mar 23 '22 at 20:07
  • Yes, so, the `include` option won't work in that situation. – MadScientist Mar 23 '22 at 20:37
1

An alternative solution to parse major.minor.patch, based on @Mike Pennington's answer:

grep -m 1 version pyproject.toml | grep -e '\d.\d.\d' -o
Alexandru Dinu
  • 1,159
  • 13
  • 24