diff --git a/.cruft.json b/.cruft.json index 053a56e8..71f52328 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "/home/tjs/git/cookiecutter-pypackage", - "commit": "55001f0fb2b470d1be2e992bfb8e006b4bc3807c", + "commit": "f391bbd6ee14ab2478c64a1f78b74bd9903cae81", "checkout": null, "context": { "cookiecutter": { diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index b58e84af..c8ecf20e 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -74,7 +74,7 @@ jobs: - name: Current Version run: | bump-my-version show current_version - CURRENT_VERSION="$(grep -E '__version__' xscen/__init__.py | cut -d ' ' -f3)" + CURRENT_VERSION="$(grep -E '__version__' xscen/__init__.py | cut -d ' ' -f3)" echo "CURRENT_VERSION=${CURRENT_VERSION}" >> $GITHUB_ENV - name: Conditional Bump Version run: | diff --git a/.github/workflows/cache-cleaner.yml b/.github/workflows/cache-cleaner.yml index 5a11be38..0bab6cd0 100644 --- a/.github/workflows/cache-cleaner.yml +++ b/.github/workflows/cache-cleaner.yml @@ -12,6 +12,8 @@ jobs: cleanup: name: Cleanup runs-on: ubuntu-latest + permissions: + actions: write steps: - name: Harden Runner uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index a8aef913..2435f67c 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -20,7 +20,13 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 with: - egress-policy: audit + disable-sudo: true + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + upload.pypi.org:443 - uses: actions/checkout@v4.1.1 - name: Set up Python3 uses: actions/setup-python@v5.0.0 diff --git a/.github/workflows/tag-testpypi.yml b/.github/workflows/tag-testpypi.yml index c3689899..fa478075 100644 --- a/.github/workflows/tag-testpypi.yml +++ b/.github/workflows/tag-testpypi.yml @@ -44,7 +44,13 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 with: - egress-policy: audit + disable-sudo: true + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + test.pypi.org:443 - uses: actions/checkout@v4.1.1 - name: Set up Python3 uses: actions/setup-python@v5.0.0 @@ -60,5 +66,5 @@ jobs: - name: Publish distribution 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@v1.8.12 with: - repository_url: https://test.pypi.org/legacy/ - skip_existing: true + repository-url: https://test.pypi.org/legacy/ + skip-existing: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5ad0303d..8982cd51 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,6 +27,11 @@ repos: - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.10.0 hooks: + - id: python-check-blanket-noqa + - id: python-no-eval + exclude: biasadjust.py + - id: python-no-log-warn + - id: python-use-type-annotations - id: rst-inline-touching-normal - repo: https://github.com/pappasam/toml-sort rev: v0.23.1 @@ -79,7 +84,7 @@ repos: hooks: - id: nbstripout files: ".ipynb" - args: [ '--extra-keys', 'metadata.kernelspec' ] + args: [ '--extra-keys=metadata.kernelspec' ] - repo: https://github.com/Yelp/detect-secrets rev: v1.4.0 hooks: diff --git a/CHANGES.rst b/CHANGES.rst index d911d770..22952443 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,17 @@ Changelog ========= +v0.9.0 (unreleased) +------------------- +Contributors to this version: Trevor James Smith (:user:`Zeitsperre`). + +Internal changes +^^^^^^^^^^^^^^^^ +* Updated the `cookiecutter` template to the latest version. (:pull:`358`): + * Addresses a handful of misconfigurations in the GitHub Workflows. + * Added a few free `grep`-based hooks for finding unwanted artifacts in the code base. + * Updated `ruff` to v0.2.0 and `black` to v24.2.0. + v0.8.3 (2024-02-28) ------------------- Contributors to this version: Juliette Lavoie (:user:`juliettelavoie`), Trevor James Smith (:user:`Zeitsperre`), Gabriel Rondeau-Genesse (:user:`RondeauG`), Pascal Bourgault (:user:`aulemahal`). diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index e22fbe37..d10ab214 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -47,7 +47,7 @@ If you are proposing a feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that contributions - are welcome :) + are welcome. :) Get Started! ------------ @@ -204,7 +204,7 @@ Before you submit a pull request, check that it meets these guidelines: #. The pull request should not break the templates. -#. The pull request should work for Python 3.9, 3.10, and 3.11. Check that the tests pass for all supported Python versions. +#. The pull request should work for Python 3.9, 3.10, 3.11, and 3.12. Check that the tests pass for all supported Python versions. Tips ---- diff --git a/docs/conf.py b/docs/conf.py index 88bb5908..3076a05c 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,13 +26,13 @@ sys.path.insert(0, os.path.abspath("..")) if os.environ.get("READTHEDOCS") and "ESMFMKFILE" not in os.environ: - # RTD doesn't activate the env, and esmpy depends on a env var set there + # RTD doesn't activate the env, and esmpy depends on an env var set there # We assume the `os` package is in {ENV}/lib/pythonX.X/os.py # See conda-forge/esmf-feedstock#91 and readthedocs/readthedocs.org#4067 os.environ["ESMFMKFILE"] = str(Path(os.__file__).parent.parent / "esmf.mk") -import xscen # noqa -import xarray # noqa +import xscen # noqa: E402,F401 +import xarray # noqa: E402 xarray.DataArray.__module__ = "xarray" xarray.Dataset.__module__ = "xarray" diff --git a/environment-dev.yml b/environment-dev.yml index fe5b5405..9ff631b4 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -38,9 +38,9 @@ dependencies: - pyarrow >=1.0.0 # Dev - babel - - black ==24.1.1 + - black ==24.2.0 - blackdoc ==0.3.9 - - bump-my-version >=0.17.1 + - bump-my-version >=0.18.3 # - coverage>=6.2.2,<7.0.0 # - coveralls>=3.3.1 - flake8 >=6.1.0 diff --git a/pyproject.toml b/pyproject.toml index c1e01542..22d05567 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ dev = [ "pip >=23.3.0", "black ==24.2.0", "blackdoc ==0.3.9", - "bump-my-version >=0.17.1", + "bump-my-version >=0.18.3", "coverage >=6.2.2,<8.0.0", "coveralls >=3.3.1", "flake8-alphabetize >=0.0.21", @@ -193,7 +193,7 @@ testpaths = "tests" markers = ["requires_netcdf: marks tests that require netcdf files to run"] [tool.ruff] -src = [""] +src = ["xscen"] line-length = 150 target-version = "py39" exclude = [ @@ -215,30 +215,30 @@ select = [ "W" ] -[tool.ruff.flake8-bandit] -check-typed-exception = true - [tool.ruff.format] line-ending = "auto" -[tool.ruff.isort] +[tool.ruff.lint.flake8-bandit] +check-typed-exception = true + +[tool.ruff.lint.isort] known-first-party = ["xscen"] case-sensitive = true detect-same-package = false lines-after-imports = 1 no-lines-before = ["future", "standard-library"] -[tool.ruff.mccabe] +[tool.ruff.lint.mccabe] max-complexity = 15 -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "xscen/**/__init__.py" = ["F401", "F403"] "tests/**/*.py" = ["D100", "D101", "D102", "D103"] -[tool.ruff.pycodestyle] +[tool.ruff.lint.pycodestyle] max-doc-length = 180 -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = "numpy" [tool.setuptools] diff --git a/tox.ini b/tox.ini index 72eb40fb..112d8473 100644 --- a/tox.ini +++ b/tox.ini @@ -19,12 +19,12 @@ download = true conda_channels = conda_env = deps = - black ==24.1.1 + black ==24.2.0 blackdoc ==0.3.9 isort ==5.13.2 flake8 flake8-rst-docstrings - ruff + ruff >=0.2.0 commands_pre = pip list commands = diff --git a/xscen/__init__.py b/xscen/__init__.py index bf2f0b5b..7e03c563 100644 --- a/xscen/__init__.py +++ b/xscen/__init__.py @@ -25,19 +25,19 @@ # Import top-level functions from .aggregate import * from .biasadjust import * -from .catalog import DataCatalog, ProjectCatalog # noqa +from .catalog import DataCatalog, ProjectCatalog from .catutils import build_path, parse_directory -from .config import CONFIG, load_config # noqa +from .config import CONFIG, load_config from .diagnostics import properties_and_measures from .ensembles import * -from .extract import ( # noqa +from .extract import ( extract_dataset, get_warming_level, search_data_catalogs, subset_warming_level, ) -from .indicators import compute_indicators # noqa -from .io import save_to_netcdf, save_to_table, save_to_zarr # noqa +from .indicators import compute_indicators +from .io import save_to_netcdf, save_to_table, save_to_zarr from .reduce import build_reduction_data, reduce_ensemble from .regrid import * from .scripting import ( @@ -58,7 +58,7 @@ def warning_on_one_line( message: str, category: Warning, filename: str, lineno: int, file=None, line=None -): # noqa: D103 +): """Monkeypatch Reformat warning so that `warnings.warn` doesn't mention itself.""" return f"{filename}:{lineno}: {category.__name__}: {message}\n" @@ -72,7 +72,8 @@ def warning_on_one_line( category=FutureWarning, module="intake_esm", message="The default of observed=False is deprecated and will be changed to True in a future version of pandas. " - "Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.", + "Pass observed=False to retain current behavior or observed=True to adopt the future default " + "and silence this warning.", ) warnings.filterwarnings( "ignore", diff --git a/xscen/catalog.py b/xscen/catalog.py index d10d3fb0..82ba671d 100644 --- a/xscen/catalog.py +++ b/xscen/catalog.py @@ -22,8 +22,7 @@ from intake_esm.cat import ESMCatalogModel from .config import CONFIG, args_as_str, recursive_update -from .utils import ( # noqa - CV, +from .utils import ( date_parser, ensure_correct_time, ensure_new_xrfreq, @@ -42,6 +41,7 @@ "ProjectCatalog", "concat_data_catalogs", "generate_id", + "subset_file_coverage", "unstack_id", ] diff --git a/xscen/catutils.py b/xscen/catutils.py index c6197571..d7b630e1 100644 --- a/xscen/catutils.py +++ b/xscen/catutils.py @@ -30,14 +30,7 @@ from .catalog import COLUMNS, DataCatalog, generate_id from .config import parse_config from .io import get_engine -from .utils import ( # noqa - CV, - date_parser, - ensure_correct_time, - ensure_new_xrfreq, - get_cat_attrs, - standardize_periods, -) +from .utils import CV, date_parser, ensure_new_xrfreq, get_cat_attrs logger = logging.getLogger(__name__) @@ -434,7 +427,7 @@ def _parse_first_ds( @parse_config -def parse_directory( # noqa:C901 +def parse_directory( # noqa: C901 directories: list[Union[str, os.PathLike]], patterns: list[str], *, diff --git a/xscen/extract.py b/xscen/extract.py index 527a4420..0a29e6ad 100644 --- a/xscen/extract.py +++ b/xscen/extract.py @@ -18,8 +18,13 @@ from intake_esm.derived import DerivedVariableRegistry from xclim.core.calendar import compare_offsets -from .catalog import DataCatalog # noqa -from .catalog import ID_COLUMNS, concat_data_catalogs, generate_id, subset_file_coverage +from .catalog import ( + ID_COLUMNS, + DataCatalog, + concat_data_catalogs, + generate_id, + subset_file_coverage, +) from .catutils import parse_from_ds from .config import parse_config from .indicators import load_xclim_module, registry_from_module diff --git a/xscen/indicators.py b/xscen/indicators.py index 02e8ff6e..68e43df5 100644 --- a/xscen/indicators.py +++ b/xscen/indicators.py @@ -21,7 +21,7 @@ logger = logging.getLogger(__name__) -__all__ = ["compute_indicators", "load_xclim_module"] +__all__ = ["compute_indicators", "load_xclim_module", "registry_from_module"] def load_xclim_module( diff --git a/xscen/utils.py b/xscen/utils.py index 4e0adad3..c629f295 100644 --- a/xscen/utils.py +++ b/xscen/utils.py @@ -33,10 +33,13 @@ logger = logging.getLogger(__name__) __all__ = [ + "CV", "add_attr", "change_units", "clean_up", "date_parser", + "ensure_correct_time", + "ensure_new_xrfreq", "get_cat_attrs", "maybe_unstack", "minimum_calendar", @@ -48,6 +51,7 @@ "unstack_dates", "unstack_fill_nan", "update_attr", + "xrfreq_to_timedelta", ] TRANSLATOR = defaultdict(lambda: lambda s: s)