From fd1007d4a10836f6b6087b10937c9cff60fc1f21 Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Wed, 10 Jun 2026 21:40:28 +0800 Subject: [PATCH 1/7] [python][ray] Support dynamic_table_options in read_paimon read_paimon now accepts a dynamic_table_options parameter that is merged into the table options via Table.copy() at read time, enabling use cases like blob-as-descriptor=true without modifying the stored table options. --- paimon-python/pypaimon/ray/ray_paimon.py | 6 +++++ .../read/datasource/split_provider.py | 14 +++++++----- .../pypaimon/tests/split_provider_test.py | 22 +++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/paimon-python/pypaimon/ray/ray_paimon.py b/paimon-python/pypaimon/ray/ray_paimon.py index 0e796dd7c223..43fef963b217 100644 --- a/paimon-python/pypaimon/ray/ray_paimon.py +++ b/paimon-python/pypaimon/ray/ray_paimon.py @@ -56,6 +56,7 @@ def read_paimon( limit: Optional[int] = None, snapshot_id: Optional[int] = None, tag_name: Optional[str] = None, + dynamic_table_options: Optional[Dict[str, str]] = None, ray_remote_args: Optional[Dict[str, Any]] = None, concurrency: Optional[int] = None, override_num_blocks: Optional[int] = None, @@ -74,6 +75,10 @@ def read_paimon( exclusive with ``tag_name``. tag_name: Optional tag name to time-travel to. Mutually exclusive with ``snapshot_id``. + dynamic_table_options: Optional table options applied at read time + via ``Table.copy()``. These override the table's stored options + without modifying them, e.g. + ``{"blob-as-descriptor": "true"}``. ray_remote_args: Optional kwargs passed to ``ray.remote`` in read tasks. concurrency: Optional max number of Ray read tasks to run concurrently. override_num_blocks: Optional override for the number of output blocks. @@ -106,6 +111,7 @@ def read_paimon( limit=limit, snapshot_id=snapshot_id, tag_name=tag_name, + dynamic_table_options=dynamic_table_options, ) if not split_provider.splits(): diff --git a/paimon-python/pypaimon/read/datasource/split_provider.py b/paimon-python/pypaimon/read/datasource/split_provider.py index e981eebb96e4..c009f56f05a6 100644 --- a/paimon-python/pypaimon/read/datasource/split_provider.py +++ b/paimon-python/pypaimon/read/datasource/split_provider.py @@ -85,6 +85,7 @@ def __init__( limit: Optional[int] = None, snapshot_id: Optional[int] = None, tag_name: Optional[str] = None, + dynamic_table_options: Optional[Dict[str, str]] = None, ): if not table_identifier: raise ValueError("table_identifier is required") @@ -101,6 +102,7 @@ def __init__( self._limit = limit self._snapshot_id = snapshot_id self._tag_name = tag_name + self._dynamic_table_options = dynamic_table_options self._table_cached = None self._splits_cached = None self._read_type_cached = None @@ -110,13 +112,15 @@ def _ensure_table(self): from pypaimon.catalog.catalog_factory import CatalogFactory catalog = CatalogFactory.create(self._catalog_options) table = catalog.get_table(self._table_identifier) - travel_options = {} + dynamic_options = {} if self._snapshot_id is not None: - travel_options["scan.snapshot-id"] = str(self._snapshot_id) + dynamic_options["scan.snapshot-id"] = str(self._snapshot_id) if self._tag_name is not None: - travel_options["scan.tag-name"] = self._tag_name - if travel_options: - table = table.copy(travel_options) + dynamic_options["scan.tag-name"] = self._tag_name + if self._dynamic_table_options: + dynamic_options.update(self._dynamic_table_options) + if dynamic_options: + table = table.copy(dynamic_options) self._table_cached = table return self._table_cached diff --git a/paimon-python/pypaimon/tests/split_provider_test.py b/paimon-python/pypaimon/tests/split_provider_test.py index 19525f8e5eef..81f14c193710 100644 --- a/paimon-python/pypaimon/tests/split_provider_test.py +++ b/paimon-python/pypaimon/tests/split_provider_test.py @@ -227,6 +227,28 @@ def test_catalog_provider_time_travel_by_tag_name(self): rows = tr.to_arrow(provider.splits()).to_pylist() self.assertEqual([r['id'] for r in rows], [11]) + def test_dynamic_table_options_blob_as_descriptor(self): + pa_schema = pa.schema([ + ('id', pa.int32()), + ('picture', pa.large_binary()), + ]) + identifier = 'default.split_provider_blob_desc' + schema = Schema.from_pyarrow_schema(pa_schema, options={ + 'blob-as-descriptor': 'false', + 'row-tracking.enabled': 'true', + 'data-evolution.enabled': 'true', + }) + catalog = CatalogFactory.create(self.catalog_options) + catalog.create_table(identifier, schema, False) + + provider = CatalogSplitProvider( + table_identifier=identifier, + catalog_options=self.catalog_options, + dynamic_table_options={'blob-as-descriptor': 'true'}, + ) + table = provider.table() + self.assertTrue(table.options.blob_as_descriptor()) + def test_pre_resolved_provider_returns_inputs(self): """PreResolvedSplitProvider just hands back what it was given.""" catalog = CatalogFactory.create(self.catalog_options) From 27da4d4214bbdfc41d3ef123862f72b89626e6e8 Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Wed, 10 Jun 2026 21:52:45 +0800 Subject: [PATCH 2/7] [python][ray] Reject conflicting snapshot_id/tag_name with dynamic_table_options --- .../pypaimon/read/datasource/split_provider.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/paimon-python/pypaimon/read/datasource/split_provider.py b/paimon-python/pypaimon/read/datasource/split_provider.py index c009f56f05a6..492dbf005ac7 100644 --- a/paimon-python/pypaimon/read/datasource/split_provider.py +++ b/paimon-python/pypaimon/read/datasource/split_provider.py @@ -95,6 +95,17 @@ def __init__( raise ValueError( "snapshot_id and tag_name cannot be set at the same time" ) + if dynamic_table_options: + if snapshot_id is not None and "scan.snapshot-id" in dynamic_table_options: + raise ValueError( + "snapshot_id and dynamic_table_options['scan.snapshot-id'] " + "cannot be set at the same time" + ) + if tag_name is not None and "scan.tag-name" in dynamic_table_options: + raise ValueError( + "tag_name and dynamic_table_options['scan.tag-name'] " + "cannot be set at the same time" + ) self._table_identifier = table_identifier self._catalog_options = catalog_options self._predicate = predicate From 4e652897448ad1cad6970b3634a2737b5d9234da Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Wed, 10 Jun 2026 22:07:51 +0800 Subject: [PATCH 3/7] [python][ray] Complete time-travel conflict detection for dynamic_table_options Reject all conflicting combinations: snapshot_id/tag_name params vs any time-travel scan key in dynamic_table_options, and multiple time-travel keys within dynamic_table_options itself. --- .../read/datasource/split_provider.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/paimon-python/pypaimon/read/datasource/split_provider.py b/paimon-python/pypaimon/read/datasource/split_provider.py index 492dbf005ac7..f0bd7994e848 100644 --- a/paimon-python/pypaimon/read/datasource/split_provider.py +++ b/paimon-python/pypaimon/read/datasource/split_provider.py @@ -91,20 +91,29 @@ def __init__( raise ValueError("table_identifier is required") if catalog_options is None: raise ValueError("catalog_options is required") + _TIME_TRAVEL_KEYS = { + "scan.snapshot-id", "scan.tag-name", + "scan.timestamp-millis", "scan.timestamp", "scan.watermark", + } + if snapshot_id is not None and tag_name is not None: raise ValueError( "snapshot_id and tag_name cannot be set at the same time" ) + if dynamic_table_options: - if snapshot_id is not None and "scan.snapshot-id" in dynamic_table_options: + dynamic_tt_keys = _TIME_TRAVEL_KEYS & dynamic_table_options.keys() + if (snapshot_id is not None or tag_name is not None) and dynamic_tt_keys: raise ValueError( - "snapshot_id and dynamic_table_options['scan.snapshot-id'] " - "cannot be set at the same time" + "snapshot_id/tag_name and dynamic_table_options " + "time-travel keys cannot be set at the same time, " + "got: {}".format(", ".join(sorted(dynamic_tt_keys))) ) - if tag_name is not None and "scan.tag-name" in dynamic_table_options: + if len(dynamic_tt_keys) > 1: raise ValueError( - "tag_name and dynamic_table_options['scan.tag-name'] " - "cannot be set at the same time" + "dynamic_table_options contains multiple time-travel " + "keys which are mutually exclusive: {}".format( + ", ".join(sorted(dynamic_tt_keys))) ) self._table_identifier = table_identifier self._catalog_options = catalog_options From 9896f1c6c9536702dc78f06cea8d97ce9ec98ae0 Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Wed, 10 Jun 2026 22:08:36 +0800 Subject: [PATCH 4/7] [python][ray] Simplify dynamic_table_options docstring --- paimon-python/pypaimon/ray/ray_paimon.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/paimon-python/pypaimon/ray/ray_paimon.py b/paimon-python/pypaimon/ray/ray_paimon.py index 43fef963b217..04f8bcee2c6b 100644 --- a/paimon-python/pypaimon/ray/ray_paimon.py +++ b/paimon-python/pypaimon/ray/ray_paimon.py @@ -75,10 +75,7 @@ def read_paimon( exclusive with ``tag_name``. tag_name: Optional tag name to time-travel to. Mutually exclusive with ``snapshot_id``. - dynamic_table_options: Optional table options applied at read time - via ``Table.copy()``. These override the table's stored options - without modifying them, e.g. - ``{"blob-as-descriptor": "true"}``. + dynamic_table_options: Optional dynamic options to override at read time. ray_remote_args: Optional kwargs passed to ``ray.remote`` in read tasks. concurrency: Optional max number of Ray read tasks to run concurrently. override_num_blocks: Optional override for the number of output blocks. From 62df94ea054200087c79cbab74dc47fa957ee96e Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Wed, 10 Jun 2026 22:17:58 +0800 Subject: [PATCH 5/7] [python][ray] Reuse SCAN_KEYS for time-travel conflict detection and consolidate tests --- .../pypaimon/read/datasource/split_provider.py | 8 +++----- paimon-python/pypaimon/tests/split_provider_test.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/paimon-python/pypaimon/read/datasource/split_provider.py b/paimon-python/pypaimon/read/datasource/split_provider.py index f0bd7994e848..bd01e75fb495 100644 --- a/paimon-python/pypaimon/read/datasource/split_provider.py +++ b/paimon-python/pypaimon/read/datasource/split_provider.py @@ -91,10 +91,8 @@ def __init__( raise ValueError("table_identifier is required") if catalog_options is None: raise ValueError("catalog_options is required") - _TIME_TRAVEL_KEYS = { - "scan.snapshot-id", "scan.tag-name", - "scan.timestamp-millis", "scan.timestamp", "scan.watermark", - } + from pypaimon.snapshot.time_travel_util import SCAN_KEYS + scan_keys = set(SCAN_KEYS) if snapshot_id is not None and tag_name is not None: raise ValueError( @@ -102,7 +100,7 @@ def __init__( ) if dynamic_table_options: - dynamic_tt_keys = _TIME_TRAVEL_KEYS & dynamic_table_options.keys() + dynamic_tt_keys = scan_keys & dynamic_table_options.keys() if (snapshot_id is not None or tag_name is not None) and dynamic_tt_keys: raise ValueError( "snapshot_id/tag_name and dynamic_table_options " diff --git a/paimon-python/pypaimon/tests/split_provider_test.py b/paimon-python/pypaimon/tests/split_provider_test.py index 81f14c193710..3f4853f57d14 100644 --- a/paimon-python/pypaimon/tests/split_provider_test.py +++ b/paimon-python/pypaimon/tests/split_provider_test.py @@ -249,6 +249,19 @@ def test_dynamic_table_options_blob_as_descriptor(self): table = provider.table() self.assertTrue(table.options.blob_as_descriptor()) + def test_dynamic_table_options_rejects_tt_conflict(self): + args = dict(table_identifier=self.identifier, + catalog_options=self.catalog_options) + with self.assertRaises(ValueError): + CatalogSplitProvider(**args, snapshot_id=1, + dynamic_table_options={'scan.tag-name': 'v1'}) + with self.assertRaises(ValueError): + CatalogSplitProvider(**args, tag_name='v1', + dynamic_table_options={'scan.snapshot-id': '1'}) + with self.assertRaises(ValueError): + CatalogSplitProvider(**args, dynamic_table_options={ + 'scan.snapshot-id': '1', 'scan.tag-name': 'v1'}) + def test_pre_resolved_provider_returns_inputs(self): """PreResolvedSplitProvider just hands back what it was given.""" catalog = CatalogFactory.create(self.catalog_options) From d42fa4cb3315bd81adf4db3159903ac05ab04601 Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Thu, 11 Jun 2026 10:48:00 +0800 Subject: [PATCH 6/7] [python][ray] Add e2e test for blob-descriptor resolve via dynamic_table_options and fix flake8 --- .../ray_data_evolution_merge_into_test.py | 81 ++++++++++++++++++- .../pypaimon/tests/split_provider_test.py | 15 ++-- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py b/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py index b70ef40a58e9..69608382df1d 100644 --- a/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py +++ b/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py @@ -523,7 +523,8 @@ def test_blob_table_feature_update(self): ('feature', pa.int32()), ]) name = f'default.tbl_{uuid.uuid4().hex[:8]}' - schema = Schema.from_pyarrow_schema(blob_schema, options=self.de_options) + schema = Schema.from_pyarrow_schema( + blob_schema, options=self.de_options) self.catalog.create_table(name, schema, False) self._write( name, @@ -586,6 +587,84 @@ def compute_feature(batch): 'num_matched': 2, 'num_inserted': 0, 'num_unchanged': 0, }) + def test_blob_descriptor_resolve_and_merge(self): + from pypaimon.table.row.blob import BlobDescriptor, Blob + from pypaimon.common.uri_reader import UriReaderFactory + + blob_schema = pa.schema([ + ('id', pa.int32()), + ('payload', pa.large_binary()), + ('feature', pa.int32()), + ]) + name = f'default.tbl_{uuid.uuid4().hex[:8]}' + schema = Schema.from_pyarrow_schema( + blob_schema, options=self.de_options) + self.catalog.create_table(name, schema, False) + self._write( + name, + pa.Table.from_pydict( + { + 'id': pa.array([1, 2, 3], type=pa.int32()), + 'payload': [b'aa', b'bbb', b'cccc'], + 'feature': pa.array([10, 20, 30], type=pa.int32()), + }, + schema=blob_schema, + ), + ) + + num_partitions = _TEST_NUM_PARTITIONS + input_ids = ray.data.from_arrow(pa.Table.from_pydict({ + 'id': pa.array([1, 3], type=pa.int32()), + })) + + target_rows = read_paimon( + name, + self.catalog_options, + projection=['id', 'payload'], + dynamic_table_options={'blob-as-descriptor': 'true'}, + ) + + matched = input_ids.join( + target_rows, join_type='inner', + num_partitions=num_partitions, on=['id'], + ) + + uri_factory = UriReaderFactory(self.catalog_options) + + def resolve_and_compute(batch): + features = [] + for desc_bytes in batch['payload'].to_pylist(): + desc = BlobDescriptor.deserialize(desc_bytes) + reader = uri_factory.create(desc.uri) + data = Blob.from_descriptor(reader, desc).to_data() + features.append(len(data) * 100) + return pa.Table.from_pydict({ + 'id': batch['id'], + 'new_feature': pa.array(features, type=pa.int32()), + }) + + updates = matched.map_batches( + resolve_and_compute, batch_format='pyarrow') + metrics = merge_into( + target=name, + source=updates, + catalog_options=self.catalog_options, + on=['id'], + when_matched=[ + WhenMatched(update={'feature': source_col('new_feature')}) + ], + num_partitions=num_partitions, + ) + + table = self.catalog.get_table(name) + rb = table.new_read_builder() + splits = rb.new_scan().plan().splits() + out = rb.new_read().to_arrow(splits).sort_by('id').to_pydict() + self.assertEqual(out['id'], [1, 2, 3]) + self.assertEqual(out['feature'], [200, 20, 400]) + self.assertEqual(out['payload'], [b'aa', b'bbb', b'cccc']) + self.assertEqual(metrics['num_matched'], 2) + def test_combined_writes_single_snapshot(self): target = self._create_table() self._write( diff --git a/paimon-python/pypaimon/tests/split_provider_test.py b/paimon-python/pypaimon/tests/split_provider_test.py index 3f4853f57d14..f18b4ae44bc5 100644 --- a/paimon-python/pypaimon/tests/split_provider_test.py +++ b/paimon-python/pypaimon/tests/split_provider_test.py @@ -253,14 +253,17 @@ def test_dynamic_table_options_rejects_tt_conflict(self): args = dict(table_identifier=self.identifier, catalog_options=self.catalog_options) with self.assertRaises(ValueError): - CatalogSplitProvider(**args, snapshot_id=1, - dynamic_table_options={'scan.tag-name': 'v1'}) + CatalogSplitProvider( + **args, snapshot_id=1, + dynamic_table_options={'scan.tag-name': 'v1'}) with self.assertRaises(ValueError): - CatalogSplitProvider(**args, tag_name='v1', - dynamic_table_options={'scan.snapshot-id': '1'}) + CatalogSplitProvider( + **args, tag_name='v1', + dynamic_table_options={'scan.snapshot-id': '1'}) with self.assertRaises(ValueError): - CatalogSplitProvider(**args, dynamic_table_options={ - 'scan.snapshot-id': '1', 'scan.tag-name': 'v1'}) + CatalogSplitProvider( + **args, dynamic_table_options={ + 'scan.snapshot-id': '1', 'scan.tag-name': 'v1'}) def test_pre_resolved_provider_returns_inputs(self): """PreResolvedSplitProvider just hands back what it was given.""" From 6b67f748c02256b4bf9fbbe6cb25f291355ab7a3 Mon Sep 17 00:00:00 2001 From: xiaohongbo Date: Thu, 11 Jun 2026 14:27:47 +0800 Subject: [PATCH 7/7] [python][ray] Rename dynamic_table_options to dynamic_options --- paimon-python/pypaimon/ray/ray_paimon.py | 6 +++--- .../pypaimon/read/datasource/split_provider.py | 16 ++++++++-------- .../tests/ray_data_evolution_merge_into_test.py | 2 +- .../pypaimon/tests/split_provider_test.py | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/paimon-python/pypaimon/ray/ray_paimon.py b/paimon-python/pypaimon/ray/ray_paimon.py index 04f8bcee2c6b..d0e7706c8347 100644 --- a/paimon-python/pypaimon/ray/ray_paimon.py +++ b/paimon-python/pypaimon/ray/ray_paimon.py @@ -56,7 +56,7 @@ def read_paimon( limit: Optional[int] = None, snapshot_id: Optional[int] = None, tag_name: Optional[str] = None, - dynamic_table_options: Optional[Dict[str, str]] = None, + dynamic_options: Optional[Dict[str, str]] = None, ray_remote_args: Optional[Dict[str, Any]] = None, concurrency: Optional[int] = None, override_num_blocks: Optional[int] = None, @@ -75,7 +75,7 @@ def read_paimon( exclusive with ``tag_name``. tag_name: Optional tag name to time-travel to. Mutually exclusive with ``snapshot_id``. - dynamic_table_options: Optional dynamic options to override at read time. + dynamic_options: Optional dynamic options to override at read time. ray_remote_args: Optional kwargs passed to ``ray.remote`` in read tasks. concurrency: Optional max number of Ray read tasks to run concurrently. override_num_blocks: Optional override for the number of output blocks. @@ -108,7 +108,7 @@ def read_paimon( limit=limit, snapshot_id=snapshot_id, tag_name=tag_name, - dynamic_table_options=dynamic_table_options, + dynamic_options=dynamic_options, ) if not split_provider.splits(): diff --git a/paimon-python/pypaimon/read/datasource/split_provider.py b/paimon-python/pypaimon/read/datasource/split_provider.py index bd01e75fb495..430eeb7cac1e 100644 --- a/paimon-python/pypaimon/read/datasource/split_provider.py +++ b/paimon-python/pypaimon/read/datasource/split_provider.py @@ -85,7 +85,7 @@ def __init__( limit: Optional[int] = None, snapshot_id: Optional[int] = None, tag_name: Optional[str] = None, - dynamic_table_options: Optional[Dict[str, str]] = None, + dynamic_options: Optional[Dict[str, str]] = None, ): if not table_identifier: raise ValueError("table_identifier is required") @@ -99,17 +99,17 @@ def __init__( "snapshot_id and tag_name cannot be set at the same time" ) - if dynamic_table_options: - dynamic_tt_keys = scan_keys & dynamic_table_options.keys() + if dynamic_options: + dynamic_tt_keys = scan_keys & dynamic_options.keys() if (snapshot_id is not None or tag_name is not None) and dynamic_tt_keys: raise ValueError( - "snapshot_id/tag_name and dynamic_table_options " + "snapshot_id/tag_name and dynamic_options " "time-travel keys cannot be set at the same time, " "got: {}".format(", ".join(sorted(dynamic_tt_keys))) ) if len(dynamic_tt_keys) > 1: raise ValueError( - "dynamic_table_options contains multiple time-travel " + "dynamic_options contains multiple time-travel " "keys which are mutually exclusive: {}".format( ", ".join(sorted(dynamic_tt_keys))) ) @@ -120,7 +120,7 @@ def __init__( self._limit = limit self._snapshot_id = snapshot_id self._tag_name = tag_name - self._dynamic_table_options = dynamic_table_options + self._dynamic_options = dynamic_options self._table_cached = None self._splits_cached = None self._read_type_cached = None @@ -135,8 +135,8 @@ def _ensure_table(self): dynamic_options["scan.snapshot-id"] = str(self._snapshot_id) if self._tag_name is not None: dynamic_options["scan.tag-name"] = self._tag_name - if self._dynamic_table_options: - dynamic_options.update(self._dynamic_table_options) + if self._dynamic_options: + dynamic_options.update(self._dynamic_options) if dynamic_options: table = table.copy(dynamic_options) self._table_cached = table diff --git a/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py b/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py index 69608382df1d..4782b1dc9342 100644 --- a/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py +++ b/paimon-python/pypaimon/tests/ray_data_evolution_merge_into_test.py @@ -621,7 +621,7 @@ def test_blob_descriptor_resolve_and_merge(self): name, self.catalog_options, projection=['id', 'payload'], - dynamic_table_options={'blob-as-descriptor': 'true'}, + dynamic_options={'blob-as-descriptor': 'true'}, ) matched = input_ids.join( diff --git a/paimon-python/pypaimon/tests/split_provider_test.py b/paimon-python/pypaimon/tests/split_provider_test.py index f18b4ae44bc5..61e14005f5fc 100644 --- a/paimon-python/pypaimon/tests/split_provider_test.py +++ b/paimon-python/pypaimon/tests/split_provider_test.py @@ -227,7 +227,7 @@ def test_catalog_provider_time_travel_by_tag_name(self): rows = tr.to_arrow(provider.splits()).to_pylist() self.assertEqual([r['id'] for r in rows], [11]) - def test_dynamic_table_options_blob_as_descriptor(self): + def test_dynamic_options_blob_as_descriptor(self): pa_schema = pa.schema([ ('id', pa.int32()), ('picture', pa.large_binary()), @@ -244,25 +244,25 @@ def test_dynamic_table_options_blob_as_descriptor(self): provider = CatalogSplitProvider( table_identifier=identifier, catalog_options=self.catalog_options, - dynamic_table_options={'blob-as-descriptor': 'true'}, + dynamic_options={'blob-as-descriptor': 'true'}, ) table = provider.table() self.assertTrue(table.options.blob_as_descriptor()) - def test_dynamic_table_options_rejects_tt_conflict(self): + def test_dynamic_options_rejects_tt_conflict(self): args = dict(table_identifier=self.identifier, catalog_options=self.catalog_options) with self.assertRaises(ValueError): CatalogSplitProvider( **args, snapshot_id=1, - dynamic_table_options={'scan.tag-name': 'v1'}) + dynamic_options={'scan.tag-name': 'v1'}) with self.assertRaises(ValueError): CatalogSplitProvider( **args, tag_name='v1', - dynamic_table_options={'scan.snapshot-id': '1'}) + dynamic_options={'scan.snapshot-id': '1'}) with self.assertRaises(ValueError): CatalogSplitProvider( - **args, dynamic_table_options={ + **args, dynamic_options={ 'scan.snapshot-id': '1', 'scan.tag-name': 'v1'}) def test_pre_resolved_provider_returns_inputs(self):