Skip to content

Modernise the build system #237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 4 additions & 14 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,8 @@ jobs:
etc/make-doc.sh # so that all files are generated!
cd docs
python -m sphinx -b doctest -d _build/doctrees source _build/doctest
- name: "Pip3 installing pylint + cpplint . . ."
run: |
pip3 install pylint cpplint
- name: "Running pylint and cpplint . . ."
run: |
python -m pylint setup.py tests/*.py libsemigroups_pybind11/*.py
python -m cpplint src/*.hpp src/*.cpp
- name: "Running ruff, pylint and cpplint . . ."
run: make lint
macosx:
strategy:
fail-fast: false
Expand Down Expand Up @@ -127,10 +122,5 @@ jobs:
etc/make-doc.sh # so that all files are generated!
cd docs
python -m sphinx -b doctest -d _build/doctrees source _build/doctest
- name: "Pip3 installing pylint + cpplint . . ."
run: |
pip3 install pylint cpplint
- name: "Running pylint and cpplint . . ."
run: |
python -m pylint setup.py tests/*.py libsemigroups_pybind11/*.py
python -m cpplint src/*.hpp src/*.cpp
- name: "Running ruff, pylint and cpplint . . ."
run: make lint
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ docs/source/api/Transf.rst
gh-pages/
htmlcov
.cache
src/libsemigroups_pybind11/_version.py
13 changes: 7 additions & 6 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,14 @@ A class with no helpers or templates
____________________________________

If the class you are binding has no templates or helper functions, then you
need to add it to the list imports in `<libsemigroups_pybind11/__init__.py>`__.
need to add it to the list imports in
`<src/libsemigroups_pybind11/__init__.py>`__.

A class with helpers
____________________

If a class has a helper namespace, this should be respected in Python by
creating a module with the same name in the ``libsemigroups_pybind11``
creating a module with the same name in the ``src/libsemigroups_pybind11``
directory. In that module, all of the relevant helper functions should be
imported from ``_libsemigroups_pybind11``.

Expand All @@ -226,7 +227,7 @@ will be one class for each combination of templates. Instead of calling these
directly, a Python function should be created that acts as a constructor, that
then calls the the corresponding ``_libsemigroups_pybind11`` constructor
depending on the keyword arguments specified. This function should then be
imported in `<libsemigroups_pybind11/__init__.py>`__.
imported in `<src/libsemigroups_pybind11/__init__.py>`__.

The documentation
-----------------
Expand Down Expand Up @@ -439,10 +440,10 @@ whilst contributing are::
│ └── index.rst
├── etc/
│ └── replace-string-in-doc.py
├── libsemigroups_pybind11/
│ ├── __init__.py
│ └── class_name.py
├── src/
| ├──libsemigroups_pybind11/
│ | ├── __init__.py
│ | └── class_name.py
│ └── class-name.cpp
├── tests/
│ └── test_class_name.py
Expand Down
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
include src/*.hpp
graft src
include tests/*.py
10 changes: 4 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ install:
pip3 install . --use-feature=in-tree-build

black:
black setup.py tests/*.py libsemigroups_pybind11/*.py docs/source/conf.py
black setup.py tests/*.py src/libsemigroups_pybind11/*.py docs/source/conf.py

check: doctest
pytest -vv tests/test_*.py

lint:
ruff check --exit-zero setup.py tests/*.py libsemigroups_pybind11/*.py docs/source/*.py
pylint --exit-zero setup.py tests/*.py libsemigroups_pybind11/*.py libsemigroups_pybind11/**/*.py
cpplint src/*.hpp src/*.cpp
etc/make-lint.sh

coverage:
@coverage run --source . --omit="tests/*" -m pytest tests/test_*.py
Expand All @@ -39,8 +37,8 @@ clean-doc:
rm -rf docs/_build

clean: clean-doc
rm -rf __pycache__ libsemigroups_pybind11.egg-info
rm -rf tests/__pycache__ libsemigroups_pybind11/__pycache__
find . -type d -name __pycache__ -prune -exec rm -rf {} \;
rm -rf libsemigroups_pybind11.egg-info
rm -f *.whl
rm -rf build/

Expand Down
111 changes: 111 additions & 0 deletions build_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2021-2024 J. D. Mitchell
#
# Distributed under the terms of the GPL license version 3.
#
# The full license is in the file LICENSE, distributed with this software.

"""
This module provides some tools for building libsemigroups_pybind11.
"""

import re
from packaging import version
import pkgconfig


def minimum_libsemigroups_version():
"""
Returns the minimum required version of libsemigroups required to make
this work.
"""
return "3.0.0"


def libsemigroups_version():
"Get the version of libsemigroups installed using pkg-config."

vers = pkgconfig.modversion("libsemigroups")
if re.search(r"\d+\.\d+\.\d+-\d+-\w{7}", vers):
# i.e. supplied is of the form: 1.1.0-6-g8b04c08
vers = re.search(r"\d+\.\d\.+\d+-\d+", vers).group(0)
return vers


def compare_version_numbers(supplied, required):
"""Returns True if supplied >= required"""

if isinstance(supplied, str) and isinstance(required, str):
if "dev" in supplied:
print(
(
"\033[93mWarning: You are using a development version of libsemigroups. This "
"may cause undocumented behaviour\033[0m"
)
)
return True
return version.parse(supplied) >= version.parse(required)
raise TypeError(
f"expected (string, string), got a ({supplied.__name__}, {required.__name__})"
)


def extra_link_args() -> str:
"""Find extra link args"""
libs_only_L = pkgconfig.libs( # pylint: disable=invalid-name
"libsemigroups"
)
# The above pkgconfig query can return an empty string (this also happens on
# the command line). This happens, for example, using pkg-config version 1.8.0
# on ArchLinux. CN 27/10/2021

assert (
len(libs_only_L) == 0 or libs_only_L[:2] == "-L"
), "The first two characters of the library path to the libsemigroups.so etc should be '-L'"

libs_only_L = [ # pylint: disable=invalid-name
x for x in libs_only_L.split(" ") if x.startswith("-L")
]

if len(libs_only_L) == 0:
libs_only_L = ["-L/usr/lib"] # pylint: disable=invalid-name
return libs_only_L


def ld_library_path() -> str:
"""Construct the LD_LIBRARY_PATH"""
return ":".join([x[2:] for x in extra_link_args()])


def validate_libsemigroups():
DISCLAIMER = """
(You should not see this message unless you are installing
libsemigroups_pybind11 from its sources. If you are not installing from the
sources, please raise an issue at:
https://github.com/libsemigroups/libsemigroups_pybind11)"""

if not pkgconfig.exists("libsemigroups"):
raise ImportError(
f"""cannot locate the libsemigroups library.
For more information about installing the libsemigroups library see
https://libsemigroups.github.io/libsemigroups_pybind11/install.html.

If libsemigroups is installed, then it cannot be located by pkg-config,
perhaps you should add the directory containing `libsemigroups.pc' to the
\"PKG_CONFIG_PATH\". The file `libsemigroups.pc' might be in one of the
following directories:
* /usr/local/lib/pkgconfig
* $CONDA_PREFIX/lib/pkgconfig if your active conda environment has pkgconfig
installed, and libsemigroups was installed with conda/mamba in this
environment.
{DISCLAIMER}"""
)

if not compare_version_numbers(
libsemigroups_version(), minimum_libsemigroups_version()
):
raise ImportError(
f"libsemigroups version at least {minimum_libsemigroups_version()}"
+ f" is required, found {libsemigroups_version()}"
)
9 changes: 5 additions & 4 deletions dev-environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ channels:
- nodefaults

dependencies:
- python=3.12
- python>=3.12
- black
- bs4
- codespell
Expand All @@ -14,12 +14,13 @@ dependencies:
- ipython
- lxml
- pip
- pybind11
- pylint
- pytest
- pybind11
- sphinx
- sphinx-copybutton
- ruff
- sphinx_rtd_theme
- sphinx-copybutton
- sphinx
- sphinxcontrib-bibtex
- pip:
- accepts
16 changes: 0 additions & 16 deletions docs/environment.yml

This file was deleted.

7 changes: 0 additions & 7 deletions environment.yml

This file was deleted.

13 changes: 9 additions & 4 deletions etc/libsemigroups_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
import os
import sys

__dir__ = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, __dir__ + "/../libsemigroups_pybind11")

from tools import minimum_libsemigroups_version
sys.path.append(
os.path.abspath(
os.path.join(
os.path.dirname(__file__),
"..",
)
)
)
from build_tools import minimum_libsemigroups_version

print(minimum_libsemigroups_version())
20 changes: 20 additions & 0 deletions etc/make-lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

if [[ $# -ne 0 ]]; then
bold "error expected 0 arguments, got $#!"
exit 1
fi

exit_code=0
python_files="setup.py tests/*.py src/libsemigroups_pybind11/*.py src/libsemigroups_pybind11/**/*.py docs/source/*.py docs/source/**/*.py"

echo "Linting with ruff . . ."
ruff check $python_files || ((exit_code = 1))

echo "Linting with pylint . . ."
pylint $python_files || ((exit_code = 1))

echo "Linting with cpplint . . ."
cpplint src/*.hpp src/*.cpp || ((exit_code = 1))

exit $exit_code
Loading