From 0bf392d63dcb17189416a1779540f870ca0ed1a1 Mon Sep 17 00:00:00 2001 From: Kasia Kozlowska <36536946+KasiaKoz@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:25:51 +0000 Subject: [PATCH] Convenience method to strip links of mode (#246) * add convenience method for stripping all links of a mode * update CHANGELOG.md * add assertion messages * lower code coverage * update cruft * pre-commit run --all-files * remove windows from PR build * remove windows from PR build --- .cruft.json | 4 ++- .github/workflows/docs.yml | 11 ++++-- .github/workflows/pr-ci.yml | 15 ++++++-- CHANGELOG.md | 3 ++ docs/overrides/main.html | 1 - docs/static/extras.css | 23 ++++++++++++- docs/static/hooks.py | 9 +++-- examples/2_2_reading_data_osm.ipynb | 1 + examples/4_2_using_network_road_pricing.ipynb | 1 + ...5_3_modifying_network_simplification.ipynb | 1 + examples/5_4_modifying_network_addition.ipynb | 1 + ...dating_network_google_directions_api.ipynb | 7 ++-- mkdocs.yml | 1 - pyproject.toml | 2 +- requirements/dev.txt | 4 +-- src/genet/core.py | 8 +++++ tests/test_core_network.py | 34 +++++++++++++++++++ 17 files changed, 108 insertions(+), 18 deletions(-) diff --git a/.cruft.json b/.cruft.json index 585a362e..4fabfc6a 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "https://github.com/arup-group/cookiecutter-pypackage", - "commit": "b7724521f898ab28f541d492aff8e2be2ed76a01", + "commit": "bb2bab415eded9682b2c1d465a281450ec922f1c", "checkout": null, "context": { "cookiecutter": { @@ -15,11 +15,13 @@ "project_short_description": "GeNet provides tools to represent and work with a multi-modal transport network with public transport (PT) services", "upload_pypi_package": "y", "upload_conda_package": "y", + "upload_aws_image": "n", "conda_channel": "city-modelling-lab", "command_line_interface": "y", "create_docker_file": "y", "create_author_file": "n", "create_jupyter_notebook_directory": "y", + "check_docs_accessibility_in_CI": "n", "open_source_license": "MIT license", "_template": "https://github.com/arup-group/cookiecutter-pypackage" } diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3812939b..22ef2b72 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,9 +3,16 @@ name: Development docs CI on: push: branches: - - "**" + - main + + pull_request: + branches: + - main paths-ignore: - tests/** + - ".github/**/*" + - "!.github/workflows/docs.yml" + jobs: docs-test: @@ -22,4 +29,4 @@ jobs: uses: arup-group/actions-city-modelling-lab/.github/workflows/docs-deploy.yml@main with: deploy_type: update_latest - notebook_kernel: genet \ No newline at end of file + notebook_kernel: genet diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml index 32e90903..99a4962f 100644 --- a/.github/workflows/pr-ci.yml +++ b/.github/workflows/pr-ci.yml @@ -11,16 +11,25 @@ on: - CONTRIBUTING.md - docs/** - mkdocs.yml + - ".github/**/*" + - "!.github/workflows/pr-ci.yml" jobs: + lint: + if: github.event.repository.private + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pre-commit/action@v3.0.1 + test: + needs: lint + if: always() && (needs.lint.result == 'success' || needs.lint.result == 'skipped') strategy: matrix: - os: [windows-latest, ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest] py3version: ["10", "12"] include: - - os: windows-latest - add_args: "" - os: ubuntu-latest add_args: coin-or-cbc - os: macos-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index c9210e03..ed31bf1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +* Convenience method to strip all links of a given mode [#243](https://github.com/arup-group/genet/issues/243) + ### Fixed * Fixed generating standard outputs by highway tag which were broken after moving to storing additional attributes in short form [#217](https://github.com/arup-group/genet/pull/217) diff --git a/docs/overrides/main.html b/docs/overrides/main.html index ae0bbbba..ba1bc12e 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -13,4 +13,3 @@ {{ super() }} {% endblock content %} - diff --git a/docs/static/extras.css b/docs/static/extras.css index c1cf3c36..d3ae7270 100644 --- a/docs/static/extras.css +++ b/docs/static/extras.css @@ -7,4 +7,25 @@ div.doc-contents:not(.first) { /* Allow tables to be horizontally scrollable. */ .md-typeset__scrollwrap { overflow-x: auto; -} \ No newline at end of file +} +/* Improve contrast of text in rendered Jupyter notebook codeblocks. */ +.jp-Notebook { + --jp-cell-prompt-not-active-opacity: 1; +} +.jp-InputArea-editor { + --jp-cell-editor-background: var(--md-code-bg-color); +} +.highlight-ipynb { + --jp-mirror-editor-number-color: var(--md-code-hl-number-color); + --jp-mirror-editor-string-color: var(--md-code-hl-string-color); + --jp-mirror-editor-operator-color: var(--md-code-hl-operator-color); + --jp-mirror-editor-meta-color: var(--md-code-hl-operator-color); + --jp-mirror-editor-comment-color: var(--md-code-hl-comment-color); + --jp-mirror-editor-keyword-color: var(--md-code-hl-keyword-color); + --jp-mirror-editor-builtin-color: var(--md-code-hl-keyword-color); + --jp-mirror-editor-variable-2-color: var(--md-code-hl-punctuation-color); + --jp-mirror-editor-punctuation-color: var(--md-code-hl-punctuation-color); + --jp-mirror-editor-property-color: var(--md-code-hl-punctuation-color); + --jp-mirror-editor-variable-color: var(--md-code-hl-variable-color); + --jp-mirror-editor-def-color: var(--md-code-hl-constant-color); +} diff --git a/docs/static/hooks.py b/docs/static/hooks.py index f3316fe0..bf2cec89 100644 --- a/docs/static/hooks.py +++ b/docs/static/hooks.py @@ -1,3 +1,5 @@ +"""Hooks to run when building documentation.""" + import tempfile from pathlib import Path @@ -50,7 +52,7 @@ def _new_file(path: Path, config: dict, src_dir: str = ".") -> File: def _api_gen(files: list, config: dict) -> dict: - """Project Python API generator + """Project Python API generator. Args: files (list): mkdocs file list. @@ -80,6 +82,7 @@ def _py_to_md(filepath: Path, api_nav: dict, config: dict) -> File: filepath (Path): Path to python file relative to the package source code directory. api_nav (dict): Nested dictionary to fill with mkdocs navigation entries. config (Config): mkdocs config dictionary. + Returns: File: mkdocs object that links the temp file to the docs directory, ready to be added to the mkdocs file list. """ @@ -114,7 +117,6 @@ def _update_nav(api_nav: dict, config: dict) -> None: api_nav (dict): Python API navigation tree. config (dict): mkdocs config dictionary (in which `nav` can be found). """ - api_reference_nav = { "Python API": [*api_nav.pop("top_level"), *[{k: v} for k, v in api_nav.items()]] } @@ -124,6 +126,7 @@ def _update_nav(api_nav: dict, config: dict) -> None: def _get_nav_list(nav: list[dict | str], ref: str) -> list: """Get navigation entry sub-page list. + Navigation list entries can be dictionaries or strings. Sub-list entries can then also be dictionaries or strings. E.g., @@ -147,6 +150,6 @@ def on_post_build(**kwargs): """After mkdocs has finished building the docs, remove the temporary directory of markdown files. Args: - config (Config): mkdocs config dictionary (unused). + **kwargs: Automatic MKDocs hook inputs. """ TEMPDIR.cleanup() diff --git a/examples/2_2_reading_data_osm.ipynb b/examples/2_2_reading_data_osm.ipynb index b3966c5a..3e1adae0 100644 --- a/examples/2_2_reading_data_osm.ipynb +++ b/examples/2_2_reading_data_osm.ipynb @@ -130,6 +130,7 @@ "outputs": [], "source": [ "import importlib_resources\n", + "\n", "from genet import read_osm" ] }, diff --git a/examples/4_2_using_network_road_pricing.ipynb b/examples/4_2_using_network_road_pricing.ipynb index 6cd08c47..c7f55edf 100644 --- a/examples/4_2_using_network_road_pricing.ipynb +++ b/examples/4_2_using_network_road_pricing.ipynb @@ -61,6 +61,7 @@ "from pathlib import Path\n", "\n", "import pandas as pd\n", + "\n", "from genet import read_matsim\n", "\n", "path_to_matsim_network = \"example_data/pt2matsim_network\"\n", diff --git a/examples/5_3_modifying_network_simplification.ipynb b/examples/5_3_modifying_network_simplification.ipynb index 490c5575..766c650f 100644 --- a/examples/5_3_modifying_network_simplification.ipynb +++ b/examples/5_3_modifying_network_simplification.ipynb @@ -56,6 +56,7 @@ ], "source": [ "import importlib_resources\n", + "\n", "from genet import read_osm\n", "\n", "n = read_osm(\n", diff --git a/examples/5_4_modifying_network_addition.ipynb b/examples/5_4_modifying_network_addition.ipynb index b8f3188d..f93b8f4d 100644 --- a/examples/5_4_modifying_network_addition.ipynb +++ b/examples/5_4_modifying_network_addition.ipynb @@ -66,6 +66,7 @@ ], "source": [ "import importlib_resources\n", + "\n", "from genet import read_osm\n", "\n", "_n_tiny = read_osm(\n", diff --git a/examples/6_2_validating_network_google_directions_api.ipynb b/examples/6_2_validating_network_google_directions_api.ipynb index 4042e0d2..c222ef67 100644 --- a/examples/6_2_validating_network_google_directions_api.ipynb +++ b/examples/6_2_validating_network_google_directions_api.ipynb @@ -30,12 +30,13 @@ "import os\n", "import random\n", "\n", - "import genet\n", "import matplotlib.pyplot as plt\n", + "from shapely.geometry import LineString\n", + "\n", + "import genet\n", "from genet import google_directions, read_matsim\n", "from genet.output.spatial import generate_geodataframes\n", - "from genet.utils.io import save_geodataframe\n", - "from shapely.geometry import LineString" + "from genet.utils.io import save_geodataframe" ] }, { diff --git a/mkdocs.yml b/mkdocs.yml index 1997d779..f68204d2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -15,7 +15,6 @@ theme: - navigation.indexes - navigation.top - content.code.copy - - content.code.annotate repo_url: https://github.com/arup-group/genet/ site_dir: .docs markdown_extensions: diff --git a/pyproject.toml b/pyproject.toml index c23a554a..0c053358 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ branch = true source = ["src/"] [tool.coverage.report] -fail_under = 94 +fail_under = 93 [tool.coverage.html] directory = "reports/coverage" diff --git a/requirements/dev.txt b/requirements/dev.txt index 57383799..0d463b0f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,10 +1,10 @@ cruft >= 2, < 3 jupyter < 2 mike >= 2, < 3 -mkdocs < 1.6 +mkdocs >= 1.6, < 2 mkdocs-material >= 9.4, < 10 mkdocs-click < 0.7 -mkdocs-jupyter < 0.24.7 +mkdocs-jupyter >= 0.24.8, < 0.25 mkdocstrings-python < 2 nbmake >= 1.5.1, < 2 pre-commit < 4 diff --git a/src/genet/core.py b/src/genet/core.py index df40f14f..c88d04e7 100644 --- a/src/genet/core.py +++ b/src/genet/core.py @@ -743,6 +743,14 @@ def subnetwork_on_spatial_condition( n_connected_components=n_connected_components, ) + def remove_mode_from_all_links(self, mode: Union[set, list, str]): + """Method to remove modes from links in-place. + + Args: + mode (Union[set, list, str]): Which mode to remove. + """ + self.remove_mode_from_links(set(self.link_id_mapping.keys()), mode) + def remove_mode_from_links(self, links: Union[set, list], mode: Union[set, list, str]): """Method to remove modes from links in-place. diff --git a/tests/test_core_network.py b/tests/test_core_network.py index 4a48c831..34ddb011 100644 --- a/tests/test_core_network.py +++ b/tests/test_core_network.py @@ -2335,6 +2335,40 @@ def test_subnetwork_on_spatial_condition_delagates_to_spatial_methods_to_get_sub ) +def test_removing_mode_from_all_links_retains_other_modes_on_links(): + n = Network("epsg:27700") + n.add_link("0", 1, 2, attribs={"modes": {"car", "bike", "piggyback"}, "length": 1}) + n.add_link("1", 2, 3, attribs={"modes": {"car", "bike"}, "length": 1}) + + n.remove_mode_from_all_links(mode="bike") + + assert n.link("0")["modes"] == {"car", "piggyback"}, "The link modes have been incorrectly set" + assert n.link("1")["modes"] == {"car"}, "The link modes have been incorrectly set" + + +def test_removing_mode_from_all_links_deletes_links_with_no_other_modes(): + n = Network("epsg:27700") + n.add_link("0", 1, 2, attribs={"modes": {"car", "bike"}, "length": 1}) + n.add_link("1", 2, 3, attribs={"modes": {"bike"}, "length": 1}) + + n.remove_mode_from_all_links(mode="bike") + + assert not n.has_link("1"), "The link with empty modes has not been removed" + + +def test_removing_mode_from_all_links_does_not_omit_any_links(): + n = Network("epsg:27700") + for i in range(10): + n.add_link(str(i), i, i + 1, attribs={"modes": {"car", "bike"}, "length": 1}) + + n.remove_mode_from_all_links(mode="bike") + + for i in range(10): + assert ( + "bike" not in n.link(str(i))["modes"] + ), f"The `bike` mode as not been deleted from link `{i}`" + + def test_removing_mode_from_links_updates_the_modes(): n = Network("epsg:27700") n.add_link("0", 1, 2, attribs={"modes": {"car", "bike"}, "length": 1})