diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f1ff7ec..80ab624 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,8 +10,8 @@ jobs: main-latest-git: uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 with: - env: '["py39"]' + env: '["py310"]' main: uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 with: - env: '["py39", "py310", "py311"]' + env: '["py310", "py311", "3.12"]' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c1e9230..ef35a63 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: rev: v3.15.0 hooks: - id: reorder-python-imports - args: [--py39-plus, --add-import, 'from __future__ import annotations'] + args: [--py310-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v3.2.0 hooks: @@ -26,7 +26,7 @@ repos: rev: v3.20.0 hooks: - id: pyupgrade - args: [--py39-plus] + args: [--py310-plus] - repo: https://github.com/hhatto/autopep8 rev: v2.3.2 hooks: diff --git a/git_code_debt/generate.py b/git_code_debt/generate.py index 97a9d2d..aee2a07 100644 --- a/git_code_debt/generate.py +++ b/git_code_debt/generate.py @@ -3,20 +3,19 @@ import argparse import collections import contextlib +import importlib.resources import itertools import multiprocessing.pool import os.path import sqlite3 from collections import Counter +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Sequence from re import Pattern -from typing import Callable from typing import TypeVar -import pkg_resources - from git_code_debt import options from git_code_debt.discovery import get_metric_parsers_from_args from git_code_debt.file_diff_stat import FileDiffStat @@ -163,13 +162,10 @@ def load_data( def create_schema(db: sqlite3.Connection) -> None: """Creates the database schema.""" - schema_dir = pkg_resources.resource_filename('git_code_debt', 'schema') - schema_files = os.listdir(schema_dir) + schema_dir = importlib.resources.files('git_code_debt.schema') - for sql_file in schema_files: - resource_filename = os.path.join(schema_dir, sql_file) - with open(resource_filename) as resource: - db.executescript(resource.read()) + for sql_file in schema_dir.iterdir(): + db.executescript(sql_file.read_text()) def get_metrics_info( diff --git a/git_code_debt/server/app.py b/git_code_debt/server/app.py index 11e6f8c..35fb8c6 100644 --- a/git_code_debt/server/app.py +++ b/git_code_debt/server/app.py @@ -1,14 +1,13 @@ from __future__ import annotations import argparse +import importlib.resources import os.path -import shutil import sqlite3 from collections.abc import Sequence from typing import NoReturn import flask -import pkg_resources from git_code_debt.server.metric_config import Config from git_code_debt.server.servlets.changes import changes @@ -53,12 +52,12 @@ def create_metric_config_if_not_exists() -> None: return print('WARNING: no metric_config.yaml detected. Creating sample config!') - shutil.copyfile( - pkg_resources.resource_filename( - 'git_code_debt.server', 'metric_config.sample.yaml', - ), - 'metric_config.yaml', + bts = importlib.resources.read_binary( + 'git_code_debt.server', + 'metric_config.sample.yaml', ) + with open('metric_config.yaml', 'wb') as f: + f.write(bts) def main(argv: Sequence[str] | None = None) -> NoReturn: diff --git a/git_code_debt/server/render_mako.py b/git_code_debt/server/render_mako.py index 5d1e106..db6bb9f 100644 --- a/git_code_debt/server/render_mako.py +++ b/git_code_debt/server/render_mako.py @@ -1,18 +1,39 @@ from __future__ import annotations +import importlib.resources from typing import Any import mako.lookup -import pkg_resources +from mako.template import Template -template_lookup = mako.lookup.TemplateLookup( - directories=[ - pkg_resources.resource_filename('git_code_debt.server', 'templates'), - ], - default_filters=['html_escape'], - imports=['from mako.filters import html_escape'], -) +class ImportlibResourcesLookup(mako.lookup.TemplateCollection): + def __init__(self, mod: str) -> None: + self.mod = mod + self._cache: dict[str, Template] = {} + + def get_template( + self, + uri: str, + relativeto: str | None = None, + ) -> Template: + if relativeto is not None: + raise NotImplementedError(f'{relativeto=}') + + try: + return self._cache[uri] + except KeyError: + pth = importlib.resources.files(self.mod).joinpath(uri) + with importlib.resources.as_file(pth) as pth: + return Template( + filename=str(pth), + lookup=self, + default_filters=['html_escape'], + imports=['from mako.filters import html_escape'], + ) + + +template_lookup = ImportlibResourcesLookup('git_code_debt.server.templates') def render_template(template_name: str, **env: Any) -> str: diff --git a/git_code_debt/util/discovery.py b/git_code_debt/util/discovery.py index 14c5fa2..ab05eb6 100644 --- a/git_code_debt/util/discovery.py +++ b/git_code_debt/util/discovery.py @@ -2,9 +2,9 @@ import inspect import pkgutil +from collections.abc import Callable from types import ModuleType from typing import Any -from typing import Callable def discover( diff --git a/setup.cfg b/setup.cfg index d1ee930..3ec2351 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,7 +24,7 @@ install_requires = mako markdown-code-blocks pyyaml -python_requires = >=3.9 +python_requires = >=3.10 [options.packages.find] exclude =