ostruct-cli 0.3.0__py3-none-any.whl → 0.5.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.
- ostruct/cli/base_errors.py +183 -0
- ostruct/cli/cli.py +830 -585
- ostruct/cli/click_options.py +338 -211
- ostruct/cli/errors.py +214 -227
- ostruct/cli/exit_codes.py +18 -0
- ostruct/cli/file_info.py +126 -69
- ostruct/cli/file_list.py +191 -72
- ostruct/cli/file_utils.py +132 -97
- ostruct/cli/path_utils.py +86 -77
- ostruct/cli/security/__init__.py +32 -0
- ostruct/cli/security/allowed_checker.py +55 -0
- ostruct/cli/security/base.py +46 -0
- ostruct/cli/security/case_manager.py +75 -0
- ostruct/cli/security/errors.py +164 -0
- ostruct/cli/security/normalization.py +161 -0
- ostruct/cli/security/safe_joiner.py +211 -0
- ostruct/cli/security/security_manager.py +366 -0
- ostruct/cli/security/symlink_resolver.py +483 -0
- ostruct/cli/security/types.py +108 -0
- ostruct/cli/security/windows_paths.py +404 -0
- ostruct/cli/serialization.py +25 -0
- ostruct/cli/template_filters.py +13 -8
- ostruct/cli/template_rendering.py +46 -22
- ostruct/cli/template_utils.py +12 -4
- ostruct/cli/template_validation.py +26 -8
- ostruct/cli/token_utils.py +43 -0
- ostruct/cli/validators.py +109 -0
- {ostruct_cli-0.3.0.dist-info → ostruct_cli-0.5.0.dist-info}/METADATA +64 -24
- ostruct_cli-0.5.0.dist-info/RECORD +42 -0
- {ostruct_cli-0.3.0.dist-info → ostruct_cli-0.5.0.dist-info}/WHEEL +1 -1
- ostruct/cli/security.py +0 -964
- ostruct/cli/security_types.py +0 -46
- ostruct_cli-0.3.0.dist-info/RECORD +0 -28
- {ostruct_cli-0.3.0.dist-info → ostruct_cli-0.5.0.dist-info}/LICENSE +0 -0
- {ostruct_cli-0.3.0.dist-info → ostruct_cli-0.5.0.dist-info}/entry_points.txt +0 -0
@@ -67,7 +67,7 @@ from jinja2 import meta
|
|
67
67
|
from jinja2.nodes import For, Name, Node
|
68
68
|
|
69
69
|
from . import template_filters
|
70
|
-
from .errors import TemplateValidationError
|
70
|
+
from .errors import TaskTemplateVariableError, TemplateValidationError
|
71
71
|
from .template_env import create_jinja_env
|
72
72
|
from .template_schema import (
|
73
73
|
DictProxy,
|
@@ -160,7 +160,8 @@ def validate_template_placeholders(
|
|
160
160
|
template_context: Optional context to validate against
|
161
161
|
|
162
162
|
Raises:
|
163
|
-
|
163
|
+
TaskTemplateVariableError: If any variables are undefined
|
164
|
+
TemplateValidationError: If template validation fails for other reasons
|
164
165
|
"""
|
165
166
|
logger = logging.getLogger(__name__)
|
166
167
|
|
@@ -309,10 +310,15 @@ def validate_template_placeholders(
|
|
309
310
|
}
|
310
311
|
|
311
312
|
if missing:
|
312
|
-
|
313
|
-
|
314
|
-
f"
|
313
|
+
# Create a more user-friendly error message
|
314
|
+
error_msg = (
|
315
|
+
f"Missing required template variable(s): {', '.join(sorted(missing))}\n"
|
316
|
+
f"Available variables: {', '.join(sorted(available_vars))}\n"
|
317
|
+
"To fix this, please provide the missing variable(s) using:\n"
|
315
318
|
)
|
319
|
+
for var in sorted(missing):
|
320
|
+
error_msg += f" -V {var}='value'\n"
|
321
|
+
raise TaskTemplateVariableError(error_msg)
|
316
322
|
|
317
323
|
logger.debug(
|
318
324
|
"Before create_validation_context - available_vars type: %s, value: %s",
|
@@ -336,8 +342,17 @@ def validate_template_placeholders(
|
|
336
342
|
try:
|
337
343
|
env.from_string(template).render(validation_context)
|
338
344
|
except jinja2.UndefinedError as e:
|
339
|
-
# Convert Jinja2 undefined errors to
|
340
|
-
|
345
|
+
# Convert Jinja2 undefined errors to TaskTemplateVariableError with helpful message
|
346
|
+
var_name = str(e).split("'")[
|
347
|
+
1
|
348
|
+
] # Extract variable name from error message
|
349
|
+
error_msg = (
|
350
|
+
f"Missing required template variable: {var_name}\n"
|
351
|
+
f"Available variables: {', '.join(sorted(available_vars))}\n"
|
352
|
+
"To fix this, please provide the variable using:\n"
|
353
|
+
f" -V {var_name}='value'"
|
354
|
+
)
|
355
|
+
raise TaskTemplateVariableError(error_msg) from e
|
341
356
|
except ValueError as e:
|
342
357
|
# Convert validation errors from template_schema to TemplateValidationError
|
343
358
|
raise TemplateValidationError(str(e))
|
@@ -348,10 +363,13 @@ def validate_template_placeholders(
|
|
348
363
|
raise
|
349
364
|
|
350
365
|
except jinja2.TemplateSyntaxError as e:
|
351
|
-
# Convert Jinja2 syntax errors to
|
366
|
+
# Convert Jinja2 syntax errors to TemplateValidationError
|
352
367
|
raise TemplateValidationError(
|
353
368
|
f"Invalid task template syntax: {str(e)}"
|
354
369
|
)
|
370
|
+
except (TaskTemplateVariableError, TemplateValidationError):
|
371
|
+
# Re-raise these without wrapping
|
372
|
+
raise
|
355
373
|
except Exception as e:
|
356
374
|
logger.error("Unexpected error during template validation: %s", str(e))
|
357
375
|
raise
|
@@ -0,0 +1,43 @@
|
|
1
|
+
"""Token estimation utilities."""
|
2
|
+
|
3
|
+
from typing import Any, Dict, List, Union
|
4
|
+
|
5
|
+
import tiktoken
|
6
|
+
|
7
|
+
|
8
|
+
def estimate_tokens_with_encoding(
|
9
|
+
messages: Union[str, Dict[str, str], List[Dict[str, str]]],
|
10
|
+
model: str,
|
11
|
+
encoder: Any = None,
|
12
|
+
) -> int:
|
13
|
+
"""Estimate the number of tokens in a chat completion.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
messages: Message content - can be string, single message dict, or list of messages
|
17
|
+
model: Model name
|
18
|
+
encoder: Optional tiktoken encoder for testing
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
int: Estimated token count
|
22
|
+
"""
|
23
|
+
if encoder is None:
|
24
|
+
# Use o200k_base for gpt-4o and o1 models
|
25
|
+
if model.startswith(("gpt-4o", "o1", "o3")):
|
26
|
+
encoder = tiktoken.get_encoding("o200k_base")
|
27
|
+
else:
|
28
|
+
encoder = tiktoken.get_encoding("cl100k_base")
|
29
|
+
|
30
|
+
if isinstance(messages, str):
|
31
|
+
return len(encoder.encode(messages))
|
32
|
+
elif isinstance(messages, dict):
|
33
|
+
return len(encoder.encode(str(messages.get("content", ""))))
|
34
|
+
else:
|
35
|
+
num_tokens = 0
|
36
|
+
for message in messages:
|
37
|
+
num_tokens += 4 # message overhead
|
38
|
+
for key, value in message.items():
|
39
|
+
num_tokens += len(encoder.encode(str(value)))
|
40
|
+
if key == "name":
|
41
|
+
num_tokens -= 1 # role is omitted
|
42
|
+
num_tokens += 2 # reply priming
|
43
|
+
return num_tokens
|
@@ -0,0 +1,109 @@
|
|
1
|
+
"""Validators for CLI options and arguments."""
|
2
|
+
|
3
|
+
import json
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Any, List, Optional, Tuple, Union
|
6
|
+
|
7
|
+
import click
|
8
|
+
|
9
|
+
from .errors import InvalidJSONError, VariableNameError
|
10
|
+
|
11
|
+
|
12
|
+
def validate_name_path_pair(
|
13
|
+
ctx: click.Context,
|
14
|
+
param: click.Parameter,
|
15
|
+
value: List[Tuple[str, Union[str, Path]]],
|
16
|
+
) -> List[Tuple[str, Union[str, Path]]]:
|
17
|
+
"""Validate name/path pairs for files and directories.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
ctx: Click context
|
21
|
+
param: Click parameter
|
22
|
+
value: List of (name, path) tuples
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
List of validated (name, Path) tuples
|
26
|
+
|
27
|
+
Raises:
|
28
|
+
click.BadParameter: If validation fails
|
29
|
+
"""
|
30
|
+
if not value:
|
31
|
+
return value
|
32
|
+
|
33
|
+
result: List[Tuple[str, Union[str, Path]]] = []
|
34
|
+
for name, path in value:
|
35
|
+
if not name.isidentifier():
|
36
|
+
raise click.BadParameter(f"Invalid variable name: {name}")
|
37
|
+
result.append((name, Path(path)))
|
38
|
+
return result
|
39
|
+
|
40
|
+
|
41
|
+
def validate_variable(
|
42
|
+
ctx: click.Context, param: click.Parameter, value: Optional[List[str]]
|
43
|
+
) -> Optional[List[Tuple[str, str]]]:
|
44
|
+
"""Validate name=value format for simple variables.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
ctx: Click context
|
48
|
+
param: Click parameter
|
49
|
+
value: List of "name=value" strings
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
List of validated (name, value) tuples
|
53
|
+
|
54
|
+
Raises:
|
55
|
+
click.BadParameter: If validation fails
|
56
|
+
"""
|
57
|
+
if not value:
|
58
|
+
return None
|
59
|
+
|
60
|
+
result = []
|
61
|
+
for var in value:
|
62
|
+
if "=" not in var:
|
63
|
+
raise click.BadParameter(
|
64
|
+
f"Variable must be in format name=value: {var}"
|
65
|
+
)
|
66
|
+
name, val = var.split("=", 1)
|
67
|
+
if not name.isidentifier():
|
68
|
+
raise click.BadParameter(f"Invalid variable name: {name}")
|
69
|
+
result.append((name, val))
|
70
|
+
return result
|
71
|
+
|
72
|
+
|
73
|
+
def validate_json_variable(
|
74
|
+
ctx: click.Context, param: click.Parameter, value: Optional[List[str]]
|
75
|
+
) -> Optional[List[Tuple[str, Any]]]:
|
76
|
+
"""Validate JSON variable format.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
ctx: Click context
|
80
|
+
param: Click parameter
|
81
|
+
value: List of "name=json_string" values
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
List of validated (name, parsed_json) tuples
|
85
|
+
|
86
|
+
Raises:
|
87
|
+
click.BadParameter: If validation fails
|
88
|
+
"""
|
89
|
+
if not value:
|
90
|
+
return None
|
91
|
+
|
92
|
+
result = []
|
93
|
+
for var in value:
|
94
|
+
if "=" not in var:
|
95
|
+
raise InvalidJSONError(
|
96
|
+
f'JSON variable must be in format name=\'{"json":"value"}\': {var}'
|
97
|
+
)
|
98
|
+
name, json_str = var.split("=", 1)
|
99
|
+
if not name.isidentifier():
|
100
|
+
raise VariableNameError(f"Invalid variable name: {name}")
|
101
|
+
try:
|
102
|
+
json_value = json.loads(json_str)
|
103
|
+
result.append((name, json_value))
|
104
|
+
except json.JSONDecodeError as e:
|
105
|
+
raise InvalidJSONError(
|
106
|
+
f"Invalid JSON value for variable {name!r}: {json_str!r}",
|
107
|
+
context={"variable_name": name},
|
108
|
+
) from e
|
109
|
+
return result
|
@@ -1,12 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: ostruct-cli
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: CLI for OpenAI Structured Output
|
5
5
|
Author: Yaniv Golan
|
6
6
|
Author-email: yaniv@golan.name
|
7
|
-
Requires-Python: >=3.
|
7
|
+
Requires-Python: >=3.10,<4.0
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
10
9
|
Classifier: Programming Language :: Python :: 3.10
|
11
10
|
Classifier: Programming Language :: Python :: 3.11
|
12
11
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -16,10 +15,11 @@ Requires-Dist: chardet (>=5.0.0,<6.0.0)
|
|
16
15
|
Requires-Dist: click (>=8.1.7,<9.0.0)
|
17
16
|
Requires-Dist: ijson (>=3.2.3,<4.0.0)
|
18
17
|
Requires-Dist: jsonschema (>=4.23.0,<5.0.0)
|
19
|
-
Requires-Dist: openai
|
18
|
+
Requires-Dist: openai (>=1.0.0,<2.0.0)
|
19
|
+
Requires-Dist: openai-structured (>=2.0.0,<3.0.0)
|
20
20
|
Requires-Dist: pydantic (>=2.6.3,<3.0.0)
|
21
21
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
22
|
-
Requires-Dist: tiktoken (>=0.
|
22
|
+
Requires-Dist: tiktoken (>=0.9.0,<0.10.0)
|
23
23
|
Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
|
24
24
|
Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
|
25
25
|
Requires-Dist: werkzeug (>=3.1.3,<4.0.0)
|
@@ -28,8 +28,8 @@ Description-Content-Type: text/markdown
|
|
28
28
|
# ostruct-cli
|
29
29
|
|
30
30
|
[](https://badge.fury.io/py/ostruct-cli)
|
31
|
-
[](https://pypi.org/project/ostruct-cli
|
32
|
-
[](https://pypi.org/project/ostruct-cli)
|
32
|
+
[](https://ostruct.readthedocs.io/en/latest/?badge=latest)
|
33
33
|
[](https://github.com/yaniv-golan/ostruct/actions/workflows/ci.yml)
|
34
34
|
[](https://opensource.org/licenses/MIT)
|
35
35
|
|
@@ -90,7 +90,16 @@ Extract information about the person: {{ stdin }}
|
|
90
90
|
4. Run the CLI:
|
91
91
|
|
92
92
|
```bash
|
93
|
-
|
93
|
+
ostruct run task.j2 schema.json
|
94
|
+
```
|
95
|
+
|
96
|
+
Or with more options:
|
97
|
+
|
98
|
+
```bash
|
99
|
+
ostruct run task.j2 schema.json \
|
100
|
+
-f content input.txt \
|
101
|
+
-m gpt-4o \
|
102
|
+
--sys-prompt "You are an expert content analyzer"
|
94
103
|
```
|
95
104
|
|
96
105
|
Output:
|
@@ -111,22 +120,63 @@ Template files use the `.j2` extension to indicate they contain Jinja2 template
|
|
111
120
|
- Makes it clear the file contains template logic
|
112
121
|
- Follows industry standards for Jinja2 templates
|
113
122
|
|
114
|
-
|
123
|
+
## CLI Options
|
124
|
+
|
125
|
+
The CLI revolves around a single subcommand called `run`. Basic usage:
|
126
|
+
|
127
|
+
```bash
|
128
|
+
ostruct run <TASK_TEMPLATE> <SCHEMA_FILE> [OPTIONS]
|
129
|
+
```
|
130
|
+
|
131
|
+
Common options include:
|
132
|
+
|
133
|
+
- File & Directory Inputs:
|
134
|
+
- `-f <NAME> <PATH>`: Map a single file to a variable name
|
135
|
+
- `-d <NAME> <DIR>`: Map a directory to a variable name
|
136
|
+
- `-p <NAME> <PATTERN>`: Map files matching a glob pattern to a variable name
|
137
|
+
- `-R, --recursive`: Enable recursive directory/pattern scanning
|
138
|
+
|
139
|
+
- Variables:
|
140
|
+
- `-V name=value`: Define a simple string variable
|
141
|
+
- `-J name='{"key":"value"}'`: Define a JSON variable
|
142
|
+
|
143
|
+
- Model Parameters:
|
144
|
+
- `-m, --model MODEL`: Select the OpenAI model (supported: gpt-4o, o1, o3-mini)
|
145
|
+
- `--temperature FLOAT`: Set sampling temperature (0.0-2.0)
|
146
|
+
- `--max-output-tokens INT`: Set maximum output tokens
|
147
|
+
- `--top-p FLOAT`: Set top-p sampling parameter (0.0-1.0)
|
148
|
+
- `--frequency-penalty FLOAT`: Adjust frequency penalty (-2.0-2.0)
|
149
|
+
- `--presence-penalty FLOAT`: Adjust presence penalty (-2.0-2.0)
|
150
|
+
- `--reasoning-effort [low|medium|high]`: Control model reasoning effort
|
151
|
+
|
152
|
+
- System Prompt:
|
153
|
+
- `--sys-prompt TEXT`: Provide system prompt directly
|
154
|
+
- `--sys-file FILE`: Load system prompt from file
|
155
|
+
- `--ignore-task-sysprompt`: Ignore system prompt in template frontmatter
|
156
|
+
|
157
|
+
- API Configuration:
|
158
|
+
- `--api-key KEY`: OpenAI API key (defaults to OPENAI_API_KEY env var)
|
159
|
+
- `--timeout FLOAT`: API timeout in seconds (default: 60.0)
|
115
160
|
|
116
161
|
## Debug Options
|
117
162
|
|
118
|
-
- `--show-model-schema`: Display the generated Pydantic model schema
|
119
163
|
- `--debug-validation`: Show detailed schema validation debugging
|
120
|
-
- `--
|
121
|
-
- `--
|
122
|
-
-
|
164
|
+
- `--debug-openai-stream`: Enable low-level debug output for OpenAI streaming
|
165
|
+
- `--progress-level {none,basic,detailed}`: Set progress reporting level
|
166
|
+
- `none`: No progress indicators
|
167
|
+
- `basic`: Show key operation steps (default)
|
168
|
+
- `detailed`: Show all steps with additional info
|
169
|
+
- `--show-model-schema`: Display the generated Pydantic model schema
|
170
|
+
- `--verbose`: Enable verbose logging
|
171
|
+
- `--dry-run`: Validate and render template without making API calls
|
172
|
+
- `--no-progress`: Disable all progress indicators
|
123
173
|
|
124
174
|
All debug and error logs are written to:
|
125
175
|
|
126
176
|
- `~/.ostruct/logs/ostruct.log`: General application logs
|
127
177
|
- `~/.ostruct/logs/openai_stream.log`: OpenAI streaming operations logs
|
128
178
|
|
129
|
-
For more detailed documentation and examples, visit our [documentation](https://ostruct
|
179
|
+
For more detailed documentation and examples, visit our [documentation](https://ostruct.readthedocs.io/).
|
130
180
|
|
131
181
|
## Development
|
132
182
|
|
@@ -173,13 +223,3 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
173
223
|
|
174
224
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
175
225
|
|
176
|
-
## Migration from openai-structured
|
177
|
-
|
178
|
-
If you were previously using the CLI bundled with openai-structured (pre-1.0.0), this is its new home. The migration is straightforward:
|
179
|
-
|
180
|
-
1. Update openai-structured to version 1.0.0 or later
|
181
|
-
2. Install ostruct-cli
|
182
|
-
3. Replace any `openai-structured` CLI commands with `ostruct`
|
183
|
-
|
184
|
-
The functionality remains the same, just moved to a dedicated package for better maintenance and focus.
|
185
|
-
|
@@ -0,0 +1,42 @@
|
|
1
|
+
ostruct/__init__.py,sha256=X6zo6V7ZNMv731Wi388aTVQngD1410ExGwGx4J6lpyo,187
|
2
|
+
ostruct/cli/__init__.py,sha256=sYHKT6o1kFy1acbXejzAvVm8Cy8U91Yf1l4DlzquHKg,409
|
3
|
+
ostruct/cli/base_errors.py,sha256=S1cQxoiALbXKPxzgLo6XdSWpzPRb7RKz0QARmu9Zt4g,5987
|
4
|
+
ostruct/cli/cache_manager.py,sha256=ej3KrRfkKKZ_lEp2JswjbJ5bW2ncsvna9NeJu81cqqs,5192
|
5
|
+
ostruct/cli/cli.py,sha256=R9k4eHpREmvQJb-JLY1VRiWZJO8fJcer1QgnaDX0RrY,74011
|
6
|
+
ostruct/cli/click_options.py,sha256=WbRJdB9sO63ChN3fnCP7XWs73DHKl0C1ervfwL11am0,11371
|
7
|
+
ostruct/cli/errors.py,sha256=Muc4PygxON7M4bdZJ7-apztK9MrF252PXLPVNEogUv0,13322
|
8
|
+
ostruct/cli/exit_codes.py,sha256=uNjvQeUGwU1mlUJYIDrExAn7YlwOXZo603yLAwpqIwk,338
|
9
|
+
ostruct/cli/file_info.py,sha256=ilpT8IuckfhadLF1QQAPLXJp7p8kVpffDEEJ2erHPZU,14485
|
10
|
+
ostruct/cli/file_list.py,sha256=jLuCd1ardoAXX8FNwPgIqEM-ixzr1xP5ZSqXo2lmrj0,11270
|
11
|
+
ostruct/cli/file_utils.py,sha256=J3-6fbEGQ7KD_bU81pAxueHLv9XV0X7f8FSMt_0AJGQ,22537
|
12
|
+
ostruct/cli/path_utils.py,sha256=j44q1OoLkqMErgK-qEuhuIZ1VyzqRIvNgxR1et9PoXA,4813
|
13
|
+
ostruct/cli/progress.py,sha256=rj9nVEco5UeZORMbzd7mFJpFGJjbH9KbBFh5oTE5Anw,3415
|
14
|
+
ostruct/cli/security/__init__.py,sha256=CQpkCgTFYlA1p6atpQeNgIKtE4LZGUKt4EbytbGKpCs,846
|
15
|
+
ostruct/cli/security/allowed_checker.py,sha256=N5UXlpjdj5zAbKk-lRDlHiHV3KtQHtJNhtZI_qGB4zw,1638
|
16
|
+
ostruct/cli/security/base.py,sha256=q9YUdHEj2eg5w8GEw5403E9OQKIjZbEiaWsvYFnCGLw,1359
|
17
|
+
ostruct/cli/security/case_manager.py,sha256=I_ZJSyntLuGx5qVzze559CI-OxsaNPSibkAN8zZ7PvE,2345
|
18
|
+
ostruct/cli/security/errors.py,sha256=VZDOGGD-jYLf6E5gCkKxrE34RJXJP_CPWGOF5jV_r4I,5230
|
19
|
+
ostruct/cli/security/normalization.py,sha256=qevvxW3hHDtD1cVvDym8LJEQD1AKenVB-0ZvjCYjn5E,5242
|
20
|
+
ostruct/cli/security/safe_joiner.py,sha256=PHowCeBAkfHfPqRwuO5Com0OemGuq3cHkdu2p9IYNT0,7107
|
21
|
+
ostruct/cli/security/security_manager.py,sha256=R54CgE7eG_0VybvjXj4fNn1jB-RHMUlnJ6Yw8BOtKKc,13512
|
22
|
+
ostruct/cli/security/symlink_resolver.py,sha256=wtZdJ_T_0FOy6B1P5ty1odEXQk9vr8BzlWeAFD4huJE,16744
|
23
|
+
ostruct/cli/security/types.py,sha256=15yuG_T4CXyAFFFdSWLjVS7ACmDGIPXhQpZ8awcDwCQ,2991
|
24
|
+
ostruct/cli/security/windows_paths.py,sha256=qxC2H2kLwtmQ7YePYde3UrmOJcGnsLEebDLh242sUaI,13453
|
25
|
+
ostruct/cli/serialization.py,sha256=ec0UswDE2onwtZVUoZaMCsGv6zW_tSKdBng2qVo6Ucs,704
|
26
|
+
ostruct/cli/template_env.py,sha256=S2ZvxuMQMicodSVqUhrw0kOzbNmlpQjSHtWlOwjXCms,1538
|
27
|
+
ostruct/cli/template_extensions.py,sha256=tJN3HGAS2yzGI8Up6STPday8NVL0VV6UCClBrtDKYr0,1623
|
28
|
+
ostruct/cli/template_filters.py,sha256=SjuQxlM5S283TS2El_AbrzETGnYoQeTpmA9sv5et3QI,19222
|
29
|
+
ostruct/cli/template_io.py,sha256=yUWO-8rZnSdX97DTMSEX8fG9CP1ISsOhm2NZN3Fab9A,8821
|
30
|
+
ostruct/cli/template_rendering.py,sha256=vp_4gvrYLd_kbQi3TYrYNniXLTeLmTaitGVBQManXvo,13342
|
31
|
+
ostruct/cli/template_schema.py,sha256=ckH4rUZnEgfm_BHS9LnMGr8LtDxRmZ0C6UBVrSp8KTc,19604
|
32
|
+
ostruct/cli/template_utils.py,sha256=Lf1TvonlRA835nxyevEBSPTEbKiz_momvQYM0ZoZDZU,8034
|
33
|
+
ostruct/cli/template_validation.py,sha256=AXa2zmsws1j-0CTFlp7fMiZR43iNLnj4h467up2JdgU,12693
|
34
|
+
ostruct/cli/token_utils.py,sha256=r4KPEO3Sec18Q6mU0aClK6XGShvusgUggXEQgEPPlaA,1369
|
35
|
+
ostruct/cli/utils.py,sha256=1UCl4rHjBWKR5EKugvlVGHiHjO3XXmqvkgeAUSyIPDU,831
|
36
|
+
ostruct/cli/validators.py,sha256=BYFZeebCPZObTUjO1TaAMpsD6h7ROkYAFn9C7uf1Q68,2992
|
37
|
+
ostruct/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
+
ostruct_cli-0.5.0.dist-info/LICENSE,sha256=QUOY6QCYVxAiH8vdrUTDqe3i9hQ5bcNczppDSVpLTjk,1068
|
39
|
+
ostruct_cli-0.5.0.dist-info/METADATA,sha256=1SaOOVJvTKEqaheLw2MZzdwtinTgw2x_ms3xerwuCKA,6533
|
40
|
+
ostruct_cli-0.5.0.dist-info/WHEEL,sha256=7dDg4QLnNKTvwIDR9Ac8jJaAmBC_owJrckbC0jjThyA,88
|
41
|
+
ostruct_cli-0.5.0.dist-info/entry_points.txt,sha256=NFq9IuqHVTem0j9zKjV8C1si_zGcP1RL6Wbvt9fUDXw,48
|
42
|
+
ostruct_cli-0.5.0.dist-info/RECORD,,
|