Skip to content

Commit 7067756

Browse files
committed
I/O: Migrate from ingestr to omniload
ingestr v1 started using the Functional Source License [1], which prevents commercial use for two years. omniload keeps using the MIT license. [1] https://fsl.software/
1 parent c3047a3 commit 7067756

25 files changed

Lines changed: 114 additions & 117 deletions

File tree

.github/workflows/postgresql.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ on:
55
pull_request:
66
paths:
77
- '.github/workflows/postgresql.yml'
8-
- 'cratedb_toolkit/io/ingestr/**'
8+
- 'cratedb_toolkit/io/omniload/**'
99
- 'cratedb_toolkit/testing/testcontainers/postgresql.py'
1010
- 'cratedb_toolkit/testing/testcontainers/util.py'
11-
- 'tests/io/ingestr/*postgresql*'
11+
- 'tests/io/omniload/*postgresql*'
1212
- 'pyproject.toml'
1313
push:
1414
branches: [ main ]
1515
paths:
1616
- '.github/workflows/postgresql.yml'
17-
- 'cratedb_toolkit/io/ingestr/**'
17+
- 'cratedb_toolkit/io/omniload/**'
1818
- 'cratedb_toolkit/testing/testcontainers/postgresql.py'
1919
- 'cratedb_toolkit/testing/testcontainers/util.py'
20-
- 'tests/io/ingestr/*postgresql*'
20+
- 'tests/io/omniload/*postgresql*'
2121
- 'pyproject.toml'
2222

2323
# Allow job to be triggered manually.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ build
1212
coverage.xml
1313
node_modules
1414
/cfr
15-
/doc/_build
15+
/doc/_build/*
1616
/tmp
1717
/var
1818
/DOWNLOAD

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
- Breaking change: Dropped support for Python 3.8 and 3.9, which have reached
55
end-of-life. The minimum supported Python version is now 3.10.
66
- Fixed a failing SQL statement during `ctk info cluster`
7+
- I/O: Migrated from `ingestr` to `omniload`. ingestr v1 started using
8+
the [Functional Source License] which prevents commercial use
9+
for two years. omniload keeps using the MIT license.
10+
11+
[Functional Source License]: https://fsl.software/
712

813
## 2026/06/17 v0.0.49
914
- Stopped leaking password to log output in `ctk cfr jobstats collect`.

cratedb_toolkit/io/ingestr/boot.py

Lines changed: 0 additions & 41 deletions
This file was deleted.
Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,51 @@
33

44
from yarl import URL
55

6-
from cratedb_toolkit.io.ingestr.boot import import_ingestr
6+
from cratedb_toolkit.io.omniload.boot import import_omniload
77
from cratedb_toolkit.model import DatabaseAddress
88

99
logger = logging.getLogger(__name__)
1010

1111

1212
@lru_cache(maxsize=1)
13-
def _get_ingestr():
13+
def _get_omniload():
1414
"""
15-
Get an ingestr API handle, cached.
15+
Get an omniload API handle, cached.
1616
"""
17-
return import_ingestr()
17+
return import_omniload()
1818

1919

20-
def ingestr_select(source_url: str) -> bool:
20+
def omniload_select(source_url: str) -> bool:
2121
"""
22-
Whether to select `ingestr` for this data source.
22+
Whether to select `omniload` for this data source.
2323
"""
24-
ingestr_available, ingestr, ConfigFieldMissingException = _get_ingestr()
24+
omniload_available, omniload, ConfigFieldMissingException = _get_omniload()
2525

26-
if not ingestr_available:
27-
logger.debug("ingestr is not installed")
26+
if not omniload_available:
27+
logger.debug("omniload is not installed")
2828
return False
2929
try:
30-
factory = ingestr.src.factory.SourceDestinationFactory(source_url, "csv:////tmp/foobar.csv")
30+
factory = omniload.src.factory.SourceDestinationFactory(source_url, "csv:////tmp/foobar.csv")
3131
factory.get_source()
32-
scheme = ingestr.src.factory.parse_scheme_from_uri(source_url)
33-
logger.info(f"Selecting ingestr for source scheme: {scheme}")
32+
scheme = omniload.src.factory.parse_scheme_from_uri(source_url)
33+
logger.info(f"Selecting omniload for source scheme: {scheme}")
3434
return True
3535
except (ImportError, ValueError, AttributeError) as ex:
3636
if "Unsupported source scheme" in str(ex):
37-
logger.debug(f"Failed to select ingestr for source url '{source_url}': {ex}")
37+
logger.debug(f"Failed to select omniload for source url '{source_url}': {ex}")
3838
else:
39-
logger.exception(f"Unexpected error with ingestr for source url: {source_url}")
39+
logger.exception(f"Unexpected error with omniload for source url: {source_url}")
4040
return False
4141
except Exception:
42-
logger.exception(f"Unexpected error with ingestr for source url: {source_url}")
42+
logger.exception(f"Unexpected error with omniload for source url: {source_url}")
4343
return False
4444

4545

46-
def ingestr_copy(source_url: str, target_address: DatabaseAddress, progress: bool = False) -> bool:
46+
def omniload_copy(source_url: str, target_address: DatabaseAddress, progress: bool = False) -> bool:
4747
"""
48-
Invoke data transfer to CrateDB from any source provided by `ingestr`.
48+
Invoke data transfer to CrateDB from any source provided by `omniload`.
4949
50-
https://cratedb-toolkit.readthedocs.io/io/ingestr/
50+
https://cratedb-toolkit.readthedocs.io/io/omniload/
5151
5252
Synopsis:
5353
@@ -63,11 +63,11 @@ def ingestr_copy(source_url: str, target_address: DatabaseAddress, progress: boo
6363
"postgresql://pguser:secret11@postgresql.example.org:5432/postgres?table=public.diamonds" \
6464
"crate://crate:na@localhost:4200/testdrive/ibis_diamonds"
6565
"""
66-
ingestr_available, ingestr, ConfigFieldMissingException = _get_ingestr()
66+
omniload_available, omniload, ConfigFieldMissingException = _get_omniload()
6767

6868
# Sanity checks.
69-
if not ingestr_available:
70-
raise ModuleNotFoundError("ingestr subsystem not installed")
69+
if not omniload_available:
70+
raise ModuleNotFoundError("omniload subsystem not installed")
7171

7272
# Compute source and target URLs and table names.
7373
# Table names use dotted notation `<schema>.<table>`.
@@ -91,7 +91,7 @@ def ingestr_copy(source_url: str, target_address: DatabaseAddress, progress: boo
9191

9292
target_uri, target_table_address = target_address.decode()
9393
target_table = target_table_address.fullname
94-
target_url = target_address.to_ingestr_url()
94+
target_url = target_address.to_omniload_url()
9595

9696
if not source_table:
9797
raise ValueError("Source table is required")
@@ -101,7 +101,7 @@ def ingestr_copy(source_url: str, target_address: DatabaseAddress, progress: boo
101101
if source_fragment:
102102
source_table += f"#{source_fragment}"
103103

104-
logger.info("Invoking ingestr")
104+
logger.info("Invoking omniload")
105105
logger.info(f"Source URL: {source_url_obj}")
106106
logger.info(f"Target URL: {target_url}")
107107
logger.info(f"Source Table: {source_table}")
@@ -114,15 +114,14 @@ def ingestr_copy(source_url: str, target_address: DatabaseAddress, progress: boo
114114
dest_uri=str(target_url),
115115
source_table=source_table,
116116
dest_table=target_table,
117-
yes=True,
118117
)
119118
if start_date is not None:
120119
ingest_kwargs["interval_start"] = start_date
121120
if batch_size is not None:
122121
ingest_kwargs["page_size"] = batch_size
123122

124123
try:
125-
ingestr.main.ingest(**ingest_kwargs)
124+
omniload.main.ingest(**ingest_kwargs)
126125
return True
127126
except ConfigFieldMissingException:
128127
logger.error(
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import logging
2+
3+
from boltons.urlutils import URL
4+
5+
logger = logging.getLogger(__name__)
6+
7+
8+
def import_omniload():
9+
"""Import omniload with CrateDB destination adapter."""
10+
try:
11+
import dlt_cratedb # noqa: F401
12+
import omniload.main
13+
import omniload.src.factory
14+
from dlt.common.configuration import ConfigFieldMissingException
15+
from omniload.src.destinations import GenericSqlDestination
16+
17+
class CrateDBDestination(GenericSqlDestination):
18+
def dlt_dest(self, uri: str, **kwargs):
19+
uri = self._replace_url(uri)
20+
import dlt_cratedb.impl.cratedb.factory
21+
22+
return dlt_cratedb.impl.cratedb.factory.cratedb(credentials=uri, **kwargs)
23+
24+
@staticmethod
25+
def _replace_url(uri: str) -> str:
26+
url_obj = URL(uri)
27+
if url_obj.scheme == "cratedb":
28+
url_obj.scheme = "postgres"
29+
return str(url_obj)
30+
31+
omniload.src.factory.SourceDestinationFactory.destinations["cratedb"] = CrateDBDestination
32+
33+
return True, omniload, ConfigFieldMissingException
34+
except ImportError:
35+
logger.error("Could not import omniload")
36+
return False, None, None

cratedb_toolkit/io/router.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,12 @@ def load_table(
119119

120120
return from_iceberg(str(source_url_obj), target_url)
121121

122-
from cratedb_toolkit.io.ingestr.api import ingestr_copy, ingestr_select
122+
from cratedb_toolkit.io.omniload.api import omniload_copy, omniload_select
123123

124124
source_url = str(source_url_obj)
125125

126-
if ingestr_select(source_url):
127-
return ingestr_copy(source_url, target, progress=True)
126+
if omniload_select(source_url):
127+
return omniload_copy(source_url, target, progress=True)
128128

129129
else:
130130
raise NotImplementedError(f"Importing resource not implemented yet: {source_url_obj}")

cratedb_toolkit/model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ def to_postgresql_url(self, port: int = 5432) -> URL:
141141
uri.port = port
142142
return uri
143143

144-
def to_ingestr_url(self, port: int = 5432) -> URL:
144+
def to_omniload_url(self, port: int = 5432) -> URL:
145145
"""
146-
Return the `cratedb://` variant of the database URI, suitable for `ingestr`.
146+
Return the `cratedb://` variant of the database URI, suitable for `omniload`.
147147
"""
148148
uri = deepcopy(self.to_postgresql_url(port))
149149
uri.scheme = "cratedb"

doc/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/_build
1+
_build/*

0 commit comments

Comments
 (0)