diff --git a/.circleci/config.yml b/.circleci/config.yml index f1260b4b..82101d9c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -108,15 +108,15 @@ jobs: docker: - image: cimg/python:3.6 - "publish": - docker: - - image: cimg/python:3.7 - steps: - - checkout - - run: - name: Upload to PyPi - command: | - ./circle-build-package + # "publish": + # docker: + # - image: cimg/python:3.7 + # steps: + # - checkout + # - run: + # name: Upload to PyPi + # command: | + # ./circle-build-package workflows: version: 2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..7a4f1c90 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,89 @@ +name: Python CI + +on: + push: + branches: + - master + tags: ['*'] + pull_request: + +concurrency: + group: test-${{ github.head_ref }} + cancel-in-progress: true + +env: + PYTHONUNBUFFERED: "1" + FORCE_COLOR: "1" + +jobs: + build: + name: Python ${{ matrix.python-version }} ${{ matrix.extra-env }} + if: >- + !contains(github.event.head_commit.message, '[skip ci]') + && !contains(github.event.head_commit.message, '[skip tests]') + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install -r test_requirements.txt + python -m pip install -e . + python -m pip check + - name: Lint + run: | + flake8 -v + - name: Test + run: | + PYTEST_ARGS=(); + PYTEST_ARGS+=(-n 2 --dist loadscope); + if [[ ! -z "$PYTEST_K_FILTER" ]]; then + PYTEST_ARGS+=(-k "$PYTEST_K_FILTER"); + fi; + pytest \ + --cov=galgebra \ + --nbval examples/ipython/ \ + test \ + --current-env \ + --sanitize-with test/.nbval_sanitize.cfg \ + "${PYTEST_ARGS[@]}" + - name: Upload coverage to Codecov + if: "matrix.python-version == '3.11'" + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + + release: + name: Create release and send to PyPI + needs: build + if: >- + github.ref_type == 'tag' + && startsWith(github.ref, 'refs/tags/v') + && !contains(github.event.head_commit.message, '[skip ci]') + && !contains(github.event.head_commit.message, '[no release]') + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Install wheel + run: | + python -m pip install wheel + - name: Build and upload package + if: success() + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..9685daa1 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,11 @@ +version: 2 +build: + os: "ubuntu-22.04" + tools: + python: "3.11" + +python: + install: + - requirements: doc/readthedocs-pip-requirements.txt + - method: pip + path: . diff --git a/README.md b/README.md index 5d39f956..fb512d14 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Symbolic Geometric Algebra/Calculus package for SymPy. [![PyPI](https://img.shields.io/pypi/v/galgebra.svg)](https://pypi.org/project/galgebra/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/galgebra.svg)](https://pypi.org/project/galgebra/) -[![Build Status on CircleCI](https://circleci.com/gh/pygae/galgebra.svg?style=shield)](https://circleci.com/gh/pygae/galgebra) +[![Python CI](https://github.com/pygae/galgebra/actions/workflows/ci.yml/badge.svg)](https://github.com/pygae/galgebra/actions/workflows/ci.yml) [![Documentation Status](https://readthedocs.org/projects/galgebra/badge/?version=latest)](https://galgebra.readthedocs.io/en/latest/?badge=latest) [![DOI](https://zenodo.org/badge/113447311.svg)](https://zenodo.org/badge/latestdoi/113447311) diff --git a/circle-build-package b/circle-build-package deleted file mode 100755 index f3fe1e58..00000000 --- a/circle-build-package +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$CI" ]; then - echo "Will only continue on CI" - exit -fi - -# if [[ $CIRCLE_BRANCH != "master" ]]; then -# echo "Will only continue for master builds" -# exit -# fi - -# build package and upload to private pypi index -echo "[distutils]" >> ~/.pypirc -echo "index-servers = pypi-private" >> ~/.pypirc -echo "[pypi-private]" >> ~/.pypirc -echo "repository=https://$PYPI_HOST" >> ~/.pypirc -echo "username=$PYPI_USERNAME" >> ~/.pypirc -echo "password=$PYPI_PASSWORD" >> ~/.pypirc -python3 -m pip install --user --upgrade twine -python3 setup.py sdist bdist_wheel -python3 -m twine upload -r pypi-private dist/* diff --git a/doc/_sphinxext/releases_hack.py b/doc/_sphinxext/releases_hack.py index 8eca8670..afe044e3 100644 --- a/doc/_sphinxext/releases_hack.py +++ b/doc/_sphinxext/releases_hack.py @@ -9,7 +9,13 @@ class release_uri: def __init__(self, releases_github_path): self._path = releases_github_path + def __contains__(self, item): + return "%s" in "https://github.com/%s/tree/%s" + def __mod__(self, release): if release[0].isdigit(): release = "v" + release return 'https://github.com/%s/tree/%s' % (self._path, release) + + def format(self, /, number): + return self.__mod__(number) diff --git a/doc/conf.py b/doc/conf.py index 40ee44f1..160cc2f5 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -250,7 +250,7 @@ # If your project is hosted on Github, set the releases_github_path setting instead, # to e.g. account/project. Releases will then use an appropriate Github URL for both # releases and issues. -releases_github_path = 'pygae/galgebra' +releases_github_path = "pygae/galgebra" releases_release_uri = releases_hack.release_uri(releases_github_path) # You may optionally set releases_debug = True to see debug output while building your docs. diff --git a/doc/readthedocs-pip-requirements.txt b/doc/readthedocs-pip-requirements.txt index 8196cd85..ebc50e19 100644 --- a/doc/readthedocs-pip-requirements.txt +++ b/doc/readthedocs-pip-requirements.txt @@ -3,9 +3,9 @@ ipython matplotlib scipy -# an unreleased commit that will eventually make the 3.1.0 release, with -# type annotations which work on cached_property --e git+https://git@github.com/sphinx-doc/sphinx.git@5460ad6925199b57b27b7d059825d3560872edbb#egg=sphinx +## an unreleased commit that will eventually make the 3.1.0 release, with +## type annotations which work on cached_property +#-e git+https://git@github.com/sphinx-doc/sphinx.git@5460ad6925199b57b27b7d059825d3560872edbb#egg=sphinx ipykernel nbsphinx diff --git a/galgebra/lt.py b/galgebra/lt.py index 32c52e77..936b7933 100644 --- a/galgebra/lt.py +++ b/galgebra/lt.py @@ -754,16 +754,17 @@ def __init__(self, f, Ga, nargs=None, fct=False): else: if isinstance(f, types.FunctionType): # Tensor defined by general multi-linear function - args, _varargs, _kwargs, _defaults = inspect.getargspec(f) + args = inspect.getfullargspec(f)[0] self.nargs = len(args) self.f = f Mlt.increment_slots(self.nargs, Ga) self.fvalue = f(*tuple(Ga._mlt_a[0:self.nargs])) else: # Tensor defined by component expression - self.f = None - self.nargs = len(args) - Mlt.increment_slots(self.nargs, Ga) - self.fvalue = f + raise NotImplementedError + # self.f = None + # self.nargs = len(args) # args isn't defined, which is why we raise NotImplementedError + # Mlt.increment_slots(self.nargs, Ga) + # self.fvalue = f def __call__(self, *args): """ diff --git a/readthedocs.yml b/readthedocs.yml deleted file mode 100644 index 29a09b25..00000000 --- a/readthedocs.yml +++ /dev/null @@ -1,10 +0,0 @@ -python: - version: 3 - -python: - pip_install: true - -requirements_file: doc/readthedocs-pip-requirements.txt - -# Don't build any extra formats -formats: [] \ No newline at end of file diff --git a/setup.py b/setup.py index 1116da22..014d61dc 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,8 @@ 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Topic :: Scientific/Engineering :: Mathematics', 'Topic :: Scientific/Engineering :: Physics', ], diff --git a/test/README.md b/test/README.md index 9a6a761a..d0ca23df 100644 --- a/test/README.md +++ b/test/README.md @@ -16,7 +16,7 @@ We are primarily using [nbval](https://github.com/computationalmodelling/nbval) The test notebooks are used as a recorder of outputs (plain text, color ANSI console output, LaTeX), the author of the test notebook will need to visually inspect the outputs in Jupyter or [nbviewer](https://nbviewer.jupyter.org/) to confirm that GAlgebra is working as expected. -Then `nbval` will be run as a plugin of `pytest` in the CI environment for various versions of Python or even of dependencies to ensure the behavior is identical by checking the actual outputs with the recorded outputs. See `.circleci/config.yml` for up-to-date instructions to run them in CI. +Then `nbval` will be run as a plugin of `pytest` in the CI environment for various versions of Python or even of dependencies to ensure the behavior is identical by checking the actual outputs with the recorded outputs. See `.github/workflows/ci.yml` for up-to-date instructions to run them in CI. ### How to maintain the examples @@ -68,4 +68,4 @@ These notebooks are to demonstrate individual scenarios of interest and they are - `inner_product.ipynb` - Demo for the definition and semantics of Hestenes' inner product adopted in GAlgebra - `verify_doc_python.ipynb` - - Unfinished verification for examples in `doc/python/` \ No newline at end of file + - Unfinished verification for examples in `doc/python/` diff --git a/test_requirements.txt b/test_requirements.txt index 61e99ca8..750a22b3 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,5 +1,7 @@ # requirements for CI +wheel sympy == 1.7 +flake8 pytest-cov ipython == 5.8.0; python_version == "2.7" nbval