diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f4b425..a9ae6d8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,14 +11,14 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.10"] + python-version: ["3.9", "3.10", "3.11", "3.13", "pypy-3.10"] include: - os: macos-latest - python-version: "3.8" + python-version: "3.9" - os: macos-latest python-version: "3.12" - os: windows-latest - python-version: "3.8" + python-version: "3.9" - os: windows-latest python-version: "3.12" runs-on: ${{ matrix.os }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1a208a5..7827a73 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ # * Run "pre-commit install". repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-toml - id: check-yaml @@ -16,16 +16,23 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.5 + rev: v0.8.4 hooks: - id: ruff args: [--fix, --show-fixes] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 + rev: v1.14.0 hooks: - id: mypy additional_dependencies: - - asphalt + - asphalt@git+https://github.com/asphalt-framework/asphalt - pytest + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal diff --git a/.readthedocs.yml b/.readthedocs.yml index 026b967..ac1099a 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.8" + python: "3.9" sphinx: configuration: docs/conf.py diff --git a/docs/conf.py b/docs/conf.py index fc9fa57..a3d90a7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,6 +7,7 @@ "sphinx.ext.autodoc", "sphinx.ext.intersphinx", "sphinx_autodoc_typehints", + "sphinx_rtd_theme", ] templates_path = ["_templates"] @@ -25,6 +26,7 @@ exclude_patterns = ["_build"] pygments_style = "sphinx" autodoc_default_options = {"members": True, "show-inheritance": True} +autodoc_inherit_docstrings = False highlight_language = "python3" todo_include_todos = False diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst index 7053ab2..a8f61a4 100644 --- a/docs/versionhistory.rst +++ b/docs/versionhistory.rst @@ -5,10 +5,9 @@ This library adheres to `Semantic Versioning `_. **UNRELEASED** -- Dropped support for Python 3.7 -- Dropped support for Asphalt earlier than 4.8 +- **BACKWARD INCOMPATIBLE** Bumped minimum Asphalt version to 5.0 - Dropped support for motor earlier than 3.3 -- Dropped support for the Asphalt context variable +- Dropped support for Python 3.7 and 3.8 **3.0.1** (2017-06-04) diff --git a/pyproject.toml b/pyproject.toml index 5ba79ef..1381f29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,15 +20,15 @@ classifiers = [ "Typing :: Typed", "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", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] -requires-python = ">=3.8" +requires-python = ">=3.9" dependencies = [ - "asphalt ~= 4.8", + "asphalt @ git+https://github.com/asphalt-framework/asphalt", "motor ~= 3.3" ] dynamic = ["version"] @@ -61,24 +61,28 @@ local_scheme = "dirty-tag" [tool.ruff.lint] extend-select = [ "ASYNC", # flake8-async - "W", # pycodestyle warnings "G", # flake8-logging-format "I", # isort "ISC", # flake8-implicit-str-concat "PGH", # pygrep-hooks - "RUF100", # unused noqa (yesqa) + "RUF", # Ruff-specific rules "UP", # pyupgrade + "W", # pycodestyle warnings ] [tool.ruff.lint.isort] known-first-party = ["asphalt.mongodb"] +known-third-party = ["asphalt.core"] + +[tool.pytest.ini_options] +addopts = ["-rsfE", "--tb=short"] +testpaths = ["tests"] [tool.mypy] -python_version = "3.8" +python_version = "3.9" strict = true -ignore_missing_imports = true explicit_package_bases = true -mypy_path = ["src"] +mypy_path = ["src", "tests"] [tool.coverage.run] source = ["asphalt.mongodb"] @@ -87,20 +91,20 @@ branch = true [tool.coverage.report] show_missing = true +exclude_also = [ + "@overload", + "if TYPE_CHECKING:" +] [tool.tox] -legacy_tox_ini = """ -[tox] -envlist = py38, py39, py310, py311, py312, pypy3 +env_list = ["py39", "py310", "py311", "py312", "py313", "pypy3"] skip_missing_interpreters = true -minversion = 4.0 -[testenv] -extras = test -commands = python -m pytest {posargs} -package = editable +[tool.tox.env_run_base] +commands = [["python", "-m", "pytest", { replace = "posargs", extend = true }]] +package = "editable" +extras = ["test"] -[testenv:docs] -extras = doc -commands = sphinx-build -n docs build/sphinx {posargs} -""" +[tool.tox.env.docs] +commands = [["sphinx-build", "-W", "-n", "docs", "build/sphinx", { replace = "posargs", extend = true }]] +extras = ["doc"] diff --git a/src/asphalt/mongodb/_component.py b/src/asphalt/mongodb/_component.py index 838e4d9..36d8f19 100644 --- a/src/asphalt/mongodb/_component.py +++ b/src/asphalt/mongodb/_component.py @@ -1,15 +1,11 @@ from __future__ import annotations -import logging -from collections.abc import AsyncGenerator, Mapping +from collections.abc import Mapping from typing import Any +from asphalt.core import Component, add_resource from motor.motor_asyncio import AsyncIOMotorClient -from asphalt.core import Component, Context, context_teardown - -logger = logging.getLogger("asphalt.mongodb") - class MongoDBComponent(Component): """ @@ -20,37 +16,15 @@ class MongoDBComponent(Component): :param client_args: a dictionary of keyword arguments to pass to :class:`~motor.motor_asyncio.AsyncIOMotorClient` - :param resource_name: default values for omitted - :class:`~motor.motor_asyncio.AsyncIOMotorClient` arguments """ - def __init__( - self, - *, - client_args: Mapping[str, Any] | None = None, - resource_name: str = "default", - ): + def __init__(self, *, client_args: Mapping[str, Any] | None = None): options = client_args or {} self._client = AsyncIOMotorClient(**options) - self.resource_name = resource_name - @context_teardown - async def start(self, ctx: Context) -> AsyncGenerator[None, Any]: - ctx.add_resource( + async def start(self) -> None: + add_resource( self._client, - self.resource_name, - ) - hosts = { - f"{host}:{port}" - for host, port in self._client.topology_description.server_descriptions() - } - logger.info( - "Configured MongoDB client (%s; hosts=%r)", - self.resource_name, - hosts, + description="MongoDB client", + teardown_callback=self._client.close, ) - - yield - - self._client.close() - logger.info("MongoDB client (%s) shut down", self.resource_name) diff --git a/tests/test_component.py b/tests/test_component.py index 6ca12c7..bd21b88 100644 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -1,11 +1,9 @@ -import logging import os import pytest +from asphalt.core import Context, get_resource_nowait from motor.motor_asyncio import AsyncIOMotorClient -from pytest import LogCaptureFixture -from asphalt.core import Context, require_resource from asphalt.mongodb import MongoDBComponent MONGODB_HOSTNAME = os.getenv("MONGODB_HOST", "localhost") @@ -13,15 +11,8 @@ pytestmark = pytest.mark.anyio -async def test_default_client(caplog: LogCaptureFixture) -> None: +async def test_default_client() -> None: """Test that the client is created and is available on the context.""" - caplog.set_level(logging.INFO, "asphalt.mongodb") - async with Context() as ctx: - await MongoDBComponent().start(ctx) - require_resource(AsyncIOMotorClient) - - assert len(caplog.messages) == 2 - assert caplog.messages == [ - "Configured MongoDB client (default; hosts={'localhost:27017'})", - "MongoDB client (default) shut down", - ] + async with Context(): + await MongoDBComponent().start() + get_resource_nowait(AsyncIOMotorClient)