docs: add runtime docs to CLI reference (#3445)

* bumps to version 1.20.0

* update the hub reference docs, add CI check

* use dependency specifier in hub for plugin version check

* minimum dlt runtime cli check

* rollaback to old fsspec min version

* fixes test_hub ci workflow

* fixes flaky test

* bumps hub extra

* updates cli docs linting

* fixes docs lock

---------

Co-authored-by: Marcin Rudolf <rudolfix@rudolfix.org>
Co-authored-by: ivasio <ivan@dlthub.com>
This commit is contained in:
ivasio
2025-12-09 17:30:53 +01:00
committed by GitHub
parent d0dc21bd45
commit 99207237fe
13 changed files with 1280 additions and 78 deletions

View File

@@ -94,6 +94,17 @@ jobs:
run: pytest tests/hub
# if: matrix.os != 'macos-latest'
- name: Test runtime client
run: |
mkdir .dlt && touch .dlt/.workspace
dlt runtime --help
# DISABLED: because docs rendering happens in non-deterministic order (of plugin discovery)
# must be fixed
# - name: Check that dlthub cli docs are up to date
# run: cd docs/tools/dlthub_cli && make check-cli-docs
# if: ${{ matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' }}
matrix_job_required_check:
name: hub | dlthub features tests
needs: run_hub_features

View File

@@ -34,7 +34,7 @@ COPY dist/dlt-${IMAGE_VERSION}.tar.gz .
RUN mkdir -p /app
WORKDIR /app
RUN uv venv && uv pip install /tmp/pydlt/dlt-${IMAGE_VERSION}.tar.gz --resolution lowest-direct && uv pip install typing-extensions==4.8.0
RUN rm -r /tmp/pydlt
# RUN rm -r /tmp/pydlt
# make sure dlt can be actually imported
RUN uv run python -c 'import dlt;import pendulum;'
@@ -50,7 +50,12 @@ RUN uv run dlt pipeline fruit_pipeline info
# enable workspace
RUN mkdir -p .dlt && touch .dlt/.workspace
# RUN dlt pipeline fruit_pipeline info
RUN uv run dlt workspace info
RUN uv run dlt workspace -v info
RUN uv run python minimal_pipeline.py
RUN uv run dlt pipeline fruit_pipeline info
RUN uv run dlt pipeline fruit_pipeline info
# install hub
RUN uv pip install /tmp/pydlt/dlt-${IMAGE_VERSION}.tar.gz[hub] --resolution lowest-direct && uv pip install typing-extensions==4.8.0
RUN uv run python minimal_pipeline.py
RUN uv run dlt --non-interactive license issue dlthub.transformation
RUN uv run dlt runtime --help

View File

@@ -6,7 +6,7 @@ from types import ModuleType
from typing import Any, Dict, Iterator, List, Optional
from urllib.parse import urlencode
from packaging.version import Version
from packaging.specifiers import SpecifierSet
from dlt.common import known_env
from dlt.common.configuration.container import Container
@@ -246,9 +246,14 @@ def ensure_plugin_version_match(
plugin_version: str,
plugin_module_name: str,
dlt_extra: str,
dlt_version_specifier: Optional[SpecifierSet] = None,
) -> None:
"""Ensures that installed dlt version matches plugin version. Plugins are tightly bound to `dlt`
and released together. Both major and minor version must match. For alpha plugins version may be 0.
"""Ensures that installed plugin version matches dlt requirements. Plugins are tightly bound
to `dlt` and released together.
If `dlt_version_specifier` is provided, it is used to check if the plugin version satisfies
the specifier. Otherwise, the specifier is read from dlt's package metadata (Requires-Dist).
If specifier cannot be determined, the function returns without checking.
Args:
pkg_name: Name of the plugin package (e.g., "dlthub")
@@ -256,30 +261,37 @@ def ensure_plugin_version_match(
plugin_version: The installed plugin version string
plugin_module_name: The module name for MissingDependencyException (e.g., "dlthub")
dlt_extra: The dlt extra to install the plugin (e.g., "hub")
dlt_version_specifier: Optional version specifier for the plugin. If not provided,
reads from dlt's package metadata.
Raises:
MissingDependencyException: If version mismatch is detected
"""
installed = Version(plugin_version)
dlt_installed = Version(dlt_version)
# Get specifier from dlt's package metadata if not provided
if dlt_version_specifier is None:
from dlt.version import get_dependency_requirement
# currently packages must match on minor version
if installed.minor != dlt_installed.minor or (
installed.major != dlt_installed.major and installed.major != 0
):
req = get_dependency_requirement(pkg_name)
if req is not None:
dlt_version_specifier = req.specifier
# If specifier still not available, exit without checking
if dlt_version_specifier is None or len(dlt_version_specifier) == 0:
return
# Use specifier.contains() for proper version check (allowing prereleases)
if not dlt_version_specifier.contains(plugin_version, prereleases=True):
from dlt.common.exceptions import MissingDependencyException
custom_msg = (
f"`{pkg_name}` is a `dlt` plugin and must be installed together with `dlt` with a "
f"matching version. `dlt` {dlt_installed.major}.{dlt_installed.minor}.x requires "
f"`{pkg_name}` 0.{dlt_installed.minor}.x but you have "
f"{plugin_version}. Please install the right version of {pkg_name} with:\n\n"
f"`{pkg_name}` is a `dlt` plugin and must satisfy version requirement "
f"`{dlt_version_specifier}` but you have {plugin_version}. "
f"Please install the right version of {pkg_name} with:\n\n"
f'pip install "dlt[{dlt_extra}]=={dlt_version}"\n\n'
"or if you are upgrading the plugin:\n\n"
f'pip install "dlt[{dlt_extra}]=={dlt_version}" -U {pkg_name}'
)
missing_dep_ex = MissingDependencyException(plugin_module_name, [])
# ImportError uses `msg` attribute for __str__, not just args
missing_dep_ex.args = (custom_msg,)
missing_dep_ex.msg = custom_msg
raise missing_dep_ex

View File

@@ -65,10 +65,16 @@ MTIME_DISPATCH = {
"az": lambda f: ensure_pendulum_datetime_utc(f["last_modified"]),
"gcs": lambda f: ensure_pendulum_datetime_utc(f["updated"]),
"https": lambda f: cast(
pendulum.DateTime, pendulum.parse(f["Last-Modified"], exact=True, strict=False)
pendulum.DateTime,
pendulum.parse(
f.get("Last-Modified", pendulum.now().isoformat()), exact=True, strict=False
),
),
"http": lambda f: cast(
pendulum.DateTime, pendulum.parse(f["Last-Modified"], exact=True, strict=False)
pendulum.DateTime,
pendulum.parse(
f.get("Last-Modified", pendulum.now().isoformat()), exact=True, strict=False
),
),
"file": lambda f: ensure_pendulum_datetime_utc(f["mtime"]),
"memory": lambda f: ensure_pendulum_datetime_utc(f["created"]),

View File

@@ -1,6 +1,8 @@
from importlib.metadata import version as pkg_version, distribution as pkg_distribution
from typing import Optional
from urllib.request import url2pathname
from urllib.parse import urlparse
from packaging.requirements import Requirement
DLT_IMPORT_NAME = "dlt"
PKG_NAME = DLT_PKG_NAME = "dlt"
@@ -30,3 +32,19 @@ def get_installed_requirement_string(
else:
package_requirement = f"{package}{ver_selector}{pkg_version(package)}"
return package_requirement
def get_dependency_requirement(
dependency_name: str, package: str = DLT_PKG_NAME
) -> Optional[Requirement]:
"""Find a specific dependency requirement from package metadata"""
dist = pkg_distribution(package)
if dist.requires is None:
return None
for req_str in dist.requires:
req = Requirement(req_str)
if req.name == dependency_name:
return req
return None

View File

@@ -1,11 +1,14 @@
.PHONY: install-dlthub, update-cli-docs, check-cli-docs
.PHONY: update-cli-docs, check-cli-docs, dev
# this must be run from `dlthub_cli` to see workspace commands
# it will use dlthub and dlt-runtime versions from dlt/docs/pyproject.toml to generate docs
install-dlthub:
uv pip install dlthub
dev:
uv sync
update-cli-docs: install-dlthub
uv run dlt --debug render-docs ../../website/docs/hub/command-line-interface.md --commands license workspace profile
update-cli-docs: dev
# generate as there's no license
RUNTIME__LICENSE="" uv run dlt --debug render-docs ../../website/docs/hub/command-line-interface.md --commands license workspace profile runtime
check-cli-docs: install-dlthub
uv run dlt --debug render-docs ../../website/docs/hub/command-line-interface.md --compare --commands license workspace profile
check-cli-docs: dev
# generate as there's no license
RUNTIME__LICENSE="" uv run dlt --debug render-docs ../../website/docs/hub/command-line-interface.md --compare --commands license workspace profile runtime

18
docs/uv.lock generated
View File

@@ -834,7 +834,7 @@ wheels = [
[[package]]
name = "dlt"
version = "1.20.0a1"
version = "1.20.0"
source = { editable = "../" }
dependencies = [
{ name = "click" },
@@ -928,13 +928,13 @@ requires-dist = [
{ name = "db-dtypes", marker = "extra == 'bigquery'", specifier = ">=1.2.0" },
{ name = "db-dtypes", marker = "extra == 'gcp'", specifier = ">=1.2.0" },
{ name = "deltalake", marker = "extra == 'deltalake'", specifier = ">=0.25.1" },
{ name = "dlt-runtime", marker = "python_full_version >= '3.10' and extra == 'hub'", specifier = ">=0.19.0a0,<0.21" },
{ name = "dlt-runtime", marker = "python_full_version >= '3.10' and extra == 'hub'", specifier = ">=0.20.0a0,<0.21" },
{ name = "dlthub", marker = "python_full_version >= '3.10' and extra == 'hub'", specifier = ">=0.20.0a1,<0.21" },
{ name = "duckdb", marker = "extra == 'duckdb'", specifier = ">=0.9" },
{ name = "duckdb", marker = "extra == 'ducklake'", specifier = ">=1.2.0" },
{ name = "duckdb", marker = "extra == 'motherduck'", specifier = ">=0.9" },
{ name = "duckdb", marker = "extra == 'workspace'", specifier = ">=0.9" },
{ name = "fsspec", specifier = ">=2025.9.0" },
{ name = "fsspec", specifier = ">=2022.4.0" },
{ name = "gcsfs", marker = "extra == 'bigquery'", specifier = ">=2022.4.0" },
{ name = "gcsfs", marker = "extra == 'clickhouse'", specifier = ">=2022.4.0" },
{ name = "gcsfs", marker = "extra == 'gcp'", specifier = ">=2022.4.0" },
@@ -1189,7 +1189,7 @@ requires-dist = [
[[package]]
name = "dlt-runtime"
version = "0.20.0a0"
version = "0.20.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
@@ -1199,22 +1199,22 @@ dependencies = [
{ name = "python-jose" },
{ name = "tabulate" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1d/f5/d5c74ba2560507493b9d5d0c98a8482e15f036f338bb2832730065679e22/dlt_runtime-0.20.0a0.tar.gz", hash = "sha256:3e9d5df91f03152c251e5f874e5a13ac1bd66d5fbac0357c11996bf4e8279c8c", size = 48300, upload-time = "2025-12-04T15:51:51.192Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d0/86/d7f057d8bdf2f3ada28bf1277b7f24a7abbb221d72788bd682176126a75c/dlt_runtime-0.20.0.tar.gz", hash = "sha256:753c7522bc01c92a453459640e482f87b647b14cc5734d754133a91968acc79f", size = 49532, upload-time = "2025-12-09T14:32:33.708Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/21/1f/ebcfea0c69a697d64f836140bfdb0f73d0be2880547dc00ff267eaad7569/dlt_runtime-0.20.0a0-py3-none-any.whl", hash = "sha256:d6498d4078980c833ea9c5cbfc8b7146488beddb77146ae6d3a2e7d7345dfb5a", size = 118233, upload-time = "2025-12-04T15:51:49.67Z" },
{ url = "https://files.pythonhosted.org/packages/4c/b0/02a6c846d89e3c27a592a929d95526036be1d607e48fca214dcbf3b7bf58/dlt_runtime-0.20.0-py3-none-any.whl", hash = "sha256:0969165672b2b3938a618ddd263e0cf8ec356d289253f58134e325e222753056", size = 119573, upload-time = "2025-12-09T14:32:32.119Z" },
]
[[package]]
name = "dlthub"
version = "0.20.0a1"
version = "0.20.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-jose" },
{ name = "ruamel-yaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/13/20/eb0246c88dd80102a4b02ad807b3459c31855ac0c983f69a2b8fe027a88c/dlthub-0.20.0a1.tar.gz", hash = "sha256:bf8e90bd22bad85ed67d497f97d763678e74a41c70bb3c17e3ae2da7897a0bde", size = 158441, upload-time = "2025-12-07T11:26:45.312Z" }
sdist = { url = "https://files.pythonhosted.org/packages/77/1b/2c079f22243462e914026172094411ed7ef1fc96c8089e0ca66d1a14038a/dlthub-0.20.1.tar.gz", hash = "sha256:7b3a188abc28601fd4bdf8f17e7925ef729d4f91fb67a6b4eb5c5dc5a04ac3a2", size = 158432, upload-time = "2025-12-09T15:18:10.813Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/40/7b/307126b81ecefbf2dd7569e2da81b2a7b9124dbdcfa6039f3e350bd097c3/dlthub-0.20.0a1-py3-none-any.whl", hash = "sha256:de1a20567da74943931e8fd3551babd345c9f7dcb1f3782d200b308a79c660ce", size = 209794, upload-time = "2025-12-07T11:26:43.808Z" },
{ url = "https://files.pythonhosted.org/packages/21/94/b2a87853102c6aa08606b2708d8f678b1e39855e8227fe111e37c32631b6/dlthub-0.20.1-py3-none-any.whl", hash = "sha256:c4d4e0c4515cd68f316ccd02c9ecc007332c861ae6f92a488f7e961935e7f1a0", size = 209767, upload-time = "2025-12-09T15:18:09.067Z" },
]
[[package]]

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[project]
name = "dlt"
version = "1.20.0a1"
version = "1.20.0"
description = "dlt is an open-source python-first scalable data loading library that does not require any backend to run."
authors = [{ name = "dltHub Inc.", email = "services@dlthub.com" }]
requires-python = ">=3.9.2, <3.15"
@@ -52,7 +52,7 @@ dependencies = [
"orjson>=3.11.0 ; python_version > '3.13'",
"tenacity>=8.0.2",
"jsonpath-ng>=1.5.3",
"fsspec>=2025.9.0",
"fsspec>=2022.4.0",
"packaging>=21.1",
"pluggy>=1.3.0",
"win-precise-time>=1.4.2 ; os_name == 'nt' and python_version < '3.13'",
@@ -189,7 +189,7 @@ workspace = [
]
hub = [
"dlthub>=0.20.0a1,<0.21 ; python_version >= '3.10'",
"dlt-runtime>=0.19.0a0,<0.21 ; python_version >= '3.10'",
"dlt-runtime>=0.20.0a0,<0.21 ; python_version >= '3.10'",
]
dbml = [

View File

@@ -174,31 +174,73 @@ def test_context_with_xdg_dir(mocker) -> None:
def test_ensure_plugin_version_match_same_versions() -> None:
"""test that matching versions pass without error."""
from packaging.specifiers import SpecifierSet
# Use explicit specifier to test specific version matching scenarios
# PEP 440 ordering: .devN < .aN < .bN < .rcN < final < .postN
# So we use .dev0 as lower bound to include all pre-releases
specifier_1_19 = SpecifierSet(">=1.19.0.dev0,<1.20.0") # includes all prereleases
specifier_2_5 = SpecifierSet(">=2.5.0.dev0,<2.6.0")
# exact same version
ensure_plugin_version_match("dlthub", "1.19.0", "1.19.0", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "1.19.5", "1.19.2", "dlthub", "hub")
ensure_plugin_version_match(
"fake-plugin", "1.19.0", "1.19.0", "fake-plugin", "hub", specifier_1_19
)
ensure_plugin_version_match(
"fake-plugin", "1.19.5", "1.19.2", "fake-plugin", "hub", specifier_1_19
)
# different patch versions are ok
ensure_plugin_version_match("dlthub", "2.5.0", "2.5.10", "dlthub", "hub")
# alpha specifiers (e.g. 1.19.0a1)
ensure_plugin_version_match("dlthub", "1.19.0a1", "1.19.0a2", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "1.19.0a1", "1.19.0", "dlthub", "hub")
# dev specifiers (e.g. 1.19.0.dev1)
ensure_plugin_version_match("dlthub", "1.19.0.dev1", "1.19.0.dev2", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "1.19.0.dev1", "1.19.0", "dlthub", "hub")
ensure_plugin_version_match(
"fake-plugin", "2.5.0", "2.5.10", "fake-plugin", "hub", specifier_2_5
)
# alpha specifiers (e.g. 1.19.0a1) - these are LESS than 1.19.0
ensure_plugin_version_match(
"fake-plugin", "1.19.0a1", "1.19.0a2", "fake-plugin", "hub", specifier_1_19
)
ensure_plugin_version_match(
"fake-plugin", "1.19.0a1", "1.19.0", "fake-plugin", "hub", specifier_1_19
)
# dev specifiers (e.g. 1.19.0.dev1) - these are LESS than 1.19.0a0
ensure_plugin_version_match(
"fake-plugin", "1.19.0.dev1", "1.19.0.dev2", "fake-plugin", "hub", specifier_1_19
)
ensure_plugin_version_match(
"fake-plugin", "1.19.0.dev1", "1.19.0", "fake-plugin", "hub", specifier_1_19
)
# post release specifiers
ensure_plugin_version_match("dlthub", "1.19.0.post1", "1.19.0.post2", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "1.19.0.post1", "1.19.0", "dlthub", "hub")
ensure_plugin_version_match(
"fake-plugin", "1.19.0.post1", "1.19.0.post2", "fake-plugin", "hub", specifier_1_19
)
ensure_plugin_version_match(
"fake-plugin", "1.19.0.post1", "1.19.0", "fake-plugin", "hub", specifier_1_19
)
def test_ensure_plugin_version_match_alpha_plugin() -> None:
"""test that alpha plugins (major=0) match any dlt major version with same minor."""
# alpha plugin (0.x.y) should match dlt 1.x.y with same minor
ensure_plugin_version_match("dlthub", "1.19.0", "0.19.0", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "1.19.5", "0.19.2", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "2.19.0", "0.19.0", "dlthub", "hub")
"""test that alpha plugins (major=0) match specifier."""
from packaging.specifiers import SpecifierSet
# specifier for 0.19.x versions (including all pre-releases)
# PEP 440 ordering: .devN < .aN < .bN < .rcN < final < .postN
specifier_0_19 = SpecifierSet(">=0.19.0.dev0,<0.20.0")
# alpha plugin (0.x.y) should match specifier
ensure_plugin_version_match(
"fake-plugin", "1.19.0", "0.19.0", "fake-plugin", "hub", specifier_0_19
)
ensure_plugin_version_match(
"fake-plugin", "1.19.5", "0.19.2", "fake-plugin", "hub", specifier_0_19
)
ensure_plugin_version_match(
"fake-plugin", "2.19.0", "0.19.0", "fake-plugin", "hub", specifier_0_19
)
# alpha plugin with alpha/dev specifiers
ensure_plugin_version_match("dlthub", "1.19.0a1", "0.19.0a2", "dlthub", "hub")
ensure_plugin_version_match("dlthub", "1.19.0.dev1", "0.19.0.dev2", "dlthub", "hub")
ensure_plugin_version_match(
"fake-plugin", "1.19.0a1", "0.19.0a2", "fake-plugin", "hub", specifier_0_19
)
ensure_plugin_version_match(
"fake-plugin", "1.19.0.dev1", "0.19.0.dev2", "fake-plugin", "hub", specifier_0_19
)
@pytest.mark.parametrize(
@@ -217,6 +259,13 @@ def test_ensure_plugin_version_match_alpha_plugin() -> None:
)
def test_ensure_plugin_version_match_mismatch(dlt_version: str, plugin_version: str) -> None:
"""test that mismatched versions raise MissingDependencyException."""
from packaging.specifiers import SpecifierSet
# Use explicit specifier that requires 1.19.x versions
specifier = SpecifierSet(">=1.19.0,<1.20.0")
with pytest.raises(MissingDependencyException) as exc_info:
ensure_plugin_version_match("dlthub", dlt_version, plugin_version, "dlthub", "hub")
assert "dlthub" in str(exc_info.value)
ensure_plugin_version_match(
"fake-plugin", dlt_version, plugin_version, "fake-plugin", "hub", specifier
)
assert "fake-plugin" in str(exc_info.value)

View File

@@ -1,8 +1,9 @@
import os
import pytest
from importlib.metadata import PackageNotFoundError
from packaging.requirements import Requirement
from dlt.version import get_installed_requirement_string
from dlt.version import get_installed_requirement_string, get_dependency_requirement
def test_installed_requirement_string() -> None:
@@ -15,3 +16,24 @@ def test_installed_requirement_string() -> None:
# this is not installed
with pytest.raises(PackageNotFoundError):
get_installed_requirement_string("requests-X")
def test_get_dependency_requirement() -> None:
# dlt depends on dlthub, so this should return a Requirement
req = get_dependency_requirement("dlthub")
assert req is not None
assert isinstance(req, Requirement)
assert req.name == "dlthub"
# click has a version specifier
assert str(req.specifier) != ""
# dlt depends on fsspec with a version constraint
req = get_dependency_requirement("fsspec")
assert req is not None
assert req.name == "fsspec"
# verify we can check version satisfaction
assert "2022.4.0" in req.specifier
# non-existent dependency returns None
req = get_dependency_requirement("non-existent-package-xyz")
assert req is None

View File

@@ -4463,14 +4463,14 @@ def test_pending_package_exception_warning() -> None:
with pytest.raises(PipelineStepFailed) as pip_ex:
pipeline.run()
# none of the jobs passed so we have pending package but not partial
# one of the job failed and package is aborted. sometimes the other
# job completed, sometimes is still pending so we disable pending test
assert pip_ex.value.step == "load"
print(str(pip_ex.value))
assert "Pending packages" not in str(pip_ex.value)
# assert "Pending packages" not in str(pip_ex.value)
assert "partially loaded" in str(pip_ex.value)
assert pip_ex.value.load_id is not None
assert pip_ex.value.is_package_partially_loaded is True
assert pip_ex.value.has_pending_data is False
# assert pip_ex.value.has_pending_data is False
def test_cleanup() -> None:

18
uv.lock generated
View File

@@ -2058,7 +2058,7 @@ wheels = [
[[package]]
name = "dlt"
version = "1.20.0a1"
version = "1.20.0"
source = { editable = "." }
dependencies = [
{ name = "click" },
@@ -2356,13 +2356,13 @@ requires-dist = [
{ name = "db-dtypes", marker = "extra == 'bigquery'", specifier = ">=1.2.0" },
{ name = "db-dtypes", marker = "extra == 'gcp'", specifier = ">=1.2.0" },
{ name = "deltalake", marker = "extra == 'deltalake'", specifier = ">=0.25.1" },
{ name = "dlt-runtime", marker = "python_full_version >= '3.10' and extra == 'hub'", specifier = ">=0.19.0a0,<0.21" },
{ name = "dlt-runtime", marker = "python_full_version >= '3.10' and extra == 'hub'", specifier = ">=0.20.0a0,<0.21" },
{ name = "dlthub", marker = "python_full_version >= '3.10' and extra == 'hub'", specifier = ">=0.20.0a1,<0.21" },
{ name = "duckdb", marker = "extra == 'duckdb'", specifier = ">=0.9" },
{ name = "duckdb", marker = "extra == 'ducklake'", specifier = ">=1.2.0" },
{ name = "duckdb", marker = "extra == 'motherduck'", specifier = ">=0.9" },
{ name = "duckdb", marker = "extra == 'workspace'", specifier = ">=0.9" },
{ name = "fsspec", specifier = ">=2025.9.0" },
{ name = "fsspec", specifier = ">=2022.4.0" },
{ name = "gcsfs", marker = "extra == 'bigquery'", specifier = ">=2022.4.0" },
{ name = "gcsfs", marker = "extra == 'clickhouse'", specifier = ">=2022.4.0" },
{ name = "gcsfs", marker = "extra == 'gcp'", specifier = ">=2022.4.0" },
@@ -2535,7 +2535,7 @@ streamlit = [{ name = "streamlit", marker = "python_full_version >= '3.9' and py
[[package]]
name = "dlt-runtime"
version = "0.20.0a0"
version = "0.20.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs", version = "25.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
@@ -2545,22 +2545,22 @@ dependencies = [
{ name = "python-jose", marker = "python_full_version >= '3.10'" },
{ name = "tabulate", marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1d/f5/d5c74ba2560507493b9d5d0c98a8482e15f036f338bb2832730065679e22/dlt_runtime-0.20.0a0.tar.gz", hash = "sha256:3e9d5df91f03152c251e5f874e5a13ac1bd66d5fbac0357c11996bf4e8279c8c", size = 48300, upload-time = "2025-12-04T15:51:51.192Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d0/86/d7f057d8bdf2f3ada28bf1277b7f24a7abbb221d72788bd682176126a75c/dlt_runtime-0.20.0.tar.gz", hash = "sha256:753c7522bc01c92a453459640e482f87b647b14cc5734d754133a91968acc79f", size = 49532, upload-time = "2025-12-09T14:32:33.708Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/21/1f/ebcfea0c69a697d64f836140bfdb0f73d0be2880547dc00ff267eaad7569/dlt_runtime-0.20.0a0-py3-none-any.whl", hash = "sha256:d6498d4078980c833ea9c5cbfc8b7146488beddb77146ae6d3a2e7d7345dfb5a", size = 118233, upload-time = "2025-12-04T15:51:49.67Z" },
{ url = "https://files.pythonhosted.org/packages/4c/b0/02a6c846d89e3c27a592a929d95526036be1d607e48fca214dcbf3b7bf58/dlt_runtime-0.20.0-py3-none-any.whl", hash = "sha256:0969165672b2b3938a618ddd263e0cf8ec356d289253f58134e325e222753056", size = 119573, upload-time = "2025-12-09T14:32:32.119Z" },
]
[[package]]
name = "dlthub"
version = "0.20.0a1"
version = "0.20.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-jose", marker = "python_full_version >= '3.10'" },
{ name = "ruamel-yaml", marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/13/20/eb0246c88dd80102a4b02ad807b3459c31855ac0c983f69a2b8fe027a88c/dlthub-0.20.0a1.tar.gz", hash = "sha256:bf8e90bd22bad85ed67d497f97d763678e74a41c70bb3c17e3ae2da7897a0bde", size = 158441, upload-time = "2025-12-07T11:26:45.312Z" }
sdist = { url = "https://files.pythonhosted.org/packages/77/1b/2c079f22243462e914026172094411ed7ef1fc96c8089e0ca66d1a14038a/dlthub-0.20.1.tar.gz", hash = "sha256:7b3a188abc28601fd4bdf8f17e7925ef729d4f91fb67a6b4eb5c5dc5a04ac3a2", size = 158432, upload-time = "2025-12-09T15:18:10.813Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/40/7b/307126b81ecefbf2dd7569e2da81b2a7b9124dbdcfa6039f3e350bd097c3/dlthub-0.20.0a1-py3-none-any.whl", hash = "sha256:de1a20567da74943931e8fd3551babd345c9f7dcb1f3782d200b308a79c660ce", size = 209794, upload-time = "2025-12-07T11:26:43.808Z" },
{ url = "https://files.pythonhosted.org/packages/21/94/b2a87853102c6aa08606b2708d8f678b1e39855e8227fe111e37c32631b6/dlthub-0.20.1-py3-none-any.whl", hash = "sha256:c4d4e0c4515cd68f316ccd02c9ecc007332c861ae6f92a488f7e961935e7f1a0", size = 209767, upload-time = "2025-12-09T15:18:09.067Z" },
]
[[package]]