From 0905bc343c979435374dff3038b0db0e3e20ff91 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 14:48:15 -0400 Subject: [PATCH 01/26] start pyprojtoml --- pyproject.toml | 108 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4cbe62e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,108 @@ +[build-system] +requires = ["setuptools>=61.0", "setuptools_scm[toml]>=6.2"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] + +[project] +name = "giddy" +dynamic = ["version"] +maintainers = [ + {name = "Wei Kang", email = "weikang9009@gmail.com"}, +] +license = {text = "BSD 3-Clause"} +description = "PySAL-giddy for exploratory spatiotemporal data analysis" +keywords = ["spatial statistics", "spatiotemporal analysis"] +readme = "README.md" +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: GIS", +] +requires-python = ">=3.9" +dependencies = [ + "esda>=2.1.1", + "libpysal>=4.0.1", + "quantecon>=0.4.7", + "scipy>=1.3", +] + +[project.urls] +Home = "https://pysal.org/giddy/" +Repository = "https://github.com/pysal/giddy" + +[project.optional-dependencies] +dev = [ + "black", + "ruff", + "pre-commit", +] +docs = [ + "nbsphinx", + "numpydoc", + "sphinx", + "sphinxcontrib-bibtex", + "sphinx_bootstrap_theme", +] +tests = [ + "codecov", + "ipywidgets", + "matplotlib", + "pytest", + "pytest-cov", + "pytest-xdist", + "splot", +] + +[tool.setuptools.packages.find] +include = [ + "giddy", + "giddy.*", +] + +[tool.black] +line-length = 88 +extend-exclude = ''' +( + docs/conf.py +) +#''' + +[tool.ruff] +line-length = 88 +select = ["E", "F", "W", "I", "UP", "N", "B", "A", "C4", "SIM", "ARG"] +target-version = "py39" +ignore = [ + "B006", + "B008", + "B009", + "B010", + "C408", + "E731", + "F401", + "F403", + "N803", + "N806", + "N999", + "UP007" +] +exclude = ["giddy/tests/*", "docs/*"] + +[tool.coverage.run] +source = ["./giddy"] + +[tool.coverage.report] +exclude_lines = [ + "if self.debug:", + "pragma: no cover", + "raise NotImplementedError", + "except ModuleNotFoundError:", + "except ImportError", +] +ignore_errors = true +omit = ["giddy/tests/*", "docs/conf.py"] From 3039e82cef9cb3b1572d2b3cdc2463fc50e984ba Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 14:48:30 -0400 Subject: [PATCH 02/26] remove manifest --- MANIFEST.in | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index fdc1fe1..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include LICENSE.txt CHANGELOG.md MANIFEST.in requirements_docs.txt requirements_tests.txt requirements.txt - From 0bf05717274d1a51117538f8461fd1f7a2c0be5a Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 14:48:46 -0400 Subject: [PATCH 03/26] remove version from __init__ --- giddy/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/giddy/__init__.py b/giddy/__init__.py index 8e89fee..ae6e098 100644 --- a/giddy/__init__.py +++ b/giddy/__init__.py @@ -1,6 +1,3 @@ -__version__ = "2.3.4" -# __version__ has to be defined in the first line - """ :mod:`giddy` --- Spatial Dynamics and Mobility ============================================== From 15c88b3489534b1596a81d4861b2a88fbc90eb7e Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 14:58:01 -0400 Subject: [PATCH 04/26] update pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 78f73a7..f49f66c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: black language_version: python3 - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.0.292" + rev: "v0.1.0" hooks: - id: ruff From d1a56a952d02a5c90e7b4c9a556e72230a723083 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:07:37 -0400 Subject: [PATCH 05/26] update README --- README.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 19b1eb9..381d0ea 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,29 @@ PySAL-giddy for exploratory spatiotemporal data analysis -======================================================== +============================================ -[![Continuous Integration](https://github.com/pysal/giddy/actions/workflows/unittests.yml/badge.svg)](https://github.com/pysal/giddy/actions/workflows/unittests.yml) -[![codecov](https://codecov.io/gh/pysal/giddy/branch/master/graph/badge.svg)](https://codecov.io/gh/pysal/giddy) +[![Continuous Integration](https://github.com/pysal/giddy/actions/workflows/testing.yml/badge.svg)](https://github.com/pysal/giddy/actions/workflows/testing.yml) +[![codecov](https://codecov.io/gh/pysal/giddy/branch/main/graph/badge.svg)](https://codecov.io/gh/pysal/giddy) [![Gitter room](https://badges.gitter.im/pysal/giddy.svg)](https://gitter.im/pysal/giddy) [![PyPI version](https://badge.fury.io/py/giddy.svg)](https://badge.fury.io/py/giddy) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7693957.svg)](https://doi.org/10.5281/zenodo.7693957) -[![badge](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/pysal/giddy/master) +[![badge](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/pysal/giddy/main) [![Downloads](https://static.pepy.tech/badge/giddy)](https://pepy.tech/project/giddy) -Giddy is an open-source python library for exploratory spatiotemporal data analysis and the analysis of -geospatial distribution dynamics. -It is under active development -for the inclusion of newly proposed analytics that consider the -role of space in the evolution of distributions over time. +Giddy is an open-source python library for exploratory spatiotemporal data analysis and the analysis of geospatial distribution dynamics. It is under active development for the inclusion of newly proposed analytics that consider the role of space in the evolution of distributions over time. *Below are six choropleth maps of U.S. state per-capita incomes from 1929 to 2004 at a fifteen-year interval.* ![us_qunitile_maps](figs/us_qunitile_maps.png) Documentation -------------- +-------------------- Online documentation is available [here](http://pysal.org/giddy/). Features --------- +------------ + - Directional LISA, inference and visualization as rose diagram [![rose_conditional](figs/rose_conditional.png)](notebooks/DirectionalLISA.ipynb) @@ -50,7 +47,7 @@ Features Examples --------- +------------- * [Directional LISA](notebooks/DirectionalLISA.ipynb) * [Markov based methods](notebooks/MarkovBasedMethods.ipynb) @@ -60,7 +57,7 @@ Examples * [Sequence methods (Optimal matching)](notebooks/Sequence.ipynb) Installation ------------- +-------------- Install the stable version released on the [Python Package Index](https://pypi.org/project/giddy/) from the command line: @@ -71,7 +68,7 @@ pip install giddy Install the development version on [pysal/giddy](https://github.com/pysal/giddy): ``` -pip install https://github.com/pysal/giddy/archive/main.zip +pip install git+https://github.com/pysal/giddy ``` #### Requirements @@ -83,25 +80,25 @@ pip install https://github.com/pysal/giddy/archive/main.zip - quantecon>=0.4.7 Contribute ----------- +-------------- PySAL-giddy is under active development and contributors are welcome. If you have any suggestion, feature request, or bug report, please open a new [issue](https://github.com/pysal/giddy/issues) on GitHub. To submit patches, please follow the PySAL development [guidelines](https://github.com/pysal/pysal/wiki) and open a [pull request](https://github.com/pysal/giddy). Once your changes get merged, you’ll automatically be added to the [Contributors List](https://github.com/pysal/giddy/graphs/contributors). Support -------- +----------- If you are having issues, please talk to us in the [gitter room](https://gitter.im/pysal/giddy). License -------- +---------- -The project is licensed under the [BSD license](https://github.com/pysal/giddy/blob/master/LICENSE.txt). +The project is licensed under the [BSD license](https://github.com/pysal/giddy/blob/main/LICENSE.txt). BibTeX Citation ---------------- +--------------------- ``` @software{wei_kang_2023_7693957, @@ -126,6 +123,6 @@ BibTeX Citation ``` Funding -------- +----------- Award #1421935 [New Approaches to Spatial Distribution Dynamics](https://www.nsf.gov/awardsearch/showAward?AWD_ID=1421935) From f33830c519c70f68a03950f4e87a63ddc027d188 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:07:51 -0400 Subject: [PATCH 06/26] update codecov --- codecov.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codecov.yml b/codecov.yml index d4442bf..7640976 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,6 +1,6 @@ codecov: notify: - after_n_builds: 16 + after_n_builds: 5 coverage: range: 50..95 round: nearest @@ -18,5 +18,5 @@ coverage: comment: layout: "reach, diff, files" behavior: once - after_n_builds: 16 + after_n_builds: 5 require_changes: true From b89187945e4f7158d59d0e466722cec003e14a73 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:09:36 -0400 Subject: [PATCH 07/26] rename CI and add MIN env tag --- .github/workflows/{unittests.yml => tests.yml} | 2 +- ci/{39.yaml => 39-MIN.yaml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{unittests.yml => tests.yml} (98%) rename ci/{39.yaml => 39-MIN.yaml} (100%) diff --git a/.github/workflows/unittests.yml b/.github/workflows/tests.yml similarity index 98% rename from .github/workflows/unittests.yml rename to .github/workflows/tests.yml index 889488e..98fb95e 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: matrix: os: [ubuntu-latest] environment-file: - - ci/39.yaml + - ci/39-MIN.yaml - ci/310.yaml - ci/311.yaml - ci/311-DEV.yaml diff --git a/ci/39.yaml b/ci/39-MIN.yaml similarity index 100% rename from ci/39.yaml rename to ci/39-MIN.yaml From 6532f63a96a34dc0c40324b3d27ea57ad51f80e8 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:10:15 -0400 Subject: [PATCH 08/26] remove setup* stuff --- giddy/__init__.py | 8 +--- requirements.txt | 5 --- requirements_docs.txt | 5 --- requirements_tests.txt | 8 ---- setup.py | 95 ------------------------------------------ 5 files changed, 1 insertion(+), 120 deletions(-) delete mode 100644 requirements.txt delete mode 100644 requirements_docs.txt delete mode 100644 requirements_tests.txt delete mode 100644 setup.py diff --git a/giddy/__init__.py b/giddy/__init__.py index ae6e098..6891649 100644 --- a/giddy/__init__.py +++ b/giddy/__init__.py @@ -4,10 +4,4 @@ """ -from . import directional -from . import ergodic -from . import markov -from . import mobility -from . import rank -from . import util -from . import sequence +from . import directional, ergodic, markov, mobility, rank, sequence, util diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 62173ce..0000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -esda>=2.1.1 -libpysal>=4.0.1 -mapclassify>=2.1.1 -quantecon>=0.4.7 -scipy>=1.3.0 diff --git a/requirements_docs.txt b/requirements_docs.txt deleted file mode 100644 index e2e48c6..0000000 --- a/requirements_docs.txt +++ /dev/null @@ -1,5 +0,0 @@ -nbsphinx -numpydoc -sphinx>=1.4.3 -sphinxcontrib-bibtex -sphinx_bootstrap_theme diff --git a/requirements_tests.txt b/requirements_tests.txt deleted file mode 100644 index 1259a06..0000000 --- a/requirements_tests.txt +++ /dev/null @@ -1,8 +0,0 @@ -codecov -ipywidgets -matplotlib -pandas -pytest -pytest-cov -pytest-xdist -splot \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index 9f90916..0000000 --- a/setup.py +++ /dev/null @@ -1,95 +0,0 @@ -"""GIDDY: GeospatIal Distribution DYnamics and Exploratory SpatioTemporal Data Analysis (ESTDA) - -Giddy is an open-source python library for exploratory spatiotemporal data analysis -and the analysis of geospatial distribution dynamics. It is under active development -for the inclusion of many newly proposed analytics that consider the -role of space in the evolution of distributions over time and has -several new features including inter- and intra-regional decomposition -of mobility association and local measures of exchange mobility in -addition to space-time LISA and spatial markov methods. Give -giddy a try if you are interested in space-time analysis! - -""" - -DOCLINES = __doc__.split("\n") - -with open("README.md", "r", encoding="utf8") as file: - long_description = file.read() - - -from setuptools import setup, find_packages -from distutils.command.build_py import build_py -import os - -# Get __version__ from giddy/__init__.py without importing the package -# __version__ has to be defined in the first line -with open("giddy/__init__.py", "r") as f: - exec(f.readline()) - -# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly -# update it when the contents of directories change. -if os.path.exists("MANIFEST"): - os.remove("MANIFEST") - - -def _get_requirements_from_files(groups_files): - groups_reqlist = {} - - for k, v in groups_files.items(): - with open(v, "r") as f: - pkg_list = f.read().splitlines() - groups_reqlist[k] = pkg_list - - return groups_reqlist - - -def setup_package(): - _groups_files = { - "base": "requirements.txt", - "tests": "requirements_tests.txt", - "docs": "requirements_docs.txt", - } - - reqs = _get_requirements_from_files(_groups_files) - install_reqs = reqs.pop("base") - extras_reqs = reqs - - setup( - name="giddy", # name of package - version=__version__, - description=DOCLINES[0], - # long_description="\n".join(DOCLINES[2:]), - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/pysal/giddy", - maintainer="Wei Kang", - maintainer_email="weikang9009@gmail.com", - py_modules=["giddy"], - python_requires=">3.6", - # setup_requires=["pytest-runner"], - # tests_require=["pytest"], - keywords="spatial statistics, spatiotemporal analysis", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Science/Research", - "Intended Audience :: Developers", - "Intended Audience :: Education", - "Topic :: Scientific/Engineering", - "Topic :: Scientific/Engineering :: GIS", - "License :: OSI Approved :: BSD License", - "Programming Language :: Python", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - ], - license="3-Clause BSD", - packages=find_packages(), - install_requires=install_reqs, - extras_require=extras_reqs, - zip_safe=False, - cmdclass={"build.py": build_py}, - ) - - -if __name__ == "__main__": - setup_package() From d8a169cd53be71d94e1b83b33837c59c6e80a724 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:18:43 -0400 Subject: [PATCH 09/26] update release action --- .github/release.yml | 16 ++++ .github/workflows/release_and_publish.yml | 95 +++++++---------------- 2 files changed, 42 insertions(+), 69 deletions(-) create mode 100644 .github/release.yml diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..f543544 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,16 @@ +changelog: + exclude: + labels: + - ignore-for-release + authors: + - dependabot + categories: + - title: Bug Fixes + labels: + - bug + - title: Enhancements + labels: + - enhancement + - title: Other Changes + labels: + - "*" diff --git a/.github/workflows/release_and_publish.yml b/.github/workflows/release_and_publish.yml index 89efcfc..c2f4e2e 100644 --- a/.github/workflows/release_and_publish.yml +++ b/.github/workflows/release_and_publish.yml @@ -1,10 +1,4 @@ -# Release package on GitHub and publish to PyPI -# IMPORTANT -- 1 MANUAL STEP -# * FOLLOWING TAGGED RELEASE -# - update CHANGELOG.md -#-------------------------------------------------- - -name: Build, Release, and publish +name: Release Package on: push: @@ -20,69 +14,32 @@ on: jobs: build: - name: Create release & publish to PyPI runs-on: ubuntu-latest steps: - - name: Checkout repo - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Build source and wheel distributions + run: | + python -m pip install --upgrade build twine + python -m build + twine check --strict dist/* - - name: Set up python - uses: actions/setup-python@v4 - with: - python-version: "3.x" + - name: Create Release Notes + uses: actions/github-script@v6 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + await github.request(`POST /repos/${{ github.repository }}/releases`, { + tag_name: "${{ github.ref }}", + generate_release_notes: true + }); - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install setuptools wheel twine jupyter urllib3 pandas pyyaml - python setup.py sdist bdist_wheel -# - name: Run Changelog -# run: | -# jupyter nbconvert --to notebook --execute --inplace --ExecutePreprocessor.timeout=-1 --ExecutePreprocessor.kernel_name=python3 tools/gitcount.ipynb -# - name: Cat Changelog -# uses: pCYSl5EDgo/cat@master -# id: changetxt -# with: -# path: ./tools/changelog.md -# env: -# TEXT: ${{ steps.changetxt.outputs.text }} -# - name: Create Release Notes -# uses: actions/github-script@v6 -# with: -# github-token: ${{secrets.GITHUB_TOKEN}} -# script: | -# await github.request(`POST /repos/${{ github.repository }}/releases`, { -# tag_name: "${{ github.ref }}", -# generate_release_notes: true -# }); -# - name: Create Release -# id: create_release -# uses: actions/create-release@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # token is provided by GHA, DO NOT create -# with: -# tag_name: ${{ github.ref }} -# release_name: Release ${{ github.ref }} -# body: ${{ steps.changetxt.outputs.text }} -# draft: false -# prerelease: false -# - name: Get Asset name -# run: | -# export PKG=$(ls dist/) -# set -- $PKG -# echo "name=$1" >> $GITHUB_ENV -# - name: Upload Release Asset -# id: upload-release-asset -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: dist/${{ env.name }} -# asset_name: ${{ env.name }} -# asset_content_type: application/zip - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_PASSWORD }} From 49f576c90a9448323e68d63a94c2170cf675689b Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:39:51 -0400 Subject: [PATCH 10/26] =?UTF-8?q?ruff=20=E2=80=93=20components.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/components.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/giddy/components.py b/giddy/components.py index 1a256a2..9a1e9d1 100644 --- a/giddy/components.py +++ b/giddy/components.py @@ -32,7 +32,7 @@ def is_component(w, ids): """ components = 0 - marks = dict([(node, 0) for node in ids]) + marks = {node: 0 for node in ids} q = [] for node in ids: if marks[node] == 0: @@ -103,7 +103,7 @@ def check_contiguity(w, neighbors, leaver): return is_component(w, ids) -class Graph(object): +class Graph: def __init__(self, undirected=True): self.nodes = set() self.edges = {} From b428be4433085ba317d081ba1624cf66e65f64d6 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:47:52 -0400 Subject: [PATCH 11/26] =?UTF-8?q?ruff=20=E2=80=93=20directional.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/directional.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/giddy/directional.py b/giddy/directional.py index 6136881..74fb804 100644 --- a/giddy/directional.py +++ b/giddy/directional.py @@ -17,7 +17,7 @@ _NEG4 = 1 - _POS4 -class Rose(object): +class Rose: """ Rose diagram based inference for directional LISAs. @@ -292,9 +292,9 @@ def permute(self, permutations=99, alternative="two.sided"): P = NEG * L + (1 - NEG) * S self.p = P else: - print(("Bad option for alternative: %s." % alternative)) + print("Bad option for alternative: %s." % alternative) - def _calc(self, Y, w, k): + def _calc(self, Y, w, k): # noqa ARG002 – Unused method argument: `k` wY = weights.lag_spatial(w, Y) dx = Y[:, -1] - Y[:, 0] dy = wY[:, -1] - wY[:, 0] From 159a62ac312b5f17f6f86821b3cb18edaec8e35f Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:48:51 -0400 Subject: [PATCH 12/26] =?UTF-8?q?ruff=20=E2=80=93=20util.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/giddy/util.py b/giddy/util.py index 02761e4..e31e609 100644 --- a/giddy/util.py +++ b/giddy/util.py @@ -4,9 +4,10 @@ __all__ = ["shuffle_matrix", "get_lower", "fill_empty_diagonals"] -import numpy as np import copy +import numpy as np + def shuffle_matrix(X, ids): """ From 5a64131e957cb88497a5e609e40b8760e5610f7a Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 15:50:50 -0400 Subject: [PATCH 13/26] =?UTF-8?q?ruff=20=E2=80=93=20sequence.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/sequence.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/giddy/sequence.py b/giddy/sequence.py index 8d9d481..0b07a12 100644 --- a/giddy/sequence.py +++ b/giddy/sequence.py @@ -7,12 +7,14 @@ __all__ = ["Sequence"] import itertools + import numpy as np import scipy.spatial.distance as d + from .markov import Markov -class Sequence(object): +class Sequence: """ Pairwise sequence analysis. @@ -172,7 +174,7 @@ class Sequence(object): >>> seqAna = Sequence([seq1,seq2,seq3], indel=indel) Traceback (most recent call last): ValueError: Please specify a proper `dist_type` or `subs_mat` and `indel` to proceed! - """ + """ # noqa E501 def __init__(self, y, subs_mat=None, dist_type=None, indel=None, cluster_type=None): y = np.asarray(y) From 4cd6ecf9ad88e77fc8e60a9e73e58b342a4dbd60 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 16:03:01 -0400 Subject: [PATCH 14/26] =?UTF-8?q?ruff=20=E2=80=93=20rank.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/rank.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/giddy/rank.py b/giddy/rank.py index efb6cf2..f574933 100644 --- a/giddy/rank.py +++ b/giddy/rank.py @@ -13,10 +13,10 @@ "Tau_Regional", ] -from scipy.stats.mstats import rankdata -from scipy.special import erfc import numpy as np from libpysal import weights +from scipy.special import erfc +from scipy.stats.mstats import rankdata class Theta: @@ -264,7 +264,7 @@ def _calc(self, x, y): return tau, pval, Concordant, Discordant, ExtraX, ExtraY -class SpatialTau(object): +class SpatialTau: """ Spatial version of Kendall's rank correlation statistic. @@ -415,7 +415,7 @@ def pseudop(sim, observed, nperm): return psim -class Tau_Local: +class Tau_Local: # noqa N801 – Class name should use CapWords convention """ Local version of the classic Tau. @@ -491,7 +491,7 @@ def __init__(self, x, y): self.tau_local = si * 1.0 / (self.n - 1) -class Tau_Local_Neighbor: +class Tau_Local_Neighbor: # noqa N801 – Class name should use CapWords convention """ Neighbor set LIMA. @@ -628,7 +628,7 @@ def __init__(self, x, y, w, permutations=0): self.tau_ln_sim = tau_ln_sim self.tau_ln_pvalues = tau_ln_pvalues - def _calc_r(self, xi, yi, xj, yj, w): + def _calc_r(self, xi, yi, xj, yj, w): # noqa ARG002 – Unused method argument: `w` dx = xi - xj dy = yi - yj dxdy = dx * dy @@ -659,7 +659,7 @@ def _calc(self, x, y, w, i=None): return tau_ln, tau_ln_weights -class Tau_Local_Neighborhood: +class Tau_Local_Neighborhood: # noqa N801 – Class name should use CapWords convention """ Neighborhood set LIMA. @@ -796,7 +796,7 @@ def __init__(self, x, y, w, permutations=0): self.tau_lnhood_pvalues = tau_lnhood_pvalues -class Tau_Regional: +class Tau_Regional: # noqa N801 – Class name should use CapWords convention """ Inter and intraregional decomposition of the classic Tau. From 0befcf0123cd013a13c0c4bd90fdf9bfd923b764 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 16:04:34 -0400 Subject: [PATCH 15/26] =?UTF-8?q?ruff=20=E2=80=93=20mobility.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/mobility.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/giddy/mobility.py b/giddy/mobility.py index 616d6fe..893dac6 100644 --- a/giddy/mobility.py +++ b/giddy/mobility.py @@ -11,7 +11,7 @@ def markov_mobility(p, measure="P", ini=None): - """ + r""" Markov-based mobility index. Parameters From 590dcec91d707dc11a1c486da031e6466f216345 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 17:34:27 -0400 Subject: [PATCH 16/26] remove coveragerc and tools --- .coveragerc | 28 -- tools/gitcount.ipynb | 627 ------------------------------------------- 2 files changed, 655 deletions(-) delete mode 100644 .coveragerc delete mode 100644 tools/gitcount.ipynb diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 3192d87..0000000 --- a/.coveragerc +++ /dev/null @@ -1,28 +0,0 @@ -# .coveragerc to control coverage.py -[run] -branch = True -include = */giddy/* -disable_warnings=include-ignored - -[report] -# Regexes for lines to exclude from consideration -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover - - # Don't complain about missing debug-only code: - def __repr__ - if self\.debug - - # Don't complain if tests don't hit defensive assertion code: - raise AssertionError - raise NotImplementedError - - # Don't complain if non-runnable code isn't run: - if 0: - if __name__ == .__main__.: - -ignore_errors = True - -[html] -directory = coverage_html_report \ No newline at end of file diff --git a/tools/gitcount.ipynb b/tools/gitcount.ipynb deleted file mode 100644 index ed19906..0000000 --- a/tools/gitcount.ipynb +++ /dev/null @@ -1,627 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## PySAL Change Log Statistics\n", - "\n", - "This notebook generates the summary statistics for a package. \n", - "\n", - "It assumes you are running this under the `tools` directory at the toplevel of the package\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Change the values only in the next cell" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get date of last tag\n", - "from subprocess import Popen, PIPE\n", - "\n", - "x, err = Popen(\n", - " 'git log -1 --tags --simplify-by-decoration --pretty=\"%ai\"| cat',\n", - " stdin=PIPE,\n", - " stdout=PIPE,\n", - " stderr=PIPE,\n", - " shell=True,\n", - ").communicate()\n", - "start_date = x.split()[0].decode(\"utf-8\")\n", - "start_date" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# today's date\n", - "import datetime\n", - "\n", - "release_date = str(datetime.datetime.today()).split()[0]\n", - "release_date" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "package_name = \"giddy\"\n", - "# release_date = '2019-12-20'\n", - "# start_date = '2019-12-20'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook will generate a file in the current directory with the name \"changelog_VERSION.md\". You can edit and append this on front of the CHANGELOG file for the package release." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import print_function\n", - "import os\n", - "import json\n", - "import re\n", - "import sys\n", - "import pandas\n", - "\n", - "from datetime import datetime, timedelta\n", - "from time import sleep\n", - "from subprocess import check_output\n", - "\n", - "try:\n", - " from urllib import urlopen\n", - "except:\n", - " from urllib.request import urlopen\n", - "\n", - "import ssl\n", - "import yaml\n", - "\n", - "context = ssl._create_unverified_context()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "CWD = os.path.abspath(os.path.curdir)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "CWD" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "since_date = '--since=\"{start}\"'.format(start=start_date)\n", - "since_date\n", - "since = datetime.strptime(start_date + \" 0:0:0\", \"%Y-%m-%d %H:%M:%S\")\n", - "since" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get __version__\n", - "f = \"../{package}/__init__.py\".format(package=package_name)\n", - "\n", - "with open(f, \"r\") as initfile:\n", - " exec(initfile.readline())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Total commits by subpackage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cmd = [\"git\", \"log\", \"--oneline\", since_date]\n", - "ncommits = len(check_output(cmd).splitlines())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ncommits" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## List Contributors" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Some of our contributors have many aliases for the same identity. So, we've added a mapping to make sure that individuals are listed once (and only once). " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "identities = {\n", - " \"Levi John Wolf\": (\"ljwolf\", \"Levi John Wolf\"),\n", - " \"Serge Rey\": (\"Serge Rey\", \"Sergio Rey\", \"sjsrey\", \"serge\"),\n", - " \"Wei Kang\": (\"Wei Kang\", \"weikang9009\"),\n", - " \"Dani Arribas-Bel\": (\"Dani Arribas-Bel\", \"darribas\"),\n", - "}\n", - "\n", - "\n", - "def regularize_identity(string):\n", - " string = string.decode()\n", - " for name, aliases in identities.items():\n", - " for alias in aliases:\n", - " if alias in string:\n", - " string = string.replace(alias, name)\n", - " if len(string.split(\" \")) > 1:\n", - " string = string.title()\n", - " return string.lstrip(\"* \")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "author_cmd = [\"git\", \"log\", \"--format=* %aN\", since_date]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import Counter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ncommits = len(check_output(cmd).splitlines())\n", - "all_authors = check_output(author_cmd).splitlines()\n", - "counter = Counter([regularize_identity(author) for author in all_authors])\n", - "# global_counter += counter\n", - "# counters.update({'.'.join((package,subpackage)): counter})\n", - "unique_authors = sorted(set(all_authors))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "unique_authors = counter.keys()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "unique_authors" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Disaggregate by PR, Issue" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from datetime import datetime, timedelta\n", - "\n", - "ISO8601 = \"%Y-%m-%dT%H:%M:%SZ\"\n", - "PER_PAGE = 100\n", - "element_pat = re.compile(r\"<(.+?)>\")\n", - "rel_pat = re.compile(r'rel=[\\'\"](\\w+)[\\'\"]')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def parse_link_header(headers):\n", - " link_s = headers.get(\"link\", \"\")\n", - " urls = element_pat.findall(link_s)\n", - " rels = rel_pat.findall(link_s)\n", - " d = {}\n", - " for rel, url in zip(rels, urls):\n", - " d[rel] = url\n", - " return d\n", - "\n", - "\n", - "def get_paged_request(url):\n", - " \"\"\"get a full list, handling APIv3's paging\"\"\"\n", - " results = []\n", - " while url:\n", - " # print(\"fetching %s\" % url, file=sys.stderr)\n", - " f = urlopen(url)\n", - " results.extend(json.load(f))\n", - " links = parse_link_header(f.headers)\n", - " url = links.get(\"next\")\n", - " return results\n", - "\n", - "\n", - "def get_issues(project=\"pysal/giddy\", state=\"closed\", pulls=False):\n", - " \"\"\"Get a list of the issues from the Github API.\"\"\"\n", - " which = \"pulls\" if pulls else \"issues\"\n", - " url = \"https://api.github.com/repos/%s/%s?state=%s&per_page=%i\" % (\n", - " project,\n", - " which,\n", - " state,\n", - " PER_PAGE,\n", - " )\n", - " return get_paged_request(url)\n", - "\n", - "\n", - "def _parse_datetime(s):\n", - " \"\"\"Parse dates in the format returned by the Github API.\"\"\"\n", - " if s:\n", - " return datetime.strptime(s, ISO8601)\n", - " else:\n", - " return datetime.fromtimestamp(0)\n", - "\n", - "\n", - "def issues2dict(issues):\n", - " \"\"\"Convert a list of issues to a dict, keyed by issue number.\"\"\"\n", - " idict = {}\n", - " for i in issues:\n", - " idict[i[\"number\"]] = i\n", - " return idict\n", - "\n", - "\n", - "def is_pull_request(issue):\n", - " \"\"\"Return True if the given issue is a pull request.\"\"\"\n", - " return \"pull_request_url\" in issue\n", - "\n", - "\n", - "def issues_closed_since(period=timedelta(days=365), project=\"pysal/pysal\", pulls=False):\n", - " \"\"\"Get all issues closed since a particular point in time. period\n", - " can either be a datetime object, or a timedelta object. In the\n", - " latter case, it is used as a time before the present.\"\"\"\n", - "\n", - " which = \"pulls\" if pulls else \"issues\"\n", - "\n", - " if isinstance(period, timedelta):\n", - " period = datetime.now() - period\n", - " url = (\n", - " \"https://api.github.com/repos/%s/%s?state=closed&sort=updated&since=%s&per_page=%i\"\n", - " % (project, which, period.strftime(ISO8601), PER_PAGE)\n", - " )\n", - " allclosed = get_paged_request(url)\n", - " # allclosed = get_issues(project=project, state='closed', pulls=pulls, since=period)\n", - " filtered = [i for i in allclosed if _parse_datetime(i[\"closed_at\"]) > period]\n", - "\n", - " # exclude rejected PRs\n", - " if pulls:\n", - " filtered = [pr for pr in filtered if pr[\"merged_at\"]]\n", - "\n", - " return filtered\n", - "\n", - "\n", - "def sorted_by_field(issues, field=\"closed_at\", reverse=False):\n", - " \"\"\"Return a list of issues sorted by closing date date.\"\"\"\n", - " return sorted(issues, key=lambda i: i[field], reverse=reverse)\n", - "\n", - "\n", - "def report(issues, show_urls=False):\n", - " \"\"\"Summary report about a list of issues, printing number and title.\"\"\"\n", - " # titles may have unicode in them, so we must encode everything below\n", - " if show_urls:\n", - " for i in issues:\n", - " role = \"ghpull\" if \"merged_at\" in i else \"ghissue\"\n", - " print(\"* :%s:`%d`: %s\" % (role, i[\"number\"], i[\"title\"].encode(\"utf-8\")))\n", - " else:\n", - " for i in issues:\n", - " print(\"* %d: %s\" % (i[\"number\"], i[\"title\"].encode(\"utf-8\")))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "all_issues = {}\n", - "all_pulls = {}\n", - "total_commits = 0\n", - "# prj='pysal/libpysal'\n", - "prj = \"pysal/{package}\".format(package=package_name)\n", - "issues = issues_closed_since(since, project=prj, pulls=False)\n", - "pulls = issues_closed_since(since, project=prj, pulls=True)\n", - "issues = sorted_by_field(issues, reverse=True)\n", - "pulls = sorted_by_field(pulls, reverse=True)\n", - "n_issues, n_pulls = map(len, (issues, pulls))\n", - "n_total = n_issues + n_pulls" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "issue_listing = []\n", - "for issue in issues:\n", - " entry = \"{title} (#{number})\".format(title=issue[\"title\"], number=issue[\"number\"])\n", - " issue_listing.append(entry)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pull_listing = []\n", - "for pull in pulls:\n", - " entry = \"{title} (#{number})\".format(title=pull[\"title\"], number=pull[\"number\"])\n", - " pull_listing.append(entry)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pull_listing" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "message = \"We closed a total of {total} issues (enhancements and bug fixes) through {pr} pull requests\".format(\n", - " total=n_total, pr=n_pulls\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "message = \"{msg}, since our last release on {previous}.\".format(\n", - " msg=message, previous=str(start_date)\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "message" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "message += \"\\n\\n## Issues Closed\\n\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(message)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "issues = \"\\n\".join([\" - \" + issue for issue in issue_listing])\n", - "message += issues\n", - "message += \"\\n\\n## Pull Requests\\n\"\n", - "pulls = \"\\n\".join([\" - \" + pull for pull in pull_listing])\n", - "message += pulls" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(message)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "people = \"\\n\".join([\" - \" + person for person in unique_authors])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(people)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "message += (\n", - " \"\\n\\nThe following individuals contributed to this release:\\n\\n{people}\".format(\n", - " people=people\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(message)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "head = \"# Version {version} ({release_date})\\n\\n\".format(\n", - " version=__version__, release_date=release_date\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# new_content = head+message+\"\\n\"\n", - "# print(new_content)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# #insert the new changes in the begining of CHANGELOG.md\n", - "# with open(\"../CHANGELOG.md\", 'r+') as file:\n", - "# content = file.read()\n", - "# file.seek(0, 0)\n", - "# file.write(new_content+ content)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# outfile = 'changelog_{version}.md'.format(version=__version__)\n", - "outfile = \"changelog.md\"\n", - "with open(outfile, \"w\") as of:\n", - " of.write(head + message)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 0f3ee43b39808b599e9104f8bfcb2d7e48abaa52 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 18:19:32 -0400 Subject: [PATCH 17/26] =?UTF-8?q?ruff=20=E2=80=93=20markov.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/markov.py | 107 ++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/giddy/markov.py b/giddy/markov.py index 6166d9f..ee17597 100644 --- a/giddy/markov.py +++ b/giddy/markov.py @@ -15,18 +15,20 @@ "GeoRank_Markov", ] -import numpy as np -from .ergodic import steady_state, mfpt -from .util import fill_empty_diagonals -from .components import Graph -from scipy import stats -from scipy.stats import rankdata +import itertools from operator import gt -from libpysal import weights -from esda.moran import Moran_Local + import mapclassify as mc -import itertools +import numpy as np import quantecon as qe +from esda.moran import Moran_Local +from libpysal import weights +from scipy import stats +from scipy.stats import rankdata + +from .components import Graph +from .ergodic import mfpt, steady_state +from .util import fill_empty_diagonals # TT predefine LISA transitions # TT[i,j] is the transition type from i to j @@ -61,7 +63,7 @@ c += 1 -class Markov(object): +class Markov: """ Classic Markov Chain estimation. @@ -239,8 +241,8 @@ def __init__(self, class_ids, classes=None, fill_empty_classes=False, summary=Tr self.cclasses_indices = markovchain.communication_classes_indices self.rclasses_indices = markovchain.recurrent_classes_indices - transient = set(list(map(tuple, self.cclasses_indices))).difference( - set(list(map(tuple, self.rclasses_indices))) + transient = set(map(tuple, self.cclasses_indices)).difference( + set(map(tuple, self.rclasses_indices)) ) self.num_tclasses = len(transient) if len(transient): @@ -258,7 +260,7 @@ def __init__(self, class_ids, classes=None, fill_empty_classes=False, summary=Tr if self.num_rclasses == 1: print("1 Recurrent class (indices):") else: - print("{0} Recurrent classes (indices):".format(self.num_rclasses)) + print(f"{self.num_rclasses} Recurrent classes (indices):") print(*self.rclasses_indices, sep=", ") if self.num_tclasses == 0: print("0 Transient classes.") @@ -266,7 +268,7 @@ def __init__(self, class_ids, classes=None, fill_empty_classes=False, summary=Tr if self.num_tclasses == 1: print("1 Transient class (indices):") else: - print("{0} Transient classes (indices):".format(self.num_tclasses)) + print(f"{self.num_tclasses} Transient classes (indices):") print(*self.tclasses_indices, sep=", ") if self.num_astates == 0: print("The Markov Chain has 0 absorbing states.") @@ -275,9 +277,8 @@ def __init__(self, class_ids, classes=None, fill_empty_classes=False, summary=Tr print("The Markov Chain has 1 absorbing state (index):") else: print( - "The Markov Chain has {0} absorbing states (indices):".format( - self.num_astates - ) + f"The Markov Chain has {self.num_astates} " + "absorbing states (indices):" ) print(*self.astates_indices, sep=", ") @@ -300,7 +301,7 @@ def sojourn_time(self): return self._st -class Spatial_Markov(object): +class Spatial_Markov: # noqa N801 – Class name should use CapWords convention """ Markov transitions conditioned on the value of the spatial lag. @@ -848,10 +849,10 @@ def s(self): return self._s @property - def S(self): + def S(self): # noqa N802 – Function name should be lowercase if not hasattr(self, "_S"): _S = [] - for i, p in enumerate(self.P): + for p in self.P: _S.append(steady_state(p)) # if np.array(_S).dtype is np.dtype('O'): self._S = np.asarray(_S, dtype=object) @@ -864,7 +865,7 @@ def f(self): return self._f @property - def F(self): + def F(self): # noqa N802 – Function name should be lowercase if not hasattr(self, "_F"): F = np.zeros_like(self.P) for i, p in enumerate(self.P): @@ -880,23 +881,23 @@ def ht(self): return self._ht @property - def Q(self): + def Q(self): # noqa N802 – Function name should be lowercase if not hasattr(self, "_Q"): self._Q = self.ht.Q return self._Q @property - def Q_p_value(self): + def Q_p_value(self): # noqa N802 – Function name should be lowercase self._Q_p_value = self.ht.Q_p_value return self._Q_p_value @property - def LR(self): + def LR(self): # noqa N802 – Function name should be lowercase self._LR = self.ht.LR return self._LR @property - def LR_p_value(self): + def LR_p_value(self): # noqa N802 – Function name should be lowercase self._LR_p_value = self.ht.LR_p_value return self._LR_p_value @@ -1145,7 +1146,7 @@ def chi2(T1, T2): return chi2, pvalue, dof -class LISA_Markov(Markov): +class LISA_Markov(Markov): # noqa N801 – Class name should use CapWords convention """ Markov for Local Indicators of Spatial Association @@ -1529,8 +1530,8 @@ def spillover(self, quadrant=1, neighbors_on=False): spill_ids.append(j) break for spill_id in spill_ids: - id = self.w.id2i[spill_id] - spill_over[id, t] = 1 + id_ = self.w.id2i[spill_id] + spill_over[id_, t] = 1 for c, component in enumerate(components1): for i in component: ii = self.w.id2i[i] @@ -1725,7 +1726,7 @@ def homogeneity( ) -class Homogeneity_Results: +class Homogeneity_Results: # noqa N801 – Class name should use CapWords convention """ Wrapper class to present homogeneity results. @@ -1861,7 +1862,7 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): contents.append(stat) stat = "%7s %20.3f %20.3f" % ("p-value", self.LR_p_value, self.Q_p_value) contents.append(stat) - print(("\n".join(contents))) + print("\n".join(contents)) print(lead) cols = ["P(%s)" % str(regime) for regime in self.regime_names] @@ -1874,14 +1875,14 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): p0 = [] line0 = ["{s: <{w}}".format(s="P(H0)", w=col_width)] line0.extend( - (["{s: >{w}}".format(s=cname, w=col_width) for cname in self.class_names]) + ["{s: >{w}}".format(s=cname, w=col_width) for cname in self.class_names] ) - print((" ".join(line0))) + print(" ".join(line0)) p0.append("&".join(line0)) for i, row in enumerate(self.p_h0): line = ["%*s" % (col_width, str(self.class_names[i]))] line.extend(["%*.3f" % (col_width, v) for v in row]) - print((" ".join(line))) + print(" ".join(line)) p0.append("&".join(line)) pmats = [p0] @@ -1890,19 +1891,19 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): p0 = [] line0 = ["{s: <{w}}".format(s="P(%s)" % regime_names[r], w=col_width)] line0.extend( - ( + [ "{s: >{w}}".format(s=cname, w=col_width) for cname in self.class_names ] - ) + ) - print((" ".join(line0))) + print(" ".join(line0)) p0.append("&".join(line0)) for i, row in enumerate(p1): line = ["%*s" % (col_width, str(self.class_names[i]))] line.extend(["%*.3f" % (col_width, v) for v in row]) - print((" ".join(line))) + print(" ".join(line)) p0.append("&".join(line)) pmats.append(p0) print(lead) @@ -1910,22 +1911,22 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): if file_name: k = self.k ks = str(k + 1) - with open(file_name, "w") as f: + with open(file_name + ".tex", "w") as f: c = [] fmt = "r" * (k + 1) s = "\\begin{tabular}{|%s|}\\hline\n" % fmt - s += "\\multicolumn{%s}{|c|}{%s}" % (ks, title) + s += "\\multicolumn{%s}{|c|}{%s}" % (ks, title) # noqa UP031 c.append(s) s = "Number of classes: %d" % int(self.k) - c.append("\\hline\\multicolumn{%s}{|l|}{%s}" % (ks, s)) + c.append("\\hline\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 s = "Number of transitions: %d" % int(self.t_total) - c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) + c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 s = "Number of regimes: %d" % int(self.m) - c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) + c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 s = "Regime names: " s += ", ".join(regime_names) - c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) - s = "\\hline\\multicolumn{2}{|l}{%s}" % ("Test") + c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 + s = "\\hline\\multicolumn{2}{|l}{%s}" % ("Test") # noqa UP031 s += "&\\multicolumn{2}{r}{LR}&\\multicolumn{2}{r|}{Q}" c.append(s) s = "Stat." @@ -1933,11 +1934,11 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): s += "&\\multicolumn{2}{r}{%.3f}" % self.LR s += "&\\multicolumn{2}{r|}{%.3f}" % self.Q c.append(s) - s = "\\multicolumn{2}{|l}{%s}" % ("DOF") + s = "\\multicolumn{2}{|l}{%s}" % ("DOF") # noqa UP031 s += "&\\multicolumn{2}{r}{%d}" % int(self.dof) s += "&\\multicolumn{2}{r|}{%d}" % int(self.dof) c.append(s) - s = "\\multicolumn{2}{|l}{%s}" % ("p-value") + s = "\\multicolumn{2}{|l}{%s}" % ("p-value") # noqa UP031 s += "&\\multicolumn{2}{r}{%.3f}" % self.LR_p_value s += "&\\multicolumn{2}{r|}{%.3f}" % self.Q_p_value c.append(s) @@ -1954,7 +1955,7 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): f.write(s1 + s2) -class FullRank_Markov(Markov): +class FullRank_Markov(Markov): # noqa N801 – Class name should use CapWords convention """ Full Rank Markov in which ranks are considered as Markov states rather than quantiles or other discretized classes. This is one way to avoid @@ -2037,7 +2038,7 @@ def __init__(self, y, fill_empty_classes=False, summary=True): r_asc = np.array([rankdata(col, method="ordinal") for col in y.T]).T # ranks by high (1) to low (n) self.ranks = r_asc.shape[0] - r_asc + 1 - super(FullRank_Markov, self).__init__( + super().__init__( self.ranks, fill_empty_classes=fill_empty_classes, summary=summary ) @@ -2079,7 +2080,7 @@ def sojourn_time(p, summary=True): >>> sojourn_time(p) Sojourn times are infinite for absorbing states! In this Markov Chain, states [2] are absorbing states. array([ 2., 1., inf]) - """ + """ # noqa E501 p = np.asarray(p) if (p.sum(axis=1) == 0).sum() > 0: @@ -2095,9 +2096,7 @@ def sojourn_time(p, summary=True): if summary: print( "Sojourn times are infinite for absorbing states! In this " - "Markov Chain, states {} are absorbing states.".format( - list(absorbing_states) - ) + f"Markov Chain, states {list(absorbing_states)} are absorbing states." ) st[non_absorbing_states] = 1 / (1 - pii[non_absorbing_states]) else: @@ -2105,7 +2104,7 @@ def sojourn_time(p, summary=True): return st -class GeoRank_Markov(Markov): +class GeoRank_Markov(Markov): # noqa N801 – Class name should use CapWords convention """ Geographic Rank Markov. Geographic units are considered as Markov states. @@ -2213,6 +2212,6 @@ def __init__(self, y, fill_empty_classes=False, summary=True): # to the order that the values occur in each cross section. ranks = np.array([rankdata(col, method="ordinal") for col in y.T]).T geo_ranks = np.argsort(ranks, axis=0) + 1 - super(GeoRank_Markov, self).__init__( + super().__init__( geo_ranks, fill_empty_classes=fill_empty_classes, summary=summary ) From d7b4f4d7384d31726e13f0ad122d00e0f0071577 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 18:20:16 -0400 Subject: [PATCH 18/26] close plot in odcstring example --- giddy/directional.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/giddy/directional.py b/giddy/directional.py index 74fb804..283f284 100644 --- a/giddy/directional.py +++ b/giddy/directional.py @@ -200,7 +200,12 @@ def __init__(self, Y, w, k=8): rose diagram conditional on the starting relative income: >>> fig1, _ = r8.plot(attribute=Y[:,0]) - >>> plt.show() + >>> plt.show(block=False) + + Close plot when finished viewing. + + >>> plt.close("all") + """ self.Y = Y From 4dcaa18bb9c9b594c240dc1715cd3778799363b0 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 18:23:31 -0400 Subject: [PATCH 19/26] doctest in CI --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 98fb95e..fd515ef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,8 +18,6 @@ on: jobs: unittests: - env: - RUN_TEST: pytest giddy --cov giddy -v -n auto -r a --cov-config .coveragerc --cov-report xml --color yes --cov-append --cov-report term-missing name: ${{ matrix.os }}, ${{ matrix.environment-file }} runs-on: ${{ matrix.os }} defaults: @@ -72,7 +70,7 @@ jobs: if: contains(matrix.environment-file, 'DEV') - name: run tests - run: ${{ env.RUN_TEST }} + run: pytest giddy --cov giddy -v -n auto -r a --doctest-modules --color yes --cov-report term-missing --cov-report xml - name: codecov uses: codecov/codecov-action@v3 From 859cfdaa1b60cbe9e0609e93366e1dd9150403b9 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 18:43:49 -0400 Subject: [PATCH 20/26] update __init__ properly --- giddy/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/giddy/__init__.py b/giddy/__init__.py index 6891649..025d8a4 100644 --- a/giddy/__init__.py +++ b/giddy/__init__.py @@ -4,4 +4,10 @@ """ +import contextlib +from importlib.metadata import PackageNotFoundError, version + from . import directional, ergodic, markov, mobility, rank, sequence, util + +with contextlib.suppress(PackageNotFoundError): + __version__ = version("giddy") From 86be9607b2ed0015d8e5b5ac0da7b80d2ed6a437 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Wed, 18 Oct 2023 18:44:34 -0400 Subject: [PATCH 21/26] =?UTF-8?q?ruff=20=E2=80=93=20ergodic.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- giddy/ergodic.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/giddy/ergodic.py b/giddy/ergodic.py index 12497ae..0216209 100644 --- a/giddy/ergodic.py +++ b/giddy/ergodic.py @@ -5,10 +5,12 @@ __all__ = ["steady_state", "var_mfpt_ergodic", "mfpt"] +from warnings import warn + import numpy as np import numpy.linalg as la import quantecon as qe -from warnings import warn + from .util import fill_empty_diagonals @@ -124,7 +126,7 @@ def steady_state(P, fill_empty_classes=False): ... ValueError: Input transition probability matrix has 1 rows full of 0s. Please set fill_empty_classes=True to set diagonal elements for these rows to be 1 to make sure the matrix is stochastic. - """ + """ # noqa E501 P = np.asarray(P) rows0 = (P.sum(axis=1) == 0).sum() @@ -293,7 +295,7 @@ def mfpt(P, fill_empty_classes=False): Traceback (most recent call last): ... ValueError: Input transition probability matrix has 1 rows full of 0s. Please set fill_empty_classes=True to set diagonal elements for these rows to be 1 to make sure the matrix is stochastic. - """ + """ # noqa E501 P = np.asarray(P) rows0 = (P.sum(axis=1) == 0).sum() @@ -325,20 +327,19 @@ def mfpt(P, fill_empty_classes=False): try: m[none0] = np.linalg.solve(p_calc, b) except np.linalg.LinAlgError as err: - if "Singular matrix" in str(err): - if (row0 == 0).sum() > 0: - index0 = set(np.argwhere(row0 == 0).flatten()) + if "Singular matrix" in str(err) and (row0 == 0).sum() > 0: + index0 = set(np.argwhere(row0 == 0).flatten()) + x = (p_calc[:, list(index0)] != 0).sum(axis=1) + setx = set(np.argwhere(x).flatten()) + while not setx.issubset(index0): + index0 = index0.union(setx) x = (p_calc[:, list(index0)] != 0).sum(axis=1) setx = set(np.argwhere(x).flatten()) - while not setx.issubset(index0): - index0 = index0.union(setx) - x = (p_calc[:, list(index0)] != 0).sum(axis=1) - setx = set(np.argwhere(x).flatten()) - none0 = np.asarray(list(set(none0).difference(index0))) - if len(none0) >= 1: - p_calc = p_calc[none0, :][:, none0] - b = b[none0] - m[none0] = np.linalg.solve(p_calc, b) + none0 = np.asarray(list(set(none0).difference(index0))) + if len(none0) >= 1: + p_calc = p_calc[none0, :][:, none0] + b = b[none0] + m[none0] = np.linalg.solve(p_calc, b) recc = ( np.nan_to_num( (np.delete(P, desti, 1)[desti] * m), 0, posinf=np.inf From 29924a3e8d7a55c687b78def4759e2b9f51273ce Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Sat, 21 Oct 2023 20:29:30 -0400 Subject: [PATCH 22/26] batch handle noqa in pyproject.toml --- giddy/directional.py | 2 +- giddy/markov.py | 29 ++++++++++++----------------- giddy/rank.py | 10 +++++----- pyproject.toml | 12 ++++++++++++ 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/giddy/directional.py b/giddy/directional.py index 283f284..5d4b36f 100644 --- a/giddy/directional.py +++ b/giddy/directional.py @@ -299,7 +299,7 @@ def permute(self, permutations=99, alternative="two.sided"): else: print("Bad option for alternative: %s." % alternative) - def _calc(self, Y, w, k): # noqa ARG002 – Unused method argument: `k` + def _calc(self, Y, w, k): wY = weights.lag_spatial(w, Y) dx = Y[:, -1] - Y[:, 0] dy = wY[:, -1] - wY[:, 0] diff --git a/giddy/markov.py b/giddy/markov.py index ee17597..ca46f0b 100644 --- a/giddy/markov.py +++ b/giddy/markov.py @@ -301,7 +301,7 @@ def sojourn_time(self): return self._st -class Spatial_Markov: # noqa N801 – Class name should use CapWords convention +class Spatial_Markov: """ Markov transitions conditioned on the value of the spatial lag. @@ -849,7 +849,7 @@ def s(self): return self._s @property - def S(self): # noqa N802 – Function name should be lowercase + def S(self): if not hasattr(self, "_S"): _S = [] for p in self.P: @@ -865,7 +865,7 @@ def f(self): return self._f @property - def F(self): # noqa N802 – Function name should be lowercase + def F(self): if not hasattr(self, "_F"): F = np.zeros_like(self.P) for i, p in enumerate(self.P): @@ -881,23 +881,23 @@ def ht(self): return self._ht @property - def Q(self): # noqa N802 – Function name should be lowercase + def Q(self): if not hasattr(self, "_Q"): self._Q = self.ht.Q return self._Q @property - def Q_p_value(self): # noqa N802 – Function name should be lowercase + def Q_p_value(self): self._Q_p_value = self.ht.Q_p_value return self._Q_p_value @property - def LR(self): # noqa N802 – Function name should be lowercase + def LR(self): self._LR = self.ht.LR return self._LR @property - def LR_p_value(self): # noqa N802 – Function name should be lowercase + def LR_p_value(self): self._LR_p_value = self.ht.LR_p_value return self._LR_p_value @@ -1146,7 +1146,7 @@ def chi2(T1, T2): return chi2, pvalue, dof -class LISA_Markov(Markov): # noqa N801 – Class name should use CapWords convention +class LISA_Markov(Markov): """ Markov for Local Indicators of Spatial Association @@ -1726,7 +1726,7 @@ def homogeneity( ) -class Homogeneity_Results: # noqa N801 – Class name should use CapWords convention +class Homogeneity_Results: """ Wrapper class to present homogeneity results. @@ -1891,12 +1891,7 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): p0 = [] line0 = ["{s: <{w}}".format(s="P(%s)" % regime_names[r], w=col_width)] line0.extend( - - [ - "{s: >{w}}".format(s=cname, w=col_width) - for cname in self.class_names - ] - + ["{s: >{w}}".format(s=cname, w=col_width) for cname in self.class_names] ) print(" ".join(line0)) p0.append("&".join(line0)) @@ -1955,7 +1950,7 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): f.write(s1 + s2) -class FullRank_Markov(Markov): # noqa N801 – Class name should use CapWords convention +class FullRank_Markov(Markov): """ Full Rank Markov in which ranks are considered as Markov states rather than quantiles or other discretized classes. This is one way to avoid @@ -2104,7 +2099,7 @@ def sojourn_time(p, summary=True): return st -class GeoRank_Markov(Markov): # noqa N801 – Class name should use CapWords convention +class GeoRank_Markov(Markov): """ Geographic Rank Markov. Geographic units are considered as Markov states. diff --git a/giddy/rank.py b/giddy/rank.py index f574933..2b92dfc 100644 --- a/giddy/rank.py +++ b/giddy/rank.py @@ -415,7 +415,7 @@ def pseudop(sim, observed, nperm): return psim -class Tau_Local: # noqa N801 – Class name should use CapWords convention +class Tau_Local: """ Local version of the classic Tau. @@ -491,7 +491,7 @@ def __init__(self, x, y): self.tau_local = si * 1.0 / (self.n - 1) -class Tau_Local_Neighbor: # noqa N801 – Class name should use CapWords convention +class Tau_Local_Neighbor: """ Neighbor set LIMA. @@ -628,7 +628,7 @@ def __init__(self, x, y, w, permutations=0): self.tau_ln_sim = tau_ln_sim self.tau_ln_pvalues = tau_ln_pvalues - def _calc_r(self, xi, yi, xj, yj, w): # noqa ARG002 – Unused method argument: `w` + def _calc_r(self, xi, yi, xj, yj, w): dx = xi - xj dy = yi - yj dxdy = dx * dy @@ -659,7 +659,7 @@ def _calc(self, x, y, w, i=None): return tau_ln, tau_ln_weights -class Tau_Local_Neighborhood: # noqa N801 – Class name should use CapWords convention +class Tau_Local_Neighborhood: """ Neighborhood set LIMA. @@ -796,7 +796,7 @@ def __init__(self, x, y, w, permutations=0): self.tau_lnhood_pvalues = tau_lnhood_pvalues -class Tau_Regional: # noqa N801 – Class name should use CapWords convention +class Tau_Regional: """ Inter and intraregional decomposition of the classic Tau. diff --git a/pyproject.toml b/pyproject.toml index 4cbe62e..a276cea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,18 @@ ignore = [ "UP007" ] exclude = ["giddy/tests/*", "docs/*"] +[tool.ruff.per-file-ignores] +"giddy/directional.py" = [ + "ARG002", # Unused method argument +] +"giddy/markov.py" = [ + "N801", # Class name should use CapWords convention + "N802", # Function name should be lowercase +] +"giddy/rank.py" = [ + "N801", + "ARG002", +] [tool.coverage.run] source = ["./giddy"] From c60e8ec4f6fa263ac68dbffef333802291a462f4 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Sat, 21 Oct 2023 21:22:36 -0400 Subject: [PATCH 23/26] handle warnings and linting more granularly --- giddy/tests/test_ergodic.py | 4 +++- pyproject.toml | 40 +++++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/giddy/tests/test_ergodic.py b/giddy/tests/test_ergodic.py index e180e37..434d88d 100644 --- a/giddy/tests/test_ergodic.py +++ b/giddy/tests/test_ergodic.py @@ -1,3 +1,4 @@ +import pytest import unittest from .. import ergodic import numpy as np @@ -58,7 +59,8 @@ def test_mfpt(self): ) np.testing.assert_array_almost_equal(exp, obs) - obs = ergodic.fmpt(self.p2) + with pytest.warns(DeprecationWarning, match="fmpt is deprecated."): + obs = ergodic.fmpt(self.p2) exp = np.array( [ [2.66666667, 2.0, np.inf], diff --git a/pyproject.toml b/pyproject.toml index a276cea..fbe5ff6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,33 +77,33 @@ extend-exclude = ''' line-length = 88 select = ["E", "F", "W", "I", "UP", "N", "B", "A", "C4", "SIM", "ARG"] target-version = "py39" -ignore = [ - "B006", - "B008", - "B009", - "B010", - "C408", - "E731", - "F401", - "F403", - "N803", - "N806", - "N999", - "UP007" -] exclude = ["giddy/tests/*", "docs/*"] [tool.ruff.per-file-ignores] +"__init__.py" = ["F401"] # imported but unused "giddy/directional.py" = [ "ARG002", # Unused method argument + "N803", # Argument name should be lowercase + "N806", # Variable in function should be lowercase +] +"giddy/ergodic.py" = [ + "N803", # Argument name should be lowercase + "N806", # Variable in function should be lowercase ] "giddy/markov.py" = [ + "B006", # Do not use mutable data structures for argument defaults "N801", # Class name should use CapWords convention "N802", # Function name should be lowercase + "N803", + "N806", ] "giddy/rank.py" = [ - "N801", "ARG002", + "N801", + "N803", + "N806", ] +"giddy/sequence.py" = ["N806"] +"giddy/util.py" = ["N803"] [tool.coverage.run] source = ["./giddy"] @@ -118,3 +118,13 @@ exclude_lines = [ ] ignore_errors = true omit = ["giddy/tests/*", "docs/conf.py"] + +[tool.pytest.ini_options] +filterwarnings = [ + "ignore:The weights matrix is not fully connected", # libpysal + "ignore:Objects based on the `Geometry` class will deprecated", # libpysa + "ignore:divide by zero encountered", + "ignore:invalid value encountered", + "ignore:numba.generated_jit is deprecated.", # numba/quantecon + "ignore:::.*quantecon.lss:19", # numba/quantecon +] \ No newline at end of file From 13f71673ad07e4e3d14249695001f02dc2648d2d Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Sat, 21 Oct 2023 21:24:57 -0400 Subject: [PATCH 24/26] typo --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index fbe5ff6..528edb7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -122,7 +122,7 @@ omit = ["giddy/tests/*", "docs/conf.py"] [tool.pytest.ini_options] filterwarnings = [ "ignore:The weights matrix is not fully connected", # libpysal - "ignore:Objects based on the `Geometry` class will deprecated", # libpysa + "ignore:Objects based on the `Geometry` class will deprecated", # libpysal "ignore:divide by zero encountered", "ignore:invalid value encountered", "ignore:numba.generated_jit is deprecated.", # numba/quantecon From 3e62357bae0ad0085ec2d7f6ce7df975b6672c2c Mon Sep 17 00:00:00 2001 From: Wei Kang Date: Tue, 24 Oct 2023 09:56:21 -0500 Subject: [PATCH 25/26] address long lines of error messages in the docstrings --- giddy/ergodic.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/giddy/ergodic.py b/giddy/ergodic.py index 0216209..b7c3dc7 100644 --- a/giddy/ergodic.py +++ b/giddy/ergodic.py @@ -124,9 +124,11 @@ def steady_state(P, fill_empty_classes=False): >>> steady_state(p, fill_empty_classes = False) Traceback (most recent call last): ... - ValueError: Input transition probability matrix has 1 rows full of 0s. Please set fill_empty_classes=True to set diagonal elements for these rows to be 1 to make sure the matrix is stochastic. + ValueError: Input transition probability matrix has 1 rows full of 0s. \ +Please set fill_empty_classes=True to set diagonal elements for these \ +rows to be 1 to make sure the matrix is stochastic. - """ # noqa E501 + """ P = np.asarray(P) rows0 = (P.sum(axis=1) == 0).sum() @@ -294,8 +296,10 @@ def mfpt(P, fill_empty_classes=False): >>> mfpt(p, fill_empty_classes=False) Traceback (most recent call last): ... - ValueError: Input transition probability matrix has 1 rows full of 0s. Please set fill_empty_classes=True to set diagonal elements for these rows to be 1 to make sure the matrix is stochastic. - """ # noqa E501 + ValueError: Input transition probability matrix has 1 rows full of 0s. \ +Please set fill_empty_classes=True to set diagonal elements for these \ +rows to be 1 to make sure the matrix is stochastic. + """ P = np.asarray(P) rows0 = (P.sum(axis=1) == 0).sum() From e6cedb370cd630632d13a8e1cb61901cb1c598f5 Mon Sep 17 00:00:00 2001 From: James Gaboardi Date: Tue, 24 Oct 2023 11:28:33 -0400 Subject: [PATCH 26/26] final migration --- giddy/ergodic.py | 2 +- giddy/markov.py | 16 ++++++++-------- pyproject.toml | 34 ++++++++++++---------------------- 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/giddy/ergodic.py b/giddy/ergodic.py index b7c3dc7..d1a3858 100644 --- a/giddy/ergodic.py +++ b/giddy/ergodic.py @@ -299,7 +299,7 @@ def mfpt(P, fill_empty_classes=False): ValueError: Input transition probability matrix has 1 rows full of 0s. \ Please set fill_empty_classes=True to set diagonal elements for these \ rows to be 1 to make sure the matrix is stochastic. - """ + """ P = np.asarray(P) rows0 = (P.sum(axis=1) == 0).sum() diff --git a/giddy/markov.py b/giddy/markov.py index ca46f0b..5b1d5a8 100644 --- a/giddy/markov.py +++ b/giddy/markov.py @@ -1910,18 +1910,18 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): c = [] fmt = "r" * (k + 1) s = "\\begin{tabular}{|%s|}\\hline\n" % fmt - s += "\\multicolumn{%s}{|c|}{%s}" % (ks, title) # noqa UP031 + s += "\\multicolumn{%s}{|c|}{%s}" % (ks, title) c.append(s) s = "Number of classes: %d" % int(self.k) - c.append("\\hline\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 + c.append("\\hline\\multicolumn{%s}{|l|}{%s}" % (ks, s)) s = "Number of transitions: %d" % int(self.t_total) - c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 + c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) s = "Number of regimes: %d" % int(self.m) - c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 + c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) s = "Regime names: " s += ", ".join(regime_names) - c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) # noqa UP031 - s = "\\hline\\multicolumn{2}{|l}{%s}" % ("Test") # noqa UP031 + c.append("\\multicolumn{%s}{|l|}{%s}" % (ks, s)) + s = "\\hline\\multicolumn{2}{|l}{%s}" % ("Test") s += "&\\multicolumn{2}{r}{LR}&\\multicolumn{2}{r|}{Q}" c.append(s) s = "Stat." @@ -1929,11 +1929,11 @@ def summary(self, file_name=None, title="Markov Homogeneity Test"): s += "&\\multicolumn{2}{r}{%.3f}" % self.LR s += "&\\multicolumn{2}{r|}{%.3f}" % self.Q c.append(s) - s = "\\multicolumn{2}{|l}{%s}" % ("DOF") # noqa UP031 + s = "\\multicolumn{2}{|l}{%s}" % ("DOF") s += "&\\multicolumn{2}{r}{%d}" % int(self.dof) s += "&\\multicolumn{2}{r|}{%d}" % int(self.dof) c.append(s) - s = "\\multicolumn{2}{|l}{%s}" % ("p-value") # noqa UP031 + s = "\\multicolumn{2}{|l}{%s}" % ("p-value") s += "&\\multicolumn{2}{r}{%.3f}" % self.LR_p_value s += "&\\multicolumn{2}{r|}{%.3f}" % self.Q_p_value c.append(s) diff --git a/pyproject.toml b/pyproject.toml index 528edb7..0c126a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,39 +79,29 @@ select = ["E", "F", "W", "I", "UP", "N", "B", "A", "C4", "SIM", "ARG"] target-version = "py39" exclude = ["giddy/tests/*", "docs/*"] [tool.ruff.per-file-ignores] -"__init__.py" = ["F401"] # imported but unused -"giddy/directional.py" = [ - "ARG002", # Unused method argument - "N803", # Argument name should be lowercase - "N806", # Variable in function should be lowercase +"__init__.py" = [ + "F401" # imported but unused ] -"giddy/ergodic.py" = [ - "N803", # Argument name should be lowercase - "N806", # Variable in function should be lowercase +"giddy/{directional,ergodic,markov,rank,sequence,util}.py" = [ + "ARG002", # Unused method argument + "N801", # Class name should use CapWords convention + "N802", # Function name should be lowercase + "N803", # Argument name should be lowercase + "N806", # Variable in function should be lowercase ] "giddy/markov.py" = [ - "B006", # Do not use mutable data structures for argument defaults - "N801", # Class name should use CapWords convention - "N802", # Function name should be lowercase - "N803", - "N806", + "B006", # Do not use mutable data structures for argument defaults + "UP031", # Use format specifiers instead of percent format ] -"giddy/rank.py" = [ - "ARG002", - "N801", - "N803", - "N806", +"giddy/{ergodic,markov,sequence}.py" = [ + "E501", # Line too long ] -"giddy/sequence.py" = ["N806"] -"giddy/util.py" = ["N803"] [tool.coverage.run] source = ["./giddy"] [tool.coverage.report] exclude_lines = [ - "if self.debug:", - "pragma: no cover", "raise NotImplementedError", "except ModuleNotFoundError:", "except ImportError",