Skip to content

Commit e14532f

Browse files
committed
Merge branch 'migration' of https://github.com/geetu040/openml-python into runs-migration-stacked
2 parents 0a7dd16 + cabaecf commit e14532f

9 files changed

Lines changed: 209 additions & 27 deletions

File tree

openml/_api/clients/http.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ def __init__( # noqa: PLR0913
116116
server: str,
117117
base_url: str,
118118
api_key: str,
119-
timeout: int,
119+
timeout_seconds: int,
120120
retries: int,
121121
retry_policy: RetryPolicy,
122122
cache: HTTPCache | None = None,
123123
) -> None:
124124
self.server = server
125125
self.base_url = base_url
126126
self.api_key = api_key
127-
self.timeout = timeout
127+
self.timeout_seconds = timeout_seconds
128128
self.retries = retries
129129
self.retry_policy = retry_policy
130130
self.cache = cache
@@ -343,7 +343,7 @@ def request(
343343
headers = request_kwargs.pop("headers", {}).copy()
344344
headers.update(self.headers)
345345

346-
timeout = request_kwargs.pop("timeout", self.timeout)
346+
timeout = request_kwargs.pop("timeout", self.timeout_seconds)
347347
files = request_kwargs.pop("files", None)
348348

349349
if use_cache and not reset_cache and self.cache is not None:

openml/_api/setup/backend.py

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
from __future__ import annotations
22

33
from copy import deepcopy
4-
from typing import Any
4+
from typing import TYPE_CHECKING, Any, cast
55

66
from .builder import APIBackendBuilder
77
from .config import Config
88

9+
if TYPE_CHECKING:
10+
from openml._api.resources import (
11+
DatasetAPI,
12+
EstimationProcedureAPI,
13+
EvaluationAPI,
14+
EvaluationMeasureAPI,
15+
FlowAPI,
16+
RunAPI,
17+
SetupAPI,
18+
StudyAPI,
19+
TaskAPI,
20+
)
21+
922

1023
class APIBackend:
1124
_instance: APIBackend | None = None
@@ -14,12 +27,41 @@ def __init__(self, config: Config | None = None):
1427
self._config: Config = config or Config()
1528
self._backend = APIBackendBuilder.build(self._config)
1629

17-
def __getattr__(self, name: str) -> Any:
18-
"""
19-
Delegate attribute access to the underlying backend.
20-
Called only if attribute is not found on RuntimeBackend.
21-
"""
22-
return getattr(self._backend, name)
30+
@property
31+
def dataset(self) -> DatasetAPI:
32+
return cast("DatasetAPI", self._backend.dataset)
33+
34+
@property
35+
def task(self) -> TaskAPI:
36+
return cast("TaskAPI", self._backend.task)
37+
38+
@property
39+
def evaluation_measure(self) -> EvaluationMeasureAPI:
40+
return cast("EvaluationMeasureAPI", self._backend.evaluation_measure)
41+
42+
@property
43+
def estimation_procedure(self) -> EstimationProcedureAPI:
44+
return cast("EstimationProcedureAPI", self._backend.estimation_procedure)
45+
46+
@property
47+
def evaluation(self) -> EvaluationAPI:
48+
return cast("EvaluationAPI", self._backend.evaluation)
49+
50+
@property
51+
def flow(self) -> FlowAPI:
52+
return cast("FlowAPI", self._backend.flow)
53+
54+
@property
55+
def study(self) -> StudyAPI:
56+
return cast("StudyAPI", self._backend.study)
57+
58+
@property
59+
def run(self) -> RunAPI:
60+
return cast("RunAPI", self._backend.run)
61+
62+
@property
63+
def setup(self) -> SetupAPI:
64+
return cast("SetupAPI", self._backend.setup)
2365

2466
@classmethod
2567
def get_instance(cls) -> APIBackend:
@@ -38,7 +80,7 @@ def set_config(cls, config: Config) -> None:
3880
instance._backend = APIBackendBuilder.build(config)
3981

4082
@classmethod
41-
def get_config_value(cls, key: str) -> Config:
83+
def get_config_value(cls, key: str) -> Any:
4284
keys = key.split(".")
4385
config_value = cls.get_instance()._config
4486
for k in keys:
@@ -60,3 +102,27 @@ def set_config_value(cls, key: str, value: Any) -> None:
60102
else:
61103
setattr(parent, keys[-1], value)
62104
cls.set_config(config)
105+
106+
@classmethod
107+
def get_config_values(cls, keys: list[str]) -> list[Any]:
108+
values = []
109+
for key in keys:
110+
value = cls.get_config_value(key)
111+
values.append(value)
112+
return values
113+
114+
@classmethod
115+
def set_config_values(cls, config_dict: dict[str, Any]) -> None:
116+
config = cls.get_instance()._config
117+
118+
for key, value in config_dict.items():
119+
keys = key.split(".")
120+
parent = config
121+
for k in keys[:-1]:
122+
parent = parent[k] if isinstance(parent, dict) else getattr(parent, k)
123+
if isinstance(parent, dict):
124+
parent[keys[-1]] = value
125+
else:
126+
setattr(parent, keys[-1], value)
127+
128+
cls.set_config(config)

openml/_api/setup/builder.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66

77
from openml._api.clients import HTTPCache, HTTPClient, MinIOClient
88
from openml._api.resources import API_REGISTRY, FallbackProxy, ResourceAPI
9+
from openml.enums import ResourceType
910

1011
if TYPE_CHECKING:
11-
from openml.enums import ResourceType
12-
1312
from .config import Config
1413

1514

@@ -18,8 +17,15 @@ def __init__(
1817
self,
1918
resource_apis: Mapping[ResourceType, ResourceAPI | FallbackProxy],
2019
):
21-
for resource_type, resource_api in resource_apis.items():
22-
setattr(self, resource_type.value, resource_api)
20+
self.dataset = resource_apis[ResourceType.DATASET]
21+
self.task = resource_apis[ResourceType.TASK]
22+
self.evaluation_measure = resource_apis[ResourceType.EVALUATION_MEASURE]
23+
self.estimation_procedure = resource_apis[ResourceType.ESTIMATION_PROCEDURE]
24+
self.evaluation = resource_apis[ResourceType.EVALUATION]
25+
self.flow = resource_apis[ResourceType.FLOW]
26+
self.study = resource_apis[ResourceType.STUDY]
27+
self.run = resource_apis[ResourceType.RUN]
28+
self.setup = resource_apis[ResourceType.SETUP]
2329

2430
@classmethod
2531
def build(cls, config: Config) -> APIBackendBuilder:
@@ -33,7 +39,7 @@ def build(cls, config: Config) -> APIBackendBuilder:
3339
server=primary_api_config.server,
3440
base_url=primary_api_config.base_url,
3541
api_key=primary_api_config.api_key,
36-
timeout=config.connection.timeout,
42+
timeout_seconds=config.connection.timeout_seconds,
3743
retries=config.connection.retries,
3844
retry_policy=config.connection.retry_policy,
3945
cache=http_cache,
@@ -51,7 +57,7 @@ def build(cls, config: Config) -> APIBackendBuilder:
5157
server=fallback_api_config.server,
5258
base_url=fallback_api_config.base_url,
5359
api_key=fallback_api_config.api_key,
54-
timeout=config.connection.timeout,
60+
timeout_seconds=config.connection.timeout_seconds,
5561
retries=config.connection.retries,
5662
retry_policy=config.connection.retry_policy,
5763
cache=http_cache,

openml/_api/setup/config.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass, field
4+
from datetime import timedelta
45

56
from openml.enums import APIVersion, RetryPolicy
67

@@ -18,7 +19,7 @@ class APIConfig:
1819
class ConnectionConfig:
1920
retries: int
2021
retry_policy: RetryPolicy
21-
timeout: int
22+
timeout_seconds: int
2223

2324

2425
@dataclass
@@ -51,13 +52,13 @@ class Config:
5152
default_factory=lambda: ConnectionConfig(
5253
retries=5,
5354
retry_policy=RetryPolicy.HUMAN,
54-
timeout=10,
55+
timeout_seconds=10,
5556
)
5657
)
5758

5859
cache: CacheConfig = field(
5960
default_factory=lambda: CacheConfig(
6061
dir=str(_resolve_default_cache_dir()),
61-
ttl=60 * 60 * 24 * 7,
62+
ttl=int(timedelta(weeks=1).total_seconds()),
6263
)
6364
)

openml/config.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from typing_extensions import TypedDict
1919
from urllib.parse import urlparse
2020

21+
from openml.enums import RetryPolicy
22+
2123
logger = logging.getLogger(__name__)
2224
openml_logger = logging.getLogger("openml")
2325
console_handler: logging.StreamHandler | None = None
@@ -206,6 +208,8 @@ def set_retry_policy(value: Literal["human", "robot"], n_retries: int | None = N
206208
retry_policy = value
207209
connection_n_retries = default_retries_by_policy[value] if n_retries is None else n_retries
208210

211+
_sync_api_config()
212+
209213

210214
class ConfigurationForExamples:
211215
"""Allows easy switching to and from a test configuration, used for examples."""
@@ -244,6 +248,8 @@ def start_using_configuration_for_example(cls) -> None:
244248
stacklevel=2,
245249
)
246250

251+
_sync_api_config()
252+
247253
@classmethod
248254
def stop_using_configuration_for_example(cls) -> None:
249255
"""Return to configuration as it was before `start_use_example_configuration`."""
@@ -262,6 +268,8 @@ def stop_using_configuration_for_example(cls) -> None:
262268
apikey = cast("str", cls._last_used_key)
263269
cls._start_last_called = False
264270

271+
_sync_api_config()
272+
265273

266274
def _handle_xdg_config_home_backwards_compatibility(
267275
xdg_home: str,
@@ -374,6 +382,8 @@ def _setup(config: _Config | None = None) -> None:
374382
short_cache_dir = Path(config["cachedir"])
375383
_root_cache_directory = short_cache_dir.expanduser().resolve()
376384

385+
_sync_api_config()
386+
377387
try:
378388
cache_exists = _root_cache_directory.exists()
379389
# create the cache subdirectory
@@ -408,6 +418,8 @@ def set_field_in_config_file(field: str, value: Any) -> None:
408418
if value is not None:
409419
fh.write(f"{f} = {value}\n")
410420

421+
_sync_api_config()
422+
411423

412424
def _parse_config(config_file: str | Path) -> _Config:
413425
"""Parse the config file, set up defaults."""
@@ -495,6 +507,8 @@ def set_root_cache_directory(root_cache_directory: str | Path) -> None:
495507
global _root_cache_directory # noqa: PLW0603
496508
_root_cache_directory = Path(root_cache_directory)
497509

510+
_sync_api_config()
511+
498512

499513
start_using_configuration_for_example = (
500514
ConfigurationForExamples.start_using_configuration_for_example
@@ -514,6 +528,28 @@ def overwrite_config_context(config: dict[str, Any]) -> Iterator[_Config]:
514528
_setup(existing_config)
515529

516530

531+
def _sync_api_config() -> None:
532+
"""Sync the new API config with the legacy config in this file."""
533+
from ._api import APIBackend
534+
535+
p = urlparse(server)
536+
v1_server = f"{p.scheme}://{p.netloc}/"
537+
v1_base_url = p.path.lstrip("/")
538+
connection_retry_policy = RetryPolicy.HUMAN if retry_policy == "human" else RetryPolicy.ROBOT
539+
cache_dir = str(_root_cache_directory)
540+
541+
APIBackend.set_config_values(
542+
{
543+
"api_configs.v1.server": v1_server,
544+
"api_configs.v1.base_url": v1_base_url,
545+
"api_configs.v1.api_key": apikey,
546+
"cache.dir": cache_dir,
547+
"connection.retry_policy": connection_retry_policy,
548+
"connection.retries": connection_n_retries,
549+
}
550+
)
551+
552+
517553
__all__ = [
518554
"get_cache_directory",
519555
"get_config_as_dict",

0 commit comments

Comments
 (0)