mayutils 2.0.0__tar.gz → 3.0.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.
- {mayutils-2.0.0 → mayutils-3.0.0}/PKG-INFO +4 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/README.md +2 -2
- {mayutils-2.0.0 → mayutils-3.0.0}/pyproject.toml +3 -2
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/__init__.py +5 -5
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/data/live.py +100 -57
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/data/queries/__init__.py +71 -47
- mayutils-3.0.0/src/mayutils/data/queries/templating.py +223 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/data/read.py +111 -55
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/databases.py +27 -6
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/filesystem/metadata.py +3 -2
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/filesystem/roots.py +1 -1
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/logging.py +1 -1
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/clearing.py +3 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/files.py +33 -25
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/types.py +2 -5
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/utilities.py +9 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/oauth.py +35 -9
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/secrets.py +3 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/webdrivers.py +11 -6
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/export/nbconvert.py +11 -8
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/export/quarto.py +6 -5
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/cloud/google.py +7 -4
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/code/notebooks/jupyter.py +39 -28
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/data/__init__.py +23 -7
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/data/snowflake/__init__.py +8 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/__init__.py +11 -7
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/csv/__init__.py +23 -4
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/feather/__init__.py +27 -7
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/parquet/__init__.py +28 -6
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/pdf/__init__.py +5 -5
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/pptx/__init__.py +2 -2
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/pptx/markdown.py +2 -2
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/sheets/__init__.py +12 -7
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/slides/__init__.py +8 -8
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/tex/__init__.py +3 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/xlsx/__init__.py +49 -16
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/streamlit/__init__.py +94 -24
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/analytics/attribution.py +3 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/colours.py +90 -14
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/__init__.py +17 -18
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/backends.py +17 -5
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/pandas/__init__.py +2 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/pandas/dataframes.py +103 -12
- mayutils-3.0.0/src/mayutils/objects/dataframes/polars/__init__.py +34 -0
- mayutils-3.0.0/src/mayutils/objects/dataframes/polars/dataframes.py +126 -0
- mayutils-3.0.0/src/mayutils/objects/dataframes/temporal.py +246 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/hashing.py +5 -4
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/types.py +7 -4
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/scripts/generate_plotly_stubs.py +3 -1
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/scripts/refresh_stubs.py +15 -11
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/console.py +68 -7
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/combine.py +4 -4
- mayutils-3.0.0/src/mayutils/visualisation/graphs/plotly/__init__.py +148 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/charts/__init__.py +71 -14
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/charts/plot.py +4 -2
- mayutils-3.0.0/src/mayutils/visualisation/graphs/plotly/traces/__init__.py +91 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/null.py +2 -1
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/utilities.py +5 -2
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/utilities.py +10 -3
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/notebook.py +7 -7
- mayutils-2.0.0/src/mayutils/objects/dataframes/polars/__init__.py +0 -30
- mayutils-2.0.0/src/mayutils/objects/dataframes/polars/dataframes.py +0 -26
- mayutils-2.0.0/src/mayutils/visualisation/graphs/plotly/__init__.py +0 -69
- mayutils-2.0.0/src/mayutils/visualisation/graphs/plotly/traces/__init__.py +0 -25
- {mayutils-2.0.0 → mayutils-3.0.0}/LICENSE +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/core/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/core/constants.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/core/extras.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/data/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/data/cache/.gitkeep +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/benchmarking.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/filesystem/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/filesystem/encoding.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/filesystem/reading.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/decorators.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/decorators.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/environment/memoisation/memory.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/export/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/export/html.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/export/images.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/cloud/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/code/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/code/notebooks/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/code/tui/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/code/tui/textual.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/code/tui/tuiplot.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/docs/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/docx/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/markdown/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/filetypes/pptx/units.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/streamlit/css/default.css +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/streamlit/images/.gitkeep +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/streamlit/views/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/streamlit/views/forbidden.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/interfaces/websites/streamlit/views/login.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/analytics/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/machine_learning/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/numba.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/numpy.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/mathematics/statistics/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/classes.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/dask/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/modin/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/pandas/index.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/pandas/series.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/pandas/stylers.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/pyarrow/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dataframes/snowflake/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/datetime/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/datetime/constants.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/datetime/datetime.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/datetime/interval.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/datetime/timezone.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/datetime/traveller.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/decorators.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/dictionaries.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/functions.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/numbers.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/paths.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/strings.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/objects/versions.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/py.typed +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/scripts/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/scripts/clear_cache.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/testing/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/matplotlib/__init__.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/matplotlib/templates.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/charts/plot.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/charts/subplot.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/charts/subplot.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/templates.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/ecdf.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/ecdf.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/icicle.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/icicle.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/kde.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/kde.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/line.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/line.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/mesh3d.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/mesh3d.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/null.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/scatter.py +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/scatter.pyi +0 -0
- {mayutils-2.0.0 → mayutils-3.0.0}/src/mayutils/visualisation/graphs/plotly/traces/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: mayutils
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Utilities for Python from Mayuran Visakan
|
|
5
5
|
Author: Mayuran Visakan
|
|
6
6
|
Author-email: Mayuran Visakan <mayuran.k.v@gmail.com>
|
|
@@ -25,6 +25,7 @@ License: MIT License
|
|
|
25
25
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
26
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
27
|
SOFTWARE.
|
|
28
|
+
Requires-Dist: jinja2>=3.1
|
|
28
29
|
Requires-Dist: pydantic>=2.11.7
|
|
29
30
|
Requires-Dist: pydantic-settings>=2.10.1
|
|
30
31
|
Requires-Dist: mayutils[async,cli,console,dataframes,datetime,filesystem,financials,google,mathematics,microsoft,notebook,numerics,pandas,pdf,plotting,secrets,snowflake,sql,statistics,streamlit,tui,web] ; extra == 'all'
|
|
@@ -150,7 +151,7 @@ Description-Content-Type: text/markdown
|
|
|
150
151
|
|
|
151
152
|
# mayutils
|
|
152
153
|
|
|
153
|
-
[](https://github.com/mayurankv/mayutils/actions/workflows/ci.yaml) [](https://pypi.org/project/mayutils/) [](https://www.python.org/downloads/) [](./LICENSE) [](https://mayurankv.github.io/mayutils/)
|
|
154
155
|
|
|
155
156
|
Utilities for Python — plotting helpers, dataframe adapters, Snowflake/SQL glue, PowerPoint/PDF export, notebook display tweaks, OAuth helpers, and a fistful of miscellaneous object helpers. Heavy dependencies are grouped behind extras so the core install stays small.
|
|
156
157
|
|
|
@@ -206,7 +207,7 @@ Full details: [docs/guides/dependency-groups.md](docs/guides/dependency-groups.m
|
|
|
206
207
|
- [Documentation](docs/guides/documentation.md)
|
|
207
208
|
- [Roadmap](docs/roadmap.md) — translated from the legacy `.todo` file
|
|
208
209
|
- [Changelog](docs/changelog.md)
|
|
209
|
-
- [API Reference](https://
|
|
210
|
+
- [API Reference](https://mayurankv.github.io/mayutils/reference/) — auto-generated from docstrings
|
|
210
211
|
|
|
211
212
|
## Contributing
|
|
212
213
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mayutils
|
|
2
2
|
|
|
3
|
-
[](https://github.com/mayurankv/mayutils/actions/workflows/ci.yaml) [](https://pypi.org/project/mayutils/) [](https://www.python.org/downloads/) [](./LICENSE) [](https://mayurankv.github.io/mayutils/)
|
|
4
4
|
|
|
5
5
|
Utilities for Python — plotting helpers, dataframe adapters, Snowflake/SQL glue, PowerPoint/PDF export, notebook display tweaks, OAuth helpers, and a fistful of miscellaneous object helpers. Heavy dependencies are grouped behind extras so the core install stays small.
|
|
6
6
|
|
|
@@ -56,7 +56,7 @@ Full details: [docs/guides/dependency-groups.md](docs/guides/dependency-groups.m
|
|
|
56
56
|
- [Documentation](docs/guides/documentation.md)
|
|
57
57
|
- [Roadmap](docs/roadmap.md) — translated from the legacy `.todo` file
|
|
58
58
|
- [Changelog](docs/changelog.md)
|
|
59
|
-
- [API Reference](https://
|
|
59
|
+
- [API Reference](https://mayurankv.github.io/mayutils/reference/) — auto-generated from docstrings
|
|
60
60
|
|
|
61
61
|
## Contributing
|
|
62
62
|
|
|
@@ -36,6 +36,7 @@ testing = ["pytest>=8.4.2"]
|
|
|
36
36
|
[project]
|
|
37
37
|
authors = [{email = "mayuran.k.v@gmail.com", name = "Mayuran Visakan"}]
|
|
38
38
|
dependencies = [
|
|
39
|
+
"jinja2>=3.1",
|
|
39
40
|
"pydantic>=2.11.7",
|
|
40
41
|
"pydantic-settings>=2.10.1"
|
|
41
42
|
]
|
|
@@ -45,7 +46,7 @@ maintainers = [{email = "mayuran.k.v@gmail.com", name = "Mayuran Visakan"}]
|
|
|
45
46
|
name = "mayutils"
|
|
46
47
|
readme = "README.md"
|
|
47
48
|
requires-python = ">=3.13,<4.0"
|
|
48
|
-
version = "
|
|
49
|
+
version = "3.0.0"
|
|
49
50
|
|
|
50
51
|
[project.optional-dependencies]
|
|
51
52
|
all = [
|
|
@@ -208,7 +209,7 @@ pre_bump_hooks = [
|
|
|
208
209
|
]
|
|
209
210
|
tag_format = "v$version"
|
|
210
211
|
update_changelog_on_bump = true
|
|
211
|
-
version = "
|
|
212
|
+
version = "3.0.0"
|
|
212
213
|
version_files = ["pyproject.toml:^version"]
|
|
213
214
|
|
|
214
215
|
[tool.mdformat]
|
|
@@ -44,15 +44,15 @@ def setup(
|
|
|
44
44
|
>>> from mayutils import setup
|
|
45
45
|
>>> setup(logging=False, plotly=False, notebook=False, pandas=False)
|
|
46
46
|
"""
|
|
47
|
-
from mayutils.core.extras import format_missing_extra_hint
|
|
48
|
-
from mayutils.environment.logging import Logger
|
|
47
|
+
from mayutils.core.extras import format_missing_extra_hint
|
|
48
|
+
from mayutils.environment.logging import Logger
|
|
49
49
|
|
|
50
50
|
if logging:
|
|
51
51
|
Logger.configure()
|
|
52
52
|
|
|
53
53
|
if plotly:
|
|
54
54
|
try:
|
|
55
|
-
from mayutils.visualisation.graphs.plotly.templates import register_templates
|
|
55
|
+
from mayutils.visualisation.graphs.plotly.templates import register_templates
|
|
56
56
|
|
|
57
57
|
register_templates()
|
|
58
58
|
except ImportError as err:
|
|
@@ -63,7 +63,7 @@ def setup(
|
|
|
63
63
|
|
|
64
64
|
if notebook:
|
|
65
65
|
try:
|
|
66
|
-
from mayutils.visualisation.notebook import Notebook
|
|
66
|
+
from mayutils.visualisation.notebook import Notebook
|
|
67
67
|
|
|
68
68
|
Notebook.setup()
|
|
69
69
|
except ImportError as err:
|
|
@@ -76,7 +76,7 @@ def setup(
|
|
|
76
76
|
|
|
77
77
|
if pandas:
|
|
78
78
|
try:
|
|
79
|
-
from mayutils.objects.dataframes import setup_pandas
|
|
79
|
+
from mayutils.objects.dataframes import setup_pandas
|
|
80
80
|
|
|
81
81
|
setup_pandas()
|
|
82
82
|
except ImportError as err:
|
|
@@ -4,22 +4,20 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any, Self, cast
|
|
6
6
|
|
|
7
|
-
from mayutils.core.extras import may_require_extras
|
|
8
7
|
from mayutils.data.queries import QUERIES_FOLDERS
|
|
9
8
|
from mayutils.data.read import render_query
|
|
10
9
|
from mayutils.environment.logging import Logger
|
|
11
10
|
from mayutils.objects.dataframes.backends import Backend, BackendOperations, DataFrames, default_backend
|
|
12
|
-
from mayutils.objects.datetime import DateTime, Interval
|
|
13
|
-
|
|
14
|
-
with may_require_extras():
|
|
15
|
-
import pandas as pd
|
|
16
11
|
|
|
17
12
|
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Mapping
|
|
18
14
|
from pathlib import Path
|
|
19
15
|
|
|
16
|
+
import pandas as pd
|
|
17
|
+
|
|
20
18
|
from mayutils.data.read import QueryReader
|
|
21
|
-
from mayutils.objects.datetime import Duration
|
|
22
|
-
from mayutils.objects.types import SQL
|
|
19
|
+
from mayutils.objects.datetime import DateTime, Duration, Interval
|
|
20
|
+
from mayutils.objects.types import SQL
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
logger = Logger.spawn()
|
|
@@ -29,14 +27,19 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
29
27
|
"""
|
|
30
28
|
Incrementally pull rows by tracking ``max(cursor_column)``.
|
|
31
29
|
|
|
32
|
-
The query template must contain a ``{cursor}`` placeholder. On
|
|
33
|
-
update the cursor is
|
|
34
|
-
the previous cursor are fetched.
|
|
30
|
+
The query template must contain a ``{{ cursor }}`` placeholder. On
|
|
31
|
+
each update the cursor is rendered into the template and only rows
|
|
32
|
+
past the previous cursor are fetched. Results are returned exactly
|
|
33
|
+
as the *reader* produces them: unlike
|
|
34
|
+
:func:`mayutils.data.read.read_query`, no automatic temporal column
|
|
35
|
+
parsing is applied, keeping the schema stable across incremental
|
|
36
|
+
fetches that are concatenated together.
|
|
35
37
|
|
|
36
38
|
Parameters
|
|
37
39
|
----------
|
|
38
40
|
query
|
|
39
|
-
SQL string or path to a ``.sql`` template containing
|
|
41
|
+
SQL string or path to a ``.sql`` template containing
|
|
42
|
+
``{{ cursor }}``.
|
|
40
43
|
cursor_column
|
|
41
44
|
Column whose maximum is tracked as the cursor.
|
|
42
45
|
initial_cursor
|
|
@@ -55,9 +58,10 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
55
58
|
:meth:`~datetime.datetime.strftime` format for datetime cursors.
|
|
56
59
|
queries_folders
|
|
57
60
|
Directories searched when *query* is a filename.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
every call.
|
|
61
|
+
template_kwargs
|
|
62
|
+
Jinja2 template variables rendered into the query template on
|
|
63
|
+
every call. The key ``cursor`` is injected per-call by
|
|
64
|
+
:meth:`fetch` and overrides any value stored here.
|
|
61
65
|
|
|
62
66
|
See Also
|
|
63
67
|
--------
|
|
@@ -82,7 +86,7 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
82
86
|
update_frequency: Duration | None = None,
|
|
83
87
|
time_format: str = "%Y-%m-%d %H:%M:%S",
|
|
84
88
|
queries_folders: tuple[Path, ...] = QUERIES_FOLDERS,
|
|
85
|
-
|
|
89
|
+
template_kwargs: Mapping[str, object] | None = None,
|
|
86
90
|
) -> None:
|
|
87
91
|
"""
|
|
88
92
|
Initialise the streaming query and perform the first fetch.
|
|
@@ -94,7 +98,7 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
94
98
|
----------
|
|
95
99
|
query
|
|
96
100
|
SQL string or path to a ``.sql`` template containing
|
|
97
|
-
``{cursor}``.
|
|
101
|
+
``{{ cursor }}``.
|
|
98
102
|
cursor_column
|
|
99
103
|
Column whose maximum is tracked as the cursor.
|
|
100
104
|
initial_cursor
|
|
@@ -115,9 +119,10 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
115
119
|
cursors.
|
|
116
120
|
queries_folders
|
|
117
121
|
Directories searched when *query* is a filename.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
on every call.
|
|
122
|
+
template_kwargs
|
|
123
|
+
Jinja2 template variables rendered into the query template
|
|
124
|
+
on every call. The key ``cursor`` is injected per-call by
|
|
125
|
+
:meth:`fetch` and overrides any value stored here.
|
|
121
126
|
|
|
122
127
|
See Also
|
|
123
128
|
--------
|
|
@@ -127,7 +132,7 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
127
132
|
--------
|
|
128
133
|
>>> from mayutils.data.live import StreamingQuery # doctest: +SKIP
|
|
129
134
|
>>> sq = StreamingQuery( # doctest: +SKIP
|
|
130
|
-
... "SELECT * FROM t WHERE id > {cursor}",
|
|
135
|
+
... "SELECT * FROM t WHERE id > {{ cursor }}",
|
|
131
136
|
... cursor_column="id",
|
|
132
137
|
... initial_cursor=0,
|
|
133
138
|
... reader=my_reader,
|
|
@@ -142,11 +147,13 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
142
147
|
self.update_frequency = update_frequency
|
|
143
148
|
self.time_format = time_format
|
|
144
149
|
self.queries_folders = queries_folders
|
|
145
|
-
self.
|
|
150
|
+
self.template_kwargs: dict[str, object] = dict(template_kwargs or {})
|
|
146
151
|
self.initial_cursor = initial_cursor
|
|
147
152
|
|
|
148
153
|
self.validate_retention()
|
|
149
154
|
|
|
155
|
+
from mayutils.objects.datetime import DateTime
|
|
156
|
+
|
|
150
157
|
self.cursor_value: Any = initial_cursor
|
|
151
158
|
self.cursor_is_datetime: bool = hasattr(initial_cursor, "strftime")
|
|
152
159
|
self._data: DataFrameType = self.fetch()
|
|
@@ -208,6 +215,8 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
208
215
|
if not self.should_update(force=force):
|
|
209
216
|
return self
|
|
210
217
|
|
|
218
|
+
from mayutils.objects.datetime import DateTime
|
|
219
|
+
|
|
211
220
|
snapshot = self.data
|
|
212
221
|
try:
|
|
213
222
|
delta = self.fetch()
|
|
@@ -248,6 +257,8 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
248
257
|
--------
|
|
249
258
|
>>> sq.reset() # doctest: +SKIP
|
|
250
259
|
"""
|
|
260
|
+
from mayutils.objects.datetime import DateTime
|
|
261
|
+
|
|
251
262
|
self._data = self.fetch()
|
|
252
263
|
self.last_updated = DateTime.now()
|
|
253
264
|
|
|
@@ -274,7 +285,7 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
274
285
|
--------
|
|
275
286
|
>>> delta = sq.fetch() # doctest: +SKIP
|
|
276
287
|
"""
|
|
277
|
-
data = self.read_query(cursor
|
|
288
|
+
data = self.read_query(template_kwargs={"cursor": self.cursor})
|
|
278
289
|
|
|
279
290
|
if len(data) != 0:
|
|
280
291
|
self.cursor_value = BackendOperations.max(data, self.cursor_column, backend=self.backend)
|
|
@@ -313,21 +324,23 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
313
324
|
self,
|
|
314
325
|
*,
|
|
315
326
|
default_suffix: str = "sql",
|
|
316
|
-
|
|
327
|
+
template_kwargs: Mapping[str, object] | None = None,
|
|
317
328
|
) -> DataFrameType:
|
|
318
329
|
"""
|
|
319
330
|
Render and execute the SQL query template.
|
|
320
331
|
|
|
321
|
-
|
|
322
|
-
|
|
332
|
+
Merges the per-call *template_kwargs* over the mapping stored at
|
|
333
|
+
construction (per-call keys win), renders the template, and
|
|
334
|
+
passes it to *reader*.
|
|
323
335
|
|
|
324
336
|
Parameters
|
|
325
337
|
----------
|
|
326
338
|
default_suffix
|
|
327
339
|
File extension appended when *query* is a filename without
|
|
328
340
|
one.
|
|
329
|
-
|
|
330
|
-
|
|
341
|
+
template_kwargs
|
|
342
|
+
Per-call Jinja2 template variables merged over the stored
|
|
343
|
+
mapping.
|
|
331
344
|
|
|
332
345
|
Returns
|
|
333
346
|
-------
|
|
@@ -339,14 +352,13 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
339
352
|
|
|
340
353
|
Examples
|
|
341
354
|
--------
|
|
342
|
-
>>> df = sq.read_query(
|
|
355
|
+
>>> df = sq.read_query(template_kwargs={"cursor": "0"}) # doctest: +SKIP
|
|
343
356
|
"""
|
|
344
357
|
rendered = render_query(
|
|
345
358
|
self.query,
|
|
346
359
|
queries_folders=self.queries_folders,
|
|
347
360
|
default_suffix=default_suffix,
|
|
348
|
-
**self.
|
|
349
|
-
**extra_kwargs,
|
|
361
|
+
template_kwargs={**self.template_kwargs, **(template_kwargs or {})},
|
|
350
362
|
)
|
|
351
363
|
|
|
352
364
|
return self.reader(
|
|
@@ -387,6 +399,8 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
387
399
|
if force or self.update_frequency is None:
|
|
388
400
|
return True
|
|
389
401
|
|
|
402
|
+
from mayutils.objects.datetime import DateTime
|
|
403
|
+
|
|
390
404
|
return (DateTime.now() - self.last_updated) > self.update_frequency
|
|
391
405
|
|
|
392
406
|
def apply_retention(
|
|
@@ -409,6 +423,8 @@ class StreamingQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
409
423
|
if self.max_age is not None and len(self.data) > 0:
|
|
410
424
|
newest = BackendOperations.max(self.data, self.cursor_column, backend=self.backend)
|
|
411
425
|
if hasattr(newest, "strftime"):
|
|
426
|
+
from mayutils.objects.datetime import DateTime
|
|
427
|
+
|
|
412
428
|
try:
|
|
413
429
|
cutoff = DateTime.parse(cast("DateTime", newest).strftime(self.time_format)) - self.max_age
|
|
414
430
|
|
|
@@ -464,9 +480,13 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
464
480
|
"""
|
|
465
481
|
Manage a sliding or expanding time window over a SQL query.
|
|
466
482
|
|
|
467
|
-
The query template must contain ``{start_timestamp}`` and
|
|
468
|
-
``{end_timestamp}`` placeholders. On each update, only the
|
|
469
|
-
since the previous window end is fetched.
|
|
483
|
+
The query template must contain ``{{ start_timestamp }}`` and
|
|
484
|
+
``{{ end_timestamp }}`` placeholders. On each update, only the
|
|
485
|
+
delta since the previous window end is fetched. Results are
|
|
486
|
+
returned exactly as the *reader* produces them: unlike
|
|
487
|
+
:func:`mayutils.data.read.read_query`, no automatic temporal column
|
|
488
|
+
parsing is applied, keeping the schema stable across windowed
|
|
489
|
+
fetches that are concatenated together.
|
|
470
490
|
|
|
471
491
|
When *deduplicate* is ``True``, rows are deduped on *index_column*
|
|
472
492
|
after each concat (keeps last), which handles re-fetched open
|
|
@@ -476,7 +496,7 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
476
496
|
----------
|
|
477
497
|
query
|
|
478
498
|
SQL string or path to a ``.sql`` template containing
|
|
479
|
-
``{start_timestamp}`` and ``{end_timestamp}``.
|
|
499
|
+
``{{ start_timestamp }}`` and ``{{ end_timestamp }}``.
|
|
480
500
|
index_column
|
|
481
501
|
Column used for deduplication and rolling-window filtering.
|
|
482
502
|
start_timestamp
|
|
@@ -499,9 +519,11 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
499
519
|
:meth:`~datetime.datetime.strftime` format for window boundaries.
|
|
500
520
|
queries_folders
|
|
501
521
|
Directories searched when *query* is a filename.
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
every call.
|
|
522
|
+
template_kwargs
|
|
523
|
+
Jinja2 template variables rendered into the query template on
|
|
524
|
+
every call. The keys ``start_timestamp`` and ``end_timestamp``
|
|
525
|
+
are injected per-call by :meth:`fetch` and override any values
|
|
526
|
+
stored here.
|
|
505
527
|
|
|
506
528
|
See Also
|
|
507
529
|
--------
|
|
@@ -528,7 +550,7 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
528
550
|
update_frequency: Duration | None = None,
|
|
529
551
|
time_format: str = "%Y-%m-%d",
|
|
530
552
|
queries_folders: tuple[Path, ...] = QUERIES_FOLDERS,
|
|
531
|
-
|
|
553
|
+
template_kwargs: Mapping[str, object] | None = None,
|
|
532
554
|
) -> None:
|
|
533
555
|
"""
|
|
534
556
|
Initialise the windowed query and perform the first fetch.
|
|
@@ -540,7 +562,7 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
540
562
|
----------
|
|
541
563
|
query
|
|
542
564
|
SQL string or path to a ``.sql`` template containing
|
|
543
|
-
``{start_timestamp}`` and ``{end_timestamp}``.
|
|
565
|
+
``{{ start_timestamp }}`` and ``{{ end_timestamp }}``.
|
|
544
566
|
index_column
|
|
545
567
|
Column used for deduplication and rolling-window filtering.
|
|
546
568
|
start_timestamp
|
|
@@ -565,9 +587,11 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
565
587
|
boundaries.
|
|
566
588
|
queries_folders
|
|
567
589
|
Directories searched when *query* is a filename.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
on every call.
|
|
590
|
+
template_kwargs
|
|
591
|
+
Jinja2 template variables rendered into the query template
|
|
592
|
+
on every call. The keys ``start_timestamp`` and
|
|
593
|
+
``end_timestamp`` are injected per-call by :meth:`fetch`
|
|
594
|
+
and override any values stored here.
|
|
571
595
|
|
|
572
596
|
See Also
|
|
573
597
|
--------
|
|
@@ -577,7 +601,7 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
577
601
|
--------
|
|
578
602
|
>>> from mayutils.data.live import WindowedQuery # doctest: +SKIP
|
|
579
603
|
>>> wq = WindowedQuery( # doctest: +SKIP
|
|
580
|
-
... "SELECT * FROM t WHERE ts BETWEEN '{start_timestamp}' AND '{end_timestamp}'",
|
|
604
|
+
... "SELECT * FROM t WHERE ts BETWEEN '{{ start_timestamp }}' AND '{{ end_timestamp }}'",
|
|
581
605
|
... index_column="ts",
|
|
582
606
|
... start_timestamp=DateTime.now(),
|
|
583
607
|
... reader=my_reader,
|
|
@@ -594,11 +618,13 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
594
618
|
self.update_frequency = update_frequency
|
|
595
619
|
self.time_format = time_format
|
|
596
620
|
self.queries_folders = queries_folders
|
|
597
|
-
self.
|
|
621
|
+
self.template_kwargs: dict[str, object] = dict(template_kwargs or {})
|
|
598
622
|
self.start_timestamp = start_timestamp
|
|
599
623
|
|
|
600
624
|
self.validate_retention()
|
|
601
625
|
|
|
626
|
+
from mayutils.objects.datetime import DateTime, Interval
|
|
627
|
+
|
|
602
628
|
self._interval: Interval[DateTime] = Interval(
|
|
603
629
|
start=start_timestamp,
|
|
604
630
|
end=DateTime.now(),
|
|
@@ -738,6 +764,8 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
738
764
|
if not self.should_update(force=force):
|
|
739
765
|
return self
|
|
740
766
|
|
|
767
|
+
from mayutils.objects.datetime import DateTime
|
|
768
|
+
|
|
741
769
|
snapshot = self.data
|
|
742
770
|
snapshot_interval = self.interval
|
|
743
771
|
try:
|
|
@@ -794,6 +822,8 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
794
822
|
--------
|
|
795
823
|
>>> wq.reset() # doctest: +SKIP
|
|
796
824
|
"""
|
|
825
|
+
from mayutils.objects.datetime import DateTime, Interval
|
|
826
|
+
|
|
797
827
|
if start_timestamp is not None:
|
|
798
828
|
self.start_timestamp = start_timestamp
|
|
799
829
|
|
|
@@ -840,10 +870,14 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
840
870
|
"""
|
|
841
871
|
if initial:
|
|
842
872
|
return self.read_query(
|
|
843
|
-
|
|
844
|
-
|
|
873
|
+
template_kwargs={
|
|
874
|
+
"start_timestamp": self._interval.start.strftime(format=self.time_format),
|
|
875
|
+
"end_timestamp": self._interval.end.strftime(format=self.time_format),
|
|
876
|
+
},
|
|
845
877
|
)
|
|
846
878
|
|
|
879
|
+
from mayutils.objects.datetime import DateTime, Interval
|
|
880
|
+
|
|
847
881
|
now = DateTime.now()
|
|
848
882
|
previous_end = self._interval.end
|
|
849
883
|
|
|
@@ -858,8 +892,10 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
858
892
|
)
|
|
859
893
|
|
|
860
894
|
delta = self.read_query(
|
|
861
|
-
|
|
862
|
-
|
|
895
|
+
template_kwargs={
|
|
896
|
+
"start_timestamp": previous_end.strftime(format=self.time_format),
|
|
897
|
+
"end_timestamp": now.strftime(format=self.time_format),
|
|
898
|
+
},
|
|
863
899
|
)
|
|
864
900
|
|
|
865
901
|
self._interval = Interval(start=new_start, end=now, absolute=True)
|
|
@@ -871,21 +907,23 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
871
907
|
/,
|
|
872
908
|
*,
|
|
873
909
|
default_suffix: str = "sql",
|
|
874
|
-
|
|
910
|
+
template_kwargs: Mapping[str, object] | None = None,
|
|
875
911
|
) -> DataFrameType:
|
|
876
912
|
"""
|
|
877
913
|
Render and execute the SQL query template.
|
|
878
914
|
|
|
879
|
-
|
|
880
|
-
|
|
915
|
+
Merges the per-call *template_kwargs* over the mapping stored at
|
|
916
|
+
construction (per-call keys win), renders the template, and
|
|
917
|
+
passes it to *reader*.
|
|
881
918
|
|
|
882
919
|
Parameters
|
|
883
920
|
----------
|
|
884
921
|
default_suffix
|
|
885
922
|
File extension appended when *query* is a filename without
|
|
886
923
|
one.
|
|
887
|
-
|
|
888
|
-
|
|
924
|
+
template_kwargs
|
|
925
|
+
Per-call Jinja2 template variables merged over the stored
|
|
926
|
+
mapping.
|
|
889
927
|
|
|
890
928
|
Returns
|
|
891
929
|
-------
|
|
@@ -898,16 +936,17 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
898
936
|
Examples
|
|
899
937
|
--------
|
|
900
938
|
>>> df = wq.read_query( # doctest: +SKIP
|
|
901
|
-
...
|
|
902
|
-
...
|
|
939
|
+
... template_kwargs={
|
|
940
|
+
... "start_timestamp": "2024-01-01",
|
|
941
|
+
... "end_timestamp": "2024-01-02",
|
|
942
|
+
... },
|
|
903
943
|
... )
|
|
904
944
|
"""
|
|
905
945
|
rendered = render_query(
|
|
906
946
|
self.query,
|
|
907
947
|
queries_folders=self.queries_folders,
|
|
908
948
|
default_suffix=default_suffix,
|
|
909
|
-
**self.
|
|
910
|
-
**extra_kwargs,
|
|
949
|
+
template_kwargs={**self.template_kwargs, **(template_kwargs or {})},
|
|
911
950
|
)
|
|
912
951
|
|
|
913
952
|
return self.reader(
|
|
@@ -948,6 +987,8 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
948
987
|
if force or self.update_frequency is None:
|
|
949
988
|
return True
|
|
950
989
|
|
|
990
|
+
from mayutils.objects.datetime import DateTime
|
|
991
|
+
|
|
951
992
|
return (DateTime.now() - self.last_updated) > self.update_frequency
|
|
952
993
|
|
|
953
994
|
def apply_retention(
|
|
@@ -970,6 +1011,8 @@ class WindowedQuery[DataFrameType: DataFrames = pd.DataFrame]:
|
|
|
970
1011
|
if self.max_age is not None and len(self.data) > 0:
|
|
971
1012
|
newest = BackendOperations.max(self.data, self.index_column, backend=self.backend)
|
|
972
1013
|
if hasattr(newest, "strftime"):
|
|
1014
|
+
from mayutils.objects.datetime import DateTime
|
|
1015
|
+
|
|
973
1016
|
try:
|
|
974
1017
|
cutoff = DateTime.parse(cast("DateTime", newest).strftime(self.time_format)) - self.max_age
|
|
975
1018
|
|