From 94d2bd4187d269d5f8d02b0924154dd230f5e221 Mon Sep 17 00:00:00 2001 From: Sveinbjorn Thordarson Date: Sat, 12 Aug 2023 00:39:09 +0000 Subject: [PATCH 1/5] f-string modernization + pyproject.toml --- .github/workflows/python-package.yml | 10 +- .gitignore | 3 + README.md | 9 +- add_placename_data.py | 2 +- pyproject.toml | 152 ++++++++++++++++++ requirements.txt | 3 - setup.py | 44 ----- {iceaddr => src/iceaddr}/__init__.py | 0 {iceaddr => src/iceaddr}/addresses.py | 0 {iceaddr => src/iceaddr}/db.py | 2 +- {iceaddr => src/iceaddr}/dist.py | 0 {iceaddr => src/iceaddr}/placenames.py | 0 {iceaddr => src/iceaddr}/postcodes.py | 0 {iceaddr => src/iceaddr}/resources/iceaddr.db | Bin 14 files changed, 165 insertions(+), 60 deletions(-) create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100755 setup.py rename {iceaddr => src/iceaddr}/__init__.py (100%) rename {iceaddr => src/iceaddr}/addresses.py (100%) rename {iceaddr => src/iceaddr}/db.py (94%) rename {iceaddr => src/iceaddr}/dist.py (100%) rename {iceaddr => src/iceaddr}/placenames.py (100%) rename {iceaddr => src/iceaddr}/postcodes.py (100%) rename {iceaddr => src/iceaddr}/resources/iceaddr.db (100%) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index ee9aa52..31b4a7d 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,7 +1,4 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Build +name: tests on: push: @@ -15,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v2 @@ -25,8 +22,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip wheel setuptools - python -m pip install pytest types-setuptools mypy + python -m pip install --upgrade pip wheel setuptools pytest types-setuptools mypy - name: Run mypy run: | mypy iceaddr/*.py diff --git a/.gitignore b/.gitignore index 58255e9..10e1de2 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ venv *.zip *.csv .vscode +*.pyc +.coverage +.coverage.* diff --git a/README.md b/README.md index ab47294..a2574dd 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # iceaddr [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/) +[![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/) [![Release](https://shields.io/github/v/release/sveinbjornt/iceaddr?display_name=tag)]() [![PyPI](https://img.shields.io/pypi/v/iceaddr)]() [![Build](https://github.com/sveinbjornt/iceaddr/actions/workflows/python-package.yml/badge.svg)]() ### Look up Icelandic street addresses, postcodes and placenames -`iceaddr` is a Python 3.7+ package to look up information about Icelandic streets, addresses, placenames, +`iceaddr` is a Python >=3.8 package to look up information about Icelandic streets, addresses, placenames, landmarks, locations and postcodes. The underlying data is contained in a local SQLite database assembled from the following sources: @@ -118,7 +118,7 @@ in the database: ```python >>> from iceaddr import nearest_addr >>> addr = nearest_addr(64.148446, -21.944933)[0] ->>> print("{0} {1}".format(addr["heiti_nf"], addr["husnr"])) +>>> print(f"{addr['heiti_nf']} {addr['husnr']}") Öldugata 2 ``` @@ -243,7 +243,7 @@ Landakotsvöllur ## Build process -To build your own version of the package, you need to have Python 3.7+ installed. +To build your own version of the package, you need to have Python >=3.8 installed. Then, after optionally creating a virtual environment, run the following command from the repository root to install dependencies: @@ -269,6 +269,7 @@ python setup.py install ## Version History +* 0.5.7: Updated address and placename data. Now requires Python 3.8+ (18/09/2024) * 0.5.6: Updated address and placename data. (11/08/2023) * 0.5.5: Updated address and placename data. Removed ISN93 coords. Now requires Python 3.7+ (11/12/2022) * 0.5.4: Updated address and placename data (09/11/2022) diff --git a/add_placename_data.py b/add_placename_data.py index 5f6c626..018c628 100755 --- a/add_placename_data.py +++ b/add_placename_data.py @@ -154,7 +154,7 @@ def add_placenames_from_is50v(dbc) -> None: # Special handling of flakes - use center point elif type(c) is list: if not c: - # print("Faulty flake: {0}".format(n)) + # print(f"Faulty flake: {n}") # pprint(i) # raise continue diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8dfe0f2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,152 @@ +[project] +name = "iceaddr" +version = "0.5.7" +description = "Look up information about Icelandic street addresses, postcodes, landmarks, locations and placenames" +authors = [ + { name = "Sveinbjorn Thordarson", email = "sveinbjorn@sveinbjorn.org" }, +] +readme = { file = "README.md", content-type = "text/markdown" } +license = { file = "LICENSE.txt" } +# For classifier list see: https://pypi.org/pypi?%3Aaction=list_classifiers +classifiers = [ + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Natural Language :: Icelandic", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Utilities", + "Topic :: Text Processing :: Linguistic", +] +requires-python = ">=3.8" +dependencies = [] + +[project.urls] +Repository = "https://github.com/sveinbjornt/iceaddr" + +[project.optional-dependencies] +# Dev dependencies +dev = [ + "pytest>=7.2.1", + # Building database + "fiona>=1.8.18", + "humanize>=0.5.1", + "reynir>=3.1.0", + # Pre-commit hook + "pre-commit>=3.3.3", + "black>=23.7.0", + "mypy>=1.5.1", + "ruff>=0.0.285", + "coverage[toml]>=7.3.1", +] + +# *** Configuration of tools *** + +[tool.pytest.ini_options] +filterwarnings = [ + # Ignore deprecation warnings in libraries, their problem not ours + "ignore::DeprecationWarning", +] + +[tool.coverage.run] +branch = true # Enable branch coverage +source = ["src/iceaddr"] # Only test coverage of `iceaddr` +command_line = "-m pytest" # Run all tests when calculating coverage + +[tool.coverage.report] +exclude_also = ["if TYPE_CHECKING:", "raise NotImplementedError"] +skip_covered = true # Skip showing fully covered files +skip_empty = true # Skip empty files +sort = "-Cover" # Sort by coverage percentage +precision = 2 # Precision of output percentage +fail_under = 65 # Fail if total covered under threshold + + +[tool.mypy] +overrides = [] + + +[tool.pyright] +typeCheckingMode = "strict" +# The following settings are off by default, even in strict mode +reportCallInDefaultInitializer = "information" +reportImplicitOverride = "information" +reportImplicitStringConcatenation = "information" +reportImportCycles = "warning" +reportMissingSuperCall = "none" +reportPropertyTypeMismatch = "warning" +reportShadowedImports = "warning" +reportUninitializedInstanceVariable = "information" +reportUnnecessaryTypeIgnoreComment = "warning" +reportUnusedCallResult = "none" + + +[tool.ruff] +# See https://beta.ruff.rs/docs/rules/ for list of rules +# Enable all rules +select = ["ALL"] +# Ignore specific rules +# (we should aim to have these as few as possible) +ignore = [ + "D", # Docstring style rules + "ANN", # Missing type annotations + "TD", # Pedantic TODO comment rules + "FIX002", # Line contains TODO rule + "SLOT000", # str subclass should define __slots__ + "SIM105", # contextlib.suppress rule + "BLE", # Blind `except:` + "A", # Shadowing of builtins + "ERA", # Commented out code + "FBT", # Forbids boolean positional arguments + "COM", # Commas (sometimes takes issue with black formatting) + "S101", # Disallow assert statements rule + "PLR0912", # "Too many statements" rule + "C90", # Function complexity rules + "UP", # Deprecation rules + "TRY", # Pedantic exception rules + "EM", # Pedantic exception message rules + "TID", # No relative parent imports rule + "TCH", # Move into type checking block - too risky, causes issues + "RSE102", # Bug: https://github.com/astral-sh/ruff/issues/5416 +] +# Silence complaints when black doesn't format +# lines that are slightly over 88 characters long +line-length = 100 + +[tool.ruff.per-file-ignores] +"./run.py" = ["T201"] +"cli_client/run.py" = ["INP001", "T201", "PLR0915"] + +[tool.ruff.isort] +section-order = [ + "future", + "typehints", + "standard-library", + "third-party", + "first-party", + "local-folder", +] + +[tool.ruff.isort.sections] +# Have typing libraries above other imports +typehints = ["typing", "typing_extensions", "types"] + +# *** Build system configuration *** + +[tool.setuptools_scm] +fallback_version = "0.0.0" + +[tool.setuptools.packages.find] +where = ["src"] +[tool.setuptools.package-data] +iceaddr = ["*.db"] + +[build-system] +requires = ["setuptools>=45", "setuptools_scm>=6.2"] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1ba539d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -fiona>=1.8.18 -humanize>=0.5.1 -reynir>=3.1.0 diff --git a/setup.py b/setup.py deleted file mode 100755 index 7c0b788..0000000 --- a/setup.py +++ /dev/null @@ -1,44 +0,0 @@ -import setuptools - -with open("README.md", "r", encoding="utf-8") as fh: - long_description = fh.read() - -setuptools.setup( - name="iceaddr", - version="0.5.6", # Also update __init__.py - author="Sveinbjorn Thordarson", - author_email="sveinbjorn@sveinbjorn.org", - license="BSD", - url="https://github.com/sveinbjornt/iceaddr", - description="Look up information about Icelandic street addresses, postcodes, landmarks, locations and placenames", - long_description=long_description, - long_description_content_type="text/markdown", - install_requires=[], - extras_require={ - "dev": [ - "pytest", - "humanize", - "fiona", - ] - }, - packages=["iceaddr"], - classifiers=[ - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Natural Language :: Icelandic", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Utilities", - "Topic :: Text Processing :: Linguistic", - ], - include_package_data=True, - zip_safe=False, -) diff --git a/iceaddr/__init__.py b/src/iceaddr/__init__.py similarity index 100% rename from iceaddr/__init__.py rename to src/iceaddr/__init__.py diff --git a/iceaddr/addresses.py b/src/iceaddr/addresses.py similarity index 100% rename from iceaddr/addresses.py rename to src/iceaddr/addresses.py diff --git a/iceaddr/db.py b/src/iceaddr/db.py similarity index 94% rename from iceaddr/db.py rename to src/iceaddr/db.py index 7adf087..ee0cab7 100755 --- a/iceaddr/db.py +++ b/src/iceaddr/db.py @@ -27,7 +27,7 @@ def connection(self) -> sqlite3.Connection: if not self.db_conn: db_path = resource_filename(__name__, _DB_REL_PATH) # Open database file in read-only mode via URI - db_uri = "file:{0}?mode=ro".format(db_path) + db_uri = f"file:{db_path}?mode=ro" self.db_conn = sqlite3.connect(db_uri, uri=True, check_same_thread=False) # Return rows as key-value dicts self.db_conn.row_factory = lambda c, r: dict( diff --git a/iceaddr/dist.py b/src/iceaddr/dist.py similarity index 100% rename from iceaddr/dist.py rename to src/iceaddr/dist.py diff --git a/iceaddr/placenames.py b/src/iceaddr/placenames.py similarity index 100% rename from iceaddr/placenames.py rename to src/iceaddr/placenames.py diff --git a/iceaddr/postcodes.py b/src/iceaddr/postcodes.py similarity index 100% rename from iceaddr/postcodes.py rename to src/iceaddr/postcodes.py diff --git a/iceaddr/resources/iceaddr.db b/src/iceaddr/resources/iceaddr.db similarity index 100% rename from iceaddr/resources/iceaddr.db rename to src/iceaddr/resources/iceaddr.db From e6de04aa1eaecbae52d62eface8131f3595f1c00 Mon Sep 17 00:00:00 2001 From: Sveinbjorn Thordarson Date: Mon, 18 Sep 2023 17:51:53 +0000 Subject: [PATCH 2/5] Improved typing, lint checker appeasement --- .gitignore | 2 +- add_placename_data.py | 4 ++-- build_db.py | 4 ++-- build_postcodes.py | 14 ++++++-------- pyproject.toml | 6 +++--- src/iceaddr/__init__.py | 6 +++--- src/iceaddr/addresses.py | 25 +++++++++++++++---------- src/iceaddr/db.py | 8 +++++--- src/iceaddr/dist.py | 3 ++- src/iceaddr/placenames.py | 5 +++-- src/iceaddr/postcodes.py | 8 +++++--- tests/test_iceaddr.py | 7 +++++-- 12 files changed, 52 insertions(+), 40 deletions(-) mode change 100755 => 100644 src/iceaddr/__init__.py mode change 100755 => 100644 src/iceaddr/addresses.py mode change 100755 => 100644 src/iceaddr/db.py mode change 100755 => 100644 src/iceaddr/dist.py mode change 100755 => 100644 src/iceaddr/placenames.py mode change 100755 => 100644 src/iceaddr/postcodes.py diff --git a/.gitignore b/.gitignore index 10e1de2..6cfa0c9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ __pycache__/ *.py[cod] *$py.class/ /dist/ -/*.egg-info +*.egg-info *.shp p3*/ /stadfangaskra.db diff --git a/add_placename_data.py b/add_placename_data.py index 018c628..64c4b3b 100755 --- a/add_placename_data.py +++ b/add_placename_data.py @@ -11,7 +11,7 @@ import sqlite3 from pathlib import Path -import fiona +import fiona # noqa from iceaddr.dist import in_iceland @@ -30,7 +30,7 @@ DEFAULT_DBNAME = "iceaddr.db" -def center_point(coords: List[Tuple]) -> Tuple[float, float]: +def center_point(coords: List[Tuple[float, float]]) -> Tuple[float, float]: """Find the center point of a given set of coordinates.""" x: float = 0 y: float = 0 diff --git a/build_db.py b/build_db.py index 2a18d20..b488a3b 100755 --- a/build_db.py +++ b/build_db.py @@ -23,7 +23,7 @@ from urllib.request import urlopen from iceaddr.dist import in_iceland -import humanize +import humanize # noqa STADFONG_REMOTE_URL = "https://fasteignaskra.is/Stadfangaskra.csv" @@ -164,7 +164,7 @@ def main() -> None: print("\tInserting: %d\r" % cnt, end="") sys.stdout.flush() - bytesize = os.stat(db_path).st_size + bytesize: int = os.stat(db_path).st_size human_size = humanize.naturalsize(bytesize) print("\nCreated database with %d entries (%s)" % (cnt, human_size)) diff --git a/build_postcodes.py b/build_postcodes.py index c6515b1..aaa6808 100755 --- a/build_postcodes.py +++ b/build_postcodes.py @@ -44,31 +44,29 @@ def main() -> None: # the dative form (þgf.). Try to lemmatise to nominative (nf.) using Reynir. postcode = int(r["Póstnúmer"]) if postcode not in pc_keys: - logging.warning( - "Postcode '{0}' did not already exist in data.".format(postcode) - ) + logging.warning(f"Postcode '{postcode}' did not already exist in data.") changed = True tp = r["Tegund"] p_dat = _clean_name(r["Staður"]) p_nom = NounPhrase(p_dat).nominative if not p_nom: - logging.warning("Unable to decline placename '{0}'".format(p_dat)) + logging.warning(f"Unable to decline placename '{p_dat}'") p_nom = p_dat if pc[postcode]["stadur_nf"] != p_nom: pc[postcode]["stadur_nf"] = p_nom - print("{0} --> {1}".format(pc[postcode]["stadur_nf"], p_nom)) + print(f"{pc[postcode]['stadur_nf']} --> {p_nom}") changed = True if pc[postcode]["stadur_tgf"] != p_dat: pc[postcode]["stadur_tgf"] = p_dat - print("{0} --> {1}".format(pc[postcode]["stadur_tgf"], p_dat)) + print(f"{pc[postcode]['stadur_tgf']} --> {p_dat}") changed = True if pc[postcode]["tegund"] != tp: pc[postcode]["tegund"] = tp - print("{0} --> {1}".format(pc[postcode]["tegund"], tp)) + print(f"{pc[postcode]['tegund']} --> {tp}") changed = True if not changed: @@ -78,5 +76,5 @@ def main() -> None: if __name__ == "__main__": - """ Command line invocation. """ + """Command line invocation.""" main() diff --git a/pyproject.toml b/pyproject.toml index 8dfe0f2..142dbce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,9 +35,9 @@ Repository = "https://github.com/sveinbjornt/iceaddr" dev = [ "pytest>=7.2.1", # Building database - "fiona>=1.8.18", - "humanize>=0.5.1", - "reynir>=3.1.0", + "fiona>=1.9.4", # for GIS data + "humanize>=0.5.1", # for progress bar + "reynir>=3.1.0", # for parsing and declining placenames # Pre-commit hook "pre-commit>=3.3.3", "black>=23.7.0", diff --git a/src/iceaddr/__init__.py b/src/iceaddr/__init__.py old mode 100755 new mode 100644 index 6c1d97b..c001ba4 --- a/src/iceaddr/__init__.py +++ b/src/iceaddr/__init__.py @@ -10,6 +10,6 @@ __author__ = "Sveinbjorn Thordarson" __version__ = "0.5.6" # Also update setup.py -from .addresses import * # noqa -from .postcodes import * # noqa -from .placenames import * # noqa +from .addresses import * # noqa: F403 +from .placenames import * # noqa: F403 +from .postcodes import * # noqa: F403 diff --git a/src/iceaddr/addresses.py b/src/iceaddr/addresses.py old mode 100755 new mode 100644 index e2602d9..545082e --- a/src/iceaddr/addresses.py +++ b/src/iceaddr/addresses.py @@ -9,13 +9,15 @@ """ -from typing import Dict, List, Any, Optional +from __future__ import annotations + +from typing import Any, Dict, List, Optional import re from .db import shared_db -from .postcodes import POSTCODES, postcodes_for_placename from .dist import distance +from .postcodes import POSTCODES, postcodes_for_placename def _add_postcode_info(addr: Dict[str, Any]) -> Dict[str, Any]: @@ -40,7 +42,7 @@ def _cap_first(s: str) -> str: return s[:1].upper() + s[1:] if s else s -def iceaddr_lookup( +def iceaddr_lookup( # noqa: PLR0913 street_name: str, number: Optional[int] = None, letter: Optional[str] = None, @@ -75,7 +77,7 @@ def iceaddr_lookup( sqlargs.append(letter) if pc: - qp = " OR ".join([" postnr=?" for p in pc]) + qp = " OR ".join([" postnr=?" for _ in pc]) sqlargs.extend([str(x) for x in pc]) q += " AND (%s) " % qp @@ -88,6 +90,9 @@ def iceaddr_lookup( return _run_addr_query(q, sqlargs) +MIN_SEARCH_STR_LEN = 3 + + def iceaddr_suggest(search_str: str, limit: int = 50) -> List[Dict[str, Any]]: """Parse search string and fetch matching addresses. Made to handle partial and full text queries in @@ -102,7 +107,7 @@ def iceaddr_suggest(search_str: str, limit: int = 50) -> List[Dict[str, Any]]: """ search_str = _cap_first(search_str.strip()) - if not search_str or len(search_str) < 3: + if not search_str or len(search_str) < MIN_SEARCH_STR_LEN: return [] items = [s.strip().split() for s in search_str.split(",")] @@ -125,13 +130,13 @@ def iceaddr_suggest(search_str: str, limit: int = 50) -> List[Dict[str, Any]]: addr = [" ".join(addr)] q = "SELECT * FROM stadfong WHERE " - qargs = list() + qargs: List[str] = [] street_name = addr[0] if len(addr) == 1: # "Ölduga" q += " (heiti_nf LIKE ? OR heiti_tgf LIKE ?) " qargs.extend([street_name + "%", street_name + "%"]) - elif len(addr) >= 2: # "Öldugötu 4" + elif len(addr) >= 2: # noqa: PLR2004 "Öldugötu 4" # Street name q += " (heiti_nf=? OR heiti_tgf=?) " qargs.extend([street_name, street_name]) @@ -146,14 +151,14 @@ def iceaddr_suggest(search_str: str, limit: int = 50) -> List[Dict[str, Any]]: # Street number's trailing character # e.g. if it's "Öldugata 4b" - if len(addr) == 3: + if len(addr) == 3: # noqa: PLR2004 q += " AND bokst LIKE ? COLLATE NOCASE" qargs.append(addr[2]) # Placename component (postcode or placename) if len(items) > 1 and items[1]: pns = items[1] - postcodes = [] + postcodes: List[str] = [] # Is it a postcode? if re.match(r"\d\d\d$", pns[0]): @@ -165,7 +170,7 @@ def iceaddr_suggest(search_str: str, limit: int = 50) -> List[Dict[str, Any]]: postcodes.extend([str(x) for x in pc]) if postcodes: - qp = " OR ".join([" postnr=? " for p in postcodes]) + qp = " OR ".join([" postnr=? " for _ in postcodes]) q += " AND (%s) " % qp qargs.extend(postcodes) diff --git a/src/iceaddr/db.py b/src/iceaddr/db.py old mode 100755 new mode 100644 index ee0cab7..1f74efc --- a/src/iceaddr/db.py +++ b/src/iceaddr/db.py @@ -10,8 +10,8 @@ """ import sqlite3 -from pkg_resources import resource_filename +from pkg_resources import resource_filename _DB_REL_PATH = "resources/iceaddr.db" @@ -26,12 +26,14 @@ def connection(self) -> sqlite3.Connection: # Open connection lazily if not self.db_conn: db_path = resource_filename(__name__, _DB_REL_PATH) + # Open database file in read-only mode via URI db_uri = f"file:{db_path}?mode=ro" self.db_conn = sqlite3.connect(db_uri, uri=True, check_same_thread=False) + # Return rows as key-value dicts - self.db_conn.row_factory = lambda c, r: dict( - zip([col[0] for col in c.description], r) + self.db_conn.row_factory = lambda c, r: dict( # type: ignore noqa: PGH003 + zip([col[0] for col in c.description], r) # type: ignore noqa: PGH003 ) return self.db_conn diff --git a/src/iceaddr/dist.py b/src/iceaddr/dist.py old mode 100755 new mode 100644 index 73680f8..c56a18d --- a/src/iceaddr/dist.py +++ b/src/iceaddr/dist.py @@ -7,11 +7,12 @@ """ +from __future__ import annotations + from typing import Tuple import math - _EARTH_RADIUS = 6371.0088 # Earth's radius in km diff --git a/src/iceaddr/placenames.py b/src/iceaddr/placenames.py old mode 100755 new mode 100644 index 99c164c..eee7812 --- a/src/iceaddr/placenames.py +++ b/src/iceaddr/placenames.py @@ -9,12 +9,13 @@ """ -from typing import List, Dict, Any +from __future__ import annotations + +from typing import Any, Dict, List from .db import shared_db from .dist import distance - # These particular placenames share a name with other, perhaps larger, placenames, # but should never the less be given priority when ordering results. HARDCODED_PRIORITY = { diff --git a/src/iceaddr/postcodes.py b/src/iceaddr/postcodes.py old mode 100755 new mode 100644 index ec20816..64f9cfb --- a/src/iceaddr/postcodes.py +++ b/src/iceaddr/postcodes.py @@ -9,9 +9,11 @@ """ -from typing import Dict, Union, List, Optional, Any +from __future__ import annotations -POSTCODES: Dict[int, Dict[str, Any]] = { +from typing import Dict, List, Optional, Union + +POSTCODES: Dict[int, Dict[str, str]] = { 101: { "lysing": "Miðborg", "stadur_nf": "Reykjavík", @@ -1418,7 +1420,7 @@ def _filter_postcodes(key: str, searchstr: str, partial: bool = False) -> List[i """Utility function to find postcodes matching a criterion.""" assert key in ["stadur", "svaedi"] p = searchstr.lower() - matches = list() + matches: List[int] = [] k1 = key + "_nf" k2 = key + "_tgf" diff --git a/tests/test_iceaddr.py b/tests/test_iceaddr.py index 1132de9..d17888f 100644 --- a/tests/test_iceaddr.py +++ b/tests/test_iceaddr.py @@ -9,6 +9,8 @@ """ +from typing import Dict, List, Optional + import sys import os @@ -57,7 +59,7 @@ def test_address_lookup(): ] for p in POSTCODE_TO_PLACENAME: - print("iceaddr_lookup('{0}', number={1}, postcode={2}".format(p[0], p[1], p[2])) + # print("iceaddr_lookup('{0}', number={1}, postcode={2}".format(p[0], p[1], p[2])) res = iceaddr_lookup(p[0], number=p[1], postcode=p[2]) assert res[0]["stadur_nf"] == p[3] assert res[0]["svaedi_nf"] == p[4] @@ -123,8 +125,9 @@ def test_postcode_data_integrity(): _verify_postcode_dict(v) -def _verify_postcode_dict(pcd): +def _verify_postcode_dict(pcd: Optional[Dict[str, str]]): """Verify the integrity of a postcode dict.""" + assert pcd is not None assert "svaedi_nf" in pcd assert "svaedi_tgf" in pcd assert "stadur_nf" in pcd From cb840a4a26b3f69cb8b0c5facd54386f127feeac Mon Sep 17 00:00:00 2001 From: Sveinbjorn Thordarson Date: Mon, 18 Sep 2023 18:30:58 +0000 Subject: [PATCH 3/5] More typing fixes, moved iceaddrb from resources dir to iceaddr/ --- add_placename_data.py | 8 ++++---- build_db.py | 12 +++++++----- pyproject.toml | 4 +--- src/iceaddr/db.py | 4 ++-- src/iceaddr/{resources => }/iceaddr.db | Bin tests/test_iceaddr.py | 20 ++++++++++---------- 6 files changed, 24 insertions(+), 24 deletions(-) rename src/iceaddr/{resources => }/iceaddr.db (100%) diff --git a/add_placename_data.py b/add_placename_data.py index 64c4b3b..d9ad074 100755 --- a/add_placename_data.py +++ b/add_placename_data.py @@ -7,11 +7,11 @@ from typing import List, Tuple -from pprint import pprint +from pprint import pprint # type: ignore import sqlite3 from pathlib import Path -import fiona # noqa +import fiona # type: ignore from iceaddr.dist import in_iceland @@ -83,7 +83,7 @@ def delete_table(dbpath: str) -> sqlite3.Connection: return dbconn -def add_placename_additions(dbc) -> None: +def add_placename_additions(dbc: sqlite3.Connection) -> None: """Read manual placename additions from text file, insert into "ornefni" DB table.""" print("Inserting placename additions") f = open("placename_additions.txt", "r") @@ -114,7 +114,7 @@ def add_placename_additions(dbc) -> None: dbc.commit() -def add_placenames_from_is50v(dbc) -> None: +def add_placenames_from_is50v(dbc: sqlite3.Connection) -> None: """Read IS50V geo layers from file, add all placenames ("örnefni") to DB.""" if not Path(GPKG_FILE).exists(): print(f"Could not find file {GPKG_FILE}") diff --git a/build_db.py b/build_db.py index b488a3b..524f116 100755 --- a/build_db.py +++ b/build_db.py @@ -10,7 +10,7 @@ """ -from typing import Iterator, Dict +from typing import Iterator, Dict, Any from builtins import input @@ -23,7 +23,7 @@ from urllib.request import urlopen from iceaddr.dist import in_iceland -import humanize # noqa +import humanize # type: ignore STADFONG_REMOTE_URL = "https://fasteignaskra.is/Stadfangaskra.csv" @@ -76,13 +76,15 @@ def create_db(path: str) -> sqlite3.Connection: return dbconn -def read_rows(dsv_file: TextIOWrapper, delimiter: str = ",") -> Iterator: +def read_rows( + dsv_file: TextIOWrapper, delimiter: str = "," +) -> Iterator[Dict[Any, Any]]: reader = csv.DictReader(dsv_file, delimiter=delimiter) for row in reader: yield row -def insert_address_entry(e: Dict, conn: sqlite3.Connection) -> None: +def insert_address_entry(e: Dict[Any, Any], conn: sqlite3.Connection) -> None: # The stadfong datafile is quite dirty so we need to # sanitise values before inserting into the database @@ -165,7 +167,7 @@ def main() -> None: sys.stdout.flush() bytesize: int = os.stat(db_path).st_size - human_size = humanize.naturalsize(bytesize) + human_size = humanize.naturalsize(bytesize) # type: ignore print("\nCreated database with %d entries (%s)" % (cnt, human_size)) diff --git a/pyproject.toml b/pyproject.toml index 142dbce..4a670fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -139,11 +139,9 @@ typehints = ["typing", "typing_extensions", "types"] # *** Build system configuration *** -[tool.setuptools_scm] -fallback_version = "0.0.0" - [tool.setuptools.packages.find] where = ["src"] + [tool.setuptools.package-data] iceaddr = ["*.db"] diff --git a/src/iceaddr/db.py b/src/iceaddr/db.py index 1f74efc..604701c 100644 --- a/src/iceaddr/db.py +++ b/src/iceaddr/db.py @@ -13,11 +13,11 @@ from pkg_resources import resource_filename -_DB_REL_PATH = "resources/iceaddr.db" +_DB_REL_PATH = "iceaddr.db" class SharedDB: - """Singleton object wrapper for local SQLite3 DB""" + """Singleton object wrapper for local SQLite3 database.""" def __init__(self): self.db_conn = None diff --git a/src/iceaddr/resources/iceaddr.db b/src/iceaddr/iceaddr.db similarity index 100% rename from src/iceaddr/resources/iceaddr.db rename to src/iceaddr/iceaddr.db diff --git a/tests/test_iceaddr.py b/tests/test_iceaddr.py index d17888f..ff01dfb 100644 --- a/tests/test_iceaddr.py +++ b/tests/test_iceaddr.py @@ -9,7 +9,7 @@ """ -from typing import Dict, List, Optional +from typing import Dict, Optional import sys import os @@ -25,17 +25,17 @@ postcodes_for_region, POSTCODES, nearest_addr, - nearest_placenames, + # nearest_placenames, ) def test_address_lookup(): """Test address lookup using various known addresses.""" ADDR_TO_POSTCODE = [ - ["Öldugata", 4, "Reykjavík", 101], - ["öldugötu", 12, "hafnarfirði", 220], - ["Tómasarhaga", 12, "Reykjavík", 107], - ["smiðjuvegur", 22, None, 200], + ("Öldugata", 4, "Reykjavík", 101), + ("öldugötu", 12, "hafnarfirði", 220), + ("Tómasarhaga", 12, "Reykjavík", 107), + ("smiðjuvegur", 22, "", 200), ] for a in ADDR_TO_POSTCODE: @@ -46,16 +46,16 @@ def test_address_lookup(): assert res and res[0]["postnr"] == 310 and res[0]["stadur_nf"] == "Borgarnes" POSTCODE_TO_PLACENAME = [ - ["Öldugata", 4, 101, "Reykjavík", "Höfuðborgarsvæðið", "Þéttbýli"], - [ + ("Öldugata", 4, 101, "Reykjavík", "Höfuðborgarsvæðið", "Þéttbýli"), + ( "dagverðardalur", 11, 400, "Ísafjörður", "Vesturland og Vestfirðir", "Þéttbýli", - ], - ["Höfðabraut", 3, 805, "Selfoss", "Suðurland og Reykjanes", "Þéttbýli"], + ), + ("Höfðabraut", 3, 805, "Selfoss", "Suðurland og Reykjanes", "Þéttbýli"), ] for p in POSTCODE_TO_PLACENAME: From 345ad1241aa54c4c7eb9dacd50f575fbd8bf538e Mon Sep 17 00:00:00 2001 From: Sveinbjorn Thordarson Date: Mon, 18 Sep 2023 18:36:15 +0000 Subject: [PATCH 4/5] Updated tests --- tests/test_iceaddr.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_iceaddr.py b/tests/test_iceaddr.py index ff01dfb..32436ce 100644 --- a/tests/test_iceaddr.py +++ b/tests/test_iceaddr.py @@ -25,7 +25,7 @@ postcodes_for_region, POSTCODES, nearest_addr, - # nearest_placenames, + nearest_placenames, ) @@ -179,10 +179,10 @@ def test_nearest_addr(): def test_nearest_placename(): """Test placename proximity function.""" - # pn = nearest_placenames(FISKISLOD_31_COORDS[0], FISKISLOD_31_COORDS[1]) - # assert len(pn) == 1 - # assert pn[0]["nafn"] == "Grandi" + pn = nearest_placenames(FISKISLOD_31_COORDS[0], FISKISLOD_31_COORDS[1]) + assert len(pn) == 1 + assert pn[0]["nafn"] == "Grandi" - # pn = nearest_placenames(OLDUGATA_4_COORDS[0], OLDUGATA_4_COORDS[1], limit=5) - # assert len(pn) == 5 - # assert "Landakotshæð" in [x["nafn"] for x in pn] + pn = nearest_placenames(OLDUGATA_4_COORDS[0], OLDUGATA_4_COORDS[1], limit=5) + assert len(pn) == 5 + assert "Landakotshæð" in [x["nafn"] for x in pn] From da82908f6b0874b3fc22f3855f092b22072c1720 Mon Sep 17 00:00:00 2001 From: Sveinbjorn Thordarson Date: Mon, 18 Sep 2023 21:51:20 +0000 Subject: [PATCH 5/5] Updated CI to use pyproject.toml, ruff linter --- .github/workflows/python-package.yml | 21 +++++++++++---------- pyproject.toml | 9 +++++---- src/iceaddr/postcodes.py | 4 +--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 31b4a7d..b5ddd5f 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -2,9 +2,11 @@ name: tests on: push: - branches: [ master ] + branches: + - '*' pull_request: - branches: [ master ] + branches: + - '*' jobs: build: @@ -12,24 +14,23 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip wheel setuptools pytest types-setuptools mypy - - name: Run mypy + python -m pip install ".[dev]" + - name: Run ruff linter run: | - mypy iceaddr/*.py + ruff src/iceaddr - name: Test with pytest run: | - python -m pytest - + python -m pytest -vvv diff --git a/pyproject.toml b/pyproject.toml index 4a670fb..9977e35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,15 +33,16 @@ Repository = "https://github.com/sveinbjornt/iceaddr" [project.optional-dependencies] # Dev dependencies dev = [ - "pytest>=7.2.1", # Building database - "fiona>=1.9.4", # for GIS data + "fiona>=1.9.4", # for processing GIS data "humanize>=0.5.1", # for progress bar "reynir>=3.1.0", # for parsing and declining placenames - # Pre-commit hook + # Linting, testing + "pytest>=7.2.1", "pre-commit>=3.3.3", "black>=23.7.0", "mypy>=1.5.1", + "types-setuptools>=68.2.0", "ruff>=0.0.285", "coverage[toml]>=7.3.1", ] @@ -135,7 +136,7 @@ section-order = [ [tool.ruff.isort.sections] # Have typing libraries above other imports -typehints = ["typing", "typing_extensions", "types"] +typehints = ["typing", "typing_extensions", "types", "types-setuptools"] # *** Build system configuration *** diff --git a/src/iceaddr/postcodes.py b/src/iceaddr/postcodes.py index 64f9cfb..75e0228 100644 --- a/src/iceaddr/postcodes.py +++ b/src/iceaddr/postcodes.py @@ -1428,9 +1428,7 @@ def _filter_postcodes(key: str, searchstr: str, partial: bool = False) -> List[i for k, v in POSTCODES.items(): nf = v[k1].lower() tgf = v[k2].lower() - if partial and (nf.startswith(p) or tgf.startswith(p)): - matches.append(k) - elif nf == p or tgf == p: + if (partial and (nf.startswith(p) or tgf.startswith(p))) or p in (nf, tgf): matches.append(k) return matches