Skip to content

Commit 796c915

Browse files
committed
rid of Config.load and left only lazy loading
1 parent f6fcefc commit 796c915

File tree

5 files changed

+53
-18
lines changed

5 files changed

+53
-18
lines changed

pyiceberg/utils/config.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ def _lowercase_dictionary_keys(input_dict: RecursiveDict) -> RecursiveDict:
5959
class Config:
6060
config: RecursiveDict
6161

62-
def __init__(self) -> None:
63-
config = self._from_configuration_files() or {}
64-
config = merge_config(config, self._from_environment_variables(config))
65-
self.config = FrozenDict(**config)
62+
def __init__(self, config: RecursiveDict | None = None) -> None:
63+
self.config = FrozenDict(**(config or {}))
6664

6765
@staticmethod
6866
def _from_configuration_files() -> RecursiveDict | None:

tests/catalog/test_base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
# under the License.
1717
# pylint:disable=redefined-outer-name
1818

19-
2019
from collections.abc import Generator
2120
from pathlib import PosixPath
2221

tests/catalog/test_bigquery_metastore.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
import os
1817
from unittest.mock import MagicMock
1918

2019
from google.api_core.exceptions import NotFound
@@ -25,6 +24,7 @@
2524
from pyiceberg.catalog.bigquery_metastore import ICEBERG_TABLE_TYPE_VALUE, TABLE_TYPE_PROP, BigQueryMetastoreCatalog
2625
from pyiceberg.exceptions import NoSuchTableError
2726
from pyiceberg.schema import Schema
27+
from pyiceberg.utils.config import Config
2828

2929

3030
def dataset_mock() -> Dataset:
@@ -59,7 +59,10 @@ def test_create_table_with_database_location(
5959

6060
mocker.patch("pyiceberg.catalog.bigquery_metastore.Client", return_value=client_mock)
6161
mocker.patch("pyiceberg.catalog.bigquery_metastore.FromInputFile.table_metadata", return_value=file_mock)
62-
mocker.patch.dict(os.environ, values={"PYICEBERG_LEGACY_CURRENT_SNAPSHOT_ID": "True"})
62+
mocker.patch(
63+
"pyiceberg.catalog.bigquery_metastore.Config",
64+
return_value=Config({"legacy-current-snapshot-id": "True"}),
65+
)
6366
mocker.patch("pyiceberg.catalog.ToOutputFile.table_metadata", return_value=None)
6467

6568
catalog_name = "test_ddb_catalog"
@@ -85,7 +88,10 @@ def test_drop_table_with_database_location(
8588

8689
mocker.patch("pyiceberg.catalog.bigquery_metastore.Client", return_value=client_mock)
8790
mocker.patch("pyiceberg.catalog.bigquery_metastore.FromInputFile.table_metadata", return_value=file_mock)
88-
mocker.patch.dict(os.environ, values={"PYICEBERG_LEGACY_CURRENT_SNAPSHOT_ID": "True"})
91+
mocker.patch(
92+
"pyiceberg.catalog.bigquery_metastore.Config",
93+
return_value=Config({"legacy-current-snapshot-id": "True"}),
94+
)
8995
mocker.patch("pyiceberg.catalog.ToOutputFile.table_metadata", return_value=None)
9096

9197
catalog_name = "test_ddb_catalog"
@@ -111,7 +117,10 @@ def test_drop_table_with_database_location(
111117
def test_drop_namespace(mocker: MockFixture, gcp_dataset_name: str) -> None:
112118
client_mock = MagicMock()
113119
mocker.patch("pyiceberg.catalog.bigquery_metastore.Client", return_value=client_mock)
114-
mocker.patch.dict(os.environ, values={"PYICEBERG_LEGACY_CURRENT_SNAPSHOT_ID": "True"})
120+
mocker.patch(
121+
"pyiceberg.catalog.bigquery_metastore.Config",
122+
return_value=Config({"legacy-current-snapshot-id": "True"}),
123+
)
115124

116125
catalog_name = "test_catalog"
117126
test_catalog = BigQueryMetastoreCatalog(catalog_name, **{"gcp.bigquery.project-id": "alexstephen-test-1"})
@@ -146,7 +155,10 @@ def test_list_tables(mocker: MockFixture, gcp_dataset_name: str) -> None:
146155
client_mock.get_table.return_value = table_mock()
147156

148157
mocker.patch("pyiceberg.catalog.bigquery_metastore.Client", return_value=client_mock)
149-
mocker.patch.dict(os.environ, values={"PYICEBERG_LEGACY_CURRENT_SNAPSHOT_ID": "True"})
158+
mocker.patch(
159+
"pyiceberg.catalog.bigquery_metastore.Config",
160+
return_value=Config({"legacy-current-snapshot-id": "True"}),
161+
)
150162

151163
catalog_name = "test_catalog"
152164
test_catalog = BigQueryMetastoreCatalog(catalog_name, **{"gcp.bigquery.project-id": "my-project"})
@@ -168,7 +180,10 @@ def test_list_namespaces(mocker: MockFixture) -> None:
168180
client_mock.list_datasets.return_value = iter([dataset_item_1, dataset_item_2])
169181

170182
mocker.patch("pyiceberg.catalog.bigquery_metastore.Client", return_value=client_mock)
171-
mocker.patch.dict(os.environ, values={"PYICEBERG_LEGACY_CURRENT_SNAPSHOT_ID": "True"})
183+
mocker.patch(
184+
"pyiceberg.catalog.bigquery_metastore.Config",
185+
return_value=Config({"legacy-current-snapshot-id": "True"}),
186+
)
172187

173188
catalog_name = "test_catalog"
174189
test_catalog = BigQueryMetastoreCatalog(catalog_name, **{"gcp.bigquery.project-id": "my-project"})

tests/catalog/test_rest.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,18 +2036,18 @@ def test_catalog_from_environment_variables(catalog_config_mock: mock.Mock, rest
20362036

20372037

20382038
@mock.patch.dict(os.environ, EXAMPLE_ENV)
2039-
@mock.patch("pyiceberg.catalog._ENV_CONFIG.get_catalog_config")
2040-
def test_catalog_from_environment_variables_override(catalog_config_mock: mock.Mock, rest_mock: Mocker) -> None:
2039+
def test_catalog_from_environment_variables_override(rest_mock: Mocker) -> None:
20412040
rest_mock.get(
20422041
"https://other-service.io/api/v1/config",
20432042
json={"defaults": {}, "overrides": {}},
20442043
status_code=200,
20452044
)
20462045
env_config: RecursiveDict = Config._from_environment_variables({})
2047-
2048-
catalog_config_mock.return_value = cast(RecursiveDict, env_config.get("catalog")).get("production")
2049-
catalog = cast(RestCatalog, load_catalog("production", uri="https://other-service.io/api"))
2050-
assert catalog.uri == "https://other-service.io/api"
2046+
mock_env_config = mock.Mock()
2047+
mock_env_config.get_catalog_config.return_value = cast(RecursiveDict, env_config.get("catalog")).get("production")
2048+
with mock.patch("pyiceberg.catalog._ENV_CONFIG", mock_env_config):
2049+
catalog = cast(RestCatalog, load_catalog("production", uri="https://other-service.io/api"))
2050+
assert catalog.uri == "https://other-service.io/api"
20512051

20522052

20532053
def test_catalog_from_parameters_empty_env(rest_mock: Mocker) -> None:

tests/utils/test_config.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,20 @@
2828

2929

3030
def test_config() -> None:
31-
"""To check if all the file lookups go well without any mocking"""
31+
"""Config() should be a pure empty container and perform no implicit IO."""
3232
assert Config()
33+
assert Config().config == {}
34+
35+
36+
def test_config_does_not_load_implicitly() -> None:
37+
with (
38+
mock.patch.object(Config, "_from_configuration_files") as from_files_mock,
39+
mock.patch.object(Config, "_from_environment_variables") as from_env_mock,
40+
):
41+
Config()
42+
43+
from_files_mock.assert_not_called()
44+
from_env_mock.assert_not_called()
3345

3446

3547
@mock.patch.dict(os.environ, EXAMPLE_ENV)
@@ -183,3 +195,14 @@ def create_config_file(path: str, uri: str | None) -> None:
183195
assert (
184196
result["catalog"]["default"]["uri"] if result else None # type: ignore
185197
) == expected_result, f"Unexpected configuration result. Expected: {expected_result}, Actual: {result}"
198+
199+
200+
def test_load_reads_file_and_environment_once(monkeypatch: pytest.MonkeyPatch) -> None:
201+
monkeypatch.setenv("PYICEBERG_CATALOG__PRODUCTION__URI", "https://env.service.io/api")
202+
with mock.patch.object(
203+
Config, "_from_configuration_files", return_value={"catalog": {"production": {"type": "rest"}}}
204+
) as files_mock:
205+
config = Config()
206+
207+
files_mock.assert_called_once()
208+
assert config.get_catalog_config("production") == {"type": "rest", "uri": "https://env.service.io/api"}

0 commit comments

Comments
 (0)