From 11fb39968dbafc4c71d9d292a01bdc910f20b369 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Wed, 11 Sep 2024 10:18:25 -0400 Subject: [PATCH] ci(backends): run backend doctests in CI (#9970) Co-authored-by: Guilherme Martins Crocetti <24530683+gmcrocetti@users.noreply.github.com> --- .github/workflows/ibis-backends.yml | 8 +++ ibis/backends/clickhouse/__init__.py | 3 +- ibis/backends/dask/__init__.py | 11 ++- ibis/backends/datafusion/__init__.py | 72 ++++++++----------- .../backends/datafusion/tests/test_connect.py | 8 +-- ibis/backends/druid/__init__.py | 27 ++++++- ibis/backends/duckdb/__init__.py | 25 ++++--- ibis/backends/exasol/__init__.py | 27 +++++++ ibis/backends/flink/__init__.py | 5 +- ibis/backends/mssql/__init__.py | 35 +++++++++ ibis/backends/mysql/__init__.py | 39 +++++----- ibis/backends/oracle/__init__.py | 27 +++++++ ibis/backends/pandas/__init__.py | 5 +- ibis/backends/polars/__init__.py | 19 +++++ ibis/backends/postgres/__init__.py | 5 +- ibis/backends/risingwave/__init__.py | 44 ++++++------ ibis/backends/sqlite/__init__.py | 19 +++-- ibis/backends/trino/__init__.py | 3 +- justfile | 15 ++++ 19 files changed, 272 insertions(+), 125 deletions(-) diff --git a/.github/workflows/ibis-backends.yml b/.github/workflows/ibis-backends.yml index ae1e18c9f8be..4a030a23891e 100644 --- a/.github/workflows/ibis-backends.yml +++ b/.github/workflows/ibis-backends.yml @@ -501,6 +501,14 @@ jobs: FLINK_REMOTE_CLUSTER_PORT: "8081" IBIS_EXAMPLES_DATA: ${{ runner.temp }}/examples-${{ matrix.backend.name }}-${{ matrix.os }}-${{ steps.install_python.outputs.python-version }} + - name: "run backend doctests: ${{ matrix.backend.name }}" + if: matrix.os == 'ubuntu-latest' + run: just backend-doctests ${{ matrix.backend.name }} + env: + FLINK_REMOTE_CLUSTER_ADDR: localhost + FLINK_REMOTE_CLUSTER_PORT: "8081" + IBIS_EXAMPLES_DATA: ${{ runner.temp }}/examples-${{ matrix.backend.name }}-${{ matrix.os }}-${{ steps.install_python.outputs.python-version }} + - name: check that no untracked files were produced shell: bash run: | diff --git a/ibis/backends/clickhouse/__init__.py b/ibis/backends/clickhouse/__init__.py index 06b344e014a8..11f9bc85ac92 100644 --- a/ibis/backends/clickhouse/__init__.py +++ b/ibis/backends/clickhouse/__init__.py @@ -143,8 +143,7 @@ def do_connect( >>> import ibis >>> client = ibis.clickhouse.connect() >>> client - - + """ if settings is None: settings = {} diff --git a/ibis/backends/dask/__init__.py b/ibis/backends/dask/__init__.py index fd5c0b6df348..8e7d683cf2a3 100644 --- a/ibis/backends/dask/__init__.py +++ b/ibis/backends/dask/__init__.py @@ -40,13 +40,12 @@ def do_connect( Examples -------- >>> import ibis + >>> import pandas as pd >>> import dask.dataframe as dd - >>> data = { - ... "t": dd.read_parquet("path/to/file.parquet"), - ... "s": dd.read_csv("path/to/file.csv"), - ... } - >>> ibis.dask.connect(data) - + >>> ibis.dask.connect( + ... {"t": dd.from_pandas(pd.DataFrame({"a": [1, 2, 3]}), npartitions=1)} + ... ) # doctest: +ELLIPSIS + """ super().do_connect(dictionary) diff --git a/ibis/backends/datafusion/__init__.py b/ibis/backends/datafusion/__init__.py index 6504f966399a..c2922e42e103 100644 --- a/ibis/backends/datafusion/__init__.py +++ b/ibis/backends/datafusion/__init__.py @@ -93,9 +93,25 @@ def do_connect( Examples -------- >>> import ibis - >>> config = {"t": "path/to/file.parquet", "s": "path/to/file.csv"} - >>> ibis.datafusion.connect(config) - + >>> config = { + ... "astronauts": "ci/ibis-testing-data/parquet/astronauts.parquet", + ... "diamonds": "ci/ibis-testing-data/csv/diamonds.csv", + ... } + >>> con = ibis.datafusion.connect(config) + >>> con.list_tables() + ['astronauts', 'diamonds'] + >>> con.table("diamonds") + DatabaseTable: diamonds + carat float64 + cut string + color string + clarity string + depth float64 + table float64 + price int64 + x float64 + y float64 + z float64 """ if isinstance(config, SessionContext): (self.con, config) = (config, None) @@ -121,7 +137,7 @@ def do_connect( config = {} for name, path in config.items(): - self.register(path, table_name=name) + self._register(path, table_name=name) @util.experimental @classmethod @@ -300,8 +316,11 @@ def list_tables( sg.select("table_name") .from_("information_schema.tables") .where(sg.column("table_schema").eq(sge.convert(database))) + .order_by("table_name") + ) + return self._filter_with_like( + self.raw_sql(query).to_pydict()["table_name"], like ) - return self.raw_sql(query).to_pydict()["table_name"] def get_schema( self, @@ -333,43 +352,14 @@ def register( table_name: str | None = None, **kwargs: Any, ) -> ir.Table: - """Register a data set with `table_name` located at `source`. - - Parameters - ---------- - source - The data source(s). May be a path to a file or directory of - parquet/csv files, a pandas dataframe, or a pyarrow table, dataset - or record batch. - table_name - The name of the table - kwargs - DataFusion-specific keyword arguments - - Examples - -------- - Register a csv: + return self._register(source, table_name, **kwargs) - >>> import ibis - >>> conn = ibis.datafusion.connect(config) - >>> conn.register("path/to/data.csv", "my_table") - >>> conn.table("my_table") - - Register a PyArrow table: - - >>> import pyarrow as pa - >>> tab = pa.table({"x": [1, 2, 3]}) - >>> conn.register(tab, "my_table") - >>> conn.table("my_table") - - Register a PyArrow dataset: - - >>> import pyarrow.dataset as ds - >>> dataset = ds.dataset("path/to/table") - >>> conn.register(dataset, "my_table") - >>> conn.table("my_table") - - """ + def _register( + self, + source: str | Path | pa.Table | pa.RecordBatch | pa.Dataset | pd.DataFrame, + table_name: str | None = None, + **kwargs: Any, + ) -> ir.Table: import pandas as pd if isinstance(source, (str, Path)): diff --git a/ibis/backends/datafusion/tests/test_connect.py b/ibis/backends/datafusion/tests/test_connect.py index 62526305c1d8..6b3773f8370f 100644 --- a/ibis/backends/datafusion/tests/test_connect.py +++ b/ibis/backends/datafusion/tests/test_connect.py @@ -25,17 +25,13 @@ def test_none_config(): def test_str_config(name_to_path): config = {name: str(path) for name, path in name_to_path.items()} - # if path.endswith((".parquet", ".csv", ".csv.gz")) connect triggers register - with pytest.warns(FutureWarning, match="v9.1"): - conn = ibis.datafusion.connect(config) + conn = ibis.datafusion.connect(config) assert sorted(conn.list_tables()) == sorted(name_to_path) def test_path_config(name_to_path): config = name_to_path - # if path.endswith((".parquet", ".csv", ".csv.gz")) connect triggers register - with pytest.warns(FutureWarning, match="v9.1"): - conn = ibis.datafusion.connect(config) + conn = ibis.datafusion.connect(config) assert sorted(conn.list_tables()) == sorted(name_to_path) diff --git a/ibis/backends/druid/__init__.py b/ibis/backends/druid/__init__.py index 2cdbe9aca0bf..3c593a77fa29 100644 --- a/ibis/backends/druid/__init__.py +++ b/ibis/backends/druid/__init__.py @@ -77,7 +77,32 @@ def current_database(self) -> str: return "druid" def do_connect(self, **kwargs: Any) -> None: - """Create an Ibis client using the passed connection parameters.""" + """Create an Ibis client using the passed connection parameters. + + Examples + -------- + >>> import ibis + >>> con = ibis.connect("druid://localhost:8082/druid/v2/sql?header=true") + >>> con.list_tables() # doctest: +ELLIPSIS + [...] + >>> t = con.table("functional_alltypes") + >>> t + DatabaseTable: functional_alltypes + __time timestamp + id int64 + bool_col int64 + tinyint_col int64 + smallint_col int64 + int_col int64 + bigint_col int64 + float_col float64 + double_col float64 + date_string_col string + string_col string + timestamp_col int64 + year int64 + month int64 + """ header = kwargs.pop("header", True) self.con = pydruid.db.connect(**kwargs, header=header) diff --git a/ibis/backends/duckdb/__init__.py b/ibis/backends/duckdb/__init__.py index 7dc8bed0f835..74f7e44ceff4 100644 --- a/ibis/backends/duckdb/__init__.py +++ b/ibis/backends/duckdb/__init__.py @@ -393,9 +393,8 @@ def do_connect( Examples -------- >>> import ibis - >>> ibis.duckdb.connect("database.ddb", threads=4, memory_limit="1GB") - - + >>> ibis.duckdb.connect(threads=4, memory_limit="1GB") # doctest: +ELLIPSIS + """ if not isinstance(database, Path) and not database.startswith( ("md:", "motherduck:", ":memory:") @@ -1037,9 +1036,8 @@ def list_tables( >>> con.create_database("my_database") >>> con.list_tables(database="my_database") [] - >>> with con.begin() as c: - ... c.exec_driver_sql("CREATE TABLE my_database.baz (a INTEGER)") # doctest: +ELLIPSIS - <...> + >>> con.raw_sql("CREATE TABLE my_database.baz (a INTEGER)") # doctest: +ELLIPSIS + >>> con.list_tables(database="my_database") ['baz'] @@ -1312,6 +1310,7 @@ def register_filesystem(self, filesystem: AbstractFileSystem): -------- >>> import ibis >>> import fsspec + >>> ibis.options.interactive = True >>> gcs = fsspec.filesystem("gcs") >>> con = ibis.duckdb.connect() >>> con.register_filesystem(gcs) @@ -1319,10 +1318,16 @@ def register_filesystem(self, filesystem: AbstractFileSystem): ... "gcs://ibis-examples/data/band_members.csv.gz", ... table_name="band_members", ... ) - DatabaseTable: band_members - name string - band string - + >>> t + ┏━━━━━━━━┳━━━━━━━━━┓ + ┃ name ┃ band ┃ + ┡━━━━━━━━╇━━━━━━━━━┩ + │ string │ string │ + ├────────┼─────────┤ + │ Mick │ Stones │ + │ John │ Beatles │ + │ Paul │ Beatles │ + └────────┴─────────┘ """ self.con.register_filesystem(filesystem) diff --git a/ibis/backends/exasol/__init__.py b/ibis/backends/exasol/__init__.py index 84e4fbd2b005..8218ac23fe31 100644 --- a/ibis/backends/exasol/__init__.py +++ b/ibis/backends/exasol/__init__.py @@ -81,6 +81,33 @@ def do_connect( kwargs Additional keyword arguments passed to `pyexasol.connect`. + Examples + -------- + >>> import os + >>> import ibis + >>> host = os.environ.get("IBIS_TEST_EXASOL_HOST", "localhost") + >>> user = os.environ.get("IBIS_TEST_EXASOL_USER", "sys") + >>> password = os.environ.get("IBIS_TEST_EXASOL_PASSWORD", "exasol") + >>> schema = os.environ.get("IBIS_TEST_EXASOL_DATABASE", "EXASOL") + >>> con = ibis.exasol.connect(schema=schema, host=host, user=user, password=password) + >>> con.list_tables() # doctest: +ELLIPSIS + [...] + >>> t = con.table("functional_alltypes") + >>> t + DatabaseTable: functional_alltypes + id int32 + bool_col boolean + tinyint_col int16 + smallint_col int16 + int_col int32 + bigint_col int64 + float_col float64 + double_col float64 + date_string_col string + string_col string + timestamp_col timestamp(3) + year int32 + month int32 """ if kwargs.pop("quote_ident", None) is not None: raise com.UnsupportedArgumentError( diff --git a/ibis/backends/flink/__init__.py b/ibis/backends/flink/__init__.py index f959ca1e5f0c..5772a83eeb1f 100644 --- a/ibis/backends/flink/__init__.py +++ b/ibis/backends/flink/__init__.py @@ -66,9 +66,8 @@ def do_connect(self, table_env: TableEnvironment) -> None: >>> import ibis >>> from pyflink.table import EnvironmentSettings, TableEnvironment >>> table_env = TableEnvironment.create(EnvironmentSettings.in_streaming_mode()) - >>> ibis.flink.connect(table_env) - - + >>> ibis.flink.connect(table_env) # doctest: +ELLIPSIS + """ self._table_env = table_env diff --git a/ibis/backends/mssql/__init__.py b/ibis/backends/mssql/__init__.py index 737175f95750..3a1f57714299 100644 --- a/ibis/backends/mssql/__init__.py +++ b/ibis/backends/mssql/__init__.py @@ -125,6 +125,41 @@ def do_connect( See https://learn.microsoft.com/en-us/sql/connect/odbc/windows/system-requirements-installation-and-driver-files kwargs Additional keyword arguments to pass to PyODBC. + + Examples + -------- + >>> import os + >>> import ibis + >>> host = os.environ.get("IBIS_TEST_MSSQL_HOST", "localhost") + >>> user = os.environ.get("IBIS_TEST_MSSQL_USER", "sa") + >>> password = os.environ.get("IBIS_TEST_MSSQL_PASSWORD", "1bis_Testing!") + >>> database = os.environ.get("IBIS_TEST_MSSQL_DATABASE", "ibis_testing") + >>> driver = os.environ.get("IBIS_TEST_MSSQL_PYODBC_DRIVER", "FreeTDS") + >>> con = ibis.mssql.connect( + ... database=database, + ... host=host, + ... user=user, + ... password=password, + ... driver=driver, + ... ) + >>> con.list_tables() # doctest: +ELLIPSIS + [...] + >>> t = con.table("functional_alltypes") + >>> t + DatabaseTable: functional_alltypes + id int32 + bool_col boolean + tinyint_col int16 + smallint_col int16 + int_col int32 + bigint_col int64 + float_col float32 + double_col float64 + date_string_col string + string_col string + timestamp_col timestamp(7) + year int32 + month int32 """ # If no user/password given, assume Windows Integrated Authentication diff --git a/ibis/backends/mysql/__init__.py b/ibis/backends/mysql/__init__.py index 4281c81831d0..84c28432b151 100644 --- a/ibis/backends/mysql/__init__.py +++ b/ibis/backends/mysql/__init__.py @@ -123,33 +123,30 @@ def do_connect( Examples -------- >>> import os - >>> import getpass + >>> import ibis >>> host = os.environ.get("IBIS_TEST_MYSQL_HOST", "localhost") - >>> user = os.environ.get("IBIS_TEST_MYSQL_USER", getpass.getuser()) - >>> password = os.environ.get("IBIS_TEST_MYSQL_PASSWORD") + >>> user = os.environ.get("IBIS_TEST_MYSQL_USER", "ibis") + >>> password = os.environ.get("IBIS_TEST_MYSQL_PASSWORD", "ibis") >>> database = os.environ.get("IBIS_TEST_MYSQL_DATABASE", "ibis_testing") - >>> con = connect(database=database, host=host, user=user, password=password) + >>> con = ibis.mysql.connect(database=database, host=host, user=user, password=password) >>> con.list_tables() # doctest: +ELLIPSIS [...] >>> t = con.table("functional_alltypes") >>> t - MySQLTable[table] - name: functional_alltypes - schema: - id : int32 - bool_col : int8 - tinyint_col : int8 - smallint_col : int16 - int_col : int32 - bigint_col : int64 - float_col : float32 - double_col : float64 - date_string_col : string - string_col : string - timestamp_col : timestamp - year : int32 - month : int32 - + DatabaseTable: functional_alltypes + id int32 + bool_col int8 + tinyint_col int8 + smallint_col int16 + int_col int32 + bigint_col int64 + float_col float32 + double_col float64 + date_string_col string + string_col string + timestamp_col timestamp + year int32 + month int32 """ self.con = pymysql.connect( user=user, diff --git a/ibis/backends/oracle/__init__.py b/ibis/backends/oracle/__init__.py index 2481175c600b..ed08714597de 100644 --- a/ibis/backends/oracle/__init__.py +++ b/ibis/backends/oracle/__init__.py @@ -121,6 +121,33 @@ def do_connect( An Oracle Data Source Name. If provided, overrides all other connection arguments except username and password. + Examples + -------- + >>> import os + >>> import ibis + >>> host = os.environ.get("IBIS_TEST_ORACLE_HOST", "localhost") + >>> user = os.environ.get("IBIS_TEST_ORACLE_USER", "ibis") + >>> password = os.environ.get("IBIS_TEST_ORACLE_PASSWORD", "ibis") + >>> database = os.environ.get("IBIS_TEST_ORACLE_DATABASE", "IBIS_TESTING") + >>> con = ibis.oracle.connect(database=database, host=host, user=user, password=password) + >>> con.list_tables() # doctest: +ELLIPSIS + [...] + >>> t = con.table("functional_alltypes") + >>> t + DatabaseTable: functional_alltypes + id int64 + bool_col int64 + tinyint_col int64 + smallint_col int64 + int_col int64 + bigint_col int64 + float_col float64 + double_col float64 + date_string_col string + string_col string + timestamp_col timestamp(3) + year int64 + month int64 """ # SID: unique name of an INSTANCE running an oracle process (a single, identifiable machine) # service name: an ALIAS to one (or many) individual instances that can diff --git a/ibis/backends/pandas/__init__.py b/ibis/backends/pandas/__init__.py index 5404e744ed01..1ac0ce2323af 100644 --- a/ibis/backends/pandas/__init__.py +++ b/ibis/backends/pandas/__init__.py @@ -48,9 +48,8 @@ def do_connect( Examples -------- >>> import ibis - >>> ibis.pandas.connect({"t": pd.DataFrame({"a": [1, 2, 3]})}) - - + >>> ibis.pandas.connect({"t": pd.DataFrame({"a": [1, 2, 3]})}) # doctest: +ELLIPSIS + """ warnings.warn( f"The {self.name} backend is slated for removal in 10.0.", diff --git a/ibis/backends/polars/__init__.py b/ibis/backends/polars/__init__.py index 8fe8df3debed..6e19290dec46 100644 --- a/ibis/backends/polars/__init__.py +++ b/ibis/backends/polars/__init__.py @@ -51,6 +51,25 @@ def do_connect( tables An optional mapping of string table names to polars LazyFrames. + Examples + -------- + >>> import ibis + >>> import polars as pl + >>> ibis.options.interactive = True + >>> lazy_frame = pl.LazyFrame( + ... {"name": ["Jimmy", "Keith"], "band": ["Led Zeppelin", "Stones"]} + ... ) + >>> con = ibis.polars.connect(tables={"band_members": lazy_frame}) + >>> t = con.table("band_members") + >>> t + ┏━━━━━━━━┳━━━━━━━━━━━━━━┓ + ┃ name ┃ band ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━┩ + │ string │ string │ + ├────────┼──────────────┤ + │ Jimmy │ Led Zeppelin │ + │ Keith │ Stones │ + └────────┴──────────────┘ """ if tables is not None and not isinstance(tables, Mapping): raise TypeError("Input to ibis.polars.connect must be a mapping") diff --git a/ibis/backends/postgres/__init__.py b/ibis/backends/postgres/__init__.py index 777b28e00b25..ad7f51508e75 100644 --- a/ibis/backends/postgres/__init__.py +++ b/ibis/backends/postgres/__init__.py @@ -223,11 +223,10 @@ def do_connect( Examples -------- >>> import os - >>> import getpass >>> import ibis >>> host = os.environ.get("IBIS_TEST_POSTGRES_HOST", "localhost") - >>> user = os.environ.get("IBIS_TEST_POSTGRES_USER", getpass.getuser()) - >>> password = os.environ.get("IBIS_TEST_POSTGRES_PASSWORD") + >>> user = os.environ.get("IBIS_TEST_POSTGRES_USER", "postgres") + >>> password = os.environ.get("IBIS_TEST_POSTGRES_PASSWORD", "postgres") >>> database = os.environ.get("IBIS_TEST_POSTGRES_DATABASE", "ibis_testing") >>> con = ibis.postgres.connect(database=database, host=host, user=user, password=password) >>> con.list_tables() # doctest: +ELLIPSIS diff --git a/ibis/backends/risingwave/__init__.py b/ibis/backends/risingwave/__init__.py index 27ae76cf9385..05927651b4b4 100644 --- a/ibis/backends/risingwave/__init__.py +++ b/ibis/backends/risingwave/__init__.py @@ -78,34 +78,36 @@ def do_connect( Examples -------- >>> import os - >>> import getpass >>> import ibis >>> host = os.environ.get("IBIS_TEST_RISINGWAVE_HOST", "localhost") - >>> user = os.environ.get("IBIS_TEST_RISINGWAVE_USER", getpass.getuser()) - >>> password = os.environ.get("IBIS_TEST_RISINGWAVE_PASSWORD") + >>> user = os.environ.get("IBIS_TEST_RISINGWAVE_USER", "root") + >>> password = os.environ.get("IBIS_TEST_RISINGWAVE_PASSWORD", "") >>> database = os.environ.get("IBIS_TEST_RISINGWAVE_DATABASE", "dev") - >>> con = connect(database=database, host=host, user=user, password=password) + >>> con = ibis.risingwave.connect( + ... database=database, + ... host=host, + ... user=user, + ... password=password, + ... port=4566, + ... ) >>> con.list_tables() # doctest: +ELLIPSIS [...] >>> t = con.table("functional_alltypes") >>> t - RisingWaveTable[table] - name: functional_alltypes - schema: - id : int32 - bool_col : boolean - tinyint_col : int16 - smallint_col : int16 - int_col : int32 - bigint_col : int64 - float_col : float32 - double_col : float64 - date_string_col : string - string_col : string - timestamp_col : timestamp - year : int32 - month : int32 - + DatabaseTable: functional_alltypes + id int32 + bool_col boolean + tinyint_col int16 + smallint_col int16 + int_col int32 + bigint_col int64 + float_col float32 + double_col float64 + date_string_col string + string_col string + timestamp_col timestamp(6) + year int32 + month int32 """ self.con = psycopg2.connect( diff --git a/ibis/backends/sqlite/__init__.py b/ibis/backends/sqlite/__init__.py index d59a1fbc39dc..cb5d252b054f 100644 --- a/ibis/backends/sqlite/__init__.py +++ b/ibis/backends/sqlite/__init__.py @@ -79,8 +79,15 @@ def do_connect( Examples -------- >>> import ibis - >>> ibis.sqlite.connect("path/to/my/sqlite.db") - + >>> con = ibis.sqlite.connect() + >>> t = con.create_table("my_table", schema=ibis.schema(dict(x="int64"))) + >>> con.insert("my_table", obj=[(1,), (2,), (3,)]) + >>> t + DatabaseTable: my_table + x int64 + >>> t.head(1).execute() + x + 0 1 """ _init_sqlite3() @@ -416,11 +423,11 @@ def attach(self, name: str, path: str | Path) -> None: Examples -------- - >>> con1 = ibis.sqlite.connect("original.db") - >>> con2 = ibis.sqlite.connect("new.db") - >>> con1.attach("new", "new.db") + >>> con1 = ibis.sqlite.connect("/tmp/original.db") + >>> con2 = ibis.sqlite.connect("/tmp/new.db") + >>> con1.attach("new", "/tmp/new.db") >>> con1.list_tables(database="new") - + [] """ with self.begin() as cur: cur.execute(f"ATTACH DATABASE {str(path)!r} AS {_quote(name)}") diff --git a/ibis/backends/trino/__init__.py b/ibis/backends/trino/__init__.py index 0c182f7c0c9a..444a23fa90bc 100644 --- a/ibis/backends/trino/__init__.py +++ b/ibis/backends/trino/__init__.py @@ -297,13 +297,12 @@ def do_connect( Connect using a URL - >>> con = ibis.connect(f"trino://user:password@host:port/{catalog}/{schema}") + >>> con = ibis.connect(f"trino://user@localhost:8080/{catalog}/{schema}") Connect using keyword arguments >>> con = ibis.trino.connect(database=catalog, schema=schema) >>> con = ibis.trino.connect(database=catalog, schema=schema, source="my-app") - """ if password is not None: if auth is not None: diff --git a/justfile b/justfile index 3ec44d356e16..e55754ef4d3f 100644 --- a/justfile +++ b/justfile @@ -59,6 +59,21 @@ check *args: ci-check *args: poetry run pytest --junitxml=junit.xml --cov=ibis --cov-report=xml:coverage.xml {{ args }} +# run backend doctests +backend-doctests backend *args: + #!/usr/bin/env bash + args=(pytest --doctest-modules {{ args }}) + for file in ibis/backends/{{ backend }}/**.py; do + if grep -qPv '.*test.+' <<< "${file}"; then + args+=("${file}") + fi + done + if [ -n "${CI}" ]; then + poetry run "${args[@]}" + else + "${args[@]}" + fi + # lint code lint: ruff format -q . --check