diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7818bef..204a481 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,4 +12,4 @@ updates: groups: github-actions: patterns: - - '*' + - '*' \ No newline at end of file diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index 7db91df..ea7b6b8 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -2,10 +2,10 @@ name: Wheels on: pull_request: - push: - tags: - - "v*" + release: + types: + - published jobs: build_bdist: @@ -28,19 +28,20 @@ jobs: arch: x86_64 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 + persist-credentials: false # For aarch64 support # https://cibuildwheel.pypa.io/en/stable/faq/#emulation - - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 with: platforms: all if: runner.os == 'Linux' && matrix.arch == 'aarch64' - name: "Building ${{ matrix.os }} (${{ matrix.arch }}) wheels" - uses: pypa/cibuildwheel@v3.0.0 + uses: pypa/cibuildwheel@5f22145df44122af0f5a201f93cf0207171beca7 # v3.0.0 env: # Skips pypy and musllinux for now. CIBW_SKIP: "pp* cp36-* cp37-* cp38-* *-musllinux*" @@ -52,19 +53,21 @@ jobs: python -c "import gsw; print(f'gsw v{gsw.__version__}')" && python -m pytest --pyargs gsw - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pypi-artifacts-${{ matrix.os }}-${{ matrix.arch }} path: ${{ github.workspace }}/wheelhouse/*.whl - + permissions: + actions: write build_sdist: name: Build source distribution runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 + persist-credentials: false - name: Build sdist run: > @@ -73,17 +76,19 @@ jobs: && twine check dist/* && check-manifest --verbose - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pypi-artifacts path: ${{ github.workspace }}/dist/*.tar.gz + permissions: + actions: write show-artifacts: needs: [build_bdist, build_sdist] name: "Show artifacts" runs-on: ubuntu-22.04 steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: pypi-artifacts* path: ${{ github.workspace }}/dist @@ -92,7 +97,8 @@ jobs: - shell: bash run: | ls -l ${{ github.workspace }}/dist - + permissions: + actions: none publish-artifacts-pypi: needs: [build_bdist, build_sdist] @@ -101,14 +107,16 @@ jobs: # upload to PyPI for every tag starting with 'v' if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: pypi-artifacts* path: ${{ github.workspace }}/dist merge-multiple: true - - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} - print_hash: true + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 + environment: + name: release + url: https://pypi.org/p/gsw + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing \ No newline at end of file diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index e5be8a1..c8342e0 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -2,10 +2,10 @@ name: Build and Deploy docs on: pull_request: - push: - tags: - - "v*" + release: + types: + - published defaults: run: @@ -15,10 +15,14 @@ jobs: run: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.x" @@ -36,7 +40,9 @@ jobs: - name: GitHub Pages action if: success() && github.event_name == 'release' - uses: peaceiris/actions-gh-pages@v4 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs/_build/html + permissions: + actions: write diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 65947d3..1746e15 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -9,6 +9,11 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - - uses: pre-commit/action@v3.0.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + permissions: + actions: none \ No newline at end of file diff --git a/.github/workflows/test_code_generation.yml b/.github/workflows/test_code_generation.yml index f002920..6d7977f 100644 --- a/.github/workflows/test_code_generation.yml +++ b/.github/workflows/test_code_generation.yml @@ -3,7 +3,7 @@ name: Test code generation on: pull_request: push: - branches: [main] + branches: [ main ] defaults: run: @@ -14,10 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.x" @@ -39,4 +42,6 @@ jobs: - name: Install gsw run: > python -m pip install -v -e . --no-deps --no-build-isolation --force-reinstall - && python -m pytest -s -rxs -v gsw/tests \ No newline at end of file + && python -m pytest -s -rxs -v gsw/tests + permissions: + actions: none \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 545d9e0..a49bd67 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,7 +3,7 @@ name: Tests on: pull_request: push: - branches: [main] + branches: [ main ] defaults: run: @@ -24,10 +24,13 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} @@ -40,3 +43,5 @@ jobs: - name: Tests run: | python -m pytest -s -rxs -v gsw/tests + permissions: + actions: none \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ae53849..dff9d98 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,13 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-ast - id: debug-statements - id: check-added-large-files - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + rev: v2.4.1 hooks: - id: codespell exclude: > @@ -20,16 +20,21 @@ repos: - --ignore-words-list=nin,preformed,wih, - repo: https://github.com/tox-dev/pyproject-fmt - rev: 1.8.0 + rev: v2.6.0 hooks: - id: pyproject-fmt - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.3.7 + rev: v0.11.13 hooks: - id: ruff +- repo: https://github.com/woodruffw/zizmor-pre-commit + rev: v1.9.0 + hooks: + - id: zizmor + ci: autofix_commit_msg: | [pre-commit.ci] auto fixes from pre-commit.com hooks diff --git a/gsw/tests/_WIP_test_ufuncs.py b/gsw/tests/_WIP_test_ufuncs.py index bd605d9..f54e816 100644 --- a/gsw/tests/_WIP_test_ufuncs.py +++ b/gsw/tests/_WIP_test_ufuncs.py @@ -29,7 +29,7 @@ def cfcf(request): def test_mechanism(cfcf): cv, cf, mfunc = cfcf - print("<%s>" % mfunc.name) + print(f"<{mfunc.name}>") def value_from_name(vname): b, name = vname.split('.') if b == 'cf': @@ -37,7 +37,7 @@ def value_from_name(vname): elif b == 'cv': return cv[name] else: - raise ValueError("Can't find cf. or cv. in %s" % vname) + raise ValueError(f"Can't find cf. or cv. in {vname}") def set_from_name(vname, value): b, name = vname.split('.') if b == 'cf': @@ -76,10 +76,10 @@ def set_from_name(vname, value): #set_from_name(mfunc.test_varstrings[0], expected - found) else: - print(">>%s<<" % mfunc.testline) + print(f">>{mfunc.testline}<<") print("missing mfunc.test_varstrings") mfunc.run() - if hasattr(mfunc, 'exception'): - print(">>>%s<<<", mfunc.exception) + if hasattr(mfunc, "exception"): + print(f">>>{mfunc.exception}<<<") else: assert mfunc.passed diff --git a/gsw/tests/check_functions.py b/gsw/tests/check_functions.py index eefb566..2c20d11 100644 --- a/gsw/tests/check_functions.py +++ b/gsw/tests/check_functions.py @@ -177,9 +177,9 @@ def run(self, locals_=None): # The following is needed for melting_ice_into_seawater. if len(self.outstrings) > 1: - rl_ind = '[:%d]' % len(self.outstrings) + rl_ind = f"[:{len(self.outstrings)}]" else: - rl_ind = '' + rl_ind = "" exec(self.runline + rl_ind, *evalargs) if len(self.outstrings) == 1: @@ -327,13 +327,13 @@ def parse_check_functions(mfile): isinstance(f.exception, exc)] ex_dict[exc] = elist - print("\n%s tests were translated from gsw_check_functions.m" % len(checks)) - print("\n%s tests ran with no error and with correct output" % len(passes)) + print(f"\n{len(checks)} tests were translated from gsw_check_functions.m") + print(f"\n{len(passes)} tests ran with no error and with correct output") if args.verbose: for f in passes: print(f.name) - print("\n%s tests had an output mismatch:" % len(failures)) + print(f"\n{len(failures)} tests had an output mismatch:") for f in failures: print(f.name) print(f.runline) @@ -348,7 +348,7 @@ def parse_check_functions(mfile): print('') - print("\n%s exceptions were raised as follows:" % len(run_problems)) + print(f"\n{len(run_problems)} exceptions were raised as follows:") for exc in etypes: print(" ", exc.__name__) strings = [" {} : {}".format(*e) for e in ex_dict[exc]] diff --git a/pyproject.toml b/pyproject.toml index 99f9cf7..74f321c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,20 +2,20 @@ build-backend = "setuptools.build_meta" requires = [ "build", - 'numpy<3,>=2.0.0rc1; python_version >= "3.9"', - 'oldest-supported-numpy; python_version < "3.9"', + "numpy>=2.0.0rc1,<3; python_version>='3.9'", + "oldest-supported-numpy; python_version<'3.9'", "pip>9.0.1", "setuptools>=42", - "setuptools_scm[toml]>=3.4", + "setuptools-scm[toml]>=3.4", "wheel", ] [project] name = "gsw" description = "Gibbs Seawater Oceanographic Package of TEOS-10" -license = {text = "BSD-3-Clause"} +license = { text = "BSD-3-Clause" } authors = [ - {name = "Eric Firing, Filipe Fernandes", email = "efiring@hawaii.edu"}, + { name = "Eric Firing, Filipe Fernandes", email = "efiring@hawaii.edu" }, ] requires-python = ">=3.8" classifiers = [ @@ -30,6 +30,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering", ] dynamic = [ @@ -39,21 +40,19 @@ dynamic = [ dependencies = [ "numpy>=1.21", ] -[project.urls] -documentation = "https://teos-10.github.io/GSW-Python/" -homepage = "https://www.teos-10.org/" -repository = "https://github.com/TEOS-10/GSW-python" +urls.documentation = "https://teos-10.github.io/GSW-Python/" +urls.homepage = "https://www.teos-10.org/" +urls.repository = "https://github.com/TEOS-10/GSW-python" [tool.setuptools] -license-files = ["LICENSE.txt"] +license-files = [ "LICENSE.txt" ] zip-safe = false include-package-data = true -packages = ["gsw", "gsw.tests"] - +packages = [ "gsw", "gsw.tests" ] [tool.setuptools.dynamic] -dependencies = {file = ["requirements.txt"]} -readme = {file = "README.md", content-type = "text/markdown"} +dependencies = { file = [ "requirements.txt" ] } +readme = { file = "README.md", content-type = "text/markdown" } [tool.setuptools_scm] write_to = "gsw/_version.py" @@ -61,49 +60,47 @@ write_to_template = "__version__ = '{version}'" tag_regex = "^(?Pv)?(?P[^\\+]+)(?P.*)?$" [tool.ruff] -lint.select = [ - "A", # flake8-builtins - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "F", # flakes - "I", # import sorting - "UP", # upgrade - "NPY201", # numpy 2.0 -] target-version = "py38" line-length = 105 -lint.ignore = [ - "F401", # module imported but unused - "E501", # line too long - "E713", # test for membership should be 'not in' -] - exclude = [ "tools", ] -[tool.ruff.lint.per-file-ignores] -"docs/conf.py" = [ - "A001", # variable is shadowing a python builtin +lint.select = [ + "A", # flake8-builtins + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "F", # flakes + "I", # import sorting + "NPY201", # numpy 2.0 + "UP", # upgrade ] -"gsw/_fixed_wrapped_ufuncs.py" = [ - "F403", #'from x import *' used; unable to detect undefined names - "F405", # 'import' may be undefined, or defined from star imports +lint.ignore = [ + "E501", # line too long + "E713", # test for membership should be 'not in' + "F401", # module imported but unused ] -"gsw/_utilities.py" = [ - "B904", # Within an ``except`` clause, raise exceptions with ``raise ... from err`` +lint.per-file-ignores."docs/conf.py" = [ + "A001", # variable is shadowing a python builtin +] +lint.per-file-ignores."gsw/_fixed_wrapped_ufuncs.py" = [ + "F403", #'from x import *' used; unable to detect undefined names + "F405", # 'import' may be undefined, or defined from star imports +] +lint.per-file-ignores."gsw/_utilities.py" = [ + "B904", # Within an ``except`` clause, raise exceptions with ``raise ... from err`` ] [tool.check-manifest] ignore = [ - "*.yml", - ".coveragerc", - "docs", - "docs/*", - "*.enc", - "tools", - "tools/*", - "gsw/_version.py", + "*.yml", + ".coveragerc", + "docs", + "docs/*", + "*.enc", + "tools", + "tools/*", + "gsw/_version.py", ]