Skip to content

Commit cd24e0e

Browse files
committed
v0.0.3
1 parent 289da58 commit cd24e0e

File tree

10 files changed

+45
-57
lines changed

10 files changed

+45
-57
lines changed

.github/workflows/build.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ jobs:
1919
- name: Install dependencies
2020
run: |
2121
python -m pip install --upgrade pip
22-
pip install pytest pytest-cov toml
22+
pip install pytest pytest-cov toml flake8 black mypy
2323
pip install -e .
2424
25-
# - name: Run tests
26-
# run: pytest --cov=runce --cov-report=xml
2725
- name: Run tests
2826
run: sh tests/run_tests_with_coverage.sh
2927

28+
- name: Run flake8
29+
run: flake8 --ignore=E501 || true
30+
31+
- name: Run mypy
32+
run: mypy renx || true
33+
3034
# - name: Verify version sync
3135
# run: |
3236
# python -c "from runce import __version__; print(__version__)" > actual_version

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
# renx - Advanced File Renaming Tool
22

33
[![Python Version](https://img.shields.io/badge/python-3.7+-blue.svg)](https://www.python.org/downloads/)
4+
[![PyPI version fury.io](https://badge.fury.io/py/renx.svg)](https://pypi.python.org/pypi/renx/)
45

56
`renx` is a powerful command-line utility for batch renaming files and directories with advanced pattern matching and transformation capabilities.
67

8+
## ☕ Support
9+
10+
If you find this project helpful, consider supporting me:
11+
12+
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/B0B01E8SY7)
13+
714
## Features
815

916
- Recursive directory traversal (top-down or bottom-up)

pyproject.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "renx"
7-
version = "0.0.2"
7+
version = "0.0.3"
88
description = "Advanced file renaming tool with regex and case transformation support"
99
readme = "README.md"
1010
authors = [
1111
{name = "JetLogic"},
1212
]
13-
license = {text = "MIT"}
13+
license-files = ["LICEN[CS]E*"]
1414
classifiers = [
1515
"Development Status :: 4 - Beta",
1616
"Intended Audience :: Developers",
1717
"Intended Audience :: System Administrators",
18-
"License :: OSI Approved :: MIT License",
1918
"Programming Language :: Python :: 3",
2019
"Programming Language :: Python :: 3.7",
2120
"Programming Language :: Python :: 3.8",
@@ -37,7 +36,7 @@ BugTracker = "https://github.com/jet-logic/renx/issues"
3736
Changelog = "https://github.com/jet-logic/renx/releases"
3837

3938
[project.scripts]
40-
renx = "renx.__main__:ScanDir.main"
39+
renx = "renx.__main__:App.main"
4140

4241
[project.optional-dependencies]
4342
test = [
@@ -58,7 +57,7 @@ python_files = "test_*.py"
5857
addopts = "--cov=renx --cov-report=term-missing"
5958

6059
[tool.black]
61-
line-length = 88
60+
line-length = 127
6261
target-version = ['py37']
6362
include = '\.pyi?$'
6463
exclude = '''

renx/__main__.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import unicodedata
55

66

7-
def text_to_ascii(text):
7+
def text_to_ascii(text: str):
88
"""
99
Converts a Unicode string to its closest ASCII equivalent by removing
1010
accent marks and other non-ASCII characters.
@@ -19,21 +19,23 @@ def __init__(self) -> None:
1919
self._entry_filters = []
2020
super().__init__()
2121

22-
def add_arguments(self, ap):
22+
def add_arguments(self, argp):
2323
self.dry_run = True
2424
self.bottom_up = True
2525
self.excludes = []
2626
self.includes = []
27-
ap.add_argument("--subs", "-s", action="append", default=[], help="subs regex")
28-
ap.add_argument("--lower", action="store_true", help="to lower case")
29-
ap.add_argument("--upper", action="store_true", help="to upper case")
30-
ap.add_argument(
27+
argp.add_argument(
28+
"--subs", "-s", action="append", default=[], help="subs regex"
29+
)
30+
argp.add_argument("--lower", action="store_true", help="to lower case")
31+
argp.add_argument("--upper", action="store_true", help="to upper case")
32+
argp.add_argument(
3133
"--urlsafe", action="store_true", help="only urlsafe characters"
3234
)
33-
if not ap.description:
34-
ap.description = "Renames files matching re substitution pattern"
35+
if not argp.description:
36+
argp.description = "Renames files matching re substitution pattern"
3537

36-
super(App, self).add_arguments(ap)
38+
super(App, self).add_arguments(argp)
3739

3840
def start(self):
3941
from re import compile as regex

renx/main.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from typing import TYPE_CHECKING, Any, Sequence
1+
from typing import TYPE_CHECKING
22

33
__version__ = "0.0.0"
44
if TYPE_CHECKING:
55
import argparse
6-
from typing import Sequence
6+
from typing import Any, Sequence
77

88
INVALID = object()
99

@@ -16,7 +16,7 @@ def __init__(self, *args: str, **kwargs):
1616
self.kwargs = kwargs
1717

1818
def _add(
19-
self, name: str, type_: type, argp: "argparse.ArgumentParser", that: Any
19+
self, name: str, type_: type, argp: "argparse.ArgumentParser", that: "Any"
2020
) -> None:
2121
"""Add argument to parser."""
2222
args = []
@@ -94,7 +94,7 @@ def add_args(x: str) -> None:
9494
argp.add_argument(*args, **kwargs)
9595

9696

97-
def _arg_fields(inst: Any) -> Any:
97+
def _arg_fields(inst: "Any") -> "Any":
9898
for c in inst.__class__.__mro__:
9999
for k, v in tuple(c.__dict__.items()):
100100
if isinstance(v, Argument):
@@ -117,7 +117,7 @@ def flag(*args: str, **kwargs) -> Argument:
117117
class Main:
118118
"""Base class for all CLI commands."""
119119

120-
def __getattr__(self, name: str) -> Any:
120+
def __getattr__(self, name: str) -> "Any":
121121
if not name.startswith("_get_"):
122122
f = getattr(self, f"_get_{name}", None)
123123
if f:
@@ -134,7 +134,11 @@ def __getattr__(self, name: str) -> Any:
134134
else:
135135
return m(name)
136136

137-
def main(self, args: Sequence[str] = None, argp: "argparse.ArgumentParser" = None):
137+
def main(
138+
self,
139+
args: "Sequence[str]|None" = None,
140+
argp: "argparse.ArgumentParser|None" = None,
141+
):
138142
"""Main entry point for the command."""
139143
if argp is None:
140144
argp = self.new_argparse()
@@ -162,7 +166,7 @@ def add_arguments(self, argp: "argparse.ArgumentParser") -> None:
162166
v._add(k, t, argp, self)
163167

164168
def parse_arguments(
165-
self, argp: "argparse.ArgumentParser", args: Sequence[str]
169+
self, argp: "argparse.ArgumentParser", args: "Sequence[str]|None"
166170
) -> None:
167171
"""Parse command line arguments."""
168172
sp = None
@@ -188,12 +192,12 @@ def parse_arguments(
188192
for k, v, t in _arg_fields(s):
189193
if k in m:
190194
setattr(s, k, m[k])
191-
p = getattr(s, "_parent_arg", None)
192-
if p:
195+
q: "Main|None" = getattr(s, "_parent_arg", None)
196+
if q:
193197
s.ready()
194198
s.start()
195199
s.done()
196-
s = p
200+
s = q
197201
else:
198202
argp.parse_args(args, self)
199203

@@ -209,6 +213,6 @@ def start(self) -> None:
209213
"""Main command execution."""
210214
pass
211215

212-
def sub_args(self) -> Any:
216+
def sub_args(self) -> "Any":
213217
"""Yield subcommands."""
214218
yield None, {}

renx/scantree.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -56,33 +56,8 @@ def add_arguments(self, argp):
5656
dest="dry_run",
5757
help="test run only",
5858
)
59-
try:
60-
name_re = self.name_re
61-
except AttributeError:
62-
self.name_re = None
63-
else:
64-
from argparse import Action
65-
from re import compile as regex, escape, I
66-
67-
def re_from_glob(s):
68-
s = escape(s)
69-
s = s.replace(r"\*", ".*")
70-
s = s.replace(r"\?", ".")
71-
return regex(s, I)
72-
73-
class GlobAction(Action):
74-
def __init__(self, option_strings, dest, nargs=None, **kwargs):
75-
if not (nargs is None or nargs == 1):
76-
raise ValueError("nargs not allowed")
77-
super().__init__(option_strings, dest, **kwargs)
78-
79-
def __call__(self, parser, namespace, values, option_string=None):
80-
# print("name_re %r %r %r" % (namespace, values, option_string))
81-
name_re.append(re_from_glob(values))
82-
# setattr(namespace, self.dest, values)
8359

8460
if self.excludes is not None or self.includes is not None:
85-
from fnmatch import translate
8661
from re import compile as regex
8762

8863
group.add_argument(

renx/walkdir.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def scan_directory(self, src: str) -> Generator[DirEntry, None, None]:
7676
yield from scandir(src)
7777
except FileNotFoundError:
7878
pass
79-
except:
79+
except Exception:
8080
if self.carry_on:
8181
pass
8282
else:

tests/test_etc.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import unittest
2-
import os
32
import tempfile
43
import subprocess
54
from pathlib import Path

tests/test_regex_substitution.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import unittest
2-
import os
32
import tempfile
43
import subprocess
54
from pathlib import Path

tests/test_urlsafe.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import unittest
2-
import os
32
import tempfile
43
import subprocess
54
from pathlib import Path

0 commit comments

Comments
 (0)