22
33import posixpath
44from abc import ABC , abstractmethod
5- from typing import TYPE_CHECKING , Any , Generic , Protocol , TypeVar , cast
5+ from collections .abc import Mapping
6+ from typing import TYPE_CHECKING , Any , Generic , TypeVar , cast
67
8+ from ._api_call import ApiCallMixin , get_api
79from ._json import Jsonifiable , JsonifiableDict , ResponseAttrs
810
911if TYPE_CHECKING :
1012 from .context import Context
1113
14+
1215# Design Notes:
1316# * Perform API calls on property retrieval
1417# * Dictionary endpoints: Retrieve all attributes during init unless provided
1518# * List endpoints: Do not retrieve until `.fetch()` is called directly. Avoids cache invalidation issues.
1619# * Only expose methods needed for `ReadOnlyDict`.
1720# * Ex: When inheriting from `dict`, we'd need to shut down `update`, `pop`, etc.
1821# * Use `ApiContextProtocol` to ensure that the class has the necessary attributes for API calls.
19- # * Inherit from `EndpointMixin ` to add all helper methods for API calls.
22+ # * Inherit from `ApiCallMixin ` to add all helper methods for API calls.
2023# * Classes should write the `path` only once within its init method.
2124# * Through regular interactions, the path should only be written once.
2225
2326
24- class ApiContextProtocol (Protocol ):
25- _ctx : Context
26- _path : str
27-
28-
2927# TODO-future?; Add type hints for the ReadOnlyDict class
3028# ArgsT = TypeVar("ArgsT", bound="ResponseAttrs")
3129
3230
3331class ReadOnlyDict (
3432 # Generic[ArgsT],
33+ Mapping ,
3534):
3635 # _attrs: ArgsT
3736 _attrs : ResponseAttrs
3837 """Resource attributes passed."""
39- _attrs_locked : bool
40- """Semaphore for locking the resource attributes. Deters setting new attributes after initialization."""
4138
4239 def __init__ (self , attrs : ResponseAttrs ) -> None :
4340 """
@@ -48,8 +45,10 @@ def __init__(self, attrs: ResponseAttrs) -> None:
4845 attrs : dict
4946 Resource attributes passed
5047 """
48+ print ("here!" , attrs )
49+ super ().__init__ ()
50+ print ("mapping attrs" , attrs )
5151 self ._attrs = attrs
52- self ._attrs_locked = True
5352
5453 def get (self , key : str , default : Any = None ) -> Any :
5554 return self ._attrs .get (key , default )
@@ -58,53 +57,37 @@ def __getitem__(self, key: str) -> Any:
5857 return self ._attrs [key ]
5958
6059 def __setitem__ (self , key : str , value : Any ) -> None :
61- if self ._attrs_locked :
62- raise AttributeError (
63- "Resource attributes are locked. "
64- "To retrieve updated values, please retrieve the parent object again."
65- )
66- self ._attrs [key ] = value
67-
68- def _set_attrs (self , ** kwargs : Any ) -> None :
69- # Unlock
70- self ._attrs_locked = False
71- # Set
72- for key , value in kwargs .items ():
73- self ._attrs [key ] = value
74- # Lock
75- self ._attrs_locked = True
60+ raise AttributeError (
61+ "Resource attributes are locked. "
62+ "To retrieve updated values, please retrieve the parent object again."
63+ )
7664
7765 def __len__ (self ) -> int :
7866 return self ._attrs .__len__ ()
7967
68+ def __iter__ (self ):
69+ return self ._attrs .__iter__ ()
8070
81- class EndpointMixin (ApiContextProtocol ):
82- _ctx : Context
83- """The context object containing the session and URL for API interactions."""
84- _path : str
85- """The HTTP path component for the resource endpoint."""
71+ def __contains__ (self , key : object ) -> bool :
72+ return self ._attrs .__contains__ (key )
8673
87- def _endpoint (self , extra_endpoint : str = "" ) -> str :
88- return self ._ctx . url + self . _path + extra_endpoint
74+ def __repr__ (self ) -> str :
75+ return repr ( self ._attrs )
8976
90- def _get_api (self , * , extra_endpoint : str = "" ) -> Jsonifiable :
91- response = self ._ctx .session .get (self ._endpoint (extra_endpoint ))
92- return response .json ()
77+ def __str__ (self ) -> str :
78+ return str (self ._attrs )
9379
94- def _delete_api (self , * , extra_endpoint : str = "" ) -> Jsonifiable :
95- response = self ._ctx .session .get (self ._endpoint (extra_endpoint ))
96- return response .json ()
80+ def keys (self ):
81+ return self ._attrs .keys ()
9782
98- def _patch_api (self , json : Jsonifiable | None , * , extra_endpoint : str = "" ) -> Jsonifiable :
99- response = self ._ctx .session .patch (self ._endpoint (extra_endpoint ), json = json )
100- return response .json ()
83+ def values (self ):
84+ return self ._attrs .values ()
10185
102- def _put_api (self , json : Jsonifiable | None , * , extra_endpoint : str = "" ) -> Jsonifiable :
103- response = self ._ctx .session .put (self ._endpoint (extra_endpoint ), json = json )
104- return response .json ()
86+ def items (self ):
87+ return self ._attrs .items ()
10588
10689
107- class ApiDictEndpoint (EndpointMixin , ReadOnlyDict ):
90+ class ApiDictEndpoint (ApiCallMixin , ReadOnlyDict ):
10891 def _get_api (self , * , extra_endpoint : str = "" ) -> JsonifiableDict | None :
10992 super ()._get_api (extra_endpoint = extra_endpoint )
11093
@@ -123,21 +106,26 @@ def __init__(self, *, ctx: Context, path: str, attrs: ResponseAttrs | None = Non
123106 attrs : dict
124107 Resource attributes passed
125108 """
126- super ().__init__ (attrs or {})
109+ # If no attributes are provided, fetch the API and set the attributes from the response
110+ print ("dict attrs" , attrs )
111+ if attrs is None :
112+ init_attrs : Jsonifiable = get_api (ctx , path )
113+ attrs = cast (ResponseAttrs , init_attrs )
114+ print ("dict init attrs" , attrs )
115+
116+ print ("pre init" )
117+ print ("super" , super ())
118+ super ().__init__ (attrs )
119+ print ("post init" )
127120 self ._ctx = ctx
128121 self ._path = path
129122
130- # If attrs is None, Fetch the API and set the attributes
131- if attrs is None :
132- init_attrs = self ._get_api () or {}
133- self ._set_attrs (** init_attrs )
134-
135123
136124T = TypeVar ("T" , bound = "ReadOnlyDict" )
137125"""A type variable that is bound to the `Active` class"""
138126
139127
140- class ApiListEndpoint (EndpointMixin , Generic [T ], ABC , object ):
128+ class ApiListEndpoint (ApiCallMixin , Generic [T ], ABC , object ):
141129 """A tuple for any HTTP GET endpoint that returns a collection."""
142130
143131 _data : tuple [T , ...]
0 commit comments