tinyfan 0.1.2__tar.gz → 0.2.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.
- {tinyfan-0.1.2 → tinyfan-0.2.0}/PKG-INFO +2 -1
- tinyfan-0.2.0/examples/README.md +12 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/configs.py +1 -1
- {tinyfan-0.1.2 → tinyfan-0.2.0}/pyproject.toml +9 -31
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/codegen.py +22 -12
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/flow.py +4 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/utils/merge.py +10 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/test_codegen.py +11 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/uv.lock +14 -1
- {tinyfan-0.1.2 → tinyfan-0.2.0}/.github/workflows/publish.yml +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/.gitignore +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/.python-version +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/README.md +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/configmap.yaml +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/getting-started.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/packaged/.python-version +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/packaged/Dockerfile +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/packaged/README.md +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/packaged/pyproject.toml +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/packaged/src/tinyfan_examples_packaged/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/packaged/src/tinyfan_examples_packaged/asset.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/resource.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/examples/secret.yaml +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/argo_typing.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/cli.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/config.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/flowrundata.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/resources/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/resources/base.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/stores/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/stores/base.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/stores/bigquery.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/stores/gcs_pickle.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/stores/naive.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/utils/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/utils/embed.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/utils/exjson.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/utils/typing.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/src/tinyfan/utils/yaml.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/codegen_samples/directory/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/codegen_samples/directory/asset.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/codegen_samples/directory/asset2.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/codegen_samples/singlefile.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/conftest.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/helpers.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/openapi2jsonschema.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/test_decorators.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/utils/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/utils/embed_samples/directory/__init__.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/utils/embed_samples/directory/dep.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/utils/embed_samples/singlefile.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/utils/test_embed.py +0 -0
- {tinyfan-0.1.2 → tinyfan-0.2.0}/tests/utils/test_exjson.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tinyfan
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Tiny Argo Workflows python devkit
|
|
5
5
|
Project-URL: Documentation, https://github.com/eunchuldev/tinyfan#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/eunchuldev/tinyfan/issues
|
|
@@ -31,6 +31,7 @@ Requires-Dist: jsonschema[format]; extra == 'dev'
|
|
|
31
31
|
Requires-Dist: mypy>=1.14; extra == 'dev'
|
|
32
32
|
Requires-Dist: pytest>=8.3.3; extra == 'dev'
|
|
33
33
|
Requires-Dist: ruff; extra == 'dev'
|
|
34
|
+
Requires-Dist: types-croniter; extra == 'dev'
|
|
34
35
|
Requires-Dist: types-jsonschema; extra == 'dev'
|
|
35
36
|
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
36
37
|
Provides-Extra: gcs
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# How to run
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
# setup k3d
|
|
5
|
+
k3d cluster create tinyfan
|
|
6
|
+
kubectl config use-context k3d-tinyfan
|
|
7
|
+
# install argowf
|
|
8
|
+
kubectl create namespace argo
|
|
9
|
+
kubectl apply -n argo -f "https://github.com/argoproj/argo-workflows/releases/download/v3.6.4/quick-start-minimal.yaml"
|
|
10
|
+
# apply manifests
|
|
11
|
+
tinyfan examples/getting-started.py | kubectl apply -n argo -f -
|
|
12
|
+
```
|
|
@@ -27,5 +27,5 @@ def trace_configs(
|
|
|
27
27
|
secretkey: SecretKeyRef,
|
|
28
28
|
):
|
|
29
29
|
print(
|
|
30
|
-
f
|
|
30
|
+
f"{constant} - {cliarg} - {configmap.get('otherkey')} - {configmapkey.get_value()} - {secret.get('othersecretkey')} - {secretkey.get_value()}"
|
|
31
31
|
)
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tinyfan"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = 'Tiny Argo Workflows python devkit'
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
|
-
keywords = [
|
|
8
|
-
|
|
9
|
-
"tinyfan",
|
|
10
|
-
"workflow",
|
|
11
|
-
"pipeline",
|
|
12
|
-
]
|
|
13
|
-
authors = [
|
|
14
|
-
{ name = "eunchuldev", email = "eunchulsong@gmail.com" },
|
|
15
|
-
]
|
|
7
|
+
keywords = ["argo-workflow", "tinyfan", "workflow", "pipeline"]
|
|
8
|
+
authors = [{ name = "eunchuldev", email = "eunchulsong@gmail.com" }]
|
|
16
9
|
classifiers = [
|
|
17
10
|
"Operating System :: OS Independent",
|
|
18
11
|
"License :: OSI Approved :: MIT License",
|
|
@@ -20,32 +13,16 @@ classifiers = [
|
|
|
20
13
|
"Programming Language :: Python :: 3.11",
|
|
21
14
|
"Programming Language :: Python :: 3.12",
|
|
22
15
|
]
|
|
23
|
-
dependencies = [
|
|
24
|
-
"croniter>=3.0.3",
|
|
25
|
-
"pyyaml>=6.0.2",
|
|
26
|
-
"typer-slim>=0.15.1",
|
|
27
|
-
]
|
|
16
|
+
dependencies = ["croniter>=3.0.3", "pyyaml>=6.0.2", "typer-slim>=0.15.1"]
|
|
28
17
|
|
|
29
18
|
[project.scripts]
|
|
30
19
|
tinyfan = "tinyfan.cli:main"
|
|
31
20
|
|
|
32
21
|
[project.optional-dependencies]
|
|
33
|
-
all = [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
]
|
|
38
|
-
gcs = [
|
|
39
|
-
"google-cloud-storage",
|
|
40
|
-
]
|
|
41
|
-
bigquery = [
|
|
42
|
-
"google-cloud-bigquery[pandas]",
|
|
43
|
-
"tinyfan[pandas]",
|
|
44
|
-
]
|
|
45
|
-
pandas = [
|
|
46
|
-
"pandas",
|
|
47
|
-
"pyarrow",
|
|
48
|
-
]
|
|
22
|
+
all = ["tinyfan[gcs]", "tinyfan[bigquery]", "tinyfan[pandas]"]
|
|
23
|
+
gcs = ["google-cloud-storage"]
|
|
24
|
+
bigquery = ["google-cloud-bigquery[pandas]", "tinyfan[pandas]"]
|
|
25
|
+
pandas = ["pandas", "pyarrow"]
|
|
49
26
|
dev = [
|
|
50
27
|
"pytest >= 8.3.3",
|
|
51
28
|
"jsonpatch>=1",
|
|
@@ -54,6 +31,7 @@ dev = [
|
|
|
54
31
|
"ruff",
|
|
55
32
|
"types-PyYAML",
|
|
56
33
|
"types-jsonschema",
|
|
34
|
+
"types-croniter",
|
|
57
35
|
]
|
|
58
36
|
|
|
59
37
|
[project.urls]
|
|
@@ -13,7 +13,7 @@ import datetime
|
|
|
13
13
|
import croniter
|
|
14
14
|
from .argo_typing import ScriptTemplate
|
|
15
15
|
from .utils.embed import embed
|
|
16
|
-
from .utils.merge import deepmerge
|
|
16
|
+
from .utils.merge import deepmerge, dropnone
|
|
17
17
|
from .config import CLI_CONFIG_STATE, Config, ConfigValue, ConfigMapKeyRef, ConfigMapRef, SecretKeyRef, SecretRef
|
|
18
18
|
from .flowrundata import FlowRunData
|
|
19
19
|
|
|
@@ -89,19 +89,21 @@ class AssetNode:
|
|
|
89
89
|
t1 = cron.get_next(datetime.datetime)
|
|
90
90
|
t2 = cron.get_next(datetime.datetime)
|
|
91
91
|
duration_sec = (t2 - t1).total_seconds()
|
|
92
|
+
data_interval_start_tmpl = (
|
|
93
|
+
f"sprig.dateModify('-{duration_sec}s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime))"
|
|
94
|
+
)
|
|
92
95
|
return re.sub(
|
|
93
96
|
r'"(\{\{tasks\.[^.]+\.outputs\.parameters\.rundata\}\})"',
|
|
94
97
|
r"\1",
|
|
95
98
|
json.dumps(
|
|
96
99
|
{
|
|
97
|
-
"ds": "{{=sprig.date('2006-01-02',
|
|
98
|
-
"ts": "{{
|
|
100
|
+
"ds": "{{=sprig.date('2006-01-02', %s)}}" % data_interval_start_tmpl,
|
|
101
|
+
"ts": "{{=%s}}" % data_interval_start_tmpl,
|
|
99
102
|
"data_interval_start": {
|
|
100
|
-
DATETIME_ANNOTATION: "{{
|
|
103
|
+
DATETIME_ANNOTATION: "{{=%s}}" % data_interval_start_tmpl,
|
|
101
104
|
},
|
|
102
105
|
"data_interval_end": {
|
|
103
|
-
DATETIME_ANNOTATION: "{{
|
|
104
|
-
% duration_sec,
|
|
106
|
+
DATETIME_ANNOTATION: "{{workflow.scheduledTime}}",
|
|
105
107
|
},
|
|
106
108
|
"parents": {
|
|
107
109
|
p.asset.name: "{{tasks.%s.outputs.parameters.rundata}}" % p.asset.name for p in self.parents
|
|
@@ -171,6 +173,7 @@ class AssetTree:
|
|
|
171
173
|
self,
|
|
172
174
|
embedded: bool = True,
|
|
173
175
|
container: ScriptTemplate = {},
|
|
176
|
+
serviceAccountName: str | None = None,
|
|
174
177
|
) -> str:
|
|
175
178
|
if len(self.nodes) == 0:
|
|
176
179
|
return ""
|
|
@@ -186,7 +189,7 @@ class AssetTree:
|
|
|
186
189
|
root_location = get_root_path(list(self.nodes.values())[0].asset.func)
|
|
187
190
|
source += embed(root_location)
|
|
188
191
|
if not root_location.endswith(".py"):
|
|
189
|
-
source += "from {{inputs.parameters.module_name}}
|
|
192
|
+
source += "from {{inputs.parameters.module_name}} import {{inputs.parameters.asset_name}}\n"
|
|
190
193
|
source += "asset = {{inputs.parameters.asset_name}}.asset\n"
|
|
191
194
|
else:
|
|
192
195
|
source = (
|
|
@@ -219,14 +222,15 @@ class AssetTree:
|
|
|
219
222
|
"apiVersion": "argoproj.io/v1alpha1",
|
|
220
223
|
"kind": "CronWorkflow",
|
|
221
224
|
"metadata": {
|
|
222
|
-
"name": f"""{self.flow.name}-{
|
|
223
|
-
"generateName": f"""{self.flow.name}-{
|
|
225
|
+
"name": f"""{self.flow.name}-{encode_schedule_to_k8sname(tz, schedule)}""",
|
|
226
|
+
"generateName": f"""{self.flow.name}-{encode_schedule_to_k8sname(tz, schedule)}-""",
|
|
224
227
|
},
|
|
225
228
|
"spec": {
|
|
226
229
|
"schedule": schedule,
|
|
227
230
|
"timezone": tz,
|
|
228
231
|
"workflowSpec": {
|
|
229
232
|
"entrypoint": "flow",
|
|
233
|
+
**dropnone({"serviceAccountName": serviceAccountName or self.flow.serviceAccountName}),
|
|
230
234
|
"podSpecPatch": yaml_dump(
|
|
231
235
|
{
|
|
232
236
|
"containers": [
|
|
@@ -249,6 +253,7 @@ class AssetTree:
|
|
|
249
253
|
"templates": [
|
|
250
254
|
{
|
|
251
255
|
"name": node.asset.name.replace("_", "-"),
|
|
256
|
+
**dropnone({"serviceAccountName": node.asset.serviceAccountName}),
|
|
252
257
|
"script": deepmerge(
|
|
253
258
|
{
|
|
254
259
|
"image": DEFAULT_IMAGE,
|
|
@@ -391,15 +396,20 @@ def codegen(
|
|
|
391
396
|
location: str | None = None,
|
|
392
397
|
embedded: bool = False,
|
|
393
398
|
container: ScriptTemplate = {},
|
|
399
|
+
serviceAccountName: str | None = None,
|
|
394
400
|
) -> str:
|
|
395
401
|
"""Generate argocd workflow resource as yaml from tinyfan definitions"""
|
|
396
402
|
CLI_CONFIG_STATE.codegen = True
|
|
397
403
|
if flow:
|
|
398
|
-
result = AssetTree(flow).compile(embedded, container)
|
|
404
|
+
result = AssetTree(flow).compile(embedded, container, serviceAccountName)
|
|
399
405
|
elif location:
|
|
400
406
|
import_all_submodules(location)
|
|
401
|
-
result = "\n---\n".join(
|
|
407
|
+
result = "\n---\n".join(
|
|
408
|
+
AssetTree(flow).compile(embedded, container, serviceAccountName) for flow in FLOW_REGISTER.values()
|
|
409
|
+
)
|
|
402
410
|
else:
|
|
403
|
-
result = "\n---\n".join(
|
|
411
|
+
result = "\n---\n".join(
|
|
412
|
+
AssetTree(flow).compile(embedded, container, serviceAccountName) for flow in FLOW_REGISTER.values()
|
|
413
|
+
)
|
|
404
414
|
CLI_CONFIG_STATE.codegen = False
|
|
405
415
|
return result
|
|
@@ -22,6 +22,7 @@ class Flow:
|
|
|
22
22
|
assets: dict[str, "Asset[Any, Any, Any]"] = field(default_factory=dict)
|
|
23
23
|
resources: dict[str, ResourceBase] | None = None
|
|
24
24
|
container: ScriptTemplate | None = None
|
|
25
|
+
serviceAccountName: str | None = None
|
|
25
26
|
store: StoreBase = field(default_factory=NaiveStore)
|
|
26
27
|
configs: dict[str, Config | ConfigValue | str | None] = field(default_factory=dict)
|
|
27
28
|
|
|
@@ -48,6 +49,7 @@ class Asset(Generic[Ret, UMeta, StoreIdx]):
|
|
|
48
49
|
depends: str | None = None
|
|
49
50
|
name: str = field(init=False)
|
|
50
51
|
container: ScriptTemplate | None = None
|
|
52
|
+
serviceAccountName: str | None = None
|
|
51
53
|
|
|
52
54
|
def __post_init__(self):
|
|
53
55
|
self.name = self.func.__name__
|
|
@@ -110,6 +112,7 @@ def asset(
|
|
|
110
112
|
tz: str | None = None,
|
|
111
113
|
metadata: UMeta | None = None,
|
|
112
114
|
container: ScriptTemplate | None = None,
|
|
115
|
+
serviceAccountName: str | None = None,
|
|
113
116
|
) -> Callable[..., AssetFunc[Ret, UMeta, StoreIdx]]:
|
|
114
117
|
def wrapper(func: Callable[..., Ret]) -> AssetFunc[Ret, UMeta, StoreIdx]:
|
|
115
118
|
asset = Asset[Ret, UMeta, StoreIdx](
|
|
@@ -121,6 +124,7 @@ def asset(
|
|
|
121
124
|
tz=tz or flow.tz,
|
|
122
125
|
metadata=metadata,
|
|
123
126
|
container=container,
|
|
127
|
+
serviceAccountName=serviceAccountName,
|
|
124
128
|
)
|
|
125
129
|
return AssetFunc(func, asset)
|
|
126
130
|
|
|
@@ -15,3 +15,13 @@ def deepmerge(dict1: T, dict2: T, *args: T) -> T:
|
|
|
15
15
|
for arg in args:
|
|
16
16
|
deepmerge(dict1, arg)
|
|
17
17
|
return dict1
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def dropnone(d: dict) -> dict:
|
|
21
|
+
dropping = []
|
|
22
|
+
for k in d:
|
|
23
|
+
if d[k] is None:
|
|
24
|
+
dropping.append(k)
|
|
25
|
+
for k in dropping:
|
|
26
|
+
del d[k]
|
|
27
|
+
return d
|
|
@@ -127,3 +127,14 @@ def test_codegen_directory(validate_crds):
|
|
|
127
127
|
if e.json_path != "$.spec.templates[0].script" or e.validator != "required":
|
|
128
128
|
raise e
|
|
129
129
|
assert_code_is_running(actual)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_rundata_data_interval(sample_flow):
|
|
133
|
+
tree = AssetTree(sample_flow)
|
|
134
|
+
node = list(tree.nodes.values())[0]
|
|
135
|
+
# rundatatmpl = node.rundatatmpl("0 * * * * *")
|
|
136
|
+
daily = node.rundatatmpl("@daily")
|
|
137
|
+
assert (
|
|
138
|
+
daily
|
|
139
|
+
== """{"ds": "{{=sprig.date('2006-01-02', sprig.dateModify('-86400.0s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime)))}}", "ts": "{{=sprig.dateModify('-86400.0s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime))}}", "data_interval_start": {"__tinyfan_datetime__": "{{=sprig.dateModify('-86400.0s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime))}}"}, "data_interval_end": {"__tinyfan_datetime__": "{{workflow.scheduledTime}}"}, "parents": {}, "asset_name": "asset1", "flow_name": "test", "module_name": "tests.test_codegen"}"""
|
|
140
|
+
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
version = 1
|
|
2
|
+
revision = 1
|
|
2
3
|
requires-python = ">=3.12"
|
|
3
4
|
|
|
4
5
|
[[package]]
|
|
@@ -774,7 +775,7 @@ wheels = [
|
|
|
774
775
|
|
|
775
776
|
[[package]]
|
|
776
777
|
name = "tinyfan"
|
|
777
|
-
version = "0.
|
|
778
|
+
version = "0.2.0"
|
|
778
779
|
source = { editable = "." }
|
|
779
780
|
dependencies = [
|
|
780
781
|
{ name = "croniter" },
|
|
@@ -800,6 +801,7 @@ dev = [
|
|
|
800
801
|
{ name = "mypy" },
|
|
801
802
|
{ name = "pytest" },
|
|
802
803
|
{ name = "ruff" },
|
|
804
|
+
{ name = "types-croniter" },
|
|
803
805
|
{ name = "types-jsonschema" },
|
|
804
806
|
{ name = "types-pyyaml" },
|
|
805
807
|
]
|
|
@@ -829,9 +831,11 @@ requires-dist = [
|
|
|
829
831
|
{ name = "tinyfan", extras = ["pandas"], marker = "extra == 'all'" },
|
|
830
832
|
{ name = "tinyfan", extras = ["pandas"], marker = "extra == 'bigquery'" },
|
|
831
833
|
{ name = "typer-slim", specifier = ">=0.15.1" },
|
|
834
|
+
{ name = "types-croniter", marker = "extra == 'dev'" },
|
|
832
835
|
{ name = "types-jsonschema", marker = "extra == 'dev'" },
|
|
833
836
|
{ name = "types-pyyaml", marker = "extra == 'dev'" },
|
|
834
837
|
]
|
|
838
|
+
provides-extras = ["all", "gcs", "bigquery", "pandas", "dev"]
|
|
835
839
|
|
|
836
840
|
[[package]]
|
|
837
841
|
name = "typer-slim"
|
|
@@ -846,6 +850,15 @@ wheels = [
|
|
|
846
850
|
{ url = "https://files.pythonhosted.org/packages/1f/7b/032ecd581e2170513bb6dc3cdb2581e20fdb94a272bae70fe93f2bca580b/typer_slim-0.15.1-py3-none-any.whl", hash = "sha256:20233cb89938ea3cca633afee10b906a1b0e7c5330f31ed8c55f4f0779efe6df", size = 44968 },
|
|
847
851
|
]
|
|
848
852
|
|
|
853
|
+
[[package]]
|
|
854
|
+
name = "types-croniter"
|
|
855
|
+
version = "5.0.1.20241205"
|
|
856
|
+
source = { registry = "https://pypi.org/simple" }
|
|
857
|
+
sdist = { url = "https://files.pythonhosted.org/packages/77/2f/f3298f148a7983df2a878d53c4a17ef1dd8654a155e11caa8decb7d79670/types_croniter-5.0.1.20241205.tar.gz", hash = "sha256:8a7cb10aa0b487c654a10c14d4e99098c92a5d68ee55c7a92a3df095831a6933", size = 10928 }
|
|
858
|
+
wheels = [
|
|
859
|
+
{ url = "https://files.pythonhosted.org/packages/dc/ec/ff0222b912fdff040a1908ea226f64ff5a1a384a4062a8714eb8b80ea5d9/types_croniter-5.0.1.20241205-py3-none-any.whl", hash = "sha256:e36e992d6a4600ddf510991a20d3273b888ecea5d77a19078348e00775ba54d3", size = 9375 },
|
|
860
|
+
]
|
|
861
|
+
|
|
849
862
|
[[package]]
|
|
850
863
|
name = "types-jsonschema"
|
|
851
864
|
version = "4.23.0.20240813"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|