blob: beed1f371cc2bb6f21caa0f7ed330149de60a795 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Execution packages hold paired Paimon backends, not common adapters."""
from pathlib import Path
import subprocess
import sys
import pytest
def test_execution_package_contains_only_backend_implementations():
root = Path(__file__).resolve().parents[1] / 'execution'
modules = {path.name for path in root.iterdir() if path.is_file() and path.suffix == '.py'}
packages = {path.name for path in root.iterdir()
if path.is_dir() and any(path.glob('*.py'))}
assert modules == {'__init__.py'}
assert packages == {'python', 'native'}
@pytest.mark.skipif(sys.version_info < (3, 7), reason='Python 3.6 retains eager package exports')
def test_common_adapters_do_not_load_either_execution_backend():
source = r"""
import importlib
import importlib.abc
import sys
class RejectExecution(importlib.abc.MetaPathFinder):
def find_spec(self, fullname, path=None, target=None):
if fullname == 'pypaimon.execution' or fullname.startswith('pypaimon.execution.'):
raise AssertionError('A common adapter imported an execution backend: ' + fullname)
sys.meta_path.insert(0, RejectExecution())
modules = [
'pypaimon.read.read_dispatch', 'pypaimon.read.read_support',
'pypaimon.read.read_explain', 'pypaimon.table.source.search_dispatch',
'pypaimon.write.backend_dispatch', 'pypaimon.write.write_dispatch',
'pypaimon.write.update_dispatch', 'pypaimon.write.input_adapter',
'pypaimon.write.merge_condition', 'pypaimon.write.merge_transform',
'pypaimon.globalindex.index_dispatch', 'pypaimon.globalindex.vindex_input',
'pypaimon.table.system.system_table_read',
'pypaimon.table.source.deletion_file', 'pypaimon.index.deletion_vector_meta',
'pypaimon.index.index_file_meta',
'pypaimon.index.dynamic_bucket', 'pypaimon.data.map_shared_shredding',
'pypaimon.data.variant_shredding', 'pypaimon.data.variant_path',
'pypaimon.schema.arrow_schema', 'pypaimon.schema.data_type_casts',
'pypaimon.schema.schema_manager', 'pypaimon.utils.file_store_path_factory',
'pypaimon.table.system.files_table', 'pypaimon.common.predicate_json_parser',
'pypaimon.common.transform_schema', 'pypaimon.common.arrow_predicate',
'pypaimon.common.external_path_provider',
'pypaimon.common.uri_reader', 'pypaimon.common.blob_index_cache',
'pypaimon.common.delta_varint_compressor', 'pypaimon.common.file_io',
]
for name in modules:
importlib.import_module(name)
from pypaimon.utils.file_store_path_factory import FileStorePathFactory
factory = FileStorePathFactory(
'/warehouse', ['p'], '__DEFAULT_PARTITION__', 'parquet', 'data-', 'changelog-',
False, False, 'zstd', external_paths=['/external'], external_path_strategy='round-robin')
provider = factory.create_external_path_provider(('x',), 0, canonical_partition=True)
assert provider.get_next_external_data_path('data.parquet') == '/external/p=x/bucket-0/data.parquet'
assert not any(name == 'pypaimon.execution' or name.startswith('pypaimon.execution.')
for name in sys.modules)
"""
result = subprocess.run([sys.executable, '-c', source],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, timeout=30)
assert result.returncode == 0, result.stdout + result.stderr