1- """Public API for the DataConnect client library."""
1+ """Public API for the DataConnect client library.
2+
3+ ``DataConnectClient`` is a thin façade over ``DataConnectService``.
4+ The ``connect()`` class method is the composition root — the only place in
5+ the SDK where concrete implementation types are wired together.
6+ """
27
38from __future__ import annotations
49
5- import json
610from types import TracebackType
7- from typing import Any
8-
9- import pyarrow as pa
10-
11- from dataconnect import _encoding
12- from dataconnect .auth import BearerTokenAuth
13- from dataconnect .framework .pyarrow_transport import PyArrowFlightTransport
14- from dataconnect .framework .transport import FlightTransport
15- from dataconnect .models import Dataset , Study
1611
17- # Flight actions / commands
18- _ACTION_LIST_STUDIES = "studies.list"
19- _ACTION_LIST_DATASETS = "datasets.list"
20- _ACTION_LIST_DATASET_VERSIONS = "dataset_versions.list"
21- _ACTION_FETCH_TICKET = "data.fetch_ticket"
22- _CMD_PUBLISH = "publish"
23- _CMD_DRY_PUBLISH = "dry_publish"
12+ from dataconnect .models import Study
13+ from dataconnect .service import DataConnectService , DefaultDataConnectService
2414
2515_DEFAULT_HOST = "enodia-gateway.platform.imedidata.com"
2616_DEFAULT_PORT = 443
2919class DataConnectClient :
3020 """Client for interacting with DataConnect services."""
3121
32- def __init__ (self , transport : FlightTransport ) -> None :
33- """Initialize the DataConnect client with a specified transport ."""
34- self ._transport = transport
22+ def __init__ (self , service : DataConnectService ) -> None :
23+ """Initialize the client with an injected service implementation ."""
24+ self ._service = service
3525
3626 @classmethod
3727 def connect (
@@ -41,37 +31,26 @@ def connect(
4131 use_tls : bool = True ,
4232 token : str = "" ,
4333 ) -> DataConnectClient :
44- """Open connection to a Flight server."""
45- location = f"grpc+tls://{ host } :{ port } "
46- transport = PyArrowFlightTransport (
47- location = location ,
48- credentials = BearerTokenAuth (token ),
49- )
50- return cls (transport )
51-
52- def studies (self ) -> list [Study ]:
34+
35+ # Import is deferred so pyarrow.flight is only loaded when this factory
36+ # is called — callers injecting a custom transport are unaffected.
37+ from dataconnect .transport .arrow_flight .transport import ArrowFlightTransport
38+
39+ transport = ArrowFlightTransport (host = host , port = port , use_tls = use_tls , token = token )
40+
41+ return cls (DefaultDataConnectService (transport ))
42+
43+ # Public API
44+
45+ def get_studies (self ) -> list [Study ]:
5346 """List the studies the client is authorized to access."""
54- rows = self ._action_json (_ACTION_LIST_STUDIES , None )
55- return [Study (** r ) for r in rows ]
56-
57- def datasets (self , study_uuid : str ) -> list [Dataset ]:
58- """List the datasets available for a given study."""
59- body = {"study_uuid" : study_uuid }
60- rows = self ._action_json (_ACTION_LIST_DATASETS , {"study_uuid" : body })
61- return [Dataset (** r ) for r in rows ]
62-
63- def fetch_data (self , dataset_uuid : str ) -> pa .Table :
64- """Fetch the data for a given dataset as a PyArrow Table."""
65- body = {"dataset_uuid" : dataset_uuid }
66- results = self ._transport .do_action (_ACTION_FETCH_TICKET , _encoding .dumps (body ))
67- if not results :
68- raise RuntimeError ("Server returned no data for the fetch_data action." )
69- return self ._transport .do_get (results ).read_all ()
47+ return self ._service .get_studies ()
7048
7149 # Lifecycle
50+
7251 def close (self ) -> None :
73- """Close the underlying transport connection."""
74- self ._transport .close ()
52+ """Close the underlying connection."""
53+ self ._service .close ()
7554
7655 def __enter__ (self ) -> DataConnectClient :
7756 return self
@@ -82,12 +61,4 @@ def __exit__(
8261 exc_value : BaseException | None ,
8362 traceback : TracebackType | None ,
8463 ) -> None :
85- self ._transport .close ()
86-
87- # Helpers
88- def _action_json (self , action : str , body : dict [str , Any ] | None ) -> Any :
89- """Execute a Flight action and return the result as JSON."""
90- results = self ._transport .do_action (action , _encoding .dumps (body or {}))
91- if not results :
92- return []
93- return json .loads (results .decode ("utf-8" ))
64+ self ._service .close ()
0 commit comments