55import os
66import sys
77import warnings
8- from functools import cached_property
98from typing import Dict , Optional , Union
109
1110from kili .adapters .authentification import is_api_key_valid
1211from kili .adapters .http_client import HttpClient
1312from kili .adapters .kili_api_gateway .kili_api_gateway import KiliAPIGateway
1413from kili .core .graphql .graphql_client import GraphQLClient , GraphQLClientName
15- from kili .domain_api import (
16- AssetsNamespace ,
17- CloudStorageNamespace ,
18- ConnectionsNamespace ,
19- IntegrationsNamespace ,
20- IssuesNamespace ,
21- LabelsNamespace ,
22- NotificationsNamespace ,
23- OrganizationsNamespace ,
24- ProjectsNamespace ,
25- TagsNamespace ,
26- UsersNamespace ,
27- )
2814from kili .entrypoints .mutations .asset import MutationsAsset
2915from kili .entrypoints .mutations .issue import MutationsIssue
3016from kili .entrypoints .mutations .notification import MutationsNotification
@@ -97,9 +83,11 @@ def __init__(
9783 verify : Optional [Union [bool , str ]] = None ,
9884 client_name : GraphQLClientName = GraphQLClientName .SDK ,
9985 graphql_client_params : Optional [Dict [str , object ]] = None ,
100- legacy : bool = True ,
10186 ) -> None :
102- """Initialize Kili client.
87+ """Initialize Kili client (legacy mode).
88+
89+ This client provides access to legacy methods through mixin inheritance.
90+ For the domain-based API, use `from kili.client_domain import Kili` instead.
10391
10492 Args:
10593 api_key: User API key generated
@@ -122,11 +110,6 @@ def __init__(
122110 client_name: For internal use only.
123111 Define the name of the graphQL client whith which graphQL calls will be sent.
124112 graphql_client_params: Parameters to pass to the graphQL client.
125- legacy: Controls namespace naming and legacy method availability.
126- When True (default), legacy methods are available and domain namespaces
127- use the '_ns' suffix (e.g., kili.assets_ns).
128- When False, legacy methods are not available and domain namespaces
129- use clean names (e.g., kili.assets).
130113
131114 Returns:
132115 Instance of the Kili client.
@@ -135,15 +118,10 @@ def __init__(
135118 ```python
136119 from kili.client import Kili
137120
138- # Legacy mode (default)
121+ # Legacy API with methods
139122 kili = Kili()
140123 kili.assets() # legacy method
141- kili.assets_ns # domain namespace
142-
143- # Modern mode
144- kili = Kili(legacy=False)
145- kili.assets # domain namespace (clean name)
146- # kili.assets() not available
124+ kili.projects() # legacy method
147125 ```
148126 """
149127 api_key = api_key or os .getenv ("KILI_API_KEY" )
@@ -172,7 +150,6 @@ def __init__(
172150 self .api_endpoint = api_endpoint
173151 self .verify = verify
174152 self .client_name = client_name
175- self ._legacy_mode = legacy
176153 self .http_client = HttpClient (kili_endpoint = api_endpoint , verify = verify , api_key = api_key )
177154 skip_checks = os .getenv ("KILI_SDK_SKIP_CHECKS" ) is not None
178155 if not skip_checks and not is_api_key_valid (
@@ -200,286 +177,3 @@ def __init__(
200177 if not skip_checks :
201178 api_key_use_cases = ApiKeyUseCases (self .kili_api_gateway )
202179 api_key_use_cases .check_expiry_of_key_is_close (api_key )
203-
204- # Domain API Namespaces - Lazy loaded properties
205- @cached_property
206- def assets_ns (self ) -> AssetsNamespace :
207- """Get the assets domain namespace.
208-
209- Returns:
210- AssetsNamespace: Assets domain namespace with lazy loading
211-
212- Examples:
213- ```python
214- kili = Kili()
215- # Namespace is instantiated on first access
216- assets_ns = kili.assets_ns
217- ```
218- """
219- return AssetsNamespace (self , self .kili_api_gateway )
220-
221- @cached_property
222- def labels_ns (self ) -> LabelsNamespace :
223- """Get the labels domain namespace.
224-
225- Returns:
226- LabelsNamespace: Labels domain namespace with lazy loading
227-
228- Examples:
229- ```python
230- kili = Kili()
231- # Namespace is instantiated on first access
232- labels_ns = kili.labels_ns
233- ```
234- """
235- return LabelsNamespace (self , self .kili_api_gateway )
236-
237- @cached_property
238- def projects_ns (self ) -> ProjectsNamespace :
239- """Get the projects domain namespace.
240-
241- Returns:
242- ProjectsNamespace: Projects domain namespace with lazy loading
243-
244- Examples:
245- ```python
246- kili = Kili()
247- # Namespace is instantiated on first access
248- projects_ns = kili.projects_ns
249- ```
250- """
251- return ProjectsNamespace (self , self .kili_api_gateway )
252-
253- @cached_property
254- def users_ns (self ) -> UsersNamespace :
255- """Get the users domain namespace.
256-
257- Returns:
258- UsersNamespace: Users domain namespace with lazy loading
259-
260- Examples:
261- ```python
262- kili = Kili()
263- # Namespace is instantiated on first access
264- users_ns = kili.users_ns
265- ```
266- """
267- return UsersNamespace (self , self .kili_api_gateway )
268-
269- @cached_property
270- def organizations_ns (self ) -> OrganizationsNamespace :
271- """Get the organizations domain namespace.
272-
273- Returns:
274- OrganizationsNamespace: Organizations domain namespace with lazy loading
275-
276- Examples:
277- ```python
278- kili = Kili()
279- # Namespace is instantiated on first access
280- organizations_ns = kili.organizations_ns
281- ```
282- """
283- return OrganizationsNamespace (self , self .kili_api_gateway )
284-
285- @cached_property
286- def issues_ns (self ) -> IssuesNamespace :
287- """Get the issues domain namespace.
288-
289- Returns:
290- IssuesNamespace: Issues domain namespace with lazy loading
291-
292- Examples:
293- ```python
294- kili = Kili()
295- # Namespace is instantiated on first access
296- issues_ns = kili.issues_ns
297- ```
298- """
299- return IssuesNamespace (self , self .kili_api_gateway )
300-
301- @cached_property
302- def notifications_ns (self ) -> NotificationsNamespace :
303- """Get the notifications domain namespace.
304-
305- Returns:
306- NotificationsNamespace: Notifications domain namespace with lazy loading
307-
308- Examples:
309- ```python
310- kili = Kili()
311- # Namespace is instantiated on first access
312- notifications_ns = kili.notifications_ns
313- ```
314- """
315- return NotificationsNamespace (self , self .kili_api_gateway )
316-
317- @cached_property
318- def tags_ns (self ) -> TagsNamespace :
319- """Get the tags domain namespace.
320-
321- Returns:
322- TagsNamespace: Tags domain namespace with lazy loading
323-
324- Examples:
325- ```python
326- kili = Kili()
327- # Namespace is instantiated on first access
328- tags_ns = kili.tags_ns
329- ```
330- """
331- return TagsNamespace (self , self .kili_api_gateway )
332-
333- @cached_property
334- def cloud_storage_ns (self ) -> CloudStorageNamespace :
335- """Get the cloud storage domain namespace.
336-
337- Returns:
338- CloudStorageNamespace: Cloud storage domain namespace with lazy loading
339-
340- Examples:
341- ```python
342- kili = Kili()
343- # Namespace is instantiated on first access
344- cloud_storage_ns = kili.cloud_storage_ns
345- ```
346- """
347- return CloudStorageNamespace (self , self .kili_api_gateway )
348-
349- @cached_property
350- def connections_ns (self ) -> ConnectionsNamespace :
351- """Get the connections domain namespace.
352-
353- Returns:
354- ConnectionsNamespace: Connections domain namespace with lazy loading
355-
356- Examples:
357- ```python
358- kili = Kili()
359- # Namespace is instantiated on first access
360- connections_ns = kili.connections_ns
361- ```
362- """
363- return ConnectionsNamespace (self , self .kili_api_gateway )
364-
365- @cached_property
366- def integrations_ns (self ) -> IntegrationsNamespace :
367- """Get the integrations domain namespace.
368-
369- Returns:
370- IntegrationsNamespace: Integrations domain namespace with lazy loading
371-
372- Examples:
373- ```python
374- kili = Kili()
375- # Namespace is instantiated on first access
376- integrations_ns = kili.integrations_ns
377- ```
378- """
379- return IntegrationsNamespace (self , self .kili_api_gateway )
380-
381- def __getattr__ (self , name : str ):
382- """Handle dynamic namespace routing based on legacy mode.
383-
384- When legacy=False, routes clean namespace names to their _ns counterparts.
385- When legacy=True, raises AttributeError for clean names to fall back to legacy methods.
386-
387- Args:
388- name: The attribute name being accessed
389-
390- Returns:
391- The appropriate namespace instance
392-
393- Raises:
394- AttributeError: When the attribute is not a recognized namespace or
395- when trying to access clean names in legacy mode
396- """
397- # Mapping of clean names to _ns property names
398- namespace_mapping = {
399- "assets" : "assets_ns" ,
400- "labels" : "labels_ns" ,
401- "projects" : "projects_ns" ,
402- "users" : "users_ns" ,
403- "organizations" : "organizations_ns" ,
404- "issues" : "issues_ns" ,
405- "notifications" : "notifications_ns" ,
406- "tags" : "tags_ns" ,
407- "cloud_storage" : "cloud_storage_ns" ,
408- "connections" : "connections_ns" ,
409- "integrations" : "integrations_ns" ,
410- }
411-
412- # In non-legacy mode, route clean names to _ns properties
413- if not self ._legacy_mode and name in namespace_mapping :
414- return getattr (self , namespace_mapping [name ])
415-
416- # For legacy mode or unrecognized attributes, raise AttributeError
417- # This allows legacy methods to be accessible through normal inheritance
418- raise AttributeError (f"'{ self .__class__ .__name__ } ' object has no attribute '{ name } '" )
419-
420- def __getattribute__ (self , name : str ):
421- """Control access to legacy methods based on legacy mode setting.
422-
423- When legacy=False, prevents access to legacy methods that conflict with
424- domain namespace names, providing clear error messages.
425-
426- Args:
427- name: The attribute name being accessed
428-
429- Returns:
430- The requested attribute
431-
432- Raises:
433- AttributeError: When trying to access legacy methods in non-legacy mode
434- """
435- # Get the attribute normally first
436- attr = super ().__getattribute__ (name )
437-
438- # Check if we're in non-legacy mode and trying to access a legacy method
439- # Use object.__getattribute__ to avoid recursion
440- try :
441- legacy_mode = object .__getattribute__ (self , "_legacy_mode" )
442- except AttributeError :
443- # If _legacy_mode is not set yet, default to legacy behavior
444- legacy_mode = True
445-
446- if not legacy_mode :
447- # Legacy method names that conflict with clean namespace names
448- legacy_method_names = {
449- "assets" ,
450- "projects" ,
451- "labels" ,
452- "users" ,
453- "organizations" ,
454- "issues" ,
455- "notifications" ,
456- "tags" ,
457- "cloud_storage" ,
458- }
459-
460- # If it's a callable legacy method, check if it should be blocked
461- if callable (attr ) and name in legacy_method_names :
462- # Check if this method comes from a legacy mixin class
463- # by examining the method's __qualname__
464- if hasattr (attr , "__func__" ) and hasattr (attr .__func__ , "__qualname__" ):
465- qualname = attr .__func__ .__qualname__
466- if any (
467- mixin_name in qualname
468- for mixin_name in [
469- "AssetClientMethods" ,
470- "ProjectClientMethods" ,
471- "LabelClientMethods" ,
472- "UserClientMethods" ,
473- "OrganizationClientMethods" ,
474- "IssueClientMethods" ,
475- "NotificationClientMethods" ,
476- "TagClientMethods" ,
477- "CloudStorageClientMethods" ,
478- ]
479- ):
480- raise AttributeError (
481- f"Legacy method '{ name } ()' is not available when legacy=False. "
482- f"Use 'kili.{ name } ' (domain namespace) instead of 'kili.{ name } ()' (legacy method)."
483- )
484-
485- return attr
0 commit comments