pathseq 0.1.0__py3-none-any.whl
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.
- pathseq/__init__.py +44 -0
- pathseq/_arithmetic_sequence.py +154 -0
- pathseq/_ast/__init__.py +22 -0
- pathseq/_ast/_base.py +236 -0
- pathseq/_ast/_formatter.py +38 -0
- pathseq/_ast/_loose_type.py +219 -0
- pathseq/_ast/_type.py +64 -0
- pathseq/_base.py +510 -0
- pathseq/_decimal_range.py +172 -0
- pathseq/_error.py +72 -0
- pathseq/_file_num_seq.py +232 -0
- pathseq/_formatter.py +85 -0
- pathseq/_from_disk.py +73 -0
- pathseq/_loose_path_sequence.py +14 -0
- pathseq/_loose_pure_path_sequence.py +126 -0
- pathseq/_parse_file_num_seq.py +77 -0
- pathseq/_parse_loose_path_sequence.py +525 -0
- pathseq/_parse_path_sequence.py +327 -0
- pathseq/_path_sequence.py +14 -0
- pathseq/_pure_path_sequence.py +58 -0
- pathseq/py.typed +0 -0
- pathseq-0.1.0.dist-info/METADATA +134 -0
- pathseq-0.1.0.dist-info/RECORD +24 -0
- pathseq-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Literal, TypeAlias, Union
|
|
5
|
+
|
|
6
|
+
from typing_extensions import Self # PY311
|
|
7
|
+
|
|
8
|
+
from ._base import (
|
|
9
|
+
non_recursive_asdict,
|
|
10
|
+
stringify_parsed_sequence,
|
|
11
|
+
Ranges,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class RangesStartName:
|
|
17
|
+
"""A parsed loose path sequence where the range starts a path's name."""
|
|
18
|
+
|
|
19
|
+
prefix: Literal[""]
|
|
20
|
+
"""An optional single character separator between the ranges and the previous component.
|
|
21
|
+
|
|
22
|
+
This is always empty for file names where the ranges start the name,
|
|
23
|
+
but is included so that :class:`~.RangesStartName`, :class:`~.RangesInName`,
|
|
24
|
+
and :class:`~.RangesEndName` all have the same attributes.
|
|
25
|
+
"""
|
|
26
|
+
ranges: Ranges
|
|
27
|
+
"""The file numbers of the files in the sequence and their formatting."""
|
|
28
|
+
postfix: str
|
|
29
|
+
"""An optional single character separator between the ranges and the next component.
|
|
30
|
+
|
|
31
|
+
In sequences where the ranges start the name,
|
|
32
|
+
this separates the :ref:`ranges <format-loose-range>` from the
|
|
33
|
+
:ref:`stem <format-loose-stem>`.
|
|
34
|
+
"""
|
|
35
|
+
stem: str
|
|
36
|
+
"""The name of the sequence, without the prefix, ranges, postfix, and suffixes."""
|
|
37
|
+
suffixes: tuple[str, ...]
|
|
38
|
+
"""The file extensions of the files in the path sequence.
|
|
39
|
+
|
|
40
|
+
Each suffix includes the leading "``.``".
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __str__(self) -> str:
|
|
44
|
+
return stringify_parsed_sequence(self)
|
|
45
|
+
|
|
46
|
+
def with_stem(self, stem: str) -> Self:
|
|
47
|
+
"""Return a new parsed sequence with the :attr:`~.RangesStartName.stem` changed.
|
|
48
|
+
|
|
49
|
+
If the stem is removed, the postfix will be as well.
|
|
50
|
+
"""
|
|
51
|
+
kwargs = non_recursive_asdict(self)
|
|
52
|
+
kwargs["stem"] = stem
|
|
53
|
+
if not stem:
|
|
54
|
+
kwargs["postfix"] = ""
|
|
55
|
+
return self.__class__(**kwargs)
|
|
56
|
+
|
|
57
|
+
def with_suffix(self, suffix: str) -> Self:
|
|
58
|
+
"""Return a new parsed sequence with the suffix changed.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
suffix: The new suffix to replace the existing one with.
|
|
62
|
+
This must start with a "." or be the empty string.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
ValueError: If an invalid suffix is given.
|
|
66
|
+
"""
|
|
67
|
+
if suffix:
|
|
68
|
+
if not suffix.startswith(".") or suffix == ".":
|
|
69
|
+
raise ValueError(f"Invalid suffix '{suffix}'")
|
|
70
|
+
|
|
71
|
+
kwargs = non_recursive_asdict(self)
|
|
72
|
+
add_suffixes = tuple(f".{s}" for s in suffix[1:].split("."))
|
|
73
|
+
kwargs["suffixes"] = self.suffixes[:-1] + add_suffixes
|
|
74
|
+
return self.__class__(**kwargs)
|
|
75
|
+
|
|
76
|
+
if self.suffixes:
|
|
77
|
+
kwargs = non_recursive_asdict(self)
|
|
78
|
+
kwargs["suffixes"] = self.suffixes[:-1]
|
|
79
|
+
return self.__class__(**kwargs)
|
|
80
|
+
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True)
|
|
85
|
+
class RangesInName:
|
|
86
|
+
"""A parsed loose range sequence where the range follows a path's stem."""
|
|
87
|
+
|
|
88
|
+
stem: str
|
|
89
|
+
"""The name of the sequence, without the prefix, ranges, postfix, and suffixes."""
|
|
90
|
+
prefix: str
|
|
91
|
+
"""An optional single character separator between the ranges and the previous component.
|
|
92
|
+
|
|
93
|
+
In sequences where the ranges are in the name,
|
|
94
|
+
this separates the :ref:`ranges <format-loose-range>` from the
|
|
95
|
+
:ref:`stem <format-loose-stem>`.
|
|
96
|
+
"""
|
|
97
|
+
ranges: Ranges
|
|
98
|
+
"""The file numbers of the files in the sequence and their formatting."""
|
|
99
|
+
postfix: str
|
|
100
|
+
"""An optional single character separator between the ranges and the next component.
|
|
101
|
+
|
|
102
|
+
In sequences where the ranges are in the name,
|
|
103
|
+
this separates the :ref:`ranges <format-loose-range>` from the
|
|
104
|
+
:ref:`suffixes <format-loose-suffixes>`.
|
|
105
|
+
"""
|
|
106
|
+
suffixes: tuple[str, ...]
|
|
107
|
+
"""The file extensions of the files in the path sequence.
|
|
108
|
+
|
|
109
|
+
Each suffix includes the leading "``.``".
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
def __str__(self) -> str:
|
|
113
|
+
return stringify_parsed_sequence(self)
|
|
114
|
+
|
|
115
|
+
def with_stem(self, stem: str) -> Self:
|
|
116
|
+
"""Return a new parsed sequence with the :attr:`~.RangesInName.stem` changed.
|
|
117
|
+
|
|
118
|
+
If the stem is removed, the prefix will be as well.
|
|
119
|
+
"""
|
|
120
|
+
kwargs = non_recursive_asdict(self)
|
|
121
|
+
kwargs["stem"] = stem
|
|
122
|
+
if not stem and self.stem:
|
|
123
|
+
kwargs["prefix"] = ""
|
|
124
|
+
return self.__class__(**kwargs)
|
|
125
|
+
|
|
126
|
+
def with_suffix(self, suffix: str) -> Self:
|
|
127
|
+
"""Return a new parsed sequence with the suffix changed.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
suffix: The new suffix to replace the existing one with.
|
|
131
|
+
This must start with a "." or be the empty string.
|
|
132
|
+
|
|
133
|
+
Raises:
|
|
134
|
+
ValueError: If an invalid suffix is given.
|
|
135
|
+
"""
|
|
136
|
+
if suffix:
|
|
137
|
+
if not suffix.startswith("."):
|
|
138
|
+
raise ValueError(f"Invalid suffix '{suffix}'")
|
|
139
|
+
|
|
140
|
+
kwargs = non_recursive_asdict(self)
|
|
141
|
+
add_suffixes = tuple(f".{s}" for s in suffix[1:].split("."))
|
|
142
|
+
kwargs["suffixes"] = self.suffixes[:-1] + add_suffixes
|
|
143
|
+
return self.__class__(**kwargs)
|
|
144
|
+
|
|
145
|
+
if self.suffixes:
|
|
146
|
+
kwargs = non_recursive_asdict(self)
|
|
147
|
+
kwargs["suffixes"] = self.suffixes[:-1]
|
|
148
|
+
if not kwargs["suffixes"]:
|
|
149
|
+
kwargs["postfix"] = ""
|
|
150
|
+
return self.__class__(**kwargs)
|
|
151
|
+
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass(frozen=True)
|
|
156
|
+
class RangesEndName:
|
|
157
|
+
"""A parsed loose range sequence where the range ends a path's name."""
|
|
158
|
+
|
|
159
|
+
stem: str
|
|
160
|
+
"""The name of the sequence, without the prefix, ranges, postfix, and suffixes."""
|
|
161
|
+
suffixes: tuple[str, ...]
|
|
162
|
+
"""The file extensions of the files in the path sequence.
|
|
163
|
+
|
|
164
|
+
Each suffix includes the leading "``.``".
|
|
165
|
+
"""
|
|
166
|
+
prefix: str
|
|
167
|
+
"""An optional single character separator between the ranges and the previous component.
|
|
168
|
+
|
|
169
|
+
In sequences where the ranges are in the name,
|
|
170
|
+
this separates the :ref:`ranges <format-loose-range>` from the
|
|
171
|
+
:ref:`suffixes <format-loose-suffixes>`.
|
|
172
|
+
"""
|
|
173
|
+
ranges: Ranges
|
|
174
|
+
"""The file numbers of the files in the sequence and their formatting."""
|
|
175
|
+
postfix: Literal[""]
|
|
176
|
+
"""An optional single character separator between the ranges and the next component.
|
|
177
|
+
|
|
178
|
+
This is always empty for file names where the ranges end the name,
|
|
179
|
+
but is included so that :class:`~.RangesStartName`, :class:`~.RangesInName`,
|
|
180
|
+
and :class:`~.RangesEndName` all have the same attributes.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
def __str__(self) -> str:
|
|
184
|
+
return stringify_parsed_sequence(self)
|
|
185
|
+
|
|
186
|
+
def with_stem(self, stem: str) -> Self:
|
|
187
|
+
"""Return a new parsed sequence with the :attr:`~.RangesEndName.stem` changed."""
|
|
188
|
+
kwargs = non_recursive_asdict(self)
|
|
189
|
+
kwargs["stem"] = stem
|
|
190
|
+
return self.__class__(**kwargs)
|
|
191
|
+
|
|
192
|
+
def with_suffix(self, suffix: str) -> Self:
|
|
193
|
+
"""Return a new parsed sequence with the suffix changed.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
suffix: The new suffix to replace the existing one with.
|
|
197
|
+
This must start with a "." or be the empty string.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
ValueError: If an invalid suffix is given.
|
|
201
|
+
"""
|
|
202
|
+
if suffix:
|
|
203
|
+
if not suffix.startswith("."):
|
|
204
|
+
raise ValueError(f"Invalid suffix '{suffix}'")
|
|
205
|
+
|
|
206
|
+
kwargs = non_recursive_asdict(self)
|
|
207
|
+
add_suffixes = tuple(f".{s}" for s in suffix[1:].split("."))
|
|
208
|
+
kwargs["suffixes"] = self.suffixes[:-1] + add_suffixes
|
|
209
|
+
return self.__class__(**kwargs)
|
|
210
|
+
|
|
211
|
+
if self.suffixes:
|
|
212
|
+
kwargs = non_recursive_asdict(self)
|
|
213
|
+
kwargs["suffixes"] = self.suffixes[:-1]
|
|
214
|
+
return self.__class__(**kwargs)
|
|
215
|
+
|
|
216
|
+
return self
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
ParsedLooseSequence: TypeAlias = Union[RangesStartName, RangesInName, RangesEndName]
|
pathseq/_ast/_type.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from typing_extensions import Self # PY311
|
|
6
|
+
|
|
7
|
+
from ._base import (
|
|
8
|
+
non_recursive_asdict,
|
|
9
|
+
stringify_parsed_sequence,
|
|
10
|
+
Ranges,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class ParsedSequence:
|
|
16
|
+
"""A parsed path sequence."""
|
|
17
|
+
|
|
18
|
+
stem: str
|
|
19
|
+
"""The name of the sequence, without the prefix, ranges, and suffixes."""
|
|
20
|
+
prefix: str
|
|
21
|
+
"""An optional single character separator between the stem and the ranges."""
|
|
22
|
+
ranges: Ranges
|
|
23
|
+
"""The file numbers of the files in the sequence and their formatting."""
|
|
24
|
+
suffixes: tuple[str, ...]
|
|
25
|
+
"""The file extensions of the files in the path sequence.
|
|
26
|
+
|
|
27
|
+
Each suffix includes the leading "``.``".
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __str__(self) -> str:
|
|
31
|
+
return stringify_parsed_sequence(self)
|
|
32
|
+
|
|
33
|
+
def with_stem(self, stem: str) -> Self:
|
|
34
|
+
"""Return a new parsed sequence with the :attr:`~.ParsedSequence.stem` changed.
|
|
35
|
+
|
|
36
|
+
If the stem is removed, the prefix will be as well.
|
|
37
|
+
"""
|
|
38
|
+
kwargs = non_recursive_asdict(self)
|
|
39
|
+
kwargs["stem"] = stem
|
|
40
|
+
if not stem and self.stem:
|
|
41
|
+
kwargs["prefix"] = ""
|
|
42
|
+
return self.__class__(**kwargs)
|
|
43
|
+
|
|
44
|
+
def with_suffix(self, suffix: str) -> Self:
|
|
45
|
+
"""Return a new parsed sequence with the suffix changed.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
suffix: The new suffix to replace the existing one with.
|
|
49
|
+
This must start with a "." or be the empty string.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ValueError: If an invalid suffix is given.
|
|
53
|
+
"""
|
|
54
|
+
kwargs = non_recursive_asdict(self)
|
|
55
|
+
if suffix:
|
|
56
|
+
if not suffix.startswith("."):
|
|
57
|
+
raise ValueError(f"Invalid suffix '{suffix}'")
|
|
58
|
+
|
|
59
|
+
add_suffixes = tuple(f".{s}" for s in suffix.split(".")[1:])
|
|
60
|
+
kwargs["suffixes"] = self.suffixes[:-1] + add_suffixes
|
|
61
|
+
else:
|
|
62
|
+
kwargs["suffixes"] = self.suffixes[:-1]
|
|
63
|
+
|
|
64
|
+
return self.__class__(**kwargs)
|