uptimely-core 0.2.0.dev0__tar.gz → 0.2.0.dev1__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.
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/PKG-INFO +7 -4
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/pyproject.toml +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/readme.md +6 -3
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/__init__.py +13 -13
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/cli/cli.py +9 -10
- uptimely_core-0.2.0.dev1/src/uptimely/cli/common.py +38 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/cli/engine.py +24 -40
- uptimely_core-0.2.0.dev1/src/uptimely/cli/explorer.py +92 -0
- uptimely_core-0.2.0.dev1/src/uptimely/cli/plan.py +18 -0
- uptimely_core-0.2.0.dev1/src/uptimely/cli/project.py +62 -0
- uptimely_core-0.2.0.dev1/src/uptimely/cli/spec.py +39 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/__init__.py +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/callable_node.py +2 -2
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/compiler.py +31 -31
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/execution_graph.py +21 -21
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/plan/models.py +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/contracts.py +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/config.py +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/engine.py +8 -39
- uptimely_core-0.2.0.dev1/src/uptimely/explorer/explorer.py +120 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/explorer/graph_render.py +21 -5
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/explorer/lineage.py +21 -15
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/explorer/plan_render.py +8 -1
- uptimely_core-0.2.0.dev0/src/uptimely/explorer/analytics_render.py → uptimely_core-0.2.0.dev1/src/uptimely/explorer/spec_render.py +32 -58
- uptimely_core-0.2.0.dev1/src/uptimely/mcp/__init__.py +5 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/mcp/server.py +130 -104
- uptimely_core-0.2.0.dev1/src/uptimely/project/__init__.py +67 -0
- uptimely_core-0.2.0.dev1/src/uptimely/project/build.py +623 -0
- uptimely_core-0.2.0.dev1/src/uptimely/project/paths.py +27 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/render.py +3 -3
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/row_context.py +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/__init__.py +10 -10
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/api.py +17 -17
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/catalog.py +8 -8
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/feature_graph/graph.py +14 -16
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/feature_graph/models.py +1 -1
- uptimely_core-0.2.0.dev1/src/uptimely/spec/json/__init__.py +1 -0
- uptimely_core-0.2.0.dev1/src/uptimely/spec/json/codec.py +41 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/model/__init__.py +6 -6
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/model/common.py +4 -4
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/model/dataset.py +2 -2
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/model/functions.py +2 -2
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/model/analytics.py → uptimely_core-0.2.0.dev1/src/uptimely/spec/model/spec.py +7 -7
- uptimely_core-0.2.0.dev1/src/uptimely/spec/python/__init__.py +7 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/conversion.py +27 -28
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/dataset.py +16 -18
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/dimension.py +3 -3
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/entity.py +3 -3
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/feature.py +3 -3
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/mappings.py +4 -4
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/ref.py +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/row_context.py +1 -1
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/python/analytics.py → uptimely_core-0.2.0.dev1/src/uptimely/spec/python/spec.py +12 -12
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/references.py +9 -11
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/resolution.py +5 -5
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/resolved.py +4 -4
- uptimely_core-0.2.0.dev1/src/uptimely/spec/validation/__init__.py +20 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/context.py +12 -12
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/dependencies.py +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/dimensions.py +10 -10
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/errors.py +2 -2
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/functions.py +6 -6
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/mappings.py +16 -16
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/validation/prepared.py +11 -11
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/validation/analytics.py → uptimely_core-0.2.0.dev1/src/uptimely/spec/validation/spec.py +4 -6
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/storage.py +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/base.html.j2 +14 -5
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/execution/data_lineage.html.j2 +2 -2
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/icons.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/index.html.j2 +10 -10
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/plan/index.html.j2 +1 -1
- uptimely_core-0.2.0.dev1/src/uptimely/templates/spec/datasets.html.j2 +5 -0
- uptimely_core-0.2.0.dev1/src/uptimely/templates/spec/dimensions.html.j2 +5 -0
- uptimely_core-0.2.0.dev1/src/uptimely/templates/spec/entities.html.j2 +5 -0
- uptimely_core-0.2.0.dev1/src/uptimely/templates/spec/features.html.j2 +5 -0
- uptimely_core-0.2.0.dev1/src/uptimely/templates/spec/functions.html.j2 +5 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/index.html.j2 +7 -7
- uptimely_core-0.2.0.dev1/src/uptimely/templates/spec/overview.html.j2 +5 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/section_header.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/sections/dataset_list.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/sections/dimensions.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/sections/entities.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/sections/entity_list.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/sections/functions.html.j2 +1 -1
- {uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics → uptimely_core-0.2.0.dev1/src/uptimely/templates/spec}/sections/overview.html.j2 +4 -4
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/json/__init__.py +0 -1
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/json/codec.py +0 -42
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/python/__init__.py +0 -7
- uptimely_core-0.2.0.dev0/src/uptimely/analytics/validation/__init__.py +0 -20
- uptimely_core-0.2.0.dev0/src/uptimely/cli/analytics.py +0 -97
- uptimely_core-0.2.0.dev0/src/uptimely/cli/common.py +0 -49
- uptimely_core-0.2.0.dev0/src/uptimely/cli/explorer.py +0 -192
- uptimely_core-0.2.0.dev0/src/uptimely/cli/plan.py +0 -64
- uptimely_core-0.2.0.dev0/src/uptimely/explorer/explorer.py +0 -127
- uptimely_core-0.2.0.dev0/src/uptimely/mcp/__init__.py +0 -5
- uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics/datasets.html.j2 +0 -5
- uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics/dimensions.html.j2 +0 -5
- uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics/entities.html.j2 +0 -5
- uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics/features.html.j2 +0 -5
- uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics/functions.html.j2 +0 -5
- uptimely_core-0.2.0.dev0/src/uptimely/templates/analytics/overview.html.j2 +0 -5
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/LICENSE +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/cli/__init__.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/cli/examples.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/plan/__init__.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/plan/serialization.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/__init__.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/backend.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/bindings.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/dataframe.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/result.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/engine/state.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/entrypoint.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/explorer/__init__.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/py.typed +0 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/feature_graph/__init__.py +0 -0
- {uptimely_core-0.2.0.dev0/src/uptimely/analytics → uptimely_core-0.2.0.dev1/src/uptimely/spec}/python/bind.py +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/base.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/feature_graph.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/feature_graph_shared.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/feature_renderer_2d.js.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/feature_renderer_3d.js.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/view_controller.js.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/graph/view_controls.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/plan/callable_graph.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/plan/callable_renderer_2d.js.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/plan/graph.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/plan/overview.html.j2 +0 -0
- {uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/templates/plan/stages.html.j2 +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uptimely-core
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev1
|
|
4
4
|
Summary: Manage data-driven numerical analytics with complex dependencies at scale
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -63,7 +63,9 @@ With pip:
|
|
|
63
63
|
|
|
64
64
|
```sh
|
|
65
65
|
pip install uptimely-core
|
|
66
|
-
uptimely examples download
|
|
66
|
+
uptimely examples download --output examples
|
|
67
|
+
uptimely project build --project-root examples/pump_analytics
|
|
68
|
+
uptimely engine run --project-root examples/pump_analytics
|
|
67
69
|
uptimely explorer serve --project-root examples/pump_analytics
|
|
68
70
|
```
|
|
69
71
|
|
|
@@ -71,11 +73,12 @@ With Poetry, from your Poetry project:
|
|
|
71
73
|
|
|
72
74
|
```sh
|
|
73
75
|
poetry add uptimely-core
|
|
74
|
-
poetry run uptimely examples download
|
|
76
|
+
poetry run uptimely examples download --output examples
|
|
77
|
+
poetry run uptimely project build --project-root examples/pump_analytics
|
|
78
|
+
poetry run uptimely engine run --project-root examples/pump_analytics
|
|
75
79
|
poetry run uptimely explorer serve --project-root examples/pump_analytics
|
|
76
80
|
```
|
|
77
81
|
|
|
78
|
-
More use cases in [examples](examples/README.md). Explore the examples files, generated resources and modify for the needs of your own project.
|
|
79
82
|
|
|
80
83
|
## Documentation
|
|
81
84
|
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "uptimely-core"
|
|
7
|
-
version = "0.2.0.
|
|
7
|
+
version = "0.2.0.dev1"
|
|
8
8
|
description = "Manage data-driven numerical analytics with complex dependencies at scale"
|
|
9
9
|
authors = [{ name = "Mikael Ahonen", email = "mikael.ahonen@uptimely.ai" }]
|
|
10
10
|
license = "MIT"
|
|
@@ -33,7 +33,9 @@ With pip:
|
|
|
33
33
|
|
|
34
34
|
```sh
|
|
35
35
|
pip install uptimely-core
|
|
36
|
-
uptimely examples download
|
|
36
|
+
uptimely examples download --output examples
|
|
37
|
+
uptimely project build --project-root examples/pump_analytics
|
|
38
|
+
uptimely engine run --project-root examples/pump_analytics
|
|
37
39
|
uptimely explorer serve --project-root examples/pump_analytics
|
|
38
40
|
```
|
|
39
41
|
|
|
@@ -41,11 +43,12 @@ With Poetry, from your Poetry project:
|
|
|
41
43
|
|
|
42
44
|
```sh
|
|
43
45
|
poetry add uptimely-core
|
|
44
|
-
poetry run uptimely examples download
|
|
46
|
+
poetry run uptimely examples download --output examples
|
|
47
|
+
poetry run uptimely project build --project-root examples/pump_analytics
|
|
48
|
+
poetry run uptimely engine run --project-root examples/pump_analytics
|
|
45
49
|
poetry run uptimely explorer serve --project-root examples/pump_analytics
|
|
46
50
|
```
|
|
47
51
|
|
|
48
|
-
More use cases in [examples](examples/README.md). Explore the examples files, generated resources and modify for the needs of your own project.
|
|
49
52
|
|
|
50
53
|
## Documentation
|
|
51
54
|
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
"""Public package namespace for uptimely."""
|
|
2
2
|
|
|
3
|
-
from .
|
|
4
|
-
|
|
3
|
+
from .compiler import CallableGraph, CallableNode, Compiler, ExecutionPlan
|
|
4
|
+
from .engine import Engine
|
|
5
|
+
from .spec import (
|
|
5
6
|
Call,
|
|
6
7
|
Dimension,
|
|
7
8
|
Entity,
|
|
8
9
|
FeatureGraph,
|
|
9
10
|
Function,
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
PreparedSpec,
|
|
12
|
+
PythonSpec,
|
|
13
|
+
Spec,
|
|
12
14
|
SubGraph,
|
|
13
15
|
from_python,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
load_spec,
|
|
17
|
+
prepare_spec,
|
|
16
18
|
write_document,
|
|
17
19
|
)
|
|
18
|
-
from .compiler import CallableGraph, CallableNode, Compiler, ExecutionPlan
|
|
19
|
-
from .engine import Engine
|
|
20
20
|
|
|
21
21
|
__all__ = [
|
|
22
|
-
"
|
|
22
|
+
"Spec",
|
|
23
23
|
"Call",
|
|
24
24
|
"CallableGraph",
|
|
25
25
|
"CallableNode",
|
|
@@ -28,11 +28,11 @@ __all__ = [
|
|
|
28
28
|
"Entity",
|
|
29
29
|
"ExecutionPlan",
|
|
30
30
|
"Function",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
31
|
+
"PythonSpec",
|
|
32
|
+
"PreparedSpec",
|
|
33
33
|
"from_python",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
34
|
+
"load_spec",
|
|
35
|
+
"prepare_spec",
|
|
36
36
|
"write_document",
|
|
37
37
|
"SubGraph",
|
|
38
38
|
"FeatureGraph",
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
-
from uptimely.cli import
|
|
5
|
+
from uptimely.cli import engine, examples, explorer, project, spec
|
|
6
6
|
|
|
7
7
|
download_examples = examples.download_examples
|
|
8
|
-
build_explorer = explorer.build_explorer
|
|
9
8
|
serve_explorer = explorer.serve_explorer
|
|
10
9
|
|
|
11
10
|
|
|
@@ -15,22 +14,22 @@ def main() -> None:
|
|
|
15
14
|
commands = parser.add_subparsers(dest="command", required=True)
|
|
16
15
|
examples.configure_parser(commands.add_parser("examples", help="Manage example projects"))
|
|
17
16
|
explorer.configure_parser(
|
|
18
|
-
commands.add_parser("explorer", help="Explore
|
|
17
|
+
commands.add_parser("explorer", help="Explore spec, lineage, and execution plans")
|
|
19
18
|
)
|
|
20
|
-
|
|
21
|
-
commands.add_parser("
|
|
19
|
+
spec.configure_parser(
|
|
20
|
+
commands.add_parser("spec", help="Inspect specs and feature dependencies")
|
|
22
21
|
)
|
|
23
|
-
|
|
22
|
+
project.configure_parser(commands.add_parser("project", help="Build project resources"))
|
|
24
23
|
engine.configure_parser(commands.add_parser("engine", help="Run analytics workflows"))
|
|
25
24
|
args = parser.parse_args()
|
|
26
25
|
if args.command == "examples":
|
|
27
26
|
examples.run(args, parser)
|
|
28
27
|
elif args.command == "explorer":
|
|
29
28
|
explorer.run(args, parser)
|
|
30
|
-
elif args.command == "
|
|
31
|
-
|
|
32
|
-
elif args.command == "
|
|
33
|
-
|
|
29
|
+
elif args.command == "spec":
|
|
30
|
+
spec.run(args, parser)
|
|
31
|
+
elif args.command == "project":
|
|
32
|
+
project.run(args, parser)
|
|
34
33
|
else:
|
|
35
34
|
engine.run(args, parser)
|
|
36
35
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Shared project paths and spec loading for CLI commands."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import pathlib
|
|
5
|
+
|
|
6
|
+
from uptimely import spec
|
|
7
|
+
from uptimely.project.build import prepare_project_root
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def configure_project_arguments(parser: argparse.ArgumentParser) -> None:
|
|
11
|
+
"""Add spec, import-root, feature-selection, and diagnostic options."""
|
|
12
|
+
parser.add_argument(
|
|
13
|
+
"--spec",
|
|
14
|
+
type=pathlib.Path,
|
|
15
|
+
help="Spec JSON to inspect (default: spec from the active project build)",
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument(
|
|
18
|
+
"--project-root",
|
|
19
|
+
type=pathlib.Path,
|
|
20
|
+
help="Root for importing function entrypoints and resolving default paths",
|
|
21
|
+
)
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--features", nargs="+", help="Select output features and their dependencies"
|
|
24
|
+
)
|
|
25
|
+
parser.add_argument("--verbose", action="store_true", help="Print diagnostic details")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def project_path(
|
|
29
|
+
path: pathlib.Path | None, project_root: pathlib.Path | None, default: pathlib.Path
|
|
30
|
+
) -> pathlib.Path:
|
|
31
|
+
"""Resolve a default beneath the project root, preserving explicit paths."""
|
|
32
|
+
return path if path is not None else (project_root or pathlib.Path()) / default
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def load_spec(path: pathlib.Path, project_root: pathlib.Path) -> spec.Spec:
|
|
36
|
+
"""Load a spec document with project functions on the import path."""
|
|
37
|
+
prepare_project_root(project_root)
|
|
38
|
+
return spec.load_spec(path)
|
|
@@ -7,8 +7,8 @@ import typing
|
|
|
7
7
|
import pydantic
|
|
8
8
|
|
|
9
9
|
from uptimely import engine as engine_module
|
|
10
|
+
from uptimely import project
|
|
10
11
|
from uptimely.cli import common, plan
|
|
11
|
-
from uptimely.compiler import plan as plan_module
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class EngineSettings(pydantic.BaseModel):
|
|
@@ -23,68 +23,52 @@ class EngineSettings(pydantic.BaseModel):
|
|
|
23
23
|
def configure_parser(parser: argparse.ArgumentParser) -> None:
|
|
24
24
|
"""Configure the engine run action."""
|
|
25
25
|
actions = parser.add_subparsers(dest="action", required=True)
|
|
26
|
-
execute = actions.add_parser("run", help="
|
|
27
|
-
common.configure_project_arguments(execute)
|
|
26
|
+
execute = actions.add_parser("run", help="Execute the active project's saved build")
|
|
28
27
|
execute.add_argument(
|
|
29
|
-
"--
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
help="Compile analytics first (default: true); false loads --plan",
|
|
28
|
+
"--project-root",
|
|
29
|
+
type=pathlib.Path,
|
|
30
|
+
help="Project root containing the active build and function entrypoints",
|
|
33
31
|
)
|
|
34
32
|
execute.add_argument(
|
|
35
|
-
"--
|
|
36
|
-
type=pathlib.Path,
|
|
37
|
-
help=(
|
|
38
|
-
"Saved plan JSON (default: _generated/compile/execution_plan.json under --project-root)"
|
|
39
|
-
),
|
|
33
|
+
"--verbose", action="store_true", help="Print execution stages and dataset details"
|
|
40
34
|
)
|
|
41
35
|
execute.add_argument(
|
|
42
36
|
"--config",
|
|
43
37
|
type=pathlib.Path,
|
|
44
38
|
help=(
|
|
45
39
|
"Backend settings and runtime bindings "
|
|
46
|
-
"(default:
|
|
40
|
+
f"(default: {project.ENGINE_CONFIG_FILE} under --project-root)"
|
|
47
41
|
),
|
|
48
42
|
)
|
|
49
43
|
|
|
50
44
|
|
|
51
45
|
def run(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
|
|
52
|
-
"""Execute
|
|
53
|
-
if args.compile == "false" and (args.analytics is not None or args.features is not None):
|
|
54
|
-
parser.error("--analytics and --features require --compile true")
|
|
55
|
-
if args.compile == "true" and args.plan is not None:
|
|
56
|
-
parser.error("--plan requires --compile false")
|
|
46
|
+
"""Execute the active saved plan and report failures explicitly."""
|
|
57
47
|
root = args.project_root or pathlib.Path.cwd()
|
|
58
|
-
config = common.project_path(args.config, args.project_root,
|
|
59
|
-
analytics_definition = common.project_path(
|
|
60
|
-
args.analytics, args.project_root, common.GENERATED_ANALYTICS_PATH
|
|
61
|
-
)
|
|
62
|
-
plan_path = common.project_path(args.plan, args.project_root, common.GENERATED_PLAN_PATH)
|
|
48
|
+
config = common.project_path(args.config, args.project_root, project.ENGINE_CONFIG_FILE)
|
|
63
49
|
try:
|
|
64
50
|
common.prepare_project_root(root)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if result.failures:
|
|
75
|
-
failures = "; ".join(result.failures.values())
|
|
76
|
-
raise RuntimeError(f"Engine flow failed: {failures}")
|
|
51
|
+
with project.read_build_bundle(root) as bundle:
|
|
52
|
+
settings = EngineSettings.model_validate_json(config.read_text(encoding="utf-8"))
|
|
53
|
+
execution_plan = bundle.execution_plan
|
|
54
|
+
result = engine_module.Engine(
|
|
55
|
+
execution_plan, config=settings.backend, bind=settings.bind
|
|
56
|
+
).execute()
|
|
57
|
+
if result.failures:
|
|
58
|
+
failures = "; ".join(result.failures.values())
|
|
59
|
+
raise RuntimeError(f"Engine flow failed: {failures}")
|
|
77
60
|
except (OSError, ValueError, ImportError, AttributeError, TypeError, RuntimeError) as error:
|
|
78
61
|
parser.exit(1, f"uptimely: error: {error}\n")
|
|
79
62
|
calculated_features = sorted({feature_id for _, _, feature_id in result.calculated_outputs})
|
|
63
|
+
scope = (
|
|
64
|
+
"all features"
|
|
65
|
+
if bundle.manifest.features is None
|
|
66
|
+
else f"selected features: {', '.join(bundle.manifest.features)}"
|
|
67
|
+
)
|
|
80
68
|
print("Engine completed the flow")
|
|
69
|
+
print(f"Build scope: {scope}")
|
|
81
70
|
print(f"{len(execution_plan.callables)} callables")
|
|
82
71
|
print("Calculated features: " + ", ".join(calculated_features))
|
|
83
|
-
print(
|
|
84
|
-
f"Analytics: {analytics_definition}"
|
|
85
|
-
if args.compile == "true"
|
|
86
|
-
else f"Execution plan: {plan_path}"
|
|
87
|
-
)
|
|
88
72
|
if args.verbose:
|
|
89
73
|
plan.print_stages(execution_plan)
|
|
90
74
|
print("\nDataset registry")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Command-line tools for building and serving the analytics explorer."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import functools
|
|
5
|
+
import pathlib
|
|
6
|
+
from http import server as http_server
|
|
7
|
+
|
|
8
|
+
from uptimely import project
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def serve_explorer(
|
|
12
|
+
directory: pathlib.Path,
|
|
13
|
+
host: str = "127.0.0.1",
|
|
14
|
+
port: int = 8001,
|
|
15
|
+
scope: str = "all features",
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Serve a saved analytics explorer website for local preview.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
directory: Saved website directory containing an index.html file.
|
|
21
|
+
host: Address to bind; defaults to localhost.
|
|
22
|
+
port: TCP port; defaults to 8001. Zero selects an available port.
|
|
23
|
+
scope: Human-readable scope of the saved execution plan.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
NotADirectoryError: The website directory does not exist or is not a directory.
|
|
27
|
+
FileNotFoundError: The website index is missing.
|
|
28
|
+
ValueError: The port is outside the valid TCP range.
|
|
29
|
+
OSError: The server cannot bind to the requested address.
|
|
30
|
+
"""
|
|
31
|
+
directory = directory.resolve()
|
|
32
|
+
if not directory.is_dir():
|
|
33
|
+
raise NotADirectoryError(f"Website directory does not exist: {directory}")
|
|
34
|
+
index = directory / project.EXPLORER_INDEX_FILE.name
|
|
35
|
+
if not index.is_file():
|
|
36
|
+
raise FileNotFoundError(
|
|
37
|
+
f"Website index not found: {index}. Generate it with 'uptimely project build'."
|
|
38
|
+
)
|
|
39
|
+
if not 0 <= port <= 65535:
|
|
40
|
+
raise ValueError("Port must be between 0 and 65535.")
|
|
41
|
+
handler = functools.partial(http_server.SimpleHTTPRequestHandler, directory=str(directory))
|
|
42
|
+
with http_server.ThreadingHTTPServer((host, port), handler) as server:
|
|
43
|
+
print(
|
|
44
|
+
f"Serving analytics explorer from {directory} at "
|
|
45
|
+
f"http://{host}:{server.server_port}/ (build scope: {scope}; Ctrl+C to stop)",
|
|
46
|
+
flush=True,
|
|
47
|
+
)
|
|
48
|
+
try:
|
|
49
|
+
server.serve_forever()
|
|
50
|
+
except KeyboardInterrupt:
|
|
51
|
+
print("\nSpec explorer server stopped.")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _port(value: str) -> int:
|
|
55
|
+
"""Parse a valid TCP port for the CLI."""
|
|
56
|
+
try:
|
|
57
|
+
port = int(value)
|
|
58
|
+
except ValueError as error:
|
|
59
|
+
raise argparse.ArgumentTypeError("Port must be an integer.") from error
|
|
60
|
+
if not 0 <= port <= 65535:
|
|
61
|
+
raise argparse.ArgumentTypeError("Port must be between 0 and 65535.")
|
|
62
|
+
return port
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def configure_parser(parser: argparse.ArgumentParser) -> None:
|
|
66
|
+
"""Configure the Explorer serve action."""
|
|
67
|
+
actions = parser.add_subparsers(dest="action", required=True)
|
|
68
|
+
serve = actions.add_parser("serve", help="Serve the active build's saved website")
|
|
69
|
+
serve.add_argument(
|
|
70
|
+
"--project-root",
|
|
71
|
+
type=pathlib.Path,
|
|
72
|
+
help="Project root containing the active build",
|
|
73
|
+
)
|
|
74
|
+
serve.add_argument("--host", default="127.0.0.1", help="Bind address (default: 127.0.0.1)")
|
|
75
|
+
serve.add_argument(
|
|
76
|
+
"--port", type=_port, default=8001, help="TCP port (default: 8001; 0 selects a free port)"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def run(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
|
|
81
|
+
"""Serve the active build's validated, saved Explorer website."""
|
|
82
|
+
project_root = (args.project_root or pathlib.Path.cwd()).resolve()
|
|
83
|
+
try:
|
|
84
|
+
with project.read_build_bundle(project_root) as bundle:
|
|
85
|
+
scope = (
|
|
86
|
+
"all features"
|
|
87
|
+
if bundle.manifest.features is None
|
|
88
|
+
else f"selected features: {', '.join(bundle.manifest.features)}"
|
|
89
|
+
)
|
|
90
|
+
serve_explorer(bundle.explorer_path, args.host, args.port, scope)
|
|
91
|
+
except (OSError, ValueError, RuntimeError) as error:
|
|
92
|
+
parser.exit(1, f"uptimely: error: {error}\n")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Display execution plan stages in the CLI."""
|
|
2
|
+
|
|
3
|
+
from uptimely.compiler import plan as plan_module
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def print_stages(plan: plan_module.ExecutionPlan) -> None:
|
|
7
|
+
"""Print execution stages and their function dependencies."""
|
|
8
|
+
callables_by_id = {callable.id: callable for callable in plan.callables}
|
|
9
|
+
print("\nExecution stages")
|
|
10
|
+
for stage_number, stage in enumerate(plan.execution_stages, 1):
|
|
11
|
+
print(f"Stage {stage_number}")
|
|
12
|
+
for callable in stage:
|
|
13
|
+
dependencies = [
|
|
14
|
+
callables_by_id[dependency_id].function_id
|
|
15
|
+
for dependency_id in callable.dependency_ids
|
|
16
|
+
]
|
|
17
|
+
suffix = f" <- [{', '.join(dependencies)}]" if dependencies else ""
|
|
18
|
+
print(f" {callable.function_id}({callable.entity_id}) -> {callable.output}{suffix}")
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Command-line orchestration for building generated project resources."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import pathlib
|
|
5
|
+
|
|
6
|
+
from uptimely.project import build as project_build
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def configure_parser(parser: argparse.ArgumentParser) -> None:
|
|
10
|
+
"""Configure the project build action."""
|
|
11
|
+
actions = parser.add_subparsers(dest="action", required=True)
|
|
12
|
+
build = actions.add_parser(
|
|
13
|
+
"build",
|
|
14
|
+
help="Build and publish a complete project bundle without running workflows",
|
|
15
|
+
)
|
|
16
|
+
source = build.add_mutually_exclusive_group()
|
|
17
|
+
source.add_argument(
|
|
18
|
+
"--entrypoint",
|
|
19
|
+
metavar="MODULE:ATTRIBUTE",
|
|
20
|
+
help="Importable module and attribute containing a PythonSpec instance",
|
|
21
|
+
)
|
|
22
|
+
source.add_argument(
|
|
23
|
+
"--spec",
|
|
24
|
+
type=pathlib.Path,
|
|
25
|
+
help="Source spec JSON path (overrides standard source discovery)",
|
|
26
|
+
)
|
|
27
|
+
build.add_argument(
|
|
28
|
+
"--project-root",
|
|
29
|
+
type=pathlib.Path,
|
|
30
|
+
help="Root added to the import path and used to resolve the output bundle",
|
|
31
|
+
)
|
|
32
|
+
build.add_argument(
|
|
33
|
+
"--features",
|
|
34
|
+
nargs="+",
|
|
35
|
+
metavar="FEATURE",
|
|
36
|
+
help="Select output features and their dependencies",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def run(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
|
|
41
|
+
"""Build and publish a complete project bundle."""
|
|
42
|
+
root = args.project_root or pathlib.Path.cwd()
|
|
43
|
+
try:
|
|
44
|
+
bundle = project_build.build_project(
|
|
45
|
+
root,
|
|
46
|
+
entrypoint=args.entrypoint,
|
|
47
|
+
source=args.spec,
|
|
48
|
+
features=args.features,
|
|
49
|
+
)
|
|
50
|
+
except (
|
|
51
|
+
project_build.BuildLockError,
|
|
52
|
+
project_build.ProjectBuildError,
|
|
53
|
+
OSError,
|
|
54
|
+
ValueError,
|
|
55
|
+
) as error:
|
|
56
|
+
parser.exit(1, f"uptimely: error: {error}\n")
|
|
57
|
+
scope = (
|
|
58
|
+
"all features" if bundle.manifest.features is None else ", ".join(bundle.manifest.features)
|
|
59
|
+
)
|
|
60
|
+
print(f"Build scope: {scope}")
|
|
61
|
+
print(f"Build bundle: {bundle.root}")
|
|
62
|
+
print(f"Compiled {len(bundle.execution_plan.callables)} callables")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Command-line tools for inspecting spec features."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import pathlib
|
|
5
|
+
|
|
6
|
+
from uptimely import project
|
|
7
|
+
from uptimely.cli import common
|
|
8
|
+
from uptimely.spec import feature_graph
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def configure_parser(parser: argparse.ArgumentParser) -> None:
|
|
12
|
+
"""Configure spec feature-graph inspection."""
|
|
13
|
+
actions = parser.add_subparsers(dest="action", required=True)
|
|
14
|
+
graph = actions.add_parser("feature-graph", help="Inspect feature dependencies")
|
|
15
|
+
common.configure_project_arguments(graph)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def run(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
|
|
19
|
+
"""Print feature graph summaries and trees."""
|
|
20
|
+
project_root = args.project_root or pathlib.Path.cwd()
|
|
21
|
+
try:
|
|
22
|
+
if args.spec is None:
|
|
23
|
+
with project.read_build_bundle(project_root) as bundle:
|
|
24
|
+
spec_definition = common.load_spec(bundle.spec_path, project_root)
|
|
25
|
+
else:
|
|
26
|
+
spec_definition = common.load_spec(args.spec, project_root)
|
|
27
|
+
graph = feature_graph.FeatureGraph(spec_definition)
|
|
28
|
+
subset = graph.subset(args.features) if args.features is not None else None
|
|
29
|
+
print(f"Feature graph: {len(graph.feature_names)} features")
|
|
30
|
+
if subset is not None:
|
|
31
|
+
print(f"Selected feature subset: {len(subset.feature_names)} features")
|
|
32
|
+
if args.verbose:
|
|
33
|
+
print("\nFeature graph")
|
|
34
|
+
graph.print_graph()
|
|
35
|
+
if subset is not None:
|
|
36
|
+
print("\nSelected feature subset")
|
|
37
|
+
subset.print_graph()
|
|
38
|
+
except (OSError, ValueError, ImportError, AttributeError, TypeError, RuntimeError) as error:
|
|
39
|
+
parser.exit(1, f"uptimely: error: {error}\n")
|
{uptimely_core-0.2.0.dev0 → uptimely_core-0.2.0.dev1}/src/uptimely/compiler/callable_node.py
RENAMED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
|
|
5
|
-
from uptimely import
|
|
5
|
+
from uptimely import render, row_context, spec
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -17,7 +17,7 @@ class CallableNode:
|
|
|
17
17
|
mapping_id: str | None = None
|
|
18
18
|
output_features: tuple[str, ...] = ()
|
|
19
19
|
args: dict[str, object] = dataclasses.field(default_factory=dict, compare=False, hash=False)
|
|
20
|
-
callable:
|
|
20
|
+
callable: spec.Call | None = dataclasses.field(default=None, compare=False, hash=False)
|
|
21
21
|
row_context: row_context.RowContext | None = dataclasses.field(
|
|
22
22
|
default=None, compare=False, hash=False
|
|
23
23
|
)
|