datamaker-py 0.9.0__tar.gz → 0.11.0__tar.gz
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.
- datamaker_py-0.11.0/PKG-INFO +143 -0
- datamaker_py-0.11.0/README.md +132 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/pyproject.toml +1 -1
- datamaker_py-0.11.0/src/datamaker/__init__.py +12 -0
- datamaker_py-0.11.0/src/datamaker/error.py +94 -0
- datamaker_py-0.11.0/src/datamaker/generated/__init__.py +7 -0
- datamaker_py-0.11.0/src/datamaker/generated/schema.py +1655 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/main.py +112 -5
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/__init__.py +2 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/api_keys.py +5 -4
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/base.py +10 -2
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/connections.py +5 -4
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/custom_types.py +20 -14
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/export_and_validation.py +3 -2
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/folders_and_utils.py +13 -12
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/generation.py +2 -1
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/keymaps.py +3 -2
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/masking_policies.py +5 -4
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/plans.py +5 -4
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/projects.py +6 -5
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/scenario_files.py +6 -5
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/sets.py +5 -4
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/teams.py +11 -10
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/templates.py +7 -6
- datamaker_py-0.11.0/src/datamaker/routes/tosca.py +270 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/routes/users.py +14 -8
- datamaker_py-0.11.0/src/datamaker/types.py +136 -0
- datamaker_py-0.11.0/src/datamaker_py.egg-info/PKG-INFO +143 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker_py.egg-info/SOURCES.txt +6 -1
- datamaker_py-0.11.0/tests/test_tosca.py +425 -0
- datamaker_py-0.9.0/PKG-INFO +0 -79
- datamaker_py-0.9.0/README.md +0 -68
- datamaker_py-0.9.0/src/datamaker/__init__.py +0 -2
- datamaker_py-0.9.0/src/datamaker/error.py +0 -2
- datamaker_py-0.9.0/src/datamaker_py.egg-info/PKG-INFO +0 -79
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/LICENSE +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/setup.cfg +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/core.py +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker/template.py +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker_py.egg-info/dependency_links.txt +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker_py.egg-info/requires.txt +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/src/datamaker_py.egg-info/top_level.txt +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/tests/test_integration.py +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/tests/test_main.py +0 -0
- {datamaker_py-0.9.0 → datamaker_py-0.11.0}/tests/test_routes.py +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: datamaker-py
|
|
3
|
+
Version: 0.11.0
|
|
4
|
+
Summary: The official Python library for the Automators DataMaker API.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
9
|
+
Requires-Dist: requests>=2.32.3
|
|
10
|
+
Dynamic: license-file
|
|
11
|
+
|
|
12
|
+
# DataMaker
|
|
13
|
+
|
|
14
|
+
[](https://opensource.org/licenses/MIT)
|
|
15
|
+
[](https://github.com/astral-sh/uv)
|
|
16
|
+
[](https://github.com/charliermarsh/ruff)
|
|
17
|
+
|
|
18
|
+
The official Python library for the Automators DataMaker API.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
You can install the package using pip:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pip install datamaker-py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
Basic example:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from datamaker import DataMaker, Template
|
|
34
|
+
|
|
35
|
+
# Create an instance of DataMaker
|
|
36
|
+
datamaker = DataMaker()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main():
|
|
40
|
+
# Define the template
|
|
41
|
+
template = Template(
|
|
42
|
+
name="basic template",
|
|
43
|
+
quantity=2,
|
|
44
|
+
fields=[
|
|
45
|
+
{"name": "first_name", "type": "First Name"},
|
|
46
|
+
{"name": "last_name", "type": "Last Name"},
|
|
47
|
+
{
|
|
48
|
+
"name": "email",
|
|
49
|
+
"type": "Derived",
|
|
50
|
+
"options": {"value": "{{first_name}}.{{last_name}}@automators.com"},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Generate data using the template
|
|
56
|
+
result = datamaker.generate(template)
|
|
57
|
+
print(result)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
main()
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Push a set into Tosca Cloud
|
|
66
|
+
|
|
67
|
+
`push_tosca_dataset` creates or replaces a native Tosca Cloud data set from a saved
|
|
68
|
+
set, an input set version, a dataset or inline rows. A Tosca test step reads it with
|
|
69
|
+
`{TDM[<data set>][<subset>][<column>]}`.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from datamaker import DataMaker, ToscaDatasetSchemaChangedError
|
|
73
|
+
|
|
74
|
+
dm = DataMaker()
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
result = dm.push_tosca_dataset(
|
|
78
|
+
integration_id,
|
|
79
|
+
name="Orders",
|
|
80
|
+
input_set_id="is_123", # or set_id=..., dataset_id=..., rows=[...]
|
|
81
|
+
on_existing="overwrite", # "fail" (default) | "overwrite" | "new"
|
|
82
|
+
)
|
|
83
|
+
print(result.dataset_id, result.rows_count, result.outcome, result.example)
|
|
84
|
+
except ToscaDatasetSchemaChangedError as e:
|
|
85
|
+
# The rows dropped a column the data set has. Pass on_schema_change="recreate"
|
|
86
|
+
# to delete and recreate it instead.
|
|
87
|
+
print("removed:", e.removed_columns, "added:", e.added_columns)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
An input set gets one Tosca subset per test case by default; `subsets_by` picks another
|
|
91
|
+
column or turns it off with `False`. `get_tosca_datasets(integration_id)` lists what a
|
|
92
|
+
space already holds.
|
|
93
|
+
|
|
94
|
+
## Autocomplete Types
|
|
95
|
+
|
|
96
|
+
This SDK automatically generates TypeScript autocomplete definitions for use in the [datamaker application](https://github.com/automators/datamaker).
|
|
97
|
+
|
|
98
|
+
The artifact is generated automatically on every push to the `main` branch and can be fetched from:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
https://raw.githubusercontent.com/automators/datamaker-py/main/artifacts/autocomplete-types.ts
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
See [`artifacts/README.md`](artifacts/README.md) for more details.
|
|
105
|
+
|
|
106
|
+
## Development & Contibutions
|
|
107
|
+
|
|
108
|
+
See the [contributing.md](/CONTRIBUTING.md) guide for details on how to contribute to this project.
|
|
109
|
+
|
|
110
|
+
## Types
|
|
111
|
+
|
|
112
|
+
Response types are **generated** from the API's OpenAPI document, not hand-written:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
spec/openapi.json -> src/datamaker/generated/schema.py -> src/datamaker/types.py
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Import from `datamaker.types`, which resolves each spec schema name to the class
|
|
119
|
+
that really matches it:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from datamaker.types import Project, Plan, Template
|
|
123
|
+
|
|
124
|
+
projects: list[Project] = dm.get_projects()
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
They are `TypedDict`s, so nothing changes at runtime — methods still return the
|
|
128
|
+
plain dicts `response.json()` produces, and `project["name"]` works exactly as
|
|
129
|
+
before. The types are checker-only.
|
|
130
|
+
|
|
131
|
+
To regenerate after the API changes:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
python scripts/generate_schema.py
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
CI runs `python scripts/generate_schema.py --check` and fails if the committed
|
|
138
|
+
types drift from the spec.
|
|
139
|
+
|
|
140
|
+
Three schemas cannot currently be generated (`SetDetail`, `PackInstallListItem`,
|
|
141
|
+
`SchemaGraphNavigation`): they are composed with `allOf`, which the generator
|
|
142
|
+
merges away rather than emitting as a named class. Methods returning those keep
|
|
143
|
+
`Dict`. The generator script lists them explicitly and fails if the set grows.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# DataMaker
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://github.com/astral-sh/uv)
|
|
5
|
+
[](https://github.com/charliermarsh/ruff)
|
|
6
|
+
|
|
7
|
+
The official Python library for the Automators DataMaker API.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
You can install the package using pip:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pip install datamaker-py
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Basic example:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from datamaker import DataMaker, Template
|
|
23
|
+
|
|
24
|
+
# Create an instance of DataMaker
|
|
25
|
+
datamaker = DataMaker()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def main():
|
|
29
|
+
# Define the template
|
|
30
|
+
template = Template(
|
|
31
|
+
name="basic template",
|
|
32
|
+
quantity=2,
|
|
33
|
+
fields=[
|
|
34
|
+
{"name": "first_name", "type": "First Name"},
|
|
35
|
+
{"name": "last_name", "type": "Last Name"},
|
|
36
|
+
{
|
|
37
|
+
"name": "email",
|
|
38
|
+
"type": "Derived",
|
|
39
|
+
"options": {"value": "{{first_name}}.{{last_name}}@automators.com"},
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Generate data using the template
|
|
45
|
+
result = datamaker.generate(template)
|
|
46
|
+
print(result)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
main()
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Push a set into Tosca Cloud
|
|
55
|
+
|
|
56
|
+
`push_tosca_dataset` creates or replaces a native Tosca Cloud data set from a saved
|
|
57
|
+
set, an input set version, a dataset or inline rows. A Tosca test step reads it with
|
|
58
|
+
`{TDM[<data set>][<subset>][<column>]}`.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from datamaker import DataMaker, ToscaDatasetSchemaChangedError
|
|
62
|
+
|
|
63
|
+
dm = DataMaker()
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
result = dm.push_tosca_dataset(
|
|
67
|
+
integration_id,
|
|
68
|
+
name="Orders",
|
|
69
|
+
input_set_id="is_123", # or set_id=..., dataset_id=..., rows=[...]
|
|
70
|
+
on_existing="overwrite", # "fail" (default) | "overwrite" | "new"
|
|
71
|
+
)
|
|
72
|
+
print(result.dataset_id, result.rows_count, result.outcome, result.example)
|
|
73
|
+
except ToscaDatasetSchemaChangedError as e:
|
|
74
|
+
# The rows dropped a column the data set has. Pass on_schema_change="recreate"
|
|
75
|
+
# to delete and recreate it instead.
|
|
76
|
+
print("removed:", e.removed_columns, "added:", e.added_columns)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
An input set gets one Tosca subset per test case by default; `subsets_by` picks another
|
|
80
|
+
column or turns it off with `False`. `get_tosca_datasets(integration_id)` lists what a
|
|
81
|
+
space already holds.
|
|
82
|
+
|
|
83
|
+
## Autocomplete Types
|
|
84
|
+
|
|
85
|
+
This SDK automatically generates TypeScript autocomplete definitions for use in the [datamaker application](https://github.com/automators/datamaker).
|
|
86
|
+
|
|
87
|
+
The artifact is generated automatically on every push to the `main` branch and can be fetched from:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
https://raw.githubusercontent.com/automators/datamaker-py/main/artifacts/autocomplete-types.ts
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
See [`artifacts/README.md`](artifacts/README.md) for more details.
|
|
94
|
+
|
|
95
|
+
## Development & Contibutions
|
|
96
|
+
|
|
97
|
+
See the [contributing.md](/CONTRIBUTING.md) guide for details on how to contribute to this project.
|
|
98
|
+
|
|
99
|
+
## Types
|
|
100
|
+
|
|
101
|
+
Response types are **generated** from the API's OpenAPI document, not hand-written:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
spec/openapi.json -> src/datamaker/generated/schema.py -> src/datamaker/types.py
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Import from `datamaker.types`, which resolves each spec schema name to the class
|
|
108
|
+
that really matches it:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from datamaker.types import Project, Plan, Template
|
|
112
|
+
|
|
113
|
+
projects: list[Project] = dm.get_projects()
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
They are `TypedDict`s, so nothing changes at runtime — methods still return the
|
|
117
|
+
plain dicts `response.json()` produces, and `project["name"]` works exactly as
|
|
118
|
+
before. The types are checker-only.
|
|
119
|
+
|
|
120
|
+
To regenerate after the API changes:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
python scripts/generate_schema.py
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
CI runs `python scripts/generate_schema.py --check` and fails if the committed
|
|
127
|
+
types drift from the spec.
|
|
128
|
+
|
|
129
|
+
Three schemas cannot currently be generated (`SetDetail`, `PackInstallListItem`,
|
|
130
|
+
`SchemaGraphNavigation`): they are composed with `allOf`, which the generator
|
|
131
|
+
merges away rather than emitting as a named class. Methods returning those keep
|
|
132
|
+
`Dict`. The generator script lists them explicitly and fails if the set grows.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .main import DataMaker # noqa
|
|
2
|
+
from .template import Template # noqa
|
|
3
|
+
from .error import ( # noqa
|
|
4
|
+
DataMakerError,
|
|
5
|
+
DataMakerAPIError,
|
|
6
|
+
ReadOnlyConnectionError,
|
|
7
|
+
ToscaDatasetExistsError,
|
|
8
|
+
ToscaDatasetLockedError,
|
|
9
|
+
ToscaDatasetSchemaChangedError,
|
|
10
|
+
ToscaDatasetTooLargeError,
|
|
11
|
+
)
|
|
12
|
+
from .routes.tosca import ToscaDatasetPushResult # noqa
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from typing import Any, List, Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DataMakerError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataMakerAPIError(DataMakerError):
|
|
9
|
+
"""The API answered with a non-2xx status.
|
|
10
|
+
|
|
11
|
+
Subclasses ``DataMakerError`` and keeps its message, so existing
|
|
12
|
+
``except DataMakerError`` handlers are unaffected. Adds the status code and
|
|
13
|
+
the decoded JSON body (``None`` when the body was not JSON).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, message: str, status_code: int, body: Any = None):
|
|
17
|
+
super().__init__(message)
|
|
18
|
+
self.status_code = status_code
|
|
19
|
+
self.body = body
|
|
20
|
+
|
|
21
|
+
def _detail(self, key: str) -> Any:
|
|
22
|
+
return self.body.get(key) if isinstance(self.body, dict) else None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ReadOnlyConnectionError(DataMakerAPIError):
|
|
26
|
+
"""403: the connection is read-only, so DataMaker refused the write."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ToscaDatasetExistsError(DataMakerAPIError):
|
|
30
|
+
"""409: a Tosca data set of that name exists and ``on_existing`` is "fail"."""
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def dataset_id(self) -> Optional[str]:
|
|
34
|
+
"""The id of the data set that is already there."""
|
|
35
|
+
return self._detail("datasetId")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ToscaDatasetLockedError(DataMakerAPIError):
|
|
39
|
+
"""409: the data set is locked in Tosca Cloud, so it cannot be overwritten.
|
|
40
|
+
|
|
41
|
+
A test run or a "Test data - Expert" step holds it. Retry once it is
|
|
42
|
+
unlocked.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def dataset_id(self) -> Optional[str]:
|
|
47
|
+
return self._detail("datasetId")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ToscaDatasetSchemaChangedError(DataMakerAPIError):
|
|
51
|
+
"""409: an overwrite would drop columns the Tosca data set has.
|
|
52
|
+
|
|
53
|
+
Tosca only overwrites in place when the columns match. Added columns are
|
|
54
|
+
handled by the API; a removed column is refused unless the push asks for
|
|
55
|
+
``on_schema_change="recreate"``.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def dataset_id(self) -> Optional[str]:
|
|
60
|
+
return self._detail("datasetId")
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def added_columns(self) -> List[str]:
|
|
64
|
+
return self._detail("added") or []
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def removed_columns(self) -> List[str]:
|
|
68
|
+
return self._detail("removed") or []
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ToscaDatasetTooLargeError(DataMakerAPIError):
|
|
72
|
+
"""413: more rows or bytes than one push may write.
|
|
73
|
+
|
|
74
|
+
The row pair (``max_rows``, ``rows``) or the byte pair (``max_bytes``,
|
|
75
|
+
``bytes``) is set, depending on which cap was hit. A set, input set or
|
|
76
|
+
dataset refused before its rows are loaded carries neither; the message
|
|
77
|
+
names the cap.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def max_rows(self) -> Optional[int]:
|
|
82
|
+
return self._detail("maxRows")
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def rows(self) -> Optional[int]:
|
|
86
|
+
return self._detail("rows")
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def max_bytes(self) -> Optional[int]:
|
|
90
|
+
return self._detail("maxBytes")
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def bytes(self) -> Optional[int]:
|
|
94
|
+
return self._detail("bytes")
|