Skip to content

Commit 9642182

Browse files
ncclementigforsyth
andauthored
refactor(api): remove schema (#10149)
BREAKING CHANGE: Removed hierarchical usage of schema. Ibis uses the following naming conventions: - schema: a mapping of column names to datatypes - database: a collection of tables - catalog: a collection of databases --------- Co-authored-by: Gil Forsyth <[email protected]> Co-authored-by: Gil Forsyth <[email protected]>
1 parent 28f7e0b commit 9642182

File tree

24 files changed

+83
-373
lines changed

24 files changed

+83
-373
lines changed

docs/backends/_utils.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,7 @@ def find_member_with_docstring(member):
4040
if base not in resolved_bases:
4141
resolved_bases.append(base)
4242

43-
# Remove `CanCreateSchema` and `CanListSchema` since they are deprecated
44-
# and we don't want to document their existence.
45-
filtered_bases = filter(lambda x: "schema" not in x.name.lower(), resolved_bases)
46-
for base in filtered_bases:
43+
for base in resolved_bases:
4744
try:
4845
parent_member = get_callable(base, member.name)
4946
except KeyError:

ibis/backends/__init__.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -741,44 +741,6 @@ def drop_database(
741741
"""
742742

743743

744-
# TODO: remove this for 10.0
745-
class CanListSchema:
746-
@util.deprecated(
747-
instead="Use `list_databases` instead`", as_of="9.0", removed_in="10.0"
748-
)
749-
def list_schemas(
750-
self, like: str | None = None, database: str | None = None
751-
) -> list[str]:
752-
return self.list_databases(like=like, catalog=database)
753-
754-
@property
755-
@util.deprecated(
756-
instead="Use `Backend.current_database` instead.",
757-
as_of="9.0",
758-
removed_in="10.0",
759-
)
760-
def current_schema(self) -> str:
761-
return self.current_database
762-
763-
764-
class CanCreateSchema(CanListSchema):
765-
@util.deprecated(
766-
instead="Use `create_database` instead", as_of="9.0", removed_in="10.0"
767-
)
768-
def create_schema(
769-
self, name: str, database: str | None = None, force: bool = False
770-
) -> None:
771-
self.create_database(name=name, catalog=database, force=force)
772-
773-
@util.deprecated(
774-
instead="Use `drop_database` instead", as_of="9.0", removed_in="10.0"
775-
)
776-
def drop_schema(
777-
self, name: str, database: str | None = None, force: bool = False
778-
) -> None:
779-
self.drop_database(name=name, catalog=database, force=force)
780-
781-
782744
class CacheEntry(NamedTuple):
783745
orig_op: ops.Relation
784746
cached_op_ref: weakref.ref[ops.Relation]

ibis/backends/bigquery/__init__.py

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import ibis.expr.schema as sch
2626
import ibis.expr.types as ir
2727
from ibis import util
28-
from ibis.backends import CanCreateDatabase, CanCreateSchema
28+
from ibis.backends import CanCreateDatabase
2929
from ibis.backends.bigquery.client import (
3030
bigquery_param,
3131
parse_project_and_dataset,
@@ -155,7 +155,7 @@ def _postprocess_arrow(
155155
return table_or_batch.rename_columns(names)
156156

157157

158-
class Backend(SQLBackend, CanCreateDatabase, CanCreateSchema):
158+
class Backend(SQLBackend, CanCreateDatabase):
159159
name = "bigquery"
160160
compiler = sc.bigquery.compiler
161161
supports_python_udfs = False
@@ -520,6 +520,10 @@ def disconnect(self) -> None:
520520

521521
def _parse_project_and_dataset(self, dataset) -> tuple[str, str]:
522522
if isinstance(dataset, sge.Table):
523+
if (sg_cat := dataset.args["catalog"]) is not None:
524+
sg_cat.args["quoted"] = False
525+
if (sg_db := dataset.args["db"]) is not None:
526+
sg_db.args["quoted"] = False
523527
dataset = dataset.sql(self.dialect)
524528
if not dataset and not self.dataset:
525529
raise ValueError("Unable to determine BigQuery dataset.")
@@ -582,9 +586,11 @@ def drop_database(
582586
self.raw_sql(stmt.sql(self.name))
583587

584588
def table(
585-
self, name: str, database: str | None = None, schema: str | None = None
589+
self,
590+
name: str,
591+
database: str | None = None,
586592
) -> ir.Table:
587-
table_loc = self._warn_and_create_table_loc(database, schema)
593+
table_loc = self._to_sqlglot_table(database)
588594
table = sg.parse_one(f"`{name}`", into=sge.Table, read=self.name)
589595

590596
# Bigquery, unlike other backends, had existing support for specifying
@@ -612,10 +618,7 @@ def table(
612618
else:
613619
db = table.db
614620

615-
database = (
616-
sg.table(None, db=db, catalog=catalog, quoted=False).sql(dialect=self.name)
617-
or None
618-
)
621+
database = sg.table(None, db=db, catalog=catalog, quoted=False) or None
619622

620623
project, dataset = self._parse_project_and_dataset(database)
621624

@@ -722,7 +725,6 @@ def insert(
722725
self,
723726
table_name: str,
724727
obj: pd.DataFrame | ir.Table | list | dict,
725-
schema: str | None = None,
726728
database: str | None = None,
727729
overwrite: bool = False,
728730
):
@@ -734,15 +736,13 @@ def insert(
734736
The name of the table to which data needs will be inserted
735737
obj
736738
The source data or expression to insert
737-
schema
738-
The name of the schema that the table is located in
739739
database
740740
Name of the attached database that the table is located in.
741741
overwrite
742742
If `True` then replace existing contents of table
743743
744744
"""
745-
table_loc = self._warn_and_create_table_loc(database, schema)
745+
table_loc = self._to_sqlglot_table(database)
746746
catalog, db = self._to_catalog_db_tuple(table_loc)
747747
if catalog is None:
748748
catalog = self.current_catalog
@@ -896,7 +896,6 @@ def list_tables(
896896
self,
897897
like: str | None = None,
898898
database: tuple[str, str] | str | None = None,
899-
schema: str | None = None,
900899
) -> list[str]:
901900
"""List the tables in the database.
902901
@@ -924,10 +923,8 @@ def list_tables(
924923
To specify a table in a separate BigQuery dataset, you can pass in the
925924
dataset and project as a string `"dataset.project"`, or as a tuple of
926925
strings `(dataset, project)`.
927-
schema
928-
[deprecated] The schema (dataset) inside `database` to perform the list against.
929926
"""
930-
table_loc = self._warn_and_create_table_loc(database, schema)
927+
table_loc = self._to_sqlglot_table(database)
931928

932929
project, dataset = self._parse_project_and_dataset(table_loc)
933930
dataset_ref = bq.DatasetReference(project, dataset)
@@ -1090,11 +1087,10 @@ def drop_table(
10901087
self,
10911088
name: str,
10921089
*,
1093-
schema: str | None = None,
10941090
database: tuple[str | str] | str | None = None,
10951091
force: bool = False,
10961092
) -> None:
1097-
table_loc = self._warn_and_create_table_loc(database, schema)
1093+
table_loc = self._to_sqlglot_table(database)
10981094
catalog, db = self._to_catalog_db_tuple(table_loc)
10991095
stmt = sge.Drop(
11001096
kind="TABLE",
@@ -1112,11 +1108,10 @@ def create_view(
11121108
name: str,
11131109
obj: ir.Table,
11141110
*,
1115-
schema: str | None = None,
11161111
database: str | None = None,
11171112
overwrite: bool = False,
11181113
) -> ir.Table:
1119-
table_loc = self._warn_and_create_table_loc(database, schema)
1114+
table_loc = self._to_sqlglot_table(database)
11201115
catalog, db = self._to_catalog_db_tuple(table_loc)
11211116

11221117
stmt = sge.Create(
@@ -1137,11 +1132,10 @@ def drop_view(
11371132
self,
11381133
name: str,
11391134
*,
1140-
schema: str | None = None,
11411135
database: str | None = None,
11421136
force: bool = False,
11431137
) -> None:
1144-
table_loc = self._warn_and_create_table_loc(database, schema)
1138+
table_loc = self._to_sqlglot_table(database)
11451139
catalog, db = self._to_catalog_db_tuple(table_loc)
11461140

11471141
stmt = sge.Drop(
@@ -1169,32 +1163,6 @@ def _register_udfs(self, expr: ir.Expr) -> None:
11691163
def _safe_raw_sql(self, *args, **kwargs):
11701164
yield self.raw_sql(*args, **kwargs)
11711165

1172-
# TODO: remove when the schema kwarg is removed
1173-
def _warn_and_create_table_loc(self, database=None, schema=None):
1174-
if schema is not None:
1175-
self._warn_schema()
1176-
if database is not None and schema is not None:
1177-
if isinstance(database, str):
1178-
table_loc = f"{database}.{schema}"
1179-
elif isinstance(database, tuple):
1180-
table_loc = database + schema
1181-
elif schema is not None:
1182-
table_loc = schema
1183-
elif database is not None:
1184-
table_loc = database
1185-
else:
1186-
table_loc = None
1187-
1188-
table_loc = self._to_sqlglot_table(table_loc)
1189-
1190-
if table_loc is not None:
1191-
if (sg_cat := table_loc.args["catalog"]) is not None:
1192-
sg_cat.args["quoted"] = False
1193-
if (sg_db := table_loc.args["db"]) is not None:
1194-
sg_db.args["quoted"] = False
1195-
1196-
return table_loc
1197-
11981166

11991167
def compile(expr, params=None, **kwargs):
12001168
"""Compile an expression for BigQuery."""

ibis/backends/bigquery/tests/system/test_client.py

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ def test_list_tables(con):
3434
tables = con.list_tables(like="functional_alltypes")
3535
assert set(tables) == {"functional_alltypes", "functional_alltypes_parted"}
3636

37+
pypi_tables = [
38+
"external",
39+
"native",
40+
]
41+
42+
assert con.list_tables()
43+
44+
assert con.list_tables(database="ibis-gbq.pypi") == pypi_tables
45+
assert con.list_tables(database=("ibis-gbq", "pypi")) == pypi_tables
46+
3747

3848
def test_current_catalog(con):
3949
assert con.current_catalog == con.billing_project
@@ -386,22 +396,6 @@ def test_create_table_with_options(con):
386396
con.drop_table(name)
387397

388398

389-
def test_list_tables_schema_warning_refactor(con):
390-
pypi_tables = [
391-
"external",
392-
"native",
393-
]
394-
395-
assert con.list_tables()
396-
397-
# Warn but succeed for schema list
398-
with pytest.raises(FutureWarning):
399-
assert con.list_tables(schema="pypi") == pypi_tables
400-
401-
assert con.list_tables(database="ibis-gbq.pypi") == pypi_tables
402-
assert con.list_tables(database=("ibis-gbq", "pypi")) == pypi_tables
403-
404-
405399
def test_create_temp_table_from_scratch(project_id, dataset_id):
406400
con = ibis.bigquery.connect(project_id=project_id, dataset_id=dataset_id)
407401
name = gen_name("bigquery_temp_table")

ibis/backends/conftest.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from ibis.backends import (
1818
CanCreateCatalog,
1919
CanCreateDatabase,
20-
CanListSchema,
2120
_get_backend_names,
2221
)
2322
from ibis.conftest import WINDOWS
@@ -424,14 +423,6 @@ def con_no_data(backend_no_data):
424423
return backend_no_data.connection
425424

426425

427-
@pytest.fixture(scope="session")
428-
def con_list_schema(con):
429-
if isinstance(con, CanListSchema):
430-
return con
431-
else:
432-
pytest.skip(f"{con.name} backend cannot create schemas")
433-
434-
435426
@pytest.fixture(scope="session")
436427
def con_create_catalog(con):
437428
if isinstance(con, CanCreateCatalog):

ibis/backends/datafusion/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import ibis.expr.schema as sch
2323
import ibis.expr.types as ir
2424
from ibis import util
25-
from ibis.backends import CanCreateCatalog, CanCreateDatabase, CanCreateSchema, NoUrl
25+
from ibis.backends import CanCreateCatalog, CanCreateDatabase, NoUrl
2626
from ibis.backends.sql import SQLBackend
2727
from ibis.backends.sql.compilers.base import C
2828
from ibis.common.dispatch import lazy_singledispatch
@@ -69,7 +69,7 @@ def as_nullable(dtype: dt.DataType) -> dt.DataType:
6969
return dtype.copy(nullable=True)
7070

7171

72-
class Backend(SQLBackend, CanCreateCatalog, CanCreateDatabase, CanCreateSchema, NoUrl):
72+
class Backend(SQLBackend, CanCreateCatalog, CanCreateDatabase, NoUrl):
7373
name = "datafusion"
7474
supports_arrays = True
7575
compiler = sc.datafusion.compiler
@@ -674,8 +674,10 @@ def create_table(
674674
return self.table(name, database=database)
675675

676676
def truncate_table(
677-
self, name: str, database: str | None = None, schema: str | None = None
678-
) -> None:
677+
self,
678+
name: str,
679+
database: str | None = None,
680+
):
679681
"""Delete all rows from a table.
680682
681683
Parameters
@@ -684,14 +686,12 @@ def truncate_table(
684686
Table name
685687
database
686688
Database name
687-
schema
688-
Schema name
689689
690690
"""
691691
# datafusion doesn't support `TRUNCATE TABLE` so we use `DELETE FROM`
692692
#
693693
# however datafusion as of 34.0.0 doesn't implement DELETE DML yet
694-
table_loc = self._warn_and_create_table_loc(database, schema)
694+
table_loc = self._to_sqlglot_table(database)
695695
catalog, db = self._to_catalog_db_tuple(table_loc)
696696

697697
ident = sg.table(name, db=db, catalog=catalog).sql(self.dialect)

0 commit comments

Comments
 (0)