Skip to content

Commit

Permalink
Make the project compatible with Towncrier >= 24.7
Browse files Browse the repository at this point in the history
Towncrier 24.7 changed the way that its `find_fragments()` function
works to accept a `Config` dataclass instead of specific components of
the config. This commit adds a new version of the
`lookup_towncrier_fragments()` helper function to use the new API, and
chooses which one to use based on the version of Towncrier obtained from
`importlib.metadata`. It also slightly changes the way that Towncrier
config can be obtained: the previous `get_towncrier_config()` function
(which returned a `dict`) is now renamed as
`get_towncrier_config_as_dict()`, and `get_towncrier_config()` returns
the new `Config` dataclass object. This API change should be ok as
`get_towncrier_config()` was only called in one place before.
  • Loading branch information
Ben Rowland authored and webknjaz committed Dec 22, 2024
1 parent e032be3 commit 2996d03
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ classifiers =
[options]
include_package_data = True
install_requires =
packaging
sphinx
towncrier >= 23
package_dir =
Expand Down
52 changes: 50 additions & 2 deletions src/sphinxcontrib/towncrier/_fragment_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@


from functools import lru_cache
from importlib.metadata import version
from pathlib import Path
from typing import Optional, Set

from sphinx.util import logging

from packaging.version import Version


try:
# pylint: disable=no-name-in-module
Expand All @@ -17,7 +20,9 @@
find_fragments,
)

from ._towncrier import get_towncrier_config # noqa: WPS436
from ._towncrier import ( # noqa: WPS436
get_towncrier_config, get_towncrier_config_as_dict,
)


logger = logging.getLogger(__name__)
Expand All @@ -42,11 +47,21 @@ def _find_config_file(base: Path) -> Path:
# pylint: disable=fixme
# FIXME: refactor `lookup_towncrier_fragments` to drop noqas
@lru_cache(maxsize=1, typed=True) # noqa: WPS210
def lookup_towncrier_fragments( # noqa: WPS210
def lookup_towncrier_fragments(
working_dir: Optional[str] = None,
config_path: Optional[str] = None,
) -> Set[Path]:
"""Emit RST-formatted Towncrier changelog fragment paths."""
tc_version = Version(version('towncrier'))

Check warning on line 55 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L55

Added line #L55 was not covered by tests
if tc_version >= Version('24.7.0'):
return _lookup_towncrier_fragments_post24_7(working_dir, config_path)
return _lookup_towncrier_fragments_pre24_7(working_dir, config_path)

Check warning on line 58 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L57-L58

Added lines #L57 - L58 were not covered by tests


# used for towncrier version 24.7 and above
def _lookup_towncrier_fragments_post24_7( # noqa: WPS210
working_dir: Optional[str] = None, config_path: Optional[str] = None,
) -> Set[Path]:
project_path = Path.cwd() if working_dir is None else Path(working_dir)

final_config_path = (
Expand All @@ -66,6 +81,39 @@ def lookup_towncrier_fragments( # noqa: WPS210
)
return set()

fragment_dir = (towncrier_config.directory or 'newsfragments')
fragment_base_directory = project_path / fragment_dir

Check warning on line 85 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L84-L85

Added lines #L84 - L85 were not covered by tests

_fragments, fragment_filenames = find_fragments(

Check warning on line 87 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L87

Added line #L87 was not covered by tests
str(fragment_base_directory), towncrier_config, strict=False,
)

return {Path(fname[0]) for fname in fragment_filenames}

Check warning on line 91 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L91

Added line #L91 was not covered by tests


# used for versions of towncrier before 24.7
def _lookup_towncrier_fragments_pre24_7( # noqa: WPS210
working_dir: Optional[str] = None, config_path: Optional[str] = None,
) -> Set[Path]:
project_path = Path.cwd() if working_dir is None else Path(working_dir)

Check warning on line 98 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L98

Added line #L98 was not covered by tests

final_config_path = (

Check warning on line 100 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L100

Added line #L100 was not covered by tests
_resolve_spec_config(project_path, config_path)
or _find_config_file(project_path)
)

try:
towncrier_config = get_towncrier_config_as_dict(

Check warning on line 106 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L105-L106

Added lines #L105 - L106 were not covered by tests
project_path,
final_config_path,
)
except KeyError as key_err:

Check warning on line 110 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L110

Added line #L110 was not covered by tests
# NOTE: The error is missing key 'towncrier' or similar
logger.warning(

Check warning on line 112 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L112

Added line #L112 was not covered by tests
f'Missing key {key_err!s} in file {final_config_path!s}',
)
return set()

Check warning on line 115 in src/sphinxcontrib/towncrier/_fragment_discovery.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_fragment_discovery.py#L115

Added line #L115 was not covered by tests

fragment_directory: Optional[str] = 'newsfragments'
try:
fragment_base_directory = project_path / towncrier_config['directory']
Expand Down
12 changes: 10 additions & 2 deletions src/sphinxcontrib/towncrier/_towncrier.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@


def get_towncrier_config(
project_path: Path,
final_config_path: Union[Path, None],
) -> Any:
"""Return the towncrier config in native format."""
return load_config_from_file(str(project_path), str(final_config_path))


def get_towncrier_config_as_dict(
project_path: Path,
final_config_path: Union[Path, None],
) -> Dict[str, Any]: # FIXME: add a better type # pylint: disable=fixme
"""Return the towncrier config dictionary."""
config = load_config_from_file(str(project_path), str(final_config_path))
native_config = get_towncrier_config(project_path, final_config_path)

Check warning on line 23 in src/sphinxcontrib/towncrier/_towncrier.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_towncrier.py#L23

Added line #L23 was not covered by tests

return _dataclass_to_dict(config)
return _dataclass_to_dict(native_config)

Check warning on line 25 in src/sphinxcontrib/towncrier/_towncrier.py

View check run for this annotation

Codecov / codecov/patch

src/sphinxcontrib/towncrier/_towncrier.py#L25

Added line #L25 was not covered by tests

0 comments on commit 2996d03

Please sign in to comment.