From 244a94cf7ce7790a0d99890c13d2572d7064c418 Mon Sep 17 00:00:00 2001 From: Xennis Date: Wed, 24 Apr 2024 23:59:27 +0200 Subject: [PATCH] Add typing and checking it via mypy --- .github/workflows/python.yml | 2 +- Makefile | 5 ++++- epidoc/api.py | 14 +++++++------- epidoc/body.py | 10 ++++++---- epidoc/header.py | 28 ++++++++++++++++------------ epidoc/normalize.py | 13 ++++++++++--- requirements.txt | 4 +++- setup.py | 6 +++--- 8 files changed, 50 insertions(+), 32 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index eb32ce1..411fbb5 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] + python-version: [ '3.9', '3.10', '3.11', '3.12' ] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/Makefile b/Makefile index 56b9351..af51371 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,14 @@ format: black --target-version py39 --line-length 132 --exclude tests/testdata/ *.py epidoc/ tests/ -check: format-check unittest +check: format-check type-check unittest format-check: black --check --target-version py39 --line-length 132 --exclude tests/testdata/ *.py epidoc/ tests/ +type-check: + mypy epidoc + unittest: python -m unittest discover diff --git a/epidoc/api.py b/epidoc/api.py index adbbb68..137c951 100644 --- a/epidoc/api.py +++ b/epidoc/api.py @@ -8,16 +8,16 @@ class EpiDoc: title = None - idno = {} + idno: dict[str, str] = {} material = None - origin_dates = [] - origin_place = {} - provenances = {} - terms = [] - languages = {} + origin_dates: list[str] = [] + origin_place: dict[str, str] = {} + provenances: dict[str, str] = {} + terms: list[str] = [] + languages: dict[str, str] = {} commentary = None edition_language = None - edition_foreign_languages = {} + edition_foreign_languages: dict[str, int] = {} @classmethod def create( diff --git a/epidoc/body.py b/epidoc/body.py index 04e76e1..24ce4ad 100644 --- a/epidoc/body.py +++ b/epidoc/body.py @@ -1,23 +1,25 @@ +from bs4 import Tag + from .normalize import _normalize class _Edition: @staticmethod - def _edition(body): + def _edition(body: Tag): return body.find("div", type="edition") # Note: limit to xml:space="preserve"? @staticmethod - def language(body): + def language(body: Tag): edition = _Edition._edition(body) if edition: return _normalize(edition.attrs.get("xml:lang")) @staticmethod - def foreign_languages(body): + def foreign_languages(body: Tag) -> dict[str, int]: edition = _Edition._edition(body) if not edition: return {} - result = {} + result: dict[str, int] = {} for elem in edition.find_all("foreign"): lang = _normalize(elem.attrs.get("xml:lang")) if not lang: diff --git a/epidoc/header.py b/epidoc/header.py index 7839701..a311cc0 100644 --- a/epidoc/header.py +++ b/epidoc/header.py @@ -1,19 +1,23 @@ +from typing import Any + +from bs4 import Tag + from .normalize import _normalize, _normalized_get_text, _normalized_attrs class _History: @staticmethod - def origin_dates(history): + def origin_dates(history: Tag): result = [] - for elem in history.origin.findAll("origdate"): + for elem in history.origin.findAll("origdate"): # type: ignore date = _normalized_attrs(elem) date["text"] = _normalized_get_text(elem) result.append(date) return result @staticmethod - def origin_place(history): - origin_place = history.origin.origplace + def origin_place(history: Tag): + origin_place = history.origin.origplace # type: ignore if not origin_place: return {} result = _normalized_attrs(origin_place) @@ -21,8 +25,8 @@ def origin_place(history): return result @staticmethod - def provenances(history): - result = {} + def provenances(history: Tag) -> dict[str, Any]: + result: dict[str, Any] = {} for elem in history.findAll("provenance"): typ = _normalize(elem.attrs.get("type")) if typ is None: @@ -31,7 +35,7 @@ def provenances(history): return result @staticmethod - def _provenance(provenance): + def _provenance(provenance: Tag): result = [] # Note: For some it's provenance.p.placename for elem in provenance.findAll("placename"): @@ -45,20 +49,20 @@ def _provenance(provenance): class _ProfileDesc: @staticmethod - def keyword_terms(profile_desc): - result = [] + def keyword_terms(profile_desc: Tag) -> list[dict[str, Any]]: + result: list[dict[str, Any]] = [] textclass = profile_desc.textclass if textclass is None: return result - for elem in textclass.keywords.findAll("term"): + for elem in textclass.keywords.findAll("term"): # type: ignore term = _normalized_attrs(elem) term["text"] = _normalized_get_text(elem) result.append(term) return result @staticmethod - def lang_usage(profile_desc): - result = {} + def lang_usage(profile_desc: Tag) -> dict[str, str]: + result: dict[str, str] = {} lang_usage = profile_desc.langusage if lang_usage is None: return result diff --git a/epidoc/normalize.py b/epidoc/normalize.py index 7399ca1..b322254 100644 --- a/epidoc/normalize.py +++ b/epidoc/normalize.py @@ -1,6 +1,13 @@ -def _normalize(v): +from typing import TypeVar, Any + +from bs4 import Tag + +T = TypeVar("T") + + +def _normalize(v: T) -> T: if isinstance(v, str): - return v.lower().strip() + return v.lower().strip() # type: ignore return v @@ -11,7 +18,7 @@ def _normalized_get_text(raw): return parsed if parsed else None -def _normalized_attrs(raw): +def _normalized_attrs(raw: Tag) -> dict[str, Any]: parsed = {} for name, value in raw.attrs.items(): parsed[_normalize(name)] = _normalize(value) diff --git a/requirements.txt b/requirements.txt index a219675..fce41d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ -beautifulsoup4==4.10.0 +beautifulsoup4==4.12.3 black==24.3.0 # Code formatter lxml==5.2.1 +mypy==1.10.0 # Type checker setuptools==69.2.0 # Only required for publish it as a package +types-beautifulsoup4==4.12.0.20240229 # Stubs for beautifulsoup4 wheel==0.43.0 # Only required for publish it as a package diff --git a/setup.py b/setup.py index 1e5e47f..417e9bb 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ long_description = f.read() requires = [ - "beautifulsoup4>=4.9.0,<5", - "lxml>=4.5,<5", + "beautifulsoup4>=4.12,<5", + "lxml>=5.2,<6", ] setuptools.setup( @@ -20,7 +20,7 @@ long_description_content_type="text/markdown", name="epidoc", packages=["epidoc"], - python_requires=">=3.6", + python_requires=">=3.9", url="https://github.com/Xennis/epidoc-parser", version="0.0.1", )