mnamer 2.5.5.dev94__tar.gz → 2.5.6.dev7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. mnamer-2.5.6.dev7/.github/actions/init/action.yml +19 -0
  2. mnamer-2.5.6.dev7/.github/actions/lint/action.yml +31 -0
  3. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/.github/actions/test/action.yml +8 -8
  4. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/.github/dependabot.yml +4 -0
  5. mnamer-2.5.6.dev7/.github/workflows/publish.yml +23 -0
  6. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/.github/workflows/pull_request.yml +5 -7
  7. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/.github/workflows/push.yml +11 -20
  8. mnamer-2.5.6.dev7/.python-version +1 -0
  9. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/Dockerfile +1 -1
  10. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/PKG-INFO +15 -7
  11. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/README.md +3 -3
  12. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/__main__.py +2 -2
  13. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/__version__.py +1 -1
  14. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/endpoints.py +1 -1
  15. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/language.py +3 -3
  16. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/metadata.py +2 -1
  17. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/providers.py +2 -3
  18. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/setting_store.py +4 -3
  19. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/target.py +6 -6
  20. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/tty.py +8 -7
  21. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/types.py +2 -2
  22. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/utils.py +13 -13
  23. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer.egg-info/PKG-INFO +15 -7
  24. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer.egg-info/SOURCES.txt +2 -2
  25. mnamer-2.5.6.dev7/mnamer.egg-info/requires.txt +8 -0
  26. mnamer-2.5.6.dev7/pyproject.toml +101 -0
  27. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_utils.py +1 -1
  28. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_endpoints__omdb.py +2 -2
  29. mnamer-2.5.6.dev7/uv.lock +937 -0
  30. mnamer-2.5.5.dev94/.github/actions/init/action.yml +0 -19
  31. mnamer-2.5.5.dev94/.github/actions/lint/action.yml +0 -46
  32. mnamer-2.5.5.dev94/.python-version +0 -1
  33. mnamer-2.5.5.dev94/mnamer.egg-info/requires.txt +0 -24
  34. mnamer-2.5.5.dev94/pyproject.toml +0 -64
  35. mnamer-2.5.5.dev94/requirements-dev.txt +0 -14
  36. mnamer-2.5.5.dev94/requirements.txt +0 -8
  37. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/.gitignore +0 -0
  38. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/.vscode/settings.json +0 -0
  39. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/LICENSE.txt +0 -0
  40. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/MANIFEST.in +0 -0
  41. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/design.eps +0 -0
  42. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/logo-2.png +0 -0
  43. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/logo-3.png +0 -0
  44. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/logo.png +0 -0
  45. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/recording.mov +0 -0
  46. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/screenshot.eps +0 -0
  47. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/assets/screenshot.png +0 -0
  48. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/makefile +0 -0
  49. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/__init__.py +0 -0
  50. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/argument.py +0 -0
  51. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/const.py +0 -0
  52. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/exceptions.py +0 -0
  53. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/frontends.py +0 -0
  54. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/py.typed +0 -0
  55. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer/setting_spec.py +0 -0
  56. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer.egg-info/dependency_links.txt +0 -0
  57. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer.egg-info/entry_points.txt +0 -0
  58. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/mnamer.egg-info/top_level.txt +0 -0
  59. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/pytest.ini +0 -0
  60. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/setup.cfg +0 -0
  61. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/__init__.py +0 -0
  62. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/conftest.py +0 -0
  63. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/e2e/__init__.py +0 -0
  64. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/e2e/conftest.py +0 -0
  65. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/e2e/test_directives.py +0 -0
  66. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/e2e/test_errors.py +0 -0
  67. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/e2e/test_moving.py +0 -0
  68. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/__init__.py +0 -0
  69. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_argument.py +0 -0
  70. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_language.py +0 -0
  71. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_metadata.py +0 -0
  72. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_setting_spec.py +0 -0
  73. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_setting_store.py +0 -0
  74. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_target.py +0 -0
  75. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/local/test_tty.py +0 -0
  76. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/__init__.py +0 -0
  77. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_endpoints__tmdb.py +0 -0
  78. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_endpoints__tvdb.py +0 -0
  79. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_endpoints__tvmaze.py +0 -0
  80. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_providers__omdb.py +0 -0
  81. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_providers__tmdb.py +0 -0
  82. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_providers__tvdb.py +0 -0
  83. {mnamer-2.5.5.dev94 → mnamer-2.5.6.dev7}/tests/network/test_providers__tvmaze.py +0 -0
@@ -0,0 +1,19 @@
1
+ name: Init
2
+ description: Sets up the environment for build, lint, and test jobs
3
+
4
+ runs:
5
+ using: composite
6
+ steps:
7
+ - uses: actions/setup-python@v5
8
+ with:
9
+ python-version: '3.12'
10
+
11
+ - name: Install uv
12
+ uses: astral-sh/setup-uv@v4
13
+ with:
14
+ enable-cache: true
15
+ cache-dependency-glob: "**/pyproject.toml"
16
+
17
+ - name: Install dependencies
18
+ shell: sh
19
+ run: uv sync --dev
@@ -0,0 +1,31 @@
1
+ name: Lint
2
+ description: Lints the codebase with ruff and mypy
3
+
4
+ inputs:
5
+ ruff:
6
+ description: Whether to run ruff
7
+ required: false
8
+ default: "true"
9
+
10
+ mypy:
11
+ description: Whether to run mypy
12
+ required: false
13
+ default: "true"
14
+
15
+ runs:
16
+ using: composite
17
+ steps:
18
+ - name: Linting with ruff
19
+ if: inputs.ruff == 'true'
20
+ run: uv run ruff check mnamer tests
21
+ shell: sh
22
+
23
+ - name: Formatting with ruff
24
+ if: inputs.ruff == 'true'
25
+ run: uv run ruff format --check mnamer tests
26
+ shell: sh
27
+
28
+ - name: Type checking with mypy
29
+ if: inputs.mypy == 'true'
30
+ run: uv run mypy mnamer tests
31
+ shell: sh
@@ -5,22 +5,22 @@ inputs:
5
5
  local:
6
6
  description: Whether to run local tests
7
7
  required: false
8
- default: true
8
+ default: "true"
9
9
 
10
10
  network:
11
11
  description: Whether to run network tests
12
12
  required: false
13
- default: true
13
+ default: "true"
14
14
 
15
15
  e2e:
16
16
  description: Whether to run end to end tests
17
17
  required: false
18
- default: true
18
+ default: "true"
19
19
 
20
20
  coverage:
21
21
  description: Whether to report coverage statistics
22
22
  required: false
23
- default: false
23
+ default: "false"
24
24
 
25
25
  runs:
26
26
  using: composite
@@ -28,7 +28,7 @@ runs:
28
28
  - name: Running Local Unit Tests
29
29
  if: inputs.local == 'true'
30
30
  run: >-
31
- python -m pytest
31
+ uv run pytest
32
32
  -m local
33
33
  --durations=10
34
34
  --cov=./
@@ -40,7 +40,7 @@ runs:
40
40
  - name: Running Network Unit Tests
41
41
  if: inputs.network == 'true'
42
42
  run: >-
43
- python -m pytest
43
+ uv run pytest
44
44
  -m network
45
45
  --reruns 3
46
46
  --durations=10
@@ -53,7 +53,7 @@ runs:
53
53
  - name: Running End to End Tests
54
54
  if: inputs.e2e == 'true'
55
55
  run: >-
56
- python -m pytest
56
+ uv run pytest
57
57
  -m e2e
58
58
  --reruns 3
59
59
  --durations=10
@@ -71,7 +71,7 @@ runs:
71
71
  && failure()
72
72
 
73
73
  - name: Reporting Coverage Statistics
74
- uses: codecov/codecov-action@v3
74
+ uses: codecov/codecov-action@v5
75
75
  if: >-
76
76
  success()
77
77
  && inputs.coverage == 'true'
@@ -9,3 +9,7 @@ updates:
9
9
  directory: "/"
10
10
  schedule:
11
11
  interval: "weekly"
12
+ - package-ecosystem: "github-actions"
13
+ directory: "/"
14
+ schedule:
15
+ interval: "weekly"
@@ -0,0 +1,23 @@
1
+ name: publish
2
+
3
+ on:
4
+ workflow_call:
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ publish-pypi:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with: { fetch-depth: 0 } # required for setuptools_scm to detect git tags
14
+ - uses: ./.github/actions/init
15
+
16
+ - name: Building
17
+ run: uv build
18
+
19
+ - name: Reporting Version
20
+ run: uv run python -m mnamer --version
21
+
22
+ - name: Uploading to PyPI
23
+ run: uv publish --token ${{secrets.pypi_password}}
@@ -7,26 +7,24 @@ jobs:
7
7
  runs-on: ubuntu-latest
8
8
 
9
9
  steps:
10
- - uses: actions/checkout@v3
10
+ - uses: actions/checkout@v4
11
11
  - uses: ./.github/actions/init
12
12
 
13
13
  - name: Linting
14
14
  uses: ./.github/actions/lint
15
15
  with:
16
- black: true
17
- isort: true
18
- pyflakes: true
16
+ ruff: true
19
17
  mypy: true
20
18
 
21
19
  test:
22
20
  runs-on: ubuntu-latest
23
21
 
24
22
  steps:
25
- - uses: actions/checkout@v3
23
+ - uses: actions/checkout@v4
26
24
  - uses: ./.github/actions/init
27
25
 
28
26
  - name: Testing (contributor)
29
- - uses: ./.github/actions/test
27
+ uses: ./.github/actions/test
30
28
  if: github.actor != 'dependabot[bot]'
31
29
  with:
32
30
  local: true
@@ -35,7 +33,7 @@ jobs:
35
33
  coverage: false
36
34
 
37
35
  - name: Testing (dependabot)
38
- - uses: ./.github/actions/test
36
+ uses: ./.github/actions/test
39
37
  if: github.actor == 'dependabot[bot]'
40
38
  with:
41
39
  local: true
@@ -2,15 +2,21 @@ name: push
2
2
 
3
3
  on:
4
4
  push:
5
+ branches:
6
+ - main
5
7
  schedule:
6
8
  - cron: "0 8 * * 1" # mondays at 8am
9
+ release:
10
+ types:
11
+ - published
12
+ - prereleased
7
13
 
8
14
  jobs:
9
15
  lint:
10
16
  runs-on: ubuntu-latest
11
17
 
12
18
  steps:
13
- - uses: actions/checkout@v3
19
+ - uses: actions/checkout@v4
14
20
  - uses: ./.github/actions/init
15
21
  - uses: ./.github/actions/lint
16
22
 
@@ -18,7 +24,7 @@ jobs:
18
24
  runs-on: ubuntu-latest
19
25
 
20
26
  steps:
21
- - uses: actions/checkout@v3
27
+ - uses: actions/checkout@v4
22
28
  - uses: ./.github/actions/init
23
29
  - uses: ./.github/actions/test
24
30
  with:
@@ -28,8 +34,6 @@ jobs:
28
34
  coverage: true
29
35
 
30
36
  publish-pypi:
31
- runs-on: ubuntu-latest
32
-
33
37
  if: >-
34
38
  success()
35
39
  && github.event_name == 'push'
@@ -39,20 +43,7 @@ jobs:
39
43
  - lint
40
44
  - test
41
45
 
42
- steps:
43
- - uses: actions/checkout@v3
44
- with: { fetch-depth: 0 } # required for setuptools_scm to detect git tags
45
- - uses: ./.github/actions/init
46
-
47
- - name: Building
48
- run: python3 -m build --sdist --wheel --no-isolation
49
-
50
- - name: Reporting Version
51
- run: python3 -m mnamer --version
46
+ secrets:
47
+ inherit
52
48
 
53
- - name: Uploading to PyPI
54
- run: >-
55
- twine upload
56
- --username __token__
57
- --password ${{secrets.pypi_password}}
58
- dist/*
49
+ uses: ./.github/workflows/publish.yml
@@ -0,0 +1 @@
1
+ 3.13
@@ -1,5 +1,5 @@
1
1
  FROM python:alpine
2
- ARG MNAMER_VERSION=2.5.4
2
+ ARG MNAMER_VERSION=2.5.5
3
3
  ARG UID=1000
4
4
  ARG GID=1000
5
5
  RUN addgroup mnamer -g $GID
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: mnamer
3
- Version: 2.5.5.dev94
3
+ Version: 2.5.6.dev7
4
4
  Summary: A command-line utility for organizing media files.
5
5
  Author-email: Jessy Williams <jessy@jessywilliams.com>
6
6
  Maintainer-email: Jessy Williams <jessy@jessywilliams.com>
@@ -27,16 +27,24 @@ License: MIT License
27
27
  SOFTWARE.
28
28
 
29
29
  Project-URL: repository, https://github.com/jkwill87/mnamer
30
- Requires-Python: >=3.10
30
+ Requires-Python: >=3.12
31
31
  Description-Content-Type: text/markdown
32
- Provides-Extra: dev
33
32
  License-File: LICENSE.txt
33
+ Requires-Dist: appdirs>=1.4.4
34
+ Requires-Dist: babelfish>=0.6.0
35
+ Requires-Dist: guessit>=3.8.0
36
+ Requires-Dist: requests>=2.32.0
37
+ Requires-Dist: requests-cache~=0.9.8
38
+ Requires-Dist: setuptools-scm>=8.0.0
39
+ Requires-Dist: teletype>=1.3.4
40
+ Requires-Dist: typing-extensions>=4.7.0
41
+ Dynamic: license-file
34
42
 
35
43
  [![PyPI](https://img.shields.io/pypi/v/mnamer.svg?style=for-the-badge)](https://pypi.python.org/pypi/mnamer)
36
44
  [![Tests](https://img.shields.io/github/actions/workflow/status/jkwill87/mnamer/.github/workflows/push.yml?branch=main&style=for-the-badge&label=Tests)](https://github.com/jkwill87/mnamer/actions/workflows/push.yml?query=branch:main)
37
45
  [![Coverage](https://img.shields.io/codecov/c/github/jkwill87/mnamer/main.svg?style=for-the-badge)](https://codecov.io/gh/jkwill87/mnamer)
38
46
  [![Licence](https://img.shields.io/github/license/jkwill87/mnamer.svg?style=for-the-badge)](https://en.wikipedia.org/wiki/MIT_License)
39
- [![Style: Black](https://img.shields.io/badge/Style-Black-black.svg?style=for-the-badge)](https://github.com/ambv/black)
47
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=for-the-badge)](https://github.com/astral-sh/ruff)
40
48
 
41
49
  <img src="https://github.com/jkwill87/mnamer/raw/main/assets/logo.png" width="450"/>
42
50
 
@@ -54,7 +62,7 @@ Check out the [wiki page](https://github.com/jkwill87/mnamer/wiki) for more deta
54
62
 
55
63
  💾 [**Installation**](https://github.com/jkwill87/mnamer/wiki/Installation)
56
64
 
57
- `$ pip3 install --user mnamer`
65
+ `$ uv add mnamer` or `$ pip3 install --user mnamer`
58
66
 
59
67
  🤖 [**Automation**](https://github.com/jkwill87/mnamer/wiki/Automation)
60
68
 
@@ -124,6 +132,6 @@ Parameters can either by entered as command line arguments or from a config file
124
132
 
125
133
  ## Contributions
126
134
 
127
- Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [black](https://black.readthedocs.io) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
135
+ Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [ruff](https://docs.astral.sh/ruff/) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
128
136
 
129
137
  Bug reports are also welcome on the [issue page](https://github.com/jkwill87/mnamer/issues). Please include any generated crash reports if applicable. Feature requests are welcome but consider checking out [if it is in the works](https://github.com/jkwill87/mnamer/issues?q=label%3Arequest) first to avoid duplication.
@@ -2,7 +2,7 @@
2
2
  [![Tests](https://img.shields.io/github/actions/workflow/status/jkwill87/mnamer/.github/workflows/push.yml?branch=main&style=for-the-badge&label=Tests)](https://github.com/jkwill87/mnamer/actions/workflows/push.yml?query=branch:main)
3
3
  [![Coverage](https://img.shields.io/codecov/c/github/jkwill87/mnamer/main.svg?style=for-the-badge)](https://codecov.io/gh/jkwill87/mnamer)
4
4
  [![Licence](https://img.shields.io/github/license/jkwill87/mnamer.svg?style=for-the-badge)](https://en.wikipedia.org/wiki/MIT_License)
5
- [![Style: Black](https://img.shields.io/badge/Style-Black-black.svg?style=for-the-badge)](https://github.com/ambv/black)
5
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=for-the-badge)](https://github.com/astral-sh/ruff)
6
6
 
7
7
  <img src="https://github.com/jkwill87/mnamer/raw/main/assets/logo.png" width="450"/>
8
8
 
@@ -20,7 +20,7 @@ Check out the [wiki page](https://github.com/jkwill87/mnamer/wiki) for more deta
20
20
 
21
21
  💾 [**Installation**](https://github.com/jkwill87/mnamer/wiki/Installation)
22
22
 
23
- `$ pip3 install --user mnamer`
23
+ `$ uv add mnamer` or `$ pip3 install --user mnamer`
24
24
 
25
25
  🤖 [**Automation**](https://github.com/jkwill87/mnamer/wiki/Automation)
26
26
 
@@ -90,6 +90,6 @@ Parameters can either by entered as command line arguments or from a config file
90
90
 
91
91
  ## Contributions
92
92
 
93
- Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [black](https://black.readthedocs.io) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
93
+ Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [ruff](https://docs.astral.sh/ruff/) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
94
94
 
95
95
  Bug reports are also welcome on the [issue page](https://github.com/jkwill87/mnamer/issues). Please include any generated crash reports if applicable. Feature requests are welcome but consider checking out [if it is in the works](https://github.com/jkwill87/mnamer/issues?q=label%3Arequest) first to avoid duplication.
@@ -17,13 +17,13 @@ def main(): # pragma: no cover
17
17
  settings.load()
18
18
  except MnamerException as e:
19
19
  tty.error(e)
20
- raise SystemExit(2)
20
+ raise SystemExit(2) from None
21
21
  try:
22
22
  frontend = Cli(settings)
23
23
  frontend.launch()
24
24
  except SystemExit:
25
25
  raise
26
- except:
26
+ except Exception:
27
27
  if IS_DEBUG:
28
28
  # allow exceptions to raised when debugging
29
29
  raise
@@ -1,4 +1,4 @@
1
1
  # file generated by setuptools_scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __version__ = "2.5.5.dev94"
4
+ __version__ = "2.5.6.dev7"
@@ -35,7 +35,7 @@ def omdb_title(
35
35
  if (not title and not id_imdb) or (title and id_imdb):
36
36
  raise MnamerException("either id_imdb or title must be specified")
37
37
  elif plot and plot not in OMDB_PLOT_TYPES:
38
- raise MnamerException("plot must be one of %s" % ",".join(OMDB_PLOT_TYPES))
38
+ raise MnamerException(f"plot must be one of {','.join(OMDB_PLOT_TYPES)}")
39
39
  url = "http://www.omdbapi.com"
40
40
  parameters = {
41
41
  "apikey": api_key,
@@ -53,8 +53,8 @@ class Language:
53
53
  try:
54
54
  if getattr(value, "alpha3", None):
55
55
  return cls(value.name, value.alpha2, value.alpha3)
56
- except:
57
- raise MnamerException("Could not determine language")
56
+ except Exception:
57
+ raise MnamerException("Could not determine language") from None
58
58
  value = value.lower()
59
59
  for row in KNOWN_LANGUAGES:
60
60
  for item in row:
@@ -99,4 +99,4 @@ class Language:
99
99
  "zh",
100
100
  }
101
101
  if language is not None and language.a2 not in valid:
102
- raise MnamerException("'lang' must be one of %s" % ",".join(valid))
102
+ raise MnamerException(f"'lang' must be one of {','.join(valid)}")
@@ -3,8 +3,9 @@ from __future__ import annotations
3
3
  import dataclasses
4
4
  import datetime as dt
5
5
  import re
6
+ from collections.abc import Callable, Mapping, Sequence
6
7
  from string import Formatter
7
- from typing import Any, Callable, Mapping, Sequence
8
+ from typing import Any
8
9
 
9
10
  from mnamer.language import Language
10
11
  from mnamer.types import MediaType
@@ -4,8 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  import datetime as dt
6
6
  from abc import ABC, abstractmethod
7
+ from collections.abc import Iterator
7
8
  from os import environ
8
- from typing import Iterator
9
9
 
10
10
  from mnamer.endpoints import (
11
11
  omdb_search,
@@ -242,8 +242,7 @@ class Tvdb(Provider):
242
242
  )
243
243
  else:
244
244
  raise MnamerNotFoundException
245
- for result in results:
246
- yield result
245
+ yield from results
247
246
 
248
247
  def _search_id(
249
248
  self,
@@ -1,7 +1,8 @@
1
1
  import dataclasses
2
2
  import json
3
+ from collections.abc import Callable
3
4
  from pathlib import Path
4
- from typing import Any, Callable
5
+ from typing import Any
5
6
 
6
7
  from mnamer.argument import ArgLoader
7
8
  from mnamer.const import SUBTITLE_CONTAINERS
@@ -424,7 +425,7 @@ class SettingStore:
424
425
  try:
425
426
  arguments = arg_loader.load()
426
427
  except RuntimeError as e:
427
- raise MnamerException(e)
428
+ raise MnamerException(e) from e
428
429
  config_path = arguments.get("config_path", crawl_out(".mnamer-v2.json"))
429
430
  config = json_loads(str(config_path)) if config_path else {}
430
431
  if not self.config_ignore and not arguments.get("config_ignore"):
@@ -447,4 +448,4 @@ class SettingStore:
447
448
 
448
449
  def formatting_for(self, media: MediaType | Metadata) -> str:
449
450
  """Returns the formatting string for a given media type or metadata."""
450
- return getattr(self, f"{ media.to_media_type().value}_format")
451
+ return getattr(self, f"{media.to_media_type().value}_format")
@@ -4,7 +4,7 @@ import datetime as dt
4
4
  from os import path
5
5
  from pathlib import Path
6
6
  from shutil import move
7
- from typing import Any, ClassVar, Type
7
+ from typing import Any, ClassVar
8
8
 
9
9
  from guessit import guessit # type: ignore
10
10
 
@@ -58,7 +58,7 @@ class Target:
58
58
  return str(self.source)
59
59
 
60
60
  @classmethod
61
- def populate_paths(cls: Type[Target], settings: SettingStore) -> list[Target]:
61
+ def populate_paths(cls: type[Target], settings: SettingStore) -> list[Target]:
62
62
  """Creates a list of Target objects for media files found in paths."""
63
63
  file_paths = crawl_in(settings.targets, settings.recurse)
64
64
  file_paths = filter_blacklist(file_paths, settings.ignore)
@@ -132,9 +132,9 @@ class Target:
132
132
  path_data[k] = Language.parse(v)
133
133
  except MnamerException:
134
134
  continue
135
- elif isinstance(v, (int, str, dt.date)):
135
+ elif isinstance(v, int | str | dt.date):
136
136
  path_data[k] = v
137
- elif isinstance(v, list) and all([isinstance(_, (int, str)) for _ in v]):
137
+ elif isinstance(v, list) and all(isinstance(_, int | str) for _ in v):
138
138
  path_data[k] = v[0]
139
139
  if self._settings.media:
140
140
  media_type = self._settings.media
@@ -244,5 +244,5 @@ class Target:
244
244
  destination_path.parent.mkdir(parents=True, exist_ok=True)
245
245
  try:
246
246
  move(str(self.source), destination_path)
247
- except OSError: # pragma: no cover
248
- raise MnamerException
247
+ except OSError as e: # pragma: no cover
248
+ raise MnamerException from e
@@ -1,7 +1,8 @@
1
1
  """Provides an interface for handling user input and printing output."""
2
2
 
3
3
  import traceback
4
- from typing import Any, Callable
4
+ from collections.abc import Callable
5
+ from typing import Any
5
6
 
6
7
  from teletype import codes
7
8
  from teletype.components import ChoiceHelper, SelectOne
@@ -28,9 +29,9 @@ def _chars() -> dict[str, str]:
28
29
  return chars
29
30
 
30
31
 
31
- def _abort_helpers() -> (
32
- tuple[ChoiceHelper[MnamerSkipException], ChoiceHelper[MnamerAbortException]]
33
- ):
32
+ def _abort_helpers() -> tuple[
33
+ ChoiceHelper[MnamerSkipException], ChoiceHelper[MnamerAbortException]
34
+ ]:
34
35
  if no_style:
35
36
  style = None
36
37
  skip_mnemonic = "[s]"
@@ -90,7 +91,7 @@ def metadata_prompt(matches: list[Metadata]) -> Metadata: # pragma: no cover
90
91
  msg("select match")
91
92
  selector = SelectOne([*matches, *_abort_helpers()], **_chars())
92
93
  choice = selector.prompt()
93
- if isinstance(choice, (MnamerAbortException, MnamerSkipException)):
94
+ if isinstance(choice, MnamerAbortException | MnamerSkipException):
94
95
  raise choice
95
96
  return choice
96
97
 
@@ -105,7 +106,7 @@ def metadata_guess(metadata: Metadata) -> Metadata: # pragma: no cover
105
106
  option = ChoiceHelper(metadata, label)
106
107
  selector = SelectOne([option, *_abort_helpers()], **_chars())
107
108
  choice = selector.prompt()
108
- if isinstance(choice, (MnamerAbortException, MnamerSkipException)):
109
+ if isinstance(choice, MnamerAbortException | MnamerSkipException):
109
110
  raise choice
110
111
  else:
111
112
  return choice
@@ -116,7 +117,7 @@ def subtitle_prompt() -> Language:
116
117
  choices = [ChoiceHelper(language, language.name) for language in Language.all()]
117
118
  selector = SelectOne([*choices, *_abort_helpers()], **_chars())
118
119
  choice = selector.prompt()
119
- if isinstance(choice, (MnamerAbortException, MnamerSkipException)):
120
+ if isinstance(choice, MnamerAbortException | MnamerSkipException):
120
121
  raise choice
121
122
  else:
122
123
  return choice
@@ -1,8 +1,8 @@
1
1
  """Enum type definitions."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import Enum
5
- from typing import Type
6
6
 
7
7
 
8
8
  class MediaType(Enum):
@@ -10,7 +10,7 @@ class MediaType(Enum):
10
10
  MOVIE = "movie"
11
11
 
12
12
  @classmethod
13
- def to_media_type(cls) -> Type[MediaType]:
13
+ def to_media_type(cls) -> type[MediaType]:
14
14
  return cls
15
15
 
16
16
 
@@ -3,10 +3,11 @@
3
3
  import datetime as dt
4
4
  import json
5
5
  import re
6
+ from collections.abc import Callable, Iterator
6
7
  from os import walk
7
8
  from os.path import exists, expanduser, expandvars, getsize, splitdrive, splitext
8
9
  from pathlib import Path, PurePath
9
- from typing import Any, Callable, Iterator
10
+ from typing import Any
10
11
  from unicodedata import normalize
11
12
 
12
13
  import requests_cache
@@ -43,7 +44,7 @@ def crawl_in(file_paths: list[Path], recurse: bool = False) -> list[Path]:
43
44
  found_files.add(Path(root, file).absolute())
44
45
  if not recurse:
45
46
  break
46
- return sorted(list(found_files))
47
+ return sorted(found_files)
47
48
 
48
49
 
49
50
  def crawl_out(filename: str | Path | PurePath) -> Path | None:
@@ -157,23 +158,22 @@ def get_session() -> requests_cache.CachedSession:
157
158
  return session
158
159
 
159
160
  if hasattr(get_session, "session"):
160
- session: requests_cache.CachedSession = getattr(get_session, "session")
161
+ session: requests_cache.CachedSession = get_session.session # type: ignore[attr-defined]
161
162
  return session
162
163
  session = make_session()
163
- setattr(get_session, "session", session)
164
+ get_session.session = session # type: ignore[attr-defined]
164
165
  return session
165
166
 
166
167
 
167
168
  def get_filesize(path: Path) -> str:
168
169
  """Returns the human-readable filesize for a given path."""
169
170
  size = float(getsize(path))
170
- for unit in ["B", "KB", "MB", "GB", "TB"]:
171
- if size < 1024.0:
172
- break
171
+ units = ["B", "KB", "MB", "GB", "TB"]
172
+ for i, unit in enumerate(units):
173
+ if size < 1024.0 or i == len(units) - 1:
174
+ return f"{size:.{2}f}{unit}"
173
175
  size /= 1024.0
174
- else:
175
- return "undetermined size"
176
- return f"{size:.{2}f}{unit}"
176
+ return "undetermined size"
177
177
 
178
178
 
179
179
  def json_dumps(d: dict[str, Any]) -> str:
@@ -194,7 +194,7 @@ def json_loads(path: str) -> dict[str, Any]:
194
194
  path = expanduser(path)
195
195
  path = expandvars(path)
196
196
  if exists(path):
197
- with open(path, mode="r") as fp:
197
+ with open(path) as fp:
198
198
  json_data = fp.read()
199
199
  return json.loads(json_data) if json_data else {}
200
200
 
@@ -242,7 +242,7 @@ def request_json(
242
242
  if isinstance(headers, dict):
243
243
  headers = clean_dict(headers)
244
244
  else:
245
- headers = dict()
245
+ headers = {}
246
246
  if isinstance(parameters, dict):
247
247
  parameters = [(k, v) for k, v in clean_dict(parameters).items()]
248
248
  if body:
@@ -269,7 +269,7 @@ def request_json(
269
269
  )
270
270
  status = response.status_code
271
271
  content = response.json() if status // 100 == 2 else None
272
- except:
272
+ except Exception:
273
273
  content = None
274
274
  status = 500
275
275
  finally: