diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7270ee84..289e50d9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -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 @@ -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 diff --git a/.gitignore b/.gitignore index c224cfdb..11477e00 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ docs/source/api/Transf.rst gh-pages/ htmlcov .cache +src/libsemigroups_pybind11/_version.py diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 7492f97d..ca684f8d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -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 ``__. +need to add it to the list imports in +``__. 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``. @@ -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 ``__. +imported in ``__. The documentation ----------------- @@ -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 diff --git a/MANIFEST.in b/MANIFEST.in index 5cfff31e..bcf45a12 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,2 @@ -include src/*.hpp +graft src +include tests/*.py diff --git a/Makefile b/Makefile index 152f90a7..b5110522 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -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/ diff --git a/build_tools/__init__.py b/build_tools/__init__.py new file mode 100644 index 00000000..c09fb606 --- /dev/null +++ b/build_tools/__init__.py @@ -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()}" + ) diff --git a/dev-environment.yml b/dev-environment.yml index 193a9014..2f4f6d8e 100644 --- a/dev-environment.yml +++ b/dev-environment.yml @@ -5,7 +5,7 @@ channels: - nodefaults dependencies: - - python=3.12 + - python>=3.12 - black - bs4 - codespell @@ -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 diff --git a/docs/environment.yml b/docs/environment.yml deleted file mode 100644 index 2cf89c92..00000000 --- a/docs/environment.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: libsemigroups-pybind11-doc - -channels: - - conda-forge - - anaconda - -dependencies: - - libsemigroups==2.0.0 - - pip - - sphinx-copybutton==0.5.2 - - sphinxcontrib-bibtex==2.6.2 - - packaging==23.2 - - pkgconfig - - pybind11==2.11.1 - - pyparsing==3.1.1 - diff --git a/environment.yml b/environment.yml deleted file mode 100644 index d42114a3..00000000 --- a/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: libsemigroups - -channels: - - conda-forge - -dependencies: - - libsemigroups diff --git a/etc/libsemigroups_version.py b/etc/libsemigroups_version.py index 18c75c29..c52c6c50 100755 --- a/etc/libsemigroups_version.py +++ b/etc/libsemigroups_version.py @@ -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()) diff --git a/etc/make-lint.sh b/etc/make-lint.sh new file mode 100755 index 00000000..e077c3b7 --- /dev/null +++ b/etc/make-lint.sh @@ -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 diff --git a/libsemigroups_pybind11/tools.py b/libsemigroups_pybind11/tools.py deleted file mode 100644 index 2215dcd1..00000000 --- a/libsemigroups_pybind11/tools.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- 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 libsemigroups_pybind11. -""" - -import re - -from packaging import version - -try: - import pkgconfig - - PKGCONFIG_IMPORTED = True -except ModuleNotFoundError: - PKGCONFIG_IMPORTED = False - - -def ordinal(n: int): - """ - Returns 1st from 1, 2nd from 2 etc. - From https://stackoverflow.com/questions/9647202/ - """ - if 11 <= (n % 100) <= 13: - suffix = "th" - else: - suffix = ["th", "st", "nd", "rd", "th"][min(n % 10, 4)] - return str(n) + suffix - - -def minimum_libsemigroups_version(): - """ - Returns the minimum required version of libsemigroups required to make - this work. - """ - return "2.7.0" - # Changed down from 2.7.1 -- do something sensible here - - -if PKGCONFIG_IMPORTED: - - 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""" - # pylint: disable=invalid-name - libs_only_L = pkgconfig.libs("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()]) diff --git a/pyproject.toml b/pyproject.toml index 3ad58062..882ad789 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,26 +1,116 @@ -[tool.black] -line-length = 80 -[tool.ruff] -lint.select = ["E", "F", "B"] -lint.ignore = ["F401"] -line-length = 100 -[tool.pylint] -disable = ["R0801", "fixme"] +# TODO: +# * Run check-manifest and populate MANIFEST.in +# * Use ruff +# * Remove .codespellrc +# * Decide on good configurations for tools +# * Remove requirements.txt +# * Use pre-commit +# * Use MyPy [build-system] requires = [ - "setuptools==75.6.0", - "wheel", - "pybind11==2.11.1", - "pkgconfig>=1.5.5", - "packaging==23.2", + "setuptools>=64", + "setuptools-scm>=8", + "pybind11", + "pkgconfig", + "packaging", ] - build-backend = "setuptools.build_meta" -[tool.pytest.ini_options] -markers = [ - "quick", - "standard", - "extreme", - "fail", +[project] +name = "libsemigroups_pybind11" +dynamic = ["version"] +description = "A python package for the libsemigroups C++ library." +readme = "README.md" +authors = [ + { name = "Joseph Edwards", email = "jde1@st-andrews.ac.uk" }, + { name = "James Mitchell", email = "jdm3@st-andrews.ac.uk" }, + { name = "Maria Tsalakou", email = "mt200@st-andrews.ac.uk" }, + { name = "Murray Whyte", email = "mw231@st-andrews.ac.uk" }, ] +# TODO: Uncomment and update +# maintainers = [{ name = "My Organization", email = "myemail@email.com" }] +requires-python = ">=3.9" +dependencies = ["graphviz", "numpy", "typing_extensions"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Mathematics", + "Natural Language :: English", +] +license = "GPL-3.0-or-later" +license-files = ["LICENSE"] + +[project.urls] +Homepage = "https://github.com/libsemigroups/libsemigroups_pybind11" +Documentation = "https://libsemigroups.github.io/libsemigroups_pybind11/" +Issues = "https://github.com/libsemigroups/libsemigroups_pybind11/issues" +Changelog = "https://libsemigroups.github.io/libsemigroups_pybind11/changelog.html" + +[project.optional-dependencies] +test = ["pytest"] +docs = [ + "sphinx_rtd_theme", + "sphinx >=8.2", + "sphinx-copybutton", + "sphinxcontrib-bibtex", +] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools_scm] +version_file = "src/libsemigroups_pybind11/_version.py" + +[tool.black] +line-length = 80 + +[tool.ruff] +line-length = 100 +lint.ignore = ["F401", "E402"] +lint.select = ["E", "F", "B"] +# Uncomment the following to have more aggressive ruff linting +# lint.extend-select = ["B", "I", "UP"] + +# [tool.ruff.format] +# docstring-code-format = true + +[tool.pytest.ini_options] +minversion = "6.0" +testpaths = ["tests"] +addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"] +console_output_style = "progress" +filterwarnings = ["error"] +markers = ["quick", "standard", "extreme", "fail"] +verbosity_test_cases = 1 +xfail_strict = true + +[tool.pylint.main] +ignore-paths = "src/libsemigroups_pybind11/_version.py" +jobs = 0 + +[tool.pylint.miscellaneous] +# List of note tags to take in consideration, separated by a comma. +# notes = ["TODO", "FIXME", "REVIEW"] +disable = ["R0801", "fixme"] +notes = [] + +[tool.pylint.similarities] +ignore-imports = "yes" + +# TODO: Decide if we want to use mypy +# [tool.mypy] +# files = "src" +# python_version = "3.9" +# strict = true +# enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] +# warn_unreachable = true + +# [[tool.mypy.overrides]] +# module = [ "_libsemigroups_pybind11", ] +# ignore_missing_imports = true diff --git a/requirements.txt b/requirements.txt index d6857707..2db5feda 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,34 @@ -setuptools==75.6.0 +accepts==2020.12.3 +argcomplete==3.6.2 +beautifulsoup4==4.13.3 +colorama==0.4.6 +cpplint==2.0.0 +eventlet==0.39.1 +exceptiongroup==1.2.2 +gevent==24.11.1 graphviz==0.20.3 -numpy==2.0.2 +greenlet==3.1.1 +numpy==2.0.2; +ox_profile==0.2.14 packaging==24.2 +pexpect==4.9.0 pkgconfig==1.5.5 +pudb==2024.1.3 pybind11==2.13.6 -pyparsing==3.2.0 +pygments==2.19.1 +pylint==3.3.5 pytest==8.3.3 -six==1.16.0 +pyyaml==6.0.2 +ruff==0.11.2 +setuptools==75.8.2 sphinx_rtd_theme==3.0.2 -sphinx==7.4.7 sphinx-copybutton==0.5.2 +# We are being slightly deceptive here. Compiling with sphinx==7.4.7 will work, +# but will cause warnings +sphinx==8.2.3;python_version>="3.11" +sphinx==7.4.7;python_version<="3.10" sphinxcontrib-bibtex==2.6.3 -typing_extensions==4.12.2 \ No newline at end of file +tomli==2.2.1 +twisted==24.11.0 +typing_extensions==4.13.0 +zope==5.13 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8be1ef2f..00000000 --- a/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[pylint.similarities] -ignore-imports=yes -notes=["TODO", "FIXME", "REVIEW"] diff --git a/setup.py b/setup.py index 71cdd485..1066b0da 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,6 @@ import glob import os import sys -from pprint import pprint import pkgconfig from pybind11.setup_helpers import ( @@ -23,133 +22,44 @@ build_ext, naive_recompile, ) -from setuptools import find_packages, setup +from setuptools import setup ParallelCompile("NPY_NUM_BUILD_JOBS", needs_recompile=naive_recompile).install() -__dir__ = os.path.abspath(os.path.dirname(__file__)) -sys.path.insert(0, __dir__ + "/libsemigroups_pybind11") +sys.path.append(os.path.abspath(os.path.dirname(__file__))) -from tools import ( # pylint: disable=import-error, wrong-import-position # noqa: E402 - compare_version_numbers, - extra_link_args, - libsemigroups_version, - minimum_libsemigroups_version, +from build_tools import ( # pylint: disable=wrong-import-position + validate_libsemigroups, ) -__version__ = "1.0.0" +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()}" - ) - - -class GetPyBind11Include: # pylint: disable=too-few-public-methods - """ - Helper class to determine the pybind11 include path - - The purpose of this class is to postpone importing pybind11 - until it is actually installed, so that the ``get_include()`` - method can be invoked. - """ - - def __init__(self, user=False): - self.user = user - - def __str__(self): - import pybind11 # pylint: disable=import-outside-toplevel - - return pybind11.get_include(self.user) - - -include_path = [ - GetPyBind11Include(), - GetPyBind11Include(user=True), -] - -for lib in ("libsemigroups", "eigen3", "fmt"): - try: - cflags_only_I = pkgconfig.cflags(lib) # pylint: disable=invalid-name - except pkgconfig.pkgconfig.PackageNotFoundError: - continue - - cflags_only_I = [ - x[2:] for x in cflags_only_I.split(" ") if x.startswith("-I") - ] - - include_path.extend(cflags_only_I) - if lib == "libsemigroups": - include_path.extend( - [os.path.join(x, "libsemigroups") for x in cflags_only_I] - ) +libsemigroups_info = pkgconfig.parse("libsemigroups") +extra_libs = set(libsemigroups_info["libraries"]) +extra_libs.remove("semigroups") +include_dirs = set(libsemigroups_info["include_dirs"]) +for lib in extra_libs: + include_dirs.update(set(pkgconfig.parse(lib)["include_dirs"])) +include_dirs = sorted(list(include_dirs)) print("Include directories are:") -pprint(include_path) +print(include_dirs) -print("Extra link args are:") -pprint(extra_link_args()) +print("Library directories args are:") +print(libsemigroups_info["library_dirs"]) ext_modules = [ Pybind11Extension( "_libsemigroups_pybind11", glob.glob("src/*.cpp"), - include_dirs=include_path, + include_dirs=include_dirs, + library_dirs=libsemigroups_info["library_dirs"], language="c++", libraries=["semigroups"], - extra_link_args=extra_link_args(), ), ] -with open(os.path.join(__dir__, "README.md"), "r", encoding="utf-8") as readme: - long_description = readme.read() - setup( - name="libsemigroups_pybind11", - version=__version__, - author="Joseph Edwards, James Mitchell, Maria Tsalakou, Murray Whyte", - author_email="jdm3@st-andrews.ac.uk", - url="https://github.com/libsemigroups/libsemigroups_pybind11", - description="A python package for the libsemigroups C++ library", - long_description=long_description, - long_description_content_type="text/markdown", ext_modules=ext_modules, - packages=find_packages(), - setup_requires=["pkgconfig>=1.5.5"], - install_requires=[ - "packaging>=20.4", - "pkgconfig>=1.5.5", - "pybind11>=2.13.0", - "graphviz>=0.20.1", - "numpy>=1.26.0", - ], - tests_require=["pytest==8.0.0"], cmdclass={"build_ext": build_ext}, - zip_safe=False, - python_requires=">=3.9.0", ) diff --git a/libsemigroups_pybind11/__init__.py b/src/libsemigroups_pybind11/__init__.py similarity index 97% rename from libsemigroups_pybind11/__init__.py rename to src/libsemigroups_pybind11/__init__.py index 7bde5047..b437c2d7 100644 --- a/libsemigroups_pybind11/__init__.py +++ b/src/libsemigroups_pybind11/__init__.py @@ -10,7 +10,7 @@ This package provides the user-facing python part of libsemigroups_pybind11 """ -import pkgconfig +from ._version import version as __version__ from .detail.dot import _Dot as Dot @@ -48,8 +48,6 @@ "https://github.com/libsemigroups/libsemigroups_pybind11)" ) -assert pkgconfig.exists("libsemigroups") - try: from _libsemigroups_pybind11 import ( # pylint: disable=no-name-in-module AhoCorasick, diff --git a/libsemigroups_pybind11/action.py b/src/libsemigroups_pybind11/action.py similarity index 100% rename from libsemigroups_pybind11/action.py rename to src/libsemigroups_pybind11/action.py diff --git a/libsemigroups_pybind11/adapters.py b/src/libsemigroups_pybind11/adapters.py similarity index 100% rename from libsemigroups_pybind11/adapters.py rename to src/libsemigroups_pybind11/adapters.py diff --git a/libsemigroups_pybind11/aho_corasick.py b/src/libsemigroups_pybind11/aho_corasick.py similarity index 100% rename from libsemigroups_pybind11/aho_corasick.py rename to src/libsemigroups_pybind11/aho_corasick.py diff --git a/libsemigroups_pybind11/bipartition.py b/src/libsemigroups_pybind11/bipartition.py similarity index 100% rename from libsemigroups_pybind11/bipartition.py rename to src/libsemigroups_pybind11/bipartition.py diff --git a/libsemigroups_pybind11/blocks.py b/src/libsemigroups_pybind11/blocks.py similarity index 100% rename from libsemigroups_pybind11/blocks.py rename to src/libsemigroups_pybind11/blocks.py diff --git a/libsemigroups_pybind11/bmat8.py b/src/libsemigroups_pybind11/bmat8.py similarity index 100% rename from libsemigroups_pybind11/bmat8.py rename to src/libsemigroups_pybind11/bmat8.py diff --git a/libsemigroups_pybind11/congruence.py b/src/libsemigroups_pybind11/congruence.py similarity index 100% rename from libsemigroups_pybind11/congruence.py rename to src/libsemigroups_pybind11/congruence.py diff --git a/libsemigroups_pybind11/detail/__init__.py b/src/libsemigroups_pybind11/detail/__init__.py similarity index 100% rename from libsemigroups_pybind11/detail/__init__.py rename to src/libsemigroups_pybind11/detail/__init__.py diff --git a/libsemigroups_pybind11/detail/congruence_common.py b/src/libsemigroups_pybind11/detail/congruence_common.py similarity index 100% rename from libsemigroups_pybind11/detail/congruence_common.py rename to src/libsemigroups_pybind11/detail/congruence_common.py diff --git a/libsemigroups_pybind11/detail/cxx_wrapper.py b/src/libsemigroups_pybind11/detail/cxx_wrapper.py similarity index 99% rename from libsemigroups_pybind11/detail/cxx_wrapper.py rename to src/libsemigroups_pybind11/detail/cxx_wrapper.py index 5a1f50cd..77c51f33 100644 --- a/libsemigroups_pybind11/detail/cxx_wrapper.py +++ b/src/libsemigroups_pybind11/detail/cxx_wrapper.py @@ -14,8 +14,6 @@ from functools import update_wrapper -import abc - from types import MethodType from typing import Any, Callable from typing_extensions import Self @@ -58,7 +56,7 @@ def register_cxx_wrapped_type(cxx_type: pybind11_type, py_type: type) -> None: _CXX_WRAPPED_TYPE_TO_PY_TYPE[cxx_type] = py_type -class CxxWrapper(metaclass=abc.ABCMeta): +class CxxWrapper: # pylint: disable=missing-class-docstring # pylint: disable=protected-access, no-member def __init__( diff --git a/libsemigroups_pybind11/detail/decorators.py b/src/libsemigroups_pybind11/detail/decorators.py similarity index 100% rename from libsemigroups_pybind11/detail/decorators.py rename to src/libsemigroups_pybind11/detail/decorators.py diff --git a/libsemigroups_pybind11/detail/dot.py b/src/libsemigroups_pybind11/detail/dot.py similarity index 100% rename from libsemigroups_pybind11/detail/dot.py rename to src/libsemigroups_pybind11/detail/dot.py diff --git a/src/libsemigroups_pybind11/detail/tools.py b/src/libsemigroups_pybind11/detail/tools.py new file mode 100644 index 00000000..2dde02de --- /dev/null +++ b/src/libsemigroups_pybind11/detail/tools.py @@ -0,0 +1,23 @@ +# -*- 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 libsemigroups_pybind11. +""" + + +def ordinal(n: int): + """ + Returns 1st from 1, 2nd from 2 etc. + From https://stackoverflow.com/questions/9647202/ + """ + if 11 <= (n % 100) <= 13: + suffix = "th" + else: + suffix = ["th", "st", "nd", "rd", "th"][min(n % 10, 4)] + return str(n) + suffix diff --git a/libsemigroups_pybind11/froidure_pin.py b/src/libsemigroups_pybind11/froidure_pin.py similarity index 100% rename from libsemigroups_pybind11/froidure_pin.py rename to src/libsemigroups_pybind11/froidure_pin.py diff --git a/libsemigroups_pybind11/is_obviously_infinite.py b/src/libsemigroups_pybind11/is_obviously_infinite.py similarity index 100% rename from libsemigroups_pybind11/is_obviously_infinite.py rename to src/libsemigroups_pybind11/is_obviously_infinite.py diff --git a/libsemigroups_pybind11/kambites.py b/src/libsemigroups_pybind11/kambites.py similarity index 100% rename from libsemigroups_pybind11/kambites.py rename to src/libsemigroups_pybind11/kambites.py diff --git a/libsemigroups_pybind11/knuth_bendix.py b/src/libsemigroups_pybind11/knuth_bendix.py similarity index 100% rename from libsemigroups_pybind11/knuth_bendix.py rename to src/libsemigroups_pybind11/knuth_bendix.py diff --git a/libsemigroups_pybind11/konieczny.py b/src/libsemigroups_pybind11/konieczny.py similarity index 100% rename from libsemigroups_pybind11/konieczny.py rename to src/libsemigroups_pybind11/konieczny.py diff --git a/libsemigroups_pybind11/matrix.py b/src/libsemigroups_pybind11/matrix.py similarity index 100% rename from libsemigroups_pybind11/matrix.py rename to src/libsemigroups_pybind11/matrix.py diff --git a/libsemigroups_pybind11/pbr.py b/src/libsemigroups_pybind11/pbr.py similarity index 100% rename from libsemigroups_pybind11/pbr.py rename to src/libsemigroups_pybind11/pbr.py diff --git a/libsemigroups_pybind11/presentation/__init__.py b/src/libsemigroups_pybind11/presentation/__init__.py similarity index 100% rename from libsemigroups_pybind11/presentation/__init__.py rename to src/libsemigroups_pybind11/presentation/__init__.py diff --git a/libsemigroups_pybind11/presentation/examples.py b/src/libsemigroups_pybind11/presentation/examples.py similarity index 100% rename from libsemigroups_pybind11/presentation/examples.py rename to src/libsemigroups_pybind11/presentation/examples.py diff --git a/libsemigroups_pybind11/schreier_sims.py b/src/libsemigroups_pybind11/schreier_sims.py similarity index 100% rename from libsemigroups_pybind11/schreier_sims.py rename to src/libsemigroups_pybind11/schreier_sims.py diff --git a/libsemigroups_pybind11/sims.py b/src/libsemigroups_pybind11/sims.py similarity index 100% rename from libsemigroups_pybind11/sims.py rename to src/libsemigroups_pybind11/sims.py diff --git a/libsemigroups_pybind11/stephen.py b/src/libsemigroups_pybind11/stephen.py similarity index 100% rename from libsemigroups_pybind11/stephen.py rename to src/libsemigroups_pybind11/stephen.py diff --git a/libsemigroups_pybind11/to.py b/src/libsemigroups_pybind11/to.py similarity index 100% rename from libsemigroups_pybind11/to.py rename to src/libsemigroups_pybind11/to.py diff --git a/libsemigroups_pybind11/todd_coxeter.py b/src/libsemigroups_pybind11/todd_coxeter.py similarity index 100% rename from libsemigroups_pybind11/todd_coxeter.py rename to src/libsemigroups_pybind11/todd_coxeter.py diff --git a/libsemigroups_pybind11/transf.py b/src/libsemigroups_pybind11/transf.py similarity index 100% rename from libsemigroups_pybind11/transf.py rename to src/libsemigroups_pybind11/transf.py diff --git a/libsemigroups_pybind11/ukkonen.py b/src/libsemigroups_pybind11/ukkonen.py similarity index 100% rename from libsemigroups_pybind11/ukkonen.py rename to src/libsemigroups_pybind11/ukkonen.py diff --git a/libsemigroups_pybind11/word_graph.py b/src/libsemigroups_pybind11/word_graph.py similarity index 100% rename from libsemigroups_pybind11/word_graph.py rename to src/libsemigroups_pybind11/word_graph.py diff --git a/libsemigroups_pybind11/words.py b/src/libsemigroups_pybind11/words.py similarity index 100% rename from libsemigroups_pybind11/words.py rename to src/libsemigroups_pybind11/words.py