From 5732cb69d55d25ab67bde76bad14937ce0d60922 Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Sat, 28 Dec 2024 16:20:23 -0700 Subject: [PATCH 1/5] build and check package in CI --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce5dadb1..b07e3494 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,12 @@ jobs: env: SKIP: no-commit-to-branch + - name: Build and check package + run: | + python -m validate_pyproject ./pyproject.toml + python -m hatch build --clean + python -m twine check --strict ./dist/* + - name: Test docs build run: python -m sphinx -E -W --keep-going -b html ./docs/source ./docs/build/html From 5a3f6eac86e07a6e17155126ceb9ba43dd890653 Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Sat, 28 Dec 2024 16:29:59 -0700 Subject: [PATCH 2/5] move docs/test optional deps from pyproject to req files --- environments/environments.json | 65 ------------------- environments/make-env-files.py | 60 ++++++++--------- environments/requirements/environments.json | 45 +++++++++++++ .../requirements-all.txt} | 1 - .../requirements/requirements-docs.txt | 3 + .../requirements/requirements-extras.txt | 12 ++++ .../requirements/requirements-tests.txt | 9 +++ environments/tests/env-ci.yml | 4 ++ environments/tests/env-test-minimum-deps.yml | 4 ++ .../tests/requirements-test-latest-deps.txt | 7 +- pyproject.toml | 2 - 11 files changed, 111 insertions(+), 101 deletions(-) delete mode 100644 environments/environments.json create mode 100644 environments/requirements/environments.json rename environments/{requirements.txt => requirements/requirements-all.txt} (99%) create mode 100644 environments/requirements/requirements-docs.txt create mode 100644 environments/requirements/requirements-extras.txt create mode 100644 environments/requirements/requirements-tests.txt diff --git a/environments/environments.json b/environments/environments.json deleted file mode 100644 index 064998df..00000000 --- a/environments/environments.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "env-test-minimum-deps": { - "filepath": "./environments/tests/env-test-minimum-deps.yml", - "needs_python": true, - "needs_dependencies": true, - "needs_optionals": true, - "which_optionals": ["entropy", "neighbors", "raster", "visualization", "tests"], - "force_pin": true, - "extras": null - }, - "env-ci": { - "filepath": "./environments/tests/env-ci.yml", - "needs_python": true, - "needs_dependencies": true, - "needs_optionals": true, - "which_optionals": null, - "force_pin": false, - "extras": null - }, - "requirements-test-latest-deps": { - "filepath": "./environments/tests/requirements-test-latest-deps.txt", - "needs_python": false, - "needs_dependencies": true, - "needs_optionals": true, - "which_optionals": null, - "force_pin": false, - "extras": null - }, - "requirements-rtd": { - "filepath": "./docs/requirements-rtd.txt", - "needs_python": false, - "needs_dependencies": false, - "needs_optionals": true, - "which_optionals": ["docs"], - "force_pin": false, - "extras": null - }, - "requirements-env": { - "filepath": "./environments/requirements.txt", - "needs_python": false, - "needs_dependencies": true, - "needs_optionals": true, - "which_optionals": null, - "force_pin": false, - "extras": [ - "bottleneck", - "cartopy", - "conda-smithy", - "folium", - "hatch", - "jupyterlab", - "nbdime", - "nbqa", - "numexpr", - "pillow", - "pip", - "pysal>24", - "python-igraph", - "seaborn", - "statsmodels", - "twine", - "validate-pyproject" - ] - } -} diff --git a/environments/make-env-files.py b/environments/make-env-files.py index 5f86c721..b043786b 100644 --- a/environments/make-env-files.py +++ b/environments/make-env-files.py @@ -13,7 +13,7 @@ # path to package's pyproject and the config json file pyproject_path = "./pyproject.toml" -environments_config_path = "./environments/environments.json" +environments_config_path = "./environments/requirements/environments.json" # what channels to specify in conda env yml files CHANNELS = ["conda-forge"] @@ -25,22 +25,16 @@ ) -def extract_optional_deps(which: list[str] | None = None) -> list[Requirement]: +def extract_optional_deps() -> list[Requirement]: """ Extract a list of the optional dependencies/versions from pyproject.toml. - Parameters - ---------- - which - Which optional dependencies to extract. If None, extract them all. - Returns ------- optional_deps """ opts = pyproject["project"]["optional-dependencies"] - opts = [v for k, v in opts.items() if k in which] if which is not None else opts.values() - return list({Requirement(o) for o in itertools.chain.from_iterable(opts)}) + return list({Requirement(o) for o in itertools.chain.from_iterable(opts.values())}) def make_requirement( @@ -94,7 +88,7 @@ def make_file(env_name: str) -> None: # it's a conda env file if it ends with ".yml", otherwise it's a pip # requirements.txt file - is_conda = env["filepath"].endswith(".yml") + is_conda = env["output_path"].endswith(".yml") # determine which dependencies to add based on the configuration depends_on = [] @@ -105,33 +99,39 @@ def make_file(env_name: str) -> None: dependencies = [Requirement(d) for d in pyproject["project"]["dependencies"]] depends_on.extend(dependencies) if env["needs_optionals"]: - optionals = extract_optional_deps(which=env["which_optionals"]) + optionals = extract_optional_deps() depends_on.extend(optionals) # make the list of requirements - requirements = sorted( + requirements = [ make_requirement(dep, force_pin=env["force_pin"], is_conda=is_conda) for dep in depends_on - ) + ] # add any extra requirements if provided in the configuration if env["extras"] is not None: - requirements = sorted(requirements + env["extras"]) - - # write the conda env yml or pip requirements.txt file to disk - with Path(env["filepath"]).open("w") as f: - if is_conda: - data = {"name": env_name, "channels": CHANNELS, "dependencies": requirements} - text = "" - for k, v in data.items(): - if isinstance(v, list): - text += k + ":\n - " + "\n - ".join(v) + "\n" - elif isinstance(v, str): - text += k + ": " + v + "\n" - f.writelines(HEADER + text) - else: - f.writelines(HEADER + "\n".join(requirements) + "\n") - - print(f"Wrote {len(requirements)} requirements to {env['filepath']!r}") # noqa: T201 + for extras_filepath in env["extras"]: + with Path(extras_filepath).open() as f: + requirements += f.read().splitlines() + + # convert the requirements to conda env yml or pip requirements.txt + requirements = sorted(requirements) + if not is_conda: + text = HEADER + "\n".join(requirements) + "\n" + else: + data = {"name": env_name, "channels": CHANNELS, "dependencies": requirements} + text = "" + for k, v in data.items(): + if isinstance(v, list): + text += k + ":\n - " + "\n - ".join(v) + "\n" + elif isinstance(v, str): + text += k + ": " + v + "\n" + text = HEADER + text + + # write the file to disk + with Path(env["output_path"]).open("w") as f: + f.writelines(text) + + print(f"Wrote {len(requirements)} requirements to {env['output_path']!r}") # noqa: T201 if __name__ == "__main__": diff --git a/environments/requirements/environments.json b/environments/requirements/environments.json new file mode 100644 index 00000000..b66d8ba0 --- /dev/null +++ b/environments/requirements/environments.json @@ -0,0 +1,45 @@ +{ + "env-ci": { + "output_path": "./environments/tests/env-ci.yml", + "needs_python": true, + "needs_dependencies": true, + "needs_optionals": true, + "force_pin": false, + "extras": ["./environments/requirements/requirements-docs.txt", + "./environments/requirements/requirements-tests.txt"] + }, + "env-test-minimum-deps": { + "output_path": "./environments/tests/env-test-minimum-deps.yml", + "needs_python": true, + "needs_dependencies": true, + "needs_optionals": true, + "force_pin": true, + "extras": ["./environments/requirements/requirements-tests.txt"] + }, + "requirements-test-latest-deps": { + "output_path": "./environments/tests/requirements-test-latest-deps.txt", + "needs_python": false, + "needs_dependencies": true, + "needs_optionals": true, + "force_pin": false, + "extras": ["./environments/requirements/requirements-tests.txt"] + }, + "requirements-rtd": { + "output_path": "./docs/requirements-rtd.txt", + "needs_python": false, + "needs_dependencies": false, + "needs_optionals": false, + "force_pin": false, + "extras": ["./environments/requirements/requirements-docs.txt"] + }, + "requirements-all": { + "output_path": "./environments/requirements/requirements-all.txt", + "needs_python": false, + "needs_dependencies": true, + "needs_optionals": true, + "force_pin": false, + "extras": ["./environments/requirements/requirements-docs.txt", + "./environments/requirements/requirements-extras.txt", + "./environments/requirements/requirements-tests.txt"] + } +} diff --git a/environments/requirements.txt b/environments/requirements/requirements-all.txt similarity index 99% rename from environments/requirements.txt rename to environments/requirements/requirements-all.txt index 0802377c..734b77be 100644 --- a/environments/requirements.txt +++ b/environments/requirements/requirements-all.txt @@ -12,7 +12,6 @@ jupyterlab lxml matplotlib>=3.5 nbdime -nbqa networkx>=2.5 numexpr numpy>=1.22 diff --git a/environments/requirements/requirements-docs.txt b/environments/requirements/requirements-docs.txt new file mode 100644 index 00000000..36b3cd9e --- /dev/null +++ b/environments/requirements/requirements-docs.txt @@ -0,0 +1,3 @@ +furo +sphinx-autodoc-typehints +sphinx>=7 diff --git a/environments/requirements/requirements-extras.txt b/environments/requirements/requirements-extras.txt new file mode 100644 index 00000000..d8204ee5 --- /dev/null +++ b/environments/requirements/requirements-extras.txt @@ -0,0 +1,12 @@ +bottleneck +cartopy +conda-smithy +folium +jupyterlab +nbdime +numexpr +pillow +pysal>24 +python-igraph +seaborn +statsmodels diff --git a/environments/requirements/requirements-tests.txt b/environments/requirements/requirements-tests.txt new file mode 100644 index 00000000..9a03fb1d --- /dev/null +++ b/environments/requirements/requirements-tests.txt @@ -0,0 +1,9 @@ +hatch +lxml +pip +pre-commit +pytest +pytest-cov +twine +typeguard +validate-pyproject diff --git a/environments/tests/env-ci.yml b/environments/tests/env-ci.yml index 7055d6bc..7f744184 100644 --- a/environments/tests/env-ci.yml +++ b/environments/tests/env-ci.yml @@ -7,11 +7,13 @@ channels: dependencies: - furo - geopandas>=1.0 + - hatch - lxml - matplotlib>=3.5 - networkx>=2.5 - numpy>=1.22 - pandas>=1.4 + - pip - pre-commit - pytest - pytest-cov @@ -24,4 +26,6 @@ dependencies: - shapely>=2.0 - sphinx-autodoc-typehints - sphinx>=7 + - twine - typeguard + - validate-pyproject diff --git a/environments/tests/env-test-minimum-deps.yml b/environments/tests/env-test-minimum-deps.yml index 66469e75..8e8485b3 100644 --- a/environments/tests/env-test-minimum-deps.yml +++ b/environments/tests/env-test-minimum-deps.yml @@ -6,11 +6,13 @@ channels: - conda-forge dependencies: - geopandas==1.0.* + - hatch - lxml - matplotlib==3.5.* - networkx==2.5.* - numpy==1.22.* - pandas==1.4.* + - pip - pre-commit - pytest - pytest-cov @@ -21,4 +23,6 @@ dependencies: - scikit-learn==0.23.* - scipy==1.5.* - shapely==2.0.* + - twine - typeguard + - validate-pyproject diff --git a/environments/tests/requirements-test-latest-deps.txt b/environments/tests/requirements-test-latest-deps.txt index 2b7c9a38..b00a1a64 100644 --- a/environments/tests/requirements-test-latest-deps.txt +++ b/environments/tests/requirements-test-latest-deps.txt @@ -1,13 +1,14 @@ # Do not edit this file. It is automatically generated by the script # environments/make-env-files.py using the environment definition data in # environments/environments.json and the requirements in pyproject.toml. -furo geopandas>=1.0 +hatch lxml matplotlib>=3.5 networkx>=2.5 numpy>=1.22 pandas>=1.4 +pip pre-commit pytest pytest-cov @@ -17,6 +18,6 @@ rio-vrt>=0.3 scikit-learn>=0.23 scipy>=1.5 shapely>=2.0 -sphinx-autodoc-typehints -sphinx>=7 +twine typeguard +validate-pyproject diff --git a/pyproject.toml b/pyproject.toml index 6defe7a4..6f1fb9da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,11 +42,9 @@ readme = "README.md" requires-python = ">=3.9" # match classifiers above and mypy version below [project.optional-dependencies] -docs = ["furo", "sphinx>=7", "sphinx-autodoc-typehints"] entropy = ["scipy>=1.5"] neighbors = ["scikit-learn>=0.23", "scipy>=1.5"] raster = ["rasterio>=1.3", "rio-vrt>=0.3"] -tests = ["lxml", "pre-commit", "pytest", "pytest-cov", "typeguard"] visualization = ["matplotlib>=3.5"] [project.urls] From 496a6db7ee117f54b39fd1eb29e7cd557ce10fdb Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Sat, 28 Dec 2024 17:04:06 -0700 Subject: [PATCH 3/5] update requirements file path --- environments/docker/Dockerfile | 2 +- environments/unix-create-env.sh | 2 +- environments/windows-create-env.bat | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/environments/docker/Dockerfile b/environments/docker/Dockerfile index 11ad4514..aa9efa08 100644 --- a/environments/docker/Dockerfile +++ b/environments/docker/Dockerfile @@ -4,7 +4,7 @@ LABEL url="https://osmnx.readthedocs.io" LABEL description="OSMnx is a Python package to easily download, model, analyze, and visualize street networks and other geospatial features from OpenStreetMap." # copy the package files needed for installation -COPY --chmod=0755 ./environments/requirements.txt ./osmnx/ +COPY --chmod=0755 ./environments/requirements/requirements-all.txt ./osmnx/ COPY --chmod=0755 ./osmnx/ ./osmnx/osmnx/ COPY --chmod=0755 ./pyproject.toml ./osmnx/ COPY --chmod=0755 ./README.md ./osmnx/ diff --git a/environments/unix-create-env.sh b/environments/unix-create-env.sh index 43b6d4dc..8387ad4a 100755 --- a/environments/unix-create-env.sh +++ b/environments/unix-create-env.sh @@ -7,7 +7,7 @@ PACKAGE=osmnx eval "$(conda shell.bash hook)" conda activate base conda env remove --yes -n $ENV || true -mamba create --yes -c conda-forge --strict-channel-priority -n $ENV --file requirements.txt +mamba create --yes -c conda-forge --strict-channel-priority -n $ENV --file ./requirements/requirements-all.txt conda activate $ENV python -m pip --python $ENV_PATH uninstall $PACKAGE --yes python -m pip --python $ENV_PATH install -e ../. diff --git a/environments/windows-create-env.bat b/environments/windows-create-env.bat index 1be878fb..aefeda04 100644 --- a/environments/windows-create-env.bat +++ b/environments/windows-create-env.bat @@ -5,7 +5,7 @@ SET PACKAGE=osmnx CALL %CONDA_ROOT%\Scripts\activate.bat && ^ conda activate base && ^ conda env remove --yes -n %ENV% && ^ -mamba create --yes -c conda-forge --strict-channel-priority -n %ENV% --file requirements.txt && ^ +mamba create --yes -c conda-forge --strict-channel-priority -n %ENV% --file requirements\requirements-all.txt && ^ conda activate %ENV% && ^ python -m pip --python %ENV_PATH%\python.exe uninstall %PACKAGE% --yes && ^ python -m pip --python %ENV_PATH%\python.exe install -e ../. && ^ From b2cedbe704a44349638931314cf28075448a1767 Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Sat, 28 Dec 2024 17:04:39 -0700 Subject: [PATCH 4/5] remove place that nominatim no longer has in its database --- tests/test_osmnx.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_osmnx.py b/tests/test_osmnx.py index 237ade7a..8edca370 100644 --- a/tests/test_osmnx.py +++ b/tests/test_osmnx.py @@ -43,7 +43,6 @@ location_point = (37.791427, -122.410018) address = "600 Montgomery St, San Francisco, California, USA" place1 = {"city": "Piedmont", "state": "California", "country": "USA"} -place2 = "SoHo, New York, NY" polygon_wkt = ( "POLYGON ((-122.262 37.869, -122.255 37.869, -122.255 37.874," "-122.262 37.874, -122.262 37.869))" @@ -88,7 +87,6 @@ def test_geocoder() -> None: """Test retrieving elements by place name and OSM ID.""" city = ox.geocode_to_gdf("R2999176", by_osmid=True) city = ox.geocode_to_gdf(place1, which_result=1) - city = ox.geocode_to_gdf(place2) city_projected = ox.projection.project_gdf(city, to_crs="epsg:3395") # test geocoding a bad query: should raise exception From 251e9d7a447294590f4d0e3ce4b6eefd5ee69f0e Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Sat, 28 Dec 2024 17:36:41 -0700 Subject: [PATCH 5/5] update header --- docs/requirements-rtd.txt | 4 ++-- environments/make-env-files.py | 4 ++-- environments/requirements/requirements-all.txt | 4 ++-- environments/tests/env-ci.yml | 4 ++-- environments/tests/env-test-minimum-deps.yml | 4 ++-- environments/tests/requirements-test-latest-deps.txt | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt index c05a3595..d6a7e71a 100644 --- a/docs/requirements-rtd.txt +++ b/docs/requirements-rtd.txt @@ -1,6 +1,6 @@ # Do not edit this file. It is automatically generated by the script -# environments/make-env-files.py using the environment definition data in -# environments/environments.json and the requirements in pyproject.toml. +# /environments/make-env-files.py using the environment definition files in +# /environments/requirements/ and the requirements in pyproject.toml. furo sphinx-autodoc-typehints sphinx>=7 diff --git a/environments/make-env-files.py b/environments/make-env-files.py index b043786b..d1c8e5fd 100644 --- a/environments/make-env-files.py +++ b/environments/make-env-files.py @@ -20,8 +20,8 @@ HEADER = ( "# Do not edit this file. It is automatically generated by the script\n" - "# environments/make-env-files.py using the environment definition data in\n" - "# environments/environments.json and the requirements in pyproject.toml.\n" + "# /environments/make-env-files.py using the environment definition files in\n" + "# /environments/requirements/ and the requirements in pyproject.toml.\n" ) diff --git a/environments/requirements/requirements-all.txt b/environments/requirements/requirements-all.txt index 734b77be..95f2a017 100644 --- a/environments/requirements/requirements-all.txt +++ b/environments/requirements/requirements-all.txt @@ -1,6 +1,6 @@ # Do not edit this file. It is automatically generated by the script -# environments/make-env-files.py using the environment definition data in -# environments/environments.json and the requirements in pyproject.toml. +# /environments/make-env-files.py using the environment definition files in +# /environments/requirements/ and the requirements in pyproject.toml. bottleneck cartopy conda-smithy diff --git a/environments/tests/env-ci.yml b/environments/tests/env-ci.yml index 7f744184..77b0cc3a 100644 --- a/environments/tests/env-ci.yml +++ b/environments/tests/env-ci.yml @@ -1,6 +1,6 @@ # Do not edit this file. It is automatically generated by the script -# environments/make-env-files.py using the environment definition data in -# environments/environments.json and the requirements in pyproject.toml. +# /environments/make-env-files.py using the environment definition files in +# /environments/requirements/ and the requirements in pyproject.toml. name: env-ci channels: - conda-forge diff --git a/environments/tests/env-test-minimum-deps.yml b/environments/tests/env-test-minimum-deps.yml index 8e8485b3..3516c4dc 100644 --- a/environments/tests/env-test-minimum-deps.yml +++ b/environments/tests/env-test-minimum-deps.yml @@ -1,6 +1,6 @@ # Do not edit this file. It is automatically generated by the script -# environments/make-env-files.py using the environment definition data in -# environments/environments.json and the requirements in pyproject.toml. +# /environments/make-env-files.py using the environment definition files in +# /environments/requirements/ and the requirements in pyproject.toml. name: env-test-minimum-deps channels: - conda-forge diff --git a/environments/tests/requirements-test-latest-deps.txt b/environments/tests/requirements-test-latest-deps.txt index b00a1a64..d1675cc2 100644 --- a/environments/tests/requirements-test-latest-deps.txt +++ b/environments/tests/requirements-test-latest-deps.txt @@ -1,6 +1,6 @@ # Do not edit this file. It is automatically generated by the script -# environments/make-env-files.py using the environment definition data in -# environments/environments.json and the requirements in pyproject.toml. +# /environments/make-env-files.py using the environment definition files in +# /environments/requirements/ and the requirements in pyproject.toml. geopandas>=1.0 hatch lxml