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.
@@ -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)