treescript-builder 0.1.4__py3-none-any.whl → 0.1.6__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.
- treescript_builder/__main__.py +4 -2
- treescript_builder/data/data_directory.py +38 -37
- treescript_builder/data/path_stack.py +2 -4
- treescript_builder/data/tree_data.py +12 -3
- treescript_builder/data/tree_state.py +3 -3
- treescript_builder/input/line_reader.py +6 -9
- treescript_builder/tree/build_validation.py +8 -8
- treescript_builder/tree/trim_validation.py +7 -10
- {treescript_builder-0.1.4.dist-info → treescript_builder-0.1.6.dist-info}/METADATA +3 -2
- {treescript_builder-0.1.4.dist-info → treescript_builder-0.1.6.dist-info}/RECORD +14 -14
- {treescript_builder-0.1.4.dist-info → treescript_builder-0.1.6.dist-info}/WHEEL +0 -0
- {treescript_builder-0.1.4.dist-info → treescript_builder-0.1.6.dist-info}/entry_points.txt +0 -0
- {treescript_builder-0.1.4.dist-info → treescript_builder-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {treescript_builder-0.1.4.dist-info → treescript_builder-0.1.6.dist-info}/top_level.txt +0 -0
treescript_builder/__main__.py
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
|
4
4
|
def main():
|
5
5
|
# Author: DK96-OS 2024 - 2025
|
6
|
+
from sys import argv
|
6
7
|
from treescript_builder.input import validate_input_arguments
|
8
|
+
input_data = validate_input_arguments(argv[1:])
|
9
|
+
#
|
7
10
|
from treescript_builder.tree import build_tree
|
8
|
-
|
9
|
-
build_tree(validate_input_arguments(argv[1:]))
|
11
|
+
build_tree(input_data)
|
10
12
|
|
11
13
|
|
12
14
|
if __name__ == "__main__":
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Data Directory Management.
|
1
|
+
""" Data Directory Management.
|
2
2
|
Author: DK96-OS 2024 - 2025
|
3
3
|
"""
|
4
4
|
from pathlib import Path
|
@@ -20,70 +20,71 @@ class DataDirectory:
|
|
20
20
|
def __init__(self, data_dir: Path):
|
21
21
|
if not isinstance(data_dir, Path) or not data_dir.exists():
|
22
22
|
exit('The Data Directory must be a Path that Exists!')
|
23
|
-
self._data_dir = data_dir
|
24
|
-
|
23
|
+
self._data_dir: Path = data_dir
|
24
|
+
self._expected_trim_data: list[str] = []
|
25
25
|
|
26
26
|
def validate_build(self, node: TreeData) -> Path | None:
|
27
27
|
""" Determine if the Data File supporting this Tree node is available.
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
**Parameters:**
|
30
|
+
- node (TreeData): The TreeData to validate.
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
**Returns:**
|
33
|
+
Path? - The Path to the Data File in the Data Directory.
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
**Raises:**
|
36
|
+
SystemExit - When the Data label is invalid, or the Data File does not exist.
|
37
37
|
"""
|
38
|
-
if node.data_label == ''
|
38
|
+
if node.data_label == '': # For compatibility with 0.1.x
|
39
39
|
return None
|
40
|
-
if
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
exit(f'Data Label ({node.data_label}) not found in Data Directory on line: {node.line_number}')
|
40
|
+
if not validate_data_label(data_label := node.get_data_label()):
|
41
|
+
exit(f'Invalid Data Label on line: {node.line_number}')
|
42
|
+
# Search in the DataDir for this Data File.
|
43
|
+
if (data_path := self._search_label(data_label)) is None:
|
44
|
+
exit(f'Label ({node.data_label}) not found in DataDirectory on Line: {node.line_number}')
|
46
45
|
return data_path
|
47
46
|
|
48
47
|
def validate_trim(self, node: TreeData) -> Path | None:
|
49
48
|
""" Determine if the File already exists in the Data Directory.
|
50
49
|
|
51
|
-
|
52
|
-
|
50
|
+
**Parameters:**
|
51
|
+
- node (TreeData): The TreeData to validate.
|
53
52
|
|
54
|
-
|
55
|
-
|
53
|
+
**Returns:**
|
54
|
+
Path? - The Path to a new File in the Data Directory.
|
56
55
|
|
57
|
-
|
58
|
-
|
56
|
+
**Raises:**
|
57
|
+
SystemExit - When the Data label is invalid, or the Data File already exists.
|
59
58
|
"""
|
60
|
-
|
61
|
-
if node.data_label == '' or node.is_dir:
|
59
|
+
if node.data_label == '': # For compatibility with 0.1.x
|
62
60
|
return None
|
63
|
-
|
64
|
-
if not validate_data_label(data_label):
|
61
|
+
if not validate_data_label(data_label := node.get_data_label()):
|
65
62
|
exit(f'Invalid Data Label on line: {node.line_number}')
|
63
|
+
# Check if another TreeData Node has this DataLabel
|
64
|
+
if data_label in self._expected_trim_data:
|
65
|
+
exit(f"Duplicate DataLabels in Trim Operation on Line: {node.line_number}")
|
66
66
|
# Check if the Data File already exists
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
if self._search_label(data_label) is not None:
|
68
|
+
exit(f'Data File already exists!\n({data_label}) on Line: {node.line_number}')
|
69
|
+
# Add the new DataLabel to the collection
|
70
|
+
self._expected_trim_data.append(data_label)
|
71
|
+
# Return the DataLabel Path
|
71
72
|
return self._data_dir / data_label
|
72
73
|
|
73
74
|
def _search_label(self, data_label: str) -> Path | None:
|
74
75
|
""" Search for a Data Label in this Data Directory.
|
75
76
|
|
76
|
-
|
77
|
-
|
77
|
+
**Parameters:**
|
78
|
+
- data_label (str): The Data Label to search for.
|
78
79
|
|
79
|
-
|
80
|
-
|
80
|
+
**Returns:**
|
81
|
+
Path? - The Path to the Data File, or None.
|
81
82
|
"""
|
82
|
-
if not validate_data_label(data_label):
|
83
|
-
return None
|
84
83
|
# Find the Data Label File
|
85
84
|
data_files = self._data_dir.glob(data_label)
|
86
85
|
try:
|
87
86
|
return next(data_files)
|
88
87
|
except StopIteration:
|
89
|
-
return None
|
88
|
+
return None
|
89
|
+
except OSError:
|
90
|
+
return None
|
@@ -17,8 +17,7 @@ class PathStack:
|
|
17
17
|
"""
|
18
18
|
|
19
19
|
def __init__(self):
|
20
|
-
|
21
|
-
self._stack = []
|
20
|
+
self._stack: list[str] = []
|
22
21
|
|
23
22
|
def push(self, directory_name: str):
|
24
23
|
""" Push a directory to the Path Stack.
|
@@ -70,8 +69,7 @@ class PathStack:
|
|
70
69
|
**Returns:**
|
71
70
|
boolean - Whether the Reduction was successful, ie 0 or more Stack pops.
|
72
71
|
"""
|
73
|
-
current_depth
|
74
|
-
if current_depth < depth or depth < 0:
|
72
|
+
if depth < 0 or (current_depth := self.get_depth()) < depth:
|
75
73
|
return False
|
76
74
|
if current_depth == depth:
|
77
75
|
return True
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Tree Node DataClass.
|
1
|
+
""" Tree Node DataClass.
|
2
2
|
Author: DK96-OS 2024 - 2025
|
3
3
|
"""
|
4
4
|
from dataclasses import dataclass
|
@@ -15,9 +15,18 @@ Fields:
|
|
15
15
|
- name (str): The Name of the Tree Node.
|
16
16
|
- data_label (str): The Data Label, may be empty string.
|
17
17
|
"""
|
18
|
-
|
19
18
|
line_number: int
|
20
19
|
depth: int
|
21
20
|
is_dir: bool
|
22
21
|
name: str
|
23
|
-
data_label: str = ''
|
22
|
+
data_label: str = ''
|
23
|
+
|
24
|
+
def get_data_label(self) -> str:
|
25
|
+
""" Obtain the string DataLabel for this TreeData Node.
|
26
|
+
- Contains the relation between these two Fields: name, data_label.
|
27
|
+
- If the DataLabel is the exclamation point !, then use the name as DataLabel.
|
28
|
+
|
29
|
+
**Returns:**
|
30
|
+
str - The DataLabel string to use for this TreeData Node. It may not have been validated.
|
31
|
+
"""
|
32
|
+
return self.name if self.data_label == '!' else self.data_label
|
@@ -24,9 +24,9 @@ class TreeState:
|
|
24
24
|
"""
|
25
25
|
|
26
26
|
def __init__(self):
|
27
|
-
self._stack = PathStack()
|
28
|
-
self._queue = []
|
29
|
-
self._prev_line_number = 0
|
27
|
+
self._stack: PathStack = PathStack()
|
28
|
+
self._queue: list = []
|
29
|
+
self._prev_line_number: int = 0
|
30
30
|
|
31
31
|
def validate_tree_data(self, node: TreeData) -> int:
|
32
32
|
""" Ensure that the next TreeData is valid, relative to current state.
|
@@ -7,14 +7,15 @@ The Default Input Reader.
|
|
7
7
|
- The Name String is the name of the line.
|
8
8
|
Author: DK96-OS 2024 - 2025
|
9
9
|
"""
|
10
|
-
from itertools import groupby
|
10
|
+
from itertools import groupby, takewhile
|
11
11
|
from sys import exit
|
12
12
|
from typing import Generator
|
13
13
|
|
14
14
|
from treescript_builder.data.tree_data import TreeData
|
15
15
|
from treescript_builder.input.string_validation import validate_dir_name, validate_name
|
16
16
|
|
17
|
-
|
17
|
+
|
18
|
+
SPACE_CHARS = (' ', ' ')
|
18
19
|
|
19
20
|
|
20
21
|
def read_input_tree(input_tree_data: str) -> Generator[TreeData, None, None]:
|
@@ -57,9 +58,7 @@ def _process_line(
|
|
57
58
|
**Raises:**
|
58
59
|
SystemExit - When Line cannot be read successfully.
|
59
60
|
"""
|
60
|
-
|
61
|
-
depth = _calculate_depth(line)
|
62
|
-
if depth < 0:
|
61
|
+
if (depth := _calculate_depth(line)) < 0:
|
63
62
|
exit(f"Invalid Space Count in Line: {line_number}")
|
64
63
|
# Remove Space
|
65
64
|
args = line.strip()
|
@@ -78,8 +77,7 @@ def _process_line(
|
|
78
77
|
else:
|
79
78
|
exit(f"Invalid Line: {line_number}")
|
80
79
|
# Validate the Node Name and Type.
|
81
|
-
node_info
|
82
|
-
if node_info is None:
|
80
|
+
if (node_info := _validate_node_name(name)) is None:
|
83
81
|
exit(f'Invalid Node on Line: {line_number}')
|
84
82
|
(is_dir, name) = node_info
|
85
83
|
return TreeData(
|
@@ -126,11 +124,10 @@ def _calculate_depth(line: str) -> int:
|
|
126
124
|
**Returns:**
|
127
125
|
int: The depth of the line in the tree structure, or -1 if space count is invalid.
|
128
126
|
"""
|
129
|
-
from itertools import takewhile
|
130
127
|
space_count = len(list(
|
131
128
|
takewhile(lambda c: c in SPACE_CHARS, line)
|
132
129
|
))
|
133
130
|
# Bit Shift Shuffle Equivalence Validation (space_count is divisible by 2)
|
134
131
|
if (depth := space_count >> 1) << 1 == space_count:
|
135
132
|
return depth
|
136
|
-
return -1 # Invalid Space Count! Someone made an off-by-one whitespace mistake!
|
133
|
+
return -1 # Invalid Space Count! Someone made an off-by-one whitespace mistake!
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Tree Validation Methods for the Build Operation.
|
1
|
+
""" Tree Validation Methods for the Build Operation.
|
2
2
|
Author: DK96-OS 2024 - 2025
|
3
3
|
"""
|
4
4
|
from pathlib import Path
|
@@ -23,11 +23,11 @@ def validate_build(
|
|
23
23
|
**Returns:**
|
24
24
|
tuple[InstructionData] - A generator that yields Instructions.
|
25
25
|
"""
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
return tuple(
|
27
|
+
_validate_build_generator(tree_data)
|
28
|
+
if data_dir_path is None else
|
29
|
+
_validate_build_generator_data(tree_data, DataDirectory(data_dir_path))
|
30
|
+
)
|
31
31
|
|
32
32
|
|
33
33
|
def _validate_build_generator(
|
@@ -37,7 +37,7 @@ def _validate_build_generator(
|
|
37
37
|
for node in tree_data:
|
38
38
|
# Error if any Nodes have Data Labels
|
39
39
|
if node.data_label != '':
|
40
|
-
exit(f"
|
40
|
+
exit(f"No DataDirectory provided, but DataLabel found on Line: {node.line_number}")
|
41
41
|
# Calculate Tree Depth Change
|
42
42
|
if tree_state.validate_tree_data(node) == 0:
|
43
43
|
if node.is_dir:
|
@@ -104,4 +104,4 @@ def _validate_build_generator_data(
|
|
104
104
|
)
|
105
105
|
# Always Finish Build Sequence with ProcessQueue
|
106
106
|
if (dir := tree_state.process_queue()) is not None:
|
107
|
-
yield InstructionData(True, dir)
|
107
|
+
yield InstructionData(True, dir)
|
@@ -19,16 +19,15 @@ def validate_trim(
|
|
19
19
|
**Parameters:**
|
20
20
|
- tree_data (Generator[TreeData]): The Generator that provides TreeData.
|
21
21
|
- data_dir_path (Path?): The optional Path to a Data Directory. Default: None.
|
22
|
-
- verbose (bool): Whether to print DataDirectory information during validation.
|
23
22
|
|
24
23
|
**Returns:**
|
25
|
-
tuple[InstructionData] - A
|
24
|
+
tuple[InstructionData] - A tuple of InstructionData.
|
26
25
|
"""
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
return tuple(
|
27
|
+
_validate_trim_generator(tree_data)
|
28
|
+
if data_dir_path is None else
|
29
|
+
_validate_trim_generator_data(tree_data, DataDirectory(data_dir_path))
|
30
|
+
)
|
32
31
|
|
33
32
|
|
34
33
|
def _validate_trim_generator(
|
@@ -48,7 +47,6 @@ def _validate_trim_generator(
|
|
48
47
|
# Pop Stack to required Depth
|
49
48
|
for i in tree_state.process_stack(node.depth):
|
50
49
|
yield InstructionData(True, i)
|
51
|
-
# Dir or File
|
52
50
|
if node.is_dir:
|
53
51
|
tree_state.add_to_stack(node.name)
|
54
52
|
else:
|
@@ -80,7 +78,6 @@ def _validate_trim_generator_data(
|
|
80
78
|
# Pop Stack to required Depth
|
81
79
|
for i in tree_state.process_stack(node.depth):
|
82
80
|
yield InstructionData(True, i)
|
83
|
-
# Dir or File
|
84
81
|
if node.is_dir:
|
85
82
|
tree_state.add_to_stack(node.name)
|
86
83
|
else:
|
@@ -91,4 +88,4 @@ def _validate_trim_generator_data(
|
|
91
88
|
)
|
92
89
|
# Finish Trim Sequence with Pop Stack
|
93
90
|
for i in tree_state.process_stack(0):
|
94
|
-
yield InstructionData(True, i)
|
91
|
+
yield InstructionData(True, i)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: treescript-builder
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.6
|
4
4
|
Summary: Builds File Trees from TreeScript. If DataLabels are present in TreeScript, a DataDirectory argument is required.
|
5
5
|
Home-page: https://github.com/DK96-OS/treescript-builder
|
6
6
|
Author: DK96-OS
|
@@ -13,9 +13,10 @@ Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
14
14
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
16
17
|
Classifier: Programming Language :: Python :: 3.12
|
17
18
|
Classifier: Programming Language :: Python :: 3.13
|
18
|
-
Requires-Python: >=3.
|
19
|
+
Requires-Python: >=3.11
|
19
20
|
Description-Content-Type: text/markdown
|
20
21
|
License-File: LICENSE
|
21
22
|
Dynamic: author
|
@@ -1,26 +1,26 @@
|
|
1
1
|
treescript_builder/__init__.py,sha256=bPuoIR3cWkK2iW_IW5By4U0d797xVpWE2z4bSVEdQRg,117
|
2
|
-
treescript_builder/__main__.py,sha256=
|
2
|
+
treescript_builder/__main__.py,sha256=IWk1m8kZFyd35b3HLGwcxqczqKWskt1keylKQFV7YNM,617
|
3
3
|
treescript_builder/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
treescript_builder/data/data_directory.py,sha256=
|
4
|
+
treescript_builder/data/data_directory.py,sha256=eqLLOyV2YTXHv1rU7xsE_Hn4oViJh4SrokRfbKfEgTA,3267
|
5
5
|
treescript_builder/data/instruction_data.py,sha256=VqJ25-1Na0b2KamuKaVDN6qGPn-8Mm89tS1rt7_RzCY,533
|
6
|
-
treescript_builder/data/path_stack.py,sha256=
|
7
|
-
treescript_builder/data/tree_data.py,sha256=
|
8
|
-
treescript_builder/data/tree_state.py,sha256=
|
6
|
+
treescript_builder/data/path_stack.py,sha256=L_1u6YVM13EO0YLzbmaA_fYCMJeN3vdTzgJBhEJX-hI,2367
|
7
|
+
treescript_builder/data/tree_data.py,sha256=iyo-op0AmM9i_ypGXSROkbdax_YJgGsYLXKIlvmXmQ0,1035
|
8
|
+
treescript_builder/data/tree_state.py,sha256=EJYSnioAlh4nD44xfeSTQrIY4WjUjckpAQ9m9MQANOo,4473
|
9
9
|
treescript_builder/input/__init__.py,sha256=JONsaG0Iq_w-b9BUpHPpc89DFG8sM8Dxrswb3tWvzY8,921
|
10
10
|
treescript_builder/input/argument_data.py,sha256=PFacb8g-RXh4-RH8foW4eINms6REWpm_knaehYAICfA,806
|
11
11
|
treescript_builder/input/argument_parser.py,sha256=ARPI-EFO5MkXSQqLjyiQPkxg-sB2jP14wf6K4y64Tog,2795
|
12
12
|
treescript_builder/input/file_validation.py,sha256=m0zxntGDkkzWLb3PQKKsxfRSSDgd0dhK35IbaUmN_gw,2404
|
13
13
|
treescript_builder/input/input_data.py,sha256=mP8FAI26UDRwfuEFWXsJJnw77Qxv_yjkuy4NFiTZVOg,479
|
14
|
-
treescript_builder/input/line_reader.py,sha256=
|
14
|
+
treescript_builder/input/line_reader.py,sha256=_jRwuODxT4frnQE0GkEPV6uJbUMpwKAc7EsR8mgSCEM,4333
|
15
15
|
treescript_builder/input/string_validation.py,sha256=6H17UWamTPp2aBC-EVX1P58E0a-F6eD1--HH8CWrmIQ,5020
|
16
16
|
treescript_builder/tree/__init__.py,sha256=3YgyrVcplTYEtFL9PuEM2k08LM8N8xsdRmNJR0rbA4s,1884
|
17
|
-
treescript_builder/tree/build_validation.py,sha256=
|
17
|
+
treescript_builder/tree/build_validation.py,sha256=huO_FRnq_anqGTaQaDfcmc_zU9pIuVaa0orglNDgQIc,4167
|
18
18
|
treescript_builder/tree/tree_builder.py,sha256=0OiJ_Rjpm9Ux1DXvP4d6lHw9CoUCpu6lTfxTmLVOTfQ,1862
|
19
19
|
treescript_builder/tree/tree_trimmer.py,sha256=4cYrnAPX4WQi9JW60K20KPWb9aAtkPYTZWeZ4scEjps,1581
|
20
|
-
treescript_builder/tree/trim_validation.py,sha256=
|
21
|
-
treescript_builder-0.1.
|
22
|
-
treescript_builder-0.1.
|
23
|
-
treescript_builder-0.1.
|
24
|
-
treescript_builder-0.1.
|
25
|
-
treescript_builder-0.1.
|
26
|
-
treescript_builder-0.1.
|
20
|
+
treescript_builder/tree/trim_validation.py,sha256=1MJjVz2JMNTDIvgJD3BMDwpzOvrKw53XXB2LIRFIWkg,3177
|
21
|
+
treescript_builder-0.1.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
22
|
+
treescript_builder-0.1.6.dist-info/METADATA,sha256=vV6W26xZ6NeaDy7sPiyXUXdePqOEXKebE6GqEHbCwzk,5299
|
23
|
+
treescript_builder-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
24
|
+
treescript_builder-0.1.6.dist-info/entry_points.txt,sha256=eOmYzJQPcGaH2GGBfwwU6UH_33tGtsK_ogxB4DnVrFI,111
|
25
|
+
treescript_builder-0.1.6.dist-info/top_level.txt,sha256=parytS3LU7PXBsMVe_puiTOva14bUCzvFwcIwF_Y3Ks,19
|
26
|
+
treescript_builder-0.1.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|