treescript-builder 0.1.3__py3-none-any.whl → 0.1.5__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.
@@ -25,4 +25,4 @@ def validate_input_arguments(arguments: list[str]) -> InputData:
25
25
  validate_input_file(arg_data.input_file_path_str),
26
26
  validate_directory(arg_data.data_dir_path_str),
27
27
  arg_data.is_reversed
28
- )
28
+ )
@@ -55,9 +55,7 @@ def _validate_arguments(
55
55
  if not validate_name(tree_file_name):
56
56
  exit("The Tree File argument was invalid.")
57
57
  # Validate Data Directory Name Syntax if Present
58
- if data_dir_name is None:
59
- pass
60
- elif not validate_name(data_dir_name):
58
+ if data_dir_name is not None and not validate_name(data_dir_name):
61
59
  exit("The Data Directory argument was invalid.")
62
60
  return ArgumentData(
63
61
  tree_file_name,
@@ -96,4 +94,4 @@ def _define_arguments() -> ArgumentParser:
96
94
  default=False,
97
95
  help='Flag to reverse the File Tree Operation'
98
96
  )
99
- return parser
97
+ return parser
@@ -3,13 +3,28 @@
3
3
  Author: DK96-OS 2024 - 2025
4
4
  """
5
5
  from pathlib import Path
6
+ from stat import S_ISLNK
6
7
  from sys import exit
7
8
 
8
9
  from treescript_builder.input.string_validation import validate_name
9
10
 
10
11
 
12
+ _FILE_SIZE_LIMIT = 32 * 1024 # 32 KB
13
+ _FILE_SIZE_LIMIT_ERROR_MSG = "File larger than 32 KB Limit."
14
+ _FILE_SYMLINK_DISABLED_MSG = "Symlink file paths are disabled."
15
+
16
+ _FILE_DOES_NOT_EXIST_MSG = "The File does not Exist."
17
+ _FILE_READ_OSERROR_MSG = "Failed to Read from File."
18
+ _FILE_VALIDATION_ERROR_MSG = "Invalid Input File Contents."
19
+
20
+ _NOT_A_DIR_ERROR_MSG = "Not a Directory."
21
+ _DIR_DOES_NOT_EXIST_MSG = "The Directory does not exist."
22
+
23
+
11
24
  def validate_input_file(file_name: str) -> str | None:
12
25
  """ Read the Input File, Validate (non-blank) data, and return Input str.
26
+ - Max FileSize is 32 KB.
27
+ - Symlink type file paths are disabled.
13
28
 
14
29
  **Parameters:**
15
30
  - file_name (str): The Name of the Input File.
@@ -18,35 +33,43 @@ def validate_input_file(file_name: str) -> str | None:
18
33
  str - The String Contents of the Input File.
19
34
 
20
35
  **Raises:**
21
- SystemExit - If the File does not exist, or is empty or blank, or read failed.
36
+ SystemExit - If the File does not exist, or is empty, blank, over 32 KB, or if the read or validation operation failed.
22
37
  """
23
38
  file_path = Path(file_name)
24
- if not file_path.exists():
25
- exit("The Input File does not Exist.")
26
39
  try:
27
- if (data := file_path.read_text()) is not None and validate_name(data):
28
- return data
40
+ if not file_path.exists():
41
+ exit(_FILE_DOES_NOT_EXIST_MSG)
42
+ if S_ISLNK((stat := file_path.lstat()).st_mode):
43
+ exit(_FILE_SYMLINK_DISABLED_MSG)
44
+ if stat.st_size > _FILE_SIZE_LIMIT:
45
+ exit(_FILE_SIZE_LIMIT_ERROR_MSG)
46
+ if (data := file_path.read_text()) is not None:
47
+ if validate_name(data):
48
+ return data
49
+ exit(_FILE_VALIDATION_ERROR_MSG)
50
+ # Fallthrough: return None
29
51
  except OSError:
30
- exit("Failed to Read from File.")
52
+ exit(_FILE_READ_OSERROR_MSG)
31
53
  return None
32
54
 
33
55
 
34
56
  def validate_directory(dir_path_str: str | None) -> Path | None:
35
- """ Ensure that if the Directory is present, it Exists.
57
+ """ Ensure that if the Directory argument is present, it Exists.
58
+ - Allows None to pass through the method.
36
59
 
37
60
  **Parameters:**
38
- - dir_path_str (str, optional): The String representation of the Path to the Directory.
61
+ - dir_path_str (str?): The String representation of the Path to the Directory.
39
62
 
40
63
  **Returns:**
41
- Path? - The , or None if given input is None.
64
+ Path? - The Path to the DataDirectory, or None if given input is None.
42
65
 
43
66
  **Raises:**
44
- SystemExit - If a given path does not exist.
67
+ SystemExit - If a given path does not exist, or is not a Directory.
45
68
  """
46
69
  if dir_path_str is None:
47
70
  return None
48
- if not validate_name(dir_path_str):
49
- exit("Data Directory is invalid")
50
71
  if (path := Path(dir_path_str)).exists():
51
- return path
52
- exit("The given Directory does not exist!")
72
+ if path.is_dir():
73
+ return path
74
+ exit(_NOT_A_DIR_ERROR_MSG)
75
+ exit(_DIR_DOES_NOT_EXIST_MSG)
@@ -1,6 +1,7 @@
1
1
  """ String Validation Methods.
2
2
  Author: DK96-OS 2024 - 2025
3
3
  """
4
+ from itertools import permutations, repeat
4
5
  from typing import Literal
5
6
 
6
7
 
@@ -10,7 +11,7 @@ def validate_name(argument) -> bool:
10
11
  - Uses the strip method to remove empty space.
11
12
 
12
13
  **Parameters:**
13
- - argument (str) : The given argument.
14
+ - argument (str): The given argument, which needs validation.
14
15
 
15
16
  **Returns:**
16
17
  bool - True if the argument qualifies as valid.
@@ -24,6 +25,10 @@ def validate_name(argument) -> bool:
24
25
 
25
26
  def validate_data_label(data_label: str) -> bool:
26
27
  """ Determine whether a Data Label is Valid.
28
+ - Allows the approved non-alphanumeric chars.
29
+ - The exclamation point (!) is a valid DataLabel, if by itself.
30
+ - If a slash char is found in the string, it is invalid.
31
+ - Small strings (length <= 2) consisting of only punctuation are invalid.
27
32
 
28
33
  **Parameters:**
29
34
  - data_label (str): The String to check for validity.
@@ -31,52 +36,62 @@ def validate_data_label(data_label: str) -> bool:
31
36
  **Returns:**
32
37
  bool - Whether the String is a valid Data Label.
33
38
  """
34
- if not 0 < len(data_label) < 100:
39
+ if len(data_label) < 3:
40
+ if '!' == data_label: # 33
41
+ return True
42
+ if data_label == '' or _is_invalid_small_tree_string(data_label):
43
+ return False
44
+ elif len(data_label) > 99:
35
45
  return False
36
- if '/' in data_label or '\\' in data_label:
37
- return False
38
- # Remove Dash Characters
39
- if '-' in data_label:
40
- data_label = data_label.replace('-', '')
41
- # Remove Underscore Characters
42
- if '_' in data_label:
43
- data_label = data_label.replace('_', '')
44
- # Remove Dot Characters
45
- if '.' in data_label:
46
- data_label = data_label.replace('.', '')
47
- if '!' == data_label:
48
- return True
49
- # All Remaining Characters must be alphanumeric
50
- return data_label.isalnum()
46
+ for ch in data_label:
47
+ n = ord(ch)
48
+ # ALLOWED: Special Punctuation (-._) Codes: 45, 46, 95
49
+ # Numbers: 48 - 57
50
+ # UpperCase: 65 - 90
51
+ # LowerCase: 97 - 122
52
+ if not (n != 47 and 45 <= n <= 57 if n < 65 else n <= 90 or n <= 122 and (n == 95 or 97 <= n)):
53
+ return False
54
+ return True
51
55
 
52
56
 
53
57
  def validate_dir_name(dir_name: str) -> str | None:
54
58
  """ Determine that a directory is correctly formatted.
55
- - This method should be called once for each slash type.
56
59
 
57
60
  **Parameters:**
58
61
  - dir_name (str): The given input to be validated.
59
62
 
60
63
  **Returns:**
61
- str | None - The valid directory name, or none if it may be a file.
64
+ str? - The valid directory name, or none if it may be a file.
62
65
 
63
66
  **Raises:**
64
67
  ValueError - When the name is not suitable for directories or files.
65
68
  """
66
- # Keep Name Length Reasonable
67
- if (name_length := len(dir_name)) >= 100:
69
+ if (name_length := len(dir_name)) >= 100: # Keep Name Length Reasonable
68
70
  raise ValueError(f'Name too Long!: {name_length}')
69
- # Check for slash characters
70
- if (name := _filter_slash_chars(dir_name)) is not None:
71
- # Is a Dir
72
- if len(name) == 0:
73
- raise ValueError('The name is empty')
74
- # Check for invalid characters (parent dir, current dir)
75
- if name in ['.', '..']:
71
+ # Check for slash chars
72
+ if (name := _filter_slash_chars(dir_name)) is not None: # Is a Dir
73
+ # Validate chars (parent dir, current dir)
74
+ if name in ['', '.', '..']:
76
75
  raise ValueError('Invalid Directory')
77
76
  return name
78
- # Is a File
79
- return None
77
+ else: # Is a File
78
+ return None
79
+
80
+
81
+ def _is_invalid_small_tree_string(tree_string: str) -> bool:
82
+ """ Checks strings of length 1 or 2 for invalid combinations of chars that are generally valid in larger strings..
83
+ - The dot strings are not allowed because they may escape the DataDirectory.
84
+ - The permutations including line characters are not allowed, to help prevent mistakes (typos) and so on.
85
+
86
+ **Parameters:**
87
+ - data_label (str): The Data Label to check, which should be of length 2 or 1.
88
+
89
+ **Returns:**
90
+ bool - True, if the given parameter is invalid, given the specific filtering criteria.
91
+ """
92
+ return tree_string in (invalid_chars := ('.', '_', '-')) or \
93
+ tree_string in (''.join(repeat(x, 2)) for x in invalid_chars) or \
94
+ tree_string in permutations(invalid_chars, 2)
80
95
 
81
96
 
82
97
  def _validate_slash_char(dir_name: str) -> Literal['\\', '/'] | None:
@@ -87,44 +102,43 @@ def _validate_slash_char(dir_name: str) -> Literal['\\', '/'] | None:
87
102
  - dir_name (str): The given input to be validated.
88
103
 
89
104
  **Returns:**
90
- str | None - The slash character used, or none if no chars were found.
105
+ str? - The slash character used, or none if no chars were found.
91
106
 
92
107
  **Raises:**
93
108
  ValueError - When the name contains both slash characters.
94
109
  """
95
- slash = None
110
+ slash: Literal['\\', '/'] | None = None
96
111
  if '/' in dir_name:
97
112
  slash = '/'
113
+ # Also check for other slash
98
114
  if '\\' in dir_name:
99
115
  if slash is not None:
100
- raise ValueError('Invalid Directory slash character combination.')
116
+ raise ValueError('Invalid character combination: forward and back slash in the same path.')
101
117
  slash = '\\'
102
118
  return slash
103
119
 
104
120
 
105
121
  def _filter_slash_chars(dir_name: str) -> str | None:
106
122
  """ Remove all of the slash characters and return the directory name.
107
- - Returns None when there are no slash characters found.
108
- - Raises ValueError when slash characters are used improperly.
123
+ - Returns None when there are no slash characters found.
109
124
 
110
125
  **Parameters:**
111
126
  - dir_name (str): The given input to be validated.
112
127
 
113
128
  **Returns:**
114
- str | None - The valid directory name, or none if it may be a file.
129
+ str? - The valid directory Name, or None if it may be a file (there were no slash chars found).
115
130
 
116
131
  **Raises:**
117
- ValueError - When the name is not suitable for directories or files.
132
+ ValueError - When the name is not suitable for directories or files, such as when slash characters are used improperly.
118
133
  """
119
- slash = _validate_slash_char(dir_name)
120
- if slash is None:
134
+ slash: Literal['\\', '/'] | None = _validate_slash_char(dir_name)
135
+ if slash is None: # No slash chars found.
121
136
  return None
122
137
  if dir_name.endswith(slash) or dir_name.startswith(slash):
123
- name = dir_name.strip(slash)
124
- # Check for internal slash characters
125
- if slash in name:
138
+ name: str = dir_name.strip(slash)
139
+ if slash in name: # Has internal slash characters
126
140
  raise ValueError('Multi-dir line detected')
127
141
  else:
128
142
  # Found slash chars only within the node name (multi-dir line)
129
143
  raise ValueError('Multi-dir line detected')
130
- return name
144
+ return name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: treescript-builder
3
- Version: 0.1.3
3
+ Version: 0.1.5
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.12
19
+ Requires-Python: >=3.11
19
20
  Description-Content-Type: text/markdown
20
21
  License-File: LICENSE
21
22
  Dynamic: author
@@ -34,27 +35,70 @@ Dynamic: summary
34
35
  Script for Building File Trees.
35
36
  - Makes your dreams come true.
36
37
 
37
- ## How To
38
- 1. Prepare Your TreeScript Designs.
39
- - Initial and Final TreeScripts.
40
- - Build New Project Package/Module.
41
- 2. Logical Order of TreeScript Builder Operations.
42
- 3. Run TreeScript Builder from the CommandLine.
43
- - Apply combinations of Operations to build TreeScript Workflows.
44
-
45
- # Project Technical Details:
38
+ ## How To Make The Most Of TreeScript
39
+ 1. Think in File Trees:
40
+ - Initial and Final Trees.
41
+ - Tree Templates for New Modules, Packages, Apps.
42
+ - Data Directory and Data Labels.
43
+ 2. Prepare Your TreeScript Designs.
44
+ - New Project in any language you want.
45
+ - New Feature in a New Module File Tree.
46
+ 3. Plan TreeScript Operations.
47
+ - Split Larger Trees into multiple TreeScript Files.
48
+ - Combine Trim and Build Operations in a Sequence to meet Workflow requirements.
49
+ - Apply other TreeScript Packages to your Workflow:
50
+ - [TreeScript-Diff] : Difference between two TreeScript files.
51
+ - [TreeScript-Files] : Convert TreeScript into a list of File Paths.
52
+ - [TreeScriptify] : Create TreeScript from existing File Trees.
53
+ 4. Run TreeScript, as part of your Workflow.
54
+ - Install; add aliases to your terminal config file, if desired.
55
+
56
+ ## Script Structure
57
+ - Directory names contain a slash char.
58
+ - The Indentation is 2 spaces per level.
59
+
60
+ ### Directory Slash Chars
61
+ - Both directions are accepted: `\`, `/`
62
+ - Start or End of the Directory Name: `\src` or `src/`
63
+ - No spaces between Name and char.
64
+
65
+ ### Example
66
+
67
+ ```treescript
68
+ src/
69
+ __init__.py
70
+ dir/
71
+ ```
72
+
73
+ # Project Technical Details
46
74
 
47
75
  ## File Tree Builder
48
76
  Execute the File Tree Builder with the `ftb` command.
49
77
  - Creates Files and Directories
50
78
  - If DataLabels are present, a DataDirectory is required.
51
79
 
52
- ### File Tree Trimmer (Remover)
80
+ ## File Tree Trimmer (Remover)
53
81
  Execute the File Tree Remover by adding the `--trim` argument.
54
82
  - Removes Files and Empty Directories.
55
83
  - DataLabels require DataDirectory.
56
84
  - Files are exported to the DataDirectory.
57
85
 
86
+ ### Builder DataLabel
87
+ A `DataLabel` is a link to Text content to be inserted into the file.
88
+ - DataLabel must be present in the DataDirectory, if present in the TreeScript File.
89
+ - DataDirectory contents are checked during the Tree Validation phase of program execution.
90
+
91
+ #### Valid DataLabels
92
+ The range of accepted DataLabel characters has been narrowed to reduce risk.
93
+ - Letters: A - z
94
+ - Numbers: 0 - 9
95
+ - Punctuation: -_.
96
+
97
+ #### Invalid DataLabels
98
+ The dot directories are invalid.
99
+ - Current Dir: .
100
+ - Parent Dir: ..
101
+
58
102
  ## Default Input Reader
59
103
  Before the Reader receives TreeScript, the input is filtered so comments and empty lines are not ever seen by the Reader.
60
104
  The Default Input Reader processes one line at a time and calculates multiple file tree node properties that it stores in dataclass objects.
@@ -65,23 +109,18 @@ It calculates for each node:
65
109
  - Depth in tree
66
110
  - (optional) DataArgument
67
111
 
68
- ## Builder Data Feature
69
- The Builder provides one additional feature that goes beyond creation of the File Tree. This feature enables Files to be created with data inserted immediately.
70
-
71
112
  ### Input Data Argument
72
113
  The Data Argument specifies what will be inserted into the file that is created. The Data Argument is provided in the Input File, immediately after the File Name (separated by a space). There are two types of Data Arguments:
73
114
  - DataLabel
74
115
  - InlineContent
75
116
 
76
- ### Builder DataLabel Feature
77
- A `DataLabel` is a link to Text content to be inserted into the file.
78
- - DataLabel is present in both the DataDirectory, and the TreeScript File.
79
-
80
117
  ## Tree Trim Data Directory Feature
81
118
  The Remover provides an additional feature beyond the removal of files in the Tree. This feature enables Files to be saved to a Data Directory when they are removed. Rather than destroying the file data, it is moved to a new directory.
82
119
 
83
-
84
120
  ## To-Do Features
121
+ - Append/Prepend
122
+ - Overwrite Prevention
123
+ - Inline Content
85
124
 
86
125
  ### Builder File Inline Content (TODO)
87
126
  `Inline Content` is written in the Tree Node Structure Input file itself. To distinguish `DataContent` from a `DataLabel`, the Content must begin with a special character.
@@ -94,7 +133,7 @@ This feature is a neat mid-sized improvement that may open up opportunities for
94
133
  - Adding a new file late in the process.
95
134
  - such as after data directory is already prepared, and you review TS and notice a little thing missing.
96
135
  - value-adding option that helps you build files faster, more convenient than the DataDirectory.
97
- - Workflows that use TreeScript.
136
+ - Workflows that use TreeScript:
98
137
  - Easier To Plan, and Communicate What You Did.
99
138
  - Package Restructuring, Migrations.
100
139
  - Test Environment Setup
@@ -6,21 +6,21 @@ treescript_builder/data/instruction_data.py,sha256=VqJ25-1Na0b2KamuKaVDN6qGPn-8M
6
6
  treescript_builder/data/path_stack.py,sha256=QqpbrhWH3VwVqbDGBZW_CU4WGiZ6f4T7eFHzTd5zL5I,2423
7
7
  treescript_builder/data/tree_data.py,sha256=zdICXPy48ysthu9PPAse00ZHdL-Lk1PKVhUp4pMgyQU,590
8
8
  treescript_builder/data/tree_state.py,sha256=bLTwKKPYIiLMExZzzMydZpGSAotzx3_W7wyrzWfb9PQ,4451
9
- treescript_builder/input/__init__.py,sha256=Ue8rD6DXZF-lu4vAoZdMjHPHL27LO3XHKxlShcBptYc,920
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
- treescript_builder/input/argument_parser.py,sha256=SImhEs4crP9iF--5LnOVihOEPXrcEbZ_6CUXeG0mL0M,2809
12
- treescript_builder/input/file_validation.py,sha256=ZEdQiFOOmhIz_nDXRsdWh70cBOxfCqNkartMeAUHEEw,1494
11
+ treescript_builder/input/argument_parser.py,sha256=ARPI-EFO5MkXSQqLjyiQPkxg-sB2jP14wf6K4y64Tog,2795
12
+ treescript_builder/input/file_validation.py,sha256=m0zxntGDkkzWLb3PQKKsxfRSSDgd0dhK35IbaUmN_gw,2404
13
13
  treescript_builder/input/input_data.py,sha256=mP8FAI26UDRwfuEFWXsJJnw77Qxv_yjkuy4NFiTZVOg,479
14
14
  treescript_builder/input/line_reader.py,sha256=_-mWwr9bfROFP34l9d787Qr7nNSqqMnzXMRKjlIwBQA,4410
15
- treescript_builder/input/string_validation.py,sha256=wG4ZEDI18ztg2g-zSed4rxOAFtxkqQbaLeBOP8AwBl0,3951
15
+ treescript_builder/input/string_validation.py,sha256=6H17UWamTPp2aBC-EVX1P58E0a-F6eD1--HH8CWrmIQ,5020
16
16
  treescript_builder/tree/__init__.py,sha256=3YgyrVcplTYEtFL9PuEM2k08LM8N8xsdRmNJR0rbA4s,1884
17
17
  treescript_builder/tree/build_validation.py,sha256=fQwNX_fovjvpq63HZ4NCYQxPrPYlmC_0gFK_LomF45I,4214
18
18
  treescript_builder/tree/tree_builder.py,sha256=0OiJ_Rjpm9Ux1DXvP4d6lHw9CoUCpu6lTfxTmLVOTfQ,1862
19
19
  treescript_builder/tree/tree_trimmer.py,sha256=4cYrnAPX4WQi9JW60K20KPWb9aAtkPYTZWeZ4scEjps,1581
20
20
  treescript_builder/tree/trim_validation.py,sha256=W5FCLBLurHSQYUanU8VmJeprL11OVa7-Z2pCZ39IchQ,3357
21
- treescript_builder-0.1.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
- treescript_builder-0.1.3.dist-info/METADATA,sha256=A0NdpQsnMnOTksy0JRSwyOCVGL2srdWkNwuWnhw6Mic,4143
23
- treescript_builder-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- treescript_builder-0.1.3.dist-info/entry_points.txt,sha256=eOmYzJQPcGaH2GGBfwwU6UH_33tGtsK_ogxB4DnVrFI,111
25
- treescript_builder-0.1.3.dist-info/top_level.txt,sha256=parytS3LU7PXBsMVe_puiTOva14bUCzvFwcIwF_Y3Ks,19
26
- treescript_builder-0.1.3.dist-info/RECORD,,
21
+ treescript_builder-0.1.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
+ treescript_builder-0.1.5.dist-info/METADATA,sha256=2tCtMWKlwKBvn8Exn9_YEx28qHZOQvRKPSnS0Hv8jDo,5299
23
+ treescript_builder-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ treescript_builder-0.1.5.dist-info/entry_points.txt,sha256=eOmYzJQPcGaH2GGBfwwU6UH_33tGtsK_ogxB4DnVrFI,111
25
+ treescript_builder-0.1.5.dist-info/top_level.txt,sha256=parytS3LU7PXBsMVe_puiTOva14bUCzvFwcIwF_Y3Ks,19
26
+ treescript_builder-0.1.5.dist-info/RECORD,,