Skip to content

Commit

Permalink
Lower minimum required python version to 3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
dzmpr committed Jul 30, 2024
1 parent cede24e commit 1211499
Show file tree
Hide file tree
Showing 16 changed files with 451 additions and 204 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
python_version: [ 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 ]

runs-on: ${{ matrix.os }}

Expand All @@ -37,7 +38,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: 3.13
python-version: ${{ matrix.python_version }}

- name: Install dependencies
run: |
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## Kataloger

[![Python version](https://img.shields.io/badge/python-3.8-blue.svg)](https://pypi.python.org/pypi/kataloger)
[![Latest version](https://img.shields.io/pypi/v/kataloger.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/kataloger)
[![Downloads](https://static.pepy.tech/badge/kataloger/month)](https://pepy.tech/project/kataloger)
[![Tests](https://github.com/dzmpr/kataloger/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/dzmpr/kataloger/actions/workflows/run-tests.yml)
[![Python version](https://img.shields.io/badge/python-3.11-blue.svg)](https://pypi.python.org/pypi/kataloger)

Kataloger can help update your project dependencies with ease! All you need is point to `libs.versions.toml` file and supply it with repositories that you use in project.

Expand Down Expand Up @@ -69,7 +69,7 @@ kataloger -p ~/ProjectDir/libs.versions.toml

### Installation

Kataloger available in Python Package Index (PyPI). You can install kataloger using pip:
Kataloger available in Python Package Index (PyPI). You can install kataloger using pip (requires python 3.8 and greater):
```commandline
pip install kataloger
```
Expand Down
4 changes: 3 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
### Changelog

* Repositories configuration file replaced with kataloger configuration file, where beside repositories can be specified catalog paths and parameters.
* Added support for more library and plugin notations in catalog.
* Repositories configuration file replaced with kataloger configuration file, where beside repositories can be specified catalog paths and parameters.
* Minimum required python version lowered to 3.8.
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ build-backend = "setuptools.build_meta"

[project]
name = "kataloger"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"aiohttp",
"yarl",
"xmltodict",
"tomli; python_version < \"3.11\"",
"importlib-resources; python_version < \"3.9\""
]
authors = [
{ name = "Dzmitry Pryskoka", email = "mr.priskoka@yandex.com" },
]
description = "CLI tool for projects that uses gradle version catalog to check dependency updates."
readme = "README.md"
license = { text = "Apache 2.0" }
requires-python = ">=3.11"
requires-python = ">=3.8"
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
Expand Down
10 changes: 6 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
aiohttp==3.9.3
aiohttp==3.9.5
aiosignal==1.3.1
async-timeout==4.0.3
attrs==23.2.0
charset-normalizer==3.3.2
frozenlist==1.4.1
pytest==8.1.1
pytest-asyncio==0.23.6
idna==3.6
pytest==8.3.2
pytest-asyncio==0.23.8
idna==3.7
multidict==6.0.5
xmltodict==0.13.0
yarl==1.9.4
tomli==2.0.1;python_version<"3.11"
importlib-resources==6.4.0;python_version<"3.9"
16 changes: 9 additions & 7 deletions src/kataloger/catalog_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,14 @@ def try_find_update(
) -> Optional[ArtifactUpdate]:
for resolver in self.update_resolvers:
(resolution, optional_update) = resolver.resolve(artifact, repositories_metadata)
match resolution:
case UpdateResolution.CANT_RESOLVE:
continue
case UpdateResolution.UPDATE_FOUND:
return optional_update
case UpdateResolution.NO_UPDATES:
return None
if resolution == UpdateResolution.CANT_RESOLVE:
continue
if resolution == UpdateResolution.UPDATE_FOUND:
return optional_update
if resolution == UpdateResolution.NO_UPDATES:
return None

message: str = f'Unexpected update resolution: "{resolution}".'
raise ValueError(message)

return None
6 changes: 2 additions & 4 deletions src/kataloger/cli/configuration_provider.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import sys
from importlib.resources import as_file, files
from pathlib import Path
from typing import List, Optional, Tuple, TypeVar

from kataloger import package_name
from kataloger.cli.argument_parser import parse_arguments
from kataloger.data.catalog import Catalog
from kataloger.data.configuration_data import ConfigurationData
from kataloger.data.kataloger_arguments import KatalogerArguments
from kataloger.data.kataloger_configuration import KatalogerConfiguration
from kataloger.data.repository import Repository
from kataloger.exceptions.kataloger_configuration_exception import KatalogerConfigurationException
from kataloger.helpers.backport_helpers import get_package_file
from kataloger.helpers.path_helpers import file_exists
from kataloger.helpers.toml_parse_helpers import load_configuration

Expand Down Expand Up @@ -115,7 +114,6 @@ def load_configuration_data(configuration_path: Optional[Path]) -> Configuration
if file_exists(configuration_candidate):
configuration_path = configuration_candidate
else:
with as_file(files(package_name).joinpath("default.configuration.toml")) as path:
configuration_path = path
configuration_path = get_package_file("default.configuration.toml")

return load_configuration(configuration_path)
5 changes: 3 additions & 2 deletions src/kataloger/data/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from pathlib import Path
from typing import Optional

from kataloger.helpers.backport_helpers import remove_suffix


@dataclass(frozen=True)
class Catalog:
Expand All @@ -10,8 +12,7 @@ class Catalog:

@staticmethod
def from_path(path: Path) -> "Catalog":
catalog_name = path.name.removesuffix(".versions.toml") if path.name.endswith(".versions.toml") else path.name
return Catalog(
name=catalog_name,
name=remove_suffix(path.name, ".versions.toml"),
path=path,
)
42 changes: 42 additions & 0 deletions src/kataloger/helpers/backport_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import sys
from pathlib import Path
from typing import Dict, Union

from kataloger import package_name
from kataloger.exceptions.kataloger_parse_exception import KatalogerParseException


def remove_suffix(string: str, suffix: str) -> str:
if sys.version_info < (3, 9):
if suffix and string.endswith(suffix):
return string[:-len(suffix)]

return string

return string.removesuffix(suffix)


def get_package_file(filename: str) -> Path:
if sys.version_info < (3, 9):
from importlib_resources import as_file, files
else:
from importlib.resources import as_file, files

with as_file(files(package_name).joinpath(filename)) as path:
return path


def load_toml(path: Path) -> Dict[str, Union[str, Dict]]:
if sys.version_info < (3, 11):
import tomli as tomllib
from tomli import TOMLDecodeError
else:
import tomllib
from tomllib import TOMLDecodeError

with Path.open(path, mode="rb") as file:
try:
return tomllib.load(file)
except TOMLDecodeError as parse_error:
message = f"Can't parse TOML in \"{path.name}\"."
raise KatalogerParseException(message) from parse_error
43 changes: 43 additions & 0 deletions src/kataloger/helpers/structural_matching_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from collections import namedtuple
from typing import Dict, Optional


def match(data: Dict, pattern: Dict) -> Optional[namedtuple]: # noqa PYI024
"""
Check if a dictionary (`data`) matches a specified pattern (`pattern`).
This function verifies if the structure and types of `data` conform to those
defined in `pattern`. If they match, a named tuple containing the matching values
is returned. If not, the function returns `None`.
:param data: The dictionary to be checked against the pattern.
:param pattern: The dictionary defining the structure and expected types for matching.
:return: A named tuple with the matching values if `data` matches `pattern`. `None` if there is no match.
:raise ValueError: If a type is used as a key in the `pattern` dictionary.
"""
if not (isinstance(data, dict) or isinstance(pattern, dict)):
return None

if len(data) != len(pattern):
return None

result_data: Dict = {}
for pattern_key, pattern_value in pattern.items():
if isinstance(pattern_key, type):
message: str = f"Can't use types as pattern keys: {pattern}. Key: {pattern_key}."
raise ValueError(message)

if pattern_key not in data:
return None

value = data[pattern_key]
if isinstance(pattern_value, type) and isinstance(value, pattern_value):
result_data[pattern_key] = value
elif isinstance(pattern_value, dict) and (mr := match(value, pattern_value)):
result_data[pattern_key] = mr
elif pattern_value == value:
result_data[pattern_key] = value
else:
return None

return namedtuple(typename="MatchResult", field_names=result_data.keys())(*result_data.values()) # noqa PYI024
Loading

0 comments on commit 1211499

Please sign in to comment.