From d7c82b1ec14db15b55029a0ebe237a940b281f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Arbel=C3=A1ez-Echeverri?= Date: Mon, 18 Mar 2024 20:10:26 +0000 Subject: [PATCH] Add lots of random fixes (#19) * Add lots of random fixes * Fix python 3.8 compatibility * Add more errors to ruff --- .github/workflows/cd.yml | 6 +++- .pre-commit-config.yaml | 23 ++++++-------- pyproject.toml | 29 +++++++---------- src/bibx/_entities/collection.py | 2 +- .../_entities/collection_builders/base.py | 3 +- .../collection_builders/scopus_bib.py | 8 +++-- .../collection_builders/scopus_ris.py | 10 +++--- src/bibx/_entities/collection_builders/wos.py | 2 +- src/bibx/algorithms/sap.py | 4 +-- stubs/bibtexparser/__init__.pyi | 3 ++ stubs/networkx/__init__.pyi | 31 +++++++++++++++++++ .../networkx/algorithms/community/louvain.pyi | 3 ++ tests/algorithms/test_sap.py | 1 - tests/entities/test_collection.py | 22 ++++++------- 14 files changed, 90 insertions(+), 57 deletions(-) create mode 100644 stubs/bibtexparser/__init__.pyi create mode 100644 stubs/networkx/__init__.pyi create mode 100644 stubs/networkx/algorithms/community/louvain.pyi diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index ea6a0e2..117140c 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -22,9 +22,13 @@ jobs: pip install setuptools wheel hatch hatch env create + - name: Make sure we didn't forget anything in pre-commit + run: | + hatch run pre-commit run --all + - name: Test with pytest run: | - hatch run test:run + hatch run pytest - name: Build and publish env: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d59cc6d..93303a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,19 +5,16 @@ repos: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - - repo: https://github.com/psf/black - rev: 22.10.0 - hooks: - - id: black - language_version: python3 - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - name: isort (python) - args: [ "--profile", "black" ] - - repo: https://github.com/charliermarsh/ruff-pre-commit + - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: 'v0.0.254' + rev: v0.3.3 hooks: + # Run the linter. - id: ruff + args: [ --fix ] + # Run the formatter. + - id: ruff-format + - repo: https://github.com/pre-commit/mirrors-mypy + rev: 'v1.9.0' + hooks: + - id: mypy diff --git a/pyproject.toml b/pyproject.toml index e05a63b..1f5c3d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,20 +17,27 @@ dependencies = [ "bibtexparser~=1.4.0", "networkx~=3.0", "typer[all]~=0.9.0", + "xlsxwriter~=3.2.0", ] [project.optional-dependencies] dev = [ - "black~=22.10.0", "pytest~=7.2.0", - "isort~=5.12.0", "pre-commit~=2.20.0", - "ruff~=0.0.254", + "ruff~=0.3.3", + "mypy~=1.9.0", ] -[tool.ruff] +[project.scripts] +bibx = "bibx.cli:app" + +[tool.ruff.lint] +select = ["I", "E", "F", "W"] ignore = ["E501"] +[tool.mypy] +mypy_path = "./stubs/" + [build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -40,17 +47,3 @@ path = "src/bibx/__init__.py" [tool.hatch.envs.default] features = ["dev"] - -[tool.hatch.envs.test] -dependencies = [ - "coverage[toml]", - "pytest", - "pytest-cov", -] -[tool.hatch.envs.test.scripts] -run-coverage = "pytest --cov-config=pyproject.toml --cov=bibx --cov=tests" -run = "run-coverage --no-cov" - -[tool.hatch.envs.docs.scripts] -build = "mkdocs build --clean --strict" -serve = "mkdocs serve --dev-addr localhost:8000" diff --git a/src/bibx/_entities/collection.py b/src/bibx/_entities/collection.py index c498988..f89edc6 100644 --- a/src/bibx/_entities/collection.py +++ b/src/bibx/_entities/collection.py @@ -98,7 +98,7 @@ def cited_by_year(self) -> Dict[int, int]: cited_items_per_year[year] = 0 for article in self.articles: - if article.times_cited is None: + if article.times_cited is None or article.year is None: continue if article.year in cited_items_per_year: cited_items_per_year[article.year] += article.times_cited diff --git a/src/bibx/_entities/collection_builders/base.py b/src/bibx/_entities/collection_builders/base.py index 5bc8afd..0f79dc2 100644 --- a/src/bibx/_entities/collection_builders/base.py +++ b/src/bibx/_entities/collection_builders/base.py @@ -4,5 +4,4 @@ class CollectionBuilder(Protocol): - def build(self) -> Collection: - ... + def build(self) -> Collection: ... diff --git a/src/bibx/_entities/collection_builders/scopus_bib.py b/src/bibx/_entities/collection_builders/scopus_bib.py index 1156a50..502cb58 100644 --- a/src/bibx/_entities/collection_builders/scopus_bib.py +++ b/src/bibx/_entities/collection_builders/scopus_bib.py @@ -32,9 +32,11 @@ def _article_from_entry(self, entry: dict) -> Article: if "author" not in entry or "year" not in entry: raise MissingCriticalInformation() if "note" in entry: - times_cited = re.search(r"cited By (\d+)", entry["note"], re.IGNORECASE) - if times_cited: - times_cited = int(times_cited.groups()[0]) + match = re.search(r"cited By (\d+)", entry["note"], re.IGNORECASE) + if match: + times_cited = int(match.groups()[0]) + else: + times_cited = None else: times_cited = None return Article( diff --git a/src/bibx/_entities/collection_builders/scopus_ris.py b/src/bibx/_entities/collection_builders/scopus_ris.py index 4201731..65f00ba 100644 --- a/src/bibx/_entities/collection_builders/scopus_ris.py +++ b/src/bibx/_entities/collection_builders/scopus_ris.py @@ -18,7 +18,7 @@ def _size(file) -> int: return size -def _int_or_nothing(raw: List[str]) -> Optional[int]: +def _int_or_nothing(raw: Optional[List[str]]) -> Optional[int]: if not raw: return None try: @@ -102,9 +102,11 @@ def _article_form_reference(cls, scopusref: str) -> Article: return Article( authors=[f"{first_name} {last_name.replace(' ', '').replace('.', '')}"], year=int(year), - journal=journal.strip().replace(".", "").upper() - if not journal.isspace() - else None, + journal=( + journal.strip().replace(".", "").upper() + if not journal.isspace() + else None + ), volume=volume_info.get("volume"), page=volume_info.get("page"), doi=doi, diff --git a/src/bibx/_entities/collection_builders/wos.py b/src/bibx/_entities/collection_builders/wos.py index 2b92ccf..bcbb947 100644 --- a/src/bibx/_entities/collection_builders/wos.py +++ b/src/bibx/_entities/collection_builders/wos.py @@ -281,7 +281,7 @@ def _get_articles_from_references( @classmethod def _parse_article_from_str(cls, article_as_str: str) -> Article: - article_data = collections.defaultdict(list) + article_data: Dict[str, List[str]] = collections.defaultdict(list) article_data.setdefault("CR", []) field = None for line in article_as_str.split("\n"): diff --git a/src/bibx/algorithms/sap.py b/src/bibx/algorithms/sap.py index 07d0332..450eb9c 100644 --- a/src/bibx/algorithms/sap.py +++ b/src/bibx/algorithms/sap.py @@ -95,7 +95,7 @@ def clean_graph(g: nx.DiGraph) -> nx.DiGraph: """ # Extract the giant component of the graph giant_component_nodes = max(nx.weakly_connected_components(g), key=len) - giant: nx.DiGraph = g.subgraph(giant_component_nodes).copy() + giant: nx.DiGraph = cast(nx.DiGraph, g.subgraph(giant_component_nodes).copy()) # Remove nodes that cite one element and are never cited themselves giant.remove_nodes_from( @@ -312,4 +312,4 @@ def _clear(graph: nx.DiGraph) -> nx.DiGraph: and graph.nodes[n][TRUNK] > 0 and graph.nodes[n][LEAF] > 0 ] - return graph.subgraph(nodes) + return cast(nx.DiGraph, graph.subgraph(nodes)) diff --git a/stubs/bibtexparser/__init__.pyi b/stubs/bibtexparser/__init__.pyi new file mode 100644 index 0000000..aeedcb6 --- /dev/null +++ b/stubs/bibtexparser/__init__.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +def load(bibtex_file, parser: Incomplete | None = None): ... diff --git a/stubs/networkx/__init__.pyi b/stubs/networkx/__init__.pyi new file mode 100644 index 0000000..d305b32 --- /dev/null +++ b/stubs/networkx/__init__.pyi @@ -0,0 +1,31 @@ +from typing import Any, Dict, Iterable, Iterator, List + +from _typeshed import Incomplete, Self + +__version__: str + +class Graph: + def subgraph(self: Self, nodes: Iterable) -> Self: ... + def copy(self: Self) -> Self: ... + @property + def nodes(self) -> Dict[str, Incomplete]: ... + def add_node(self, node: str, **kwargs) -> None: ... + def add_edge(self, u: str, v: str, **kwargs) -> None: ... + def add_edges_from(self, edges: Iterable) -> None: ... + def remove_nodes_from(self, edges: Iterable) -> None: ... + def remove_edges_from(self, edges: Iterable) -> None: ... + def __iter__(self) -> Iterator[str]: ... + def in_degree(self, node: str) -> int: ... + def out_degree(self, node: str) -> int: ... + +class DiGraph(Graph): + def to_undirected(self) -> Graph: ... + def successors(self, node: str) -> Iterable[str]: ... + def predecessors(self, node: str) -> Iterable[str]: ... + +# NOTE: The attr parameter of this function is quite more complicated than this +def set_node_attributes(g: DiGraph, attr: Any, name: str) -> None: ... +def topological_sort(g: DiGraph) -> Iterable[str]: ... +def selfloop_edges(g: DiGraph) -> Iterable[str]: ... +def weakly_connected_components(g: DiGraph) -> Iterable[List[str]]: ... +def strongly_connected_components(g: DiGraph) -> Iterable[List[str]]: ... diff --git a/stubs/networkx/algorithms/community/louvain.pyi b/stubs/networkx/algorithms/community/louvain.pyi new file mode 100644 index 0000000..06e7aa6 --- /dev/null +++ b/stubs/networkx/algorithms/community/louvain.pyi @@ -0,0 +1,3 @@ +from networkx import Graph + +def louvain_communities(g: Graph): ... diff --git a/tests/algorithms/test_sap.py b/tests/algorithms/test_sap.py index 437c50d..e6bb5ae 100644 --- a/tests/algorithms/test_sap.py +++ b/tests/algorithms/test_sap.py @@ -1,5 +1,4 @@ import networkx as nx - from bibx.algorithms.sap import Sap diff --git a/tests/entities/test_collection.py b/tests/entities/test_collection.py index 03510ed..0bd4648 100644 --- a/tests/entities/test_collection.py +++ b/tests/entities/test_collection.py @@ -13,7 +13,7 @@ times_cited=0, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -28,7 +28,7 @@ times_cited=2, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -43,7 +43,7 @@ times_cited=12, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -58,7 +58,7 @@ times_cited=2, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -73,7 +73,7 @@ times_cited=0, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -88,7 +88,7 @@ times_cited=None, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -103,7 +103,7 @@ times_cited=1, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -118,7 +118,7 @@ times_cited=20, references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -132,7 +132,7 @@ doi="19", references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -146,7 +146,7 @@ doi="19", references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ), @@ -159,7 +159,7 @@ doi="19", references=[], keywords=[], - sources=[], + sources=set(), extra={}, _label=None, ),