Skip to content

Commit 6cc90f7

Browse files
authored
Update CI and dependencies (#39)
1 parent c6648f7 commit 6cc90f7

11 files changed

Lines changed: 84 additions & 140 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
- push
55
- pull_request
66

7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.ref }}
9+
cancel-in-progress: true
10+
711
env:
812
publish-python-version: 3.12
913

@@ -28,6 +32,7 @@ jobs:
2832
with:
2933
python-version: ${{ matrix.python-version }}
3034
allow-prereleases: true
35+
cache: 'pip'
3136
- name: Install dependencies
3237
run: |
3338
python -m pip install --upgrade pip

.github/workflows/pr_towncrier.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
env:
1414
PR_NUMBER: ${{ github.event.number }}
1515
run: |
16-
if [ ! -f "changes/${PR_NUMBER}.feature" ] && [ ! -f "changes/${PR_NUMBER}.bugfix" ] && [ ! -f "changes/${PR_NUMBER}.doc" ] && [ ! -f "changes/${PR_NUMBER}.removal" ] && [ ! -f "changes/${PR_NUMBER}.misc" ]; then
16+
if [ ! -f "changes/${PR_NUMBER}.feature.rst" ] && [ ! -f "changes/${PR_NUMBER}.bugfix.rst" ] && [ ! -f "changes/${PR_NUMBER}.doc.rst" ] && [ ! -f "changes/${PR_NUMBER}.removal.rst" ] && [ ! -f "changes/${PR_NUMBER}.misc.rst" ]; then
1717
echo "Towncrier file for #${PR_NUMBER} not found. Please add a changes file to the `changes/` directory. See README.rst for more information."
1818
exit 1
1919
fi

.pre-commit-config.yaml

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1+
ci:
2+
autofix_prs: true
3+
autoupdate_schedule: weekly
4+
15
repos:
26
- repo: https://github.com/pre-commit/pre-commit-hooks
37
rev: 'v6.0.0'
48
hooks:
59
- id: end-of-file-fixer
610
- id: trailing-whitespace
7-
- repo: https://github.com/psf/black
8-
rev: '25.12.0'
11+
- repo: https://github.com/astral-sh/ruff-pre-commit
12+
rev: 'v0.15.1'
913
hooks:
10-
- id: black
11-
args:
12-
- --safe
13-
- --quiet
14+
- id: ruff
15+
args: [--fix]
16+
files: ^(didl_lite|tests)/.+\.py$
17+
- id: ruff-format
1418
files: ^(didl_lite|tests)/.+\.py$
1519
- repo: https://github.com/codespell-project/codespell
1620
rev: 'v2.4.1'
@@ -21,20 +25,6 @@ repos:
2125
- --quiet-level=2
2226
exclude_types: [csv, json]
2327
exclude: ^tests/fixtures/
24-
- repo: https://github.com/pycqa/flake8
25-
rev: '7.3.0'
26-
hooks:
27-
- id: flake8
28-
additional_dependencies:
29-
- flake8-docstrings==1.7.0
30-
- pydocstyle==6.3.0
31-
files: ^(didl_lite|tests)/.+\.py$
32-
- repo: https://github.com/PyCQA/isort
33-
rev: '7.0.0'
34-
hooks:
35-
- id: isort
36-
args:
37-
- --profile=black
3828
- repo: https://github.com/pre-commit/mirrors-mypy
3929
rev: 'v1.19.1'
4030
hooks:
@@ -43,3 +33,7 @@ repos:
4333
additional_dependencies:
4434
- pytest==9.0.2
4535
files: ^(didl_lite|tests)/.+\.py$
36+
- repo: https://github.com/fpgmaas/deptry
37+
rev: '0.24.0'
38+
hooks:
39+
- id: deptry

changes/39.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update CI and dependencies

didl_lite/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
"""DIDL-Lite (Digital Item Declaration Language) tools for Python."""
32

43
from didl_lite import didl_lite # noqa: F401

didl_lite/didl_lite.py

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
"""DIDL-Lite (Digital Item Declaration Language) tools for Python."""
32
# pylint: disable=too-many-lines
43

@@ -101,9 +100,7 @@ def __init__(
101100
self.xml_el = xml_el
102101
self.descriptors = descriptors if descriptors else []
103102

104-
def _ensure_required_properties(
105-
self, strict: bool, properties: Mapping[str, Any]
106-
) -> None:
103+
def _ensure_required_properties(self, strict: bool, properties: Mapping[str, Any]) -> None:
107104
"""Check if all required properties are given."""
108105
if not strict:
109106
return
@@ -184,9 +181,7 @@ def to_xml(self) -> ET.Element:
184181
continue
185182
key = didl_property_def_key(property_def)
186183

187-
if (
188-
getattr(self, key) is None or key == "res"
189-
): # no resources, handled later on
184+
if getattr(self, key) is None or key == "res": # no resources, handled later on
190185
continue
191186

192187
tag = property_def[0] + ":" + property_def[1]
@@ -245,11 +240,7 @@ def __setattr__(self, name: str, value: Any) -> None:
245240
def __repr__(self) -> str:
246241
"""Evaluatable string representation of this object."""
247242
class_name = type(self).__name__
248-
attr = ", ".join(
249-
f"{key}={val!r}"
250-
for key, val in self.__dict__.items()
251-
if key not in ("class", "xml_el")
252-
)
243+
attr = ", ".join(f"{key}={val!r}" for key, val in self.__dict__.items() if key not in ("class", "xml_el"))
253244
return f"{class_name}({attr})"
254245

255246

@@ -660,11 +651,7 @@ def to_xml(self) -> ET.Element:
660651
def __repr__(self) -> str:
661652
"""Evaluatable string representation of this object."""
662653
class_name = type(self).__name__
663-
attr = ", ".join(
664-
f"{key}={val!r}"
665-
for key, val in self.__dict__.items()
666-
if key not in ("class", "xml_el")
667-
)
654+
attr = ", ".join(f"{key}={val!r}" for key, val in self.__dict__.items() if key not in ("class", "xml_el"))
668655
children_repr = ", ".join(repr(child) for child in self)
669656
return f"{class_name}({attr}, children=[{children_repr}])"
670657

@@ -988,11 +975,7 @@ def to_xml(self) -> ET.Element:
988975
def __repr__(self) -> str:
989976
"""Evaluatable string representation of this object."""
990977
class_name = type(self).__name__
991-
attr = ", ".join(
992-
f"{key}={val!r}"
993-
for key, val in self.__dict__.items()
994-
if val is not None and key != "xml_el"
995-
)
978+
attr = ", ".join(f"{key}={val!r}" for key, val in self.__dict__.items() if val is not None and key != "xml_el")
996979
return f"{class_name}({attr})"
997980

998981

@@ -1045,11 +1028,7 @@ def __getattr__(self, name: str) -> Any:
10451028
def __repr__(self) -> str:
10461029
"""Evaluatable string representation of this object."""
10471030
class_name = type(self).__name__
1048-
attr = ", ".join(
1049-
f"{key}={val!r}"
1050-
for key, val in self.__dict__.items()
1051-
if val is not None and key != "xml_el"
1052-
)
1031+
attr = ", ".join(f"{key}={val!r}" for key, val in self.__dict__.items() if val is not None and key != "xml_el")
10531032
return f"{class_name}({attr})"
10541033

10551034

@@ -1071,9 +1050,7 @@ def to_xml_string(*objects: DidlObject) -> bytes:
10711050
return ET.tostring(root_el)
10721051

10731052

1074-
def from_xml_string(
1075-
xml_string: str, strict: bool = True
1076-
) -> List[Union[DidlObject, Descriptor]]:
1053+
def from_xml_string(xml_string: str, strict: bool = True) -> List[Union[DidlObject, Descriptor]]:
10771054
"""Parse DIDL-Lite XML string."""
10781055
if not strict:
10791056
# Find all prefixes used in tags, e.g., <prefix:tag ...>
@@ -1083,9 +1060,7 @@ def from_xml_string(
10831060
defined_prefixes = set(re.findall(r"xmlns:([a-zA-Z0-9]+)=", xml_string))
10841061

10851062
# Identify prefixes used but not defined.
1086-
missing_prefixes = (
1087-
used_prefixes - defined_prefixes - {"DIDL-Lite", "dc", "upnp", "dlna"}
1088-
)
1063+
missing_prefixes = used_prefixes - defined_prefixes - {"DIDL-Lite", "dc", "upnp", "dlna"}
10891064

10901065
# Remove the "if missing_prefixes:" line and just keep the for loop
10911066
for prefix in missing_prefixes:
@@ -1099,17 +1074,15 @@ def from_xml_string(
10991074
return from_xml_el(xml_el, strict)
11001075

11011076

1102-
def from_xml_el(
1103-
xml_el: ET.Element, strict: bool = True
1104-
) -> List[Union[DidlObject, Descriptor]]:
1077+
def from_xml_el(xml_el: ET.Element, strict: bool = True) -> List[Union[DidlObject, Descriptor]]:
11051078
"""Convert XML Element to DIDL Objects."""
11061079
didl_objects = [] # type: List[Union[DidlObject, Descriptor]]
11071080

11081081
# items and containers, in order
11091082
for child_el in xml_el:
1110-
if child_el.tag != expand_namespace_tag(
1111-
"didl_lite:item"
1112-
) and child_el.tag != expand_namespace_tag("didl_lite:container"):
1083+
if child_el.tag != expand_namespace_tag("didl_lite:item") and child_el.tag != expand_namespace_tag(
1084+
"didl_lite:container"
1085+
):
11131086
continue
11141087

11151088
# construct item
@@ -1139,9 +1112,7 @@ def from_xml_el(
11391112

11401113

11411114
# upnp_class to python type mapping
1142-
def type_by_upnp_class(
1143-
upnp_class: str, strict: bool = True
1144-
) -> Optional[Type[DidlObject]]:
1115+
def type_by_upnp_class(upnp_class: str, strict: bool = True) -> Optional[Type[DidlObject]]:
11451116
"""Get DidlObject-type by upnp_class.
11461117
11471118
When strict is False, the upnp_class lookup will be done ignoring string

pylintrc

Lines changed: 0 additions & 2 deletions
This file was deleted.

pyproject.toml

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ version = { attr = "didl_lite.__version__" }
4646
[tool.setuptools.package-data]
4747
didl_lite = ["py.typed"]
4848

49-
[tool.flake8]
50-
max-line-length = 99
51-
5249
[tool.mypy]
5350
check_untyped_defs = true
5451
disallow_untyped_calls = true
@@ -61,3 +58,37 @@ warn_redundant_casts = true
6158
warn_return_any = true
6259
warn_unused_configs = true
6360
warn_unused_ignores = true
61+
62+
[tool.ruff]
63+
line-length = 119
64+
65+
[tool.ruff.lint]
66+
select = ["C901", "D", "E", "F", "I", "W"]
67+
ignore = ["D202"]
68+
69+
[tool.ruff.lint.mccabe]
70+
max-complexity = 25
71+
72+
[tool.ruff.lint.pydocstyle]
73+
convention = "pep257"
74+
75+
[tool.ruff.lint.isort]
76+
known-first-party = ["didl_lite"]
77+
78+
[tool.deptry]
79+
package_module_name_map = { "pytest" = "pytest" }
80+
81+
[tool.deptry.per_rule_ignores]
82+
DEP002 = ["pytest"]
83+
84+
[tool.pylint.format]
85+
max-line-length = 119
86+
87+
[tool.pylint.basic]
88+
good-names = ["otherItem", "storageMedium"]
89+
90+
[tool.codespell]
91+
ignore-words-list = "wan"
92+
93+
[tool.coverage.run]
94+
source = ["didl_lite"]

setup.cfg

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,3 @@ tag_name = {new_version}
77
[bumpversion:file:didl_lite/__init__.py]
88
search = __version__ = "{current_version}"
99
replace = __version__ = "{new_version}"
10-
11-
[bdist_wheel]
12-
python-tag = py3
13-
14-
[metadata]
15-
license_file = LICENSE.md
16-
17-
[flake8]
18-
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
19-
max-line-length = 119
20-
max-complexity = 25
21-
ignore =
22-
E501,
23-
W503,
24-
E203,
25-
D202,
26-
W504
27-
noqa-require-code = True
28-
29-
[mypy]
30-
check_untyped_defs = true
31-
disallow_untyped_calls = true
32-
disallow_untyped_defs = true
33-
disallow_incomplete_defs = true
34-
disallow_untyped_decorators = true
35-
no_implicit_optional = true
36-
warn_incomplete_stub = true
37-
warn_redundant_casts = true
38-
warn_return_any = true
39-
warn_unused_configs = true
40-
warn_unused_ignores = true
41-
42-
[codespell]
43-
ignore-words-list = wan
44-
45-
[coverage:run]
46-
source = didl_lite

tests/test_didl_lite.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
"""Unit tests for didl_lite."""
32

43
import pytest
@@ -234,9 +233,7 @@ def test_container_from_xml(self) -> None:
234233

235234
def test_container_to_xml(self) -> None:
236235
"""Test container to XML."""
237-
container = didl_lite.Album(
238-
id="0", parent_id="0", title="Audio Item Title", restricted="1"
239-
)
236+
container = didl_lite.Album(id="0", parent_id="0", title="Audio Item Title", restricted="1")
240237
resource = didl_lite.Resource("url", "protocol_info")
241238
item = didl_lite.AudioItem(
242239
id="0",
@@ -285,9 +282,7 @@ def test_container_repr(self) -> None:
285282
# pylint: disable=import-outside-toplevel
286283
from didl_lite.didl_lite import Album, AudioItem, Resource
287284

288-
container = Album(
289-
id="0", parent_id="0", title="Audio Item Title", restricted="1"
290-
)
285+
container = Album(id="0", parent_id="0", title="Audio Item Title", restricted="1")
291286
resource = Resource("url", "protocol_info")
292287
item = AudioItem(
293288
id="0",
@@ -427,9 +422,7 @@ def test_descriptor_from_xml_container_item(self) -> None:
427422

428423
def test_descriptor_to_xml(self) -> None:
429424
"""Test descriptor to XML."""
430-
descriptor = didl_lite.Descriptor(
431-
id="1", name_space="ns", type="type", text="Text"
432-
)
425+
descriptor = didl_lite.Descriptor(id="1", name_space="ns", type="type", text="Text")
433426
item = didl_lite.AudioItem(
434427
id="0",
435428
parent_id="0",
@@ -468,9 +461,7 @@ def test_descriptor_repr(self) -> None:
468461

469462
descriptor_repr = repr(descriptor)
470463
descriptor_remade = eval(descriptor_repr) # pylint: disable=eval-used
471-
assert ET.tostring(descriptor.to_xml()) == ET.tostring(
472-
descriptor_remade.to_xml()
473-
)
464+
assert ET.tostring(descriptor.to_xml()) == ET.tostring(descriptor_remade.to_xml())
474465

475466
def test_item_order(self) -> None:
476467
"""Test item ordering."""
@@ -608,9 +599,7 @@ def test_extra_properties(self) -> None:
608599

609600
def test_default_properties_set(self) -> None:
610601
"""Test defaults for item properties."""
611-
item = didl_lite.VideoItem(
612-
id="0", parent_id="0", title="Video Item Title", restricted="1"
613-
)
602+
item = didl_lite.VideoItem(id="0", parent_id="0", title="Video Item Title", restricted="1")
614603
assert hasattr(item, "genre_type") # property is set
615604

616605
def test_property_case(self) -> None:

0 commit comments

Comments
 (0)