1+ import posixpath
12import warnings
23from abc import ABC , abstractmethod
34from dataclasses import dataclass
@@ -50,84 +51,105 @@ def __init__(self, params: ResourceParameters) -> None:
5051
5152
5253class Active (ABC , Resource ):
53- def __init__ (self , ctx : Context , parent : Optional [ "Active" ] = None , ** kwargs ):
54- """A base class representing an active resource.
54+ def __init__ (self , ctx : Context , path : str , / , ** attributes ):
55+ """A dict abstraction for any HTTP endpoint that returns a singular resource.
5556
5657 Extends the `Resource` class and provides additional functionality for via the session context and an optional parent resource.
5758
5859 Parameters
5960 ----------
6061 ctx : Context
6162 The context object containing the session and URL for API interactions.
62- parent : Optional[Active], optional
63- An optional parent resource that establishes a hierarchical relationship, by default None.
64- **kwargs : dict
65- Additional keyword arguments passed to the parent `Resource` class.
63+ path : str
64+ The HTTP path component for the resource endpoint
65+ **attributes : dict
66+ Resource attributes passed
6667 """
6768 params = ResourceParameters (ctx .session , ctx .url )
68- super ().__init__ (params , ** kwargs )
69+ super ().__init__ (params , ** attributes )
6970 self ._ctx = ctx
70- self ._parent = parent
71+ self ._path = path
7172
7273
7374T = TypeVar ("T" , bound = "Active" )
7475"""A type variable that is bound to the `Active` class"""
7576
7677
7778class ActiveSequence (ABC , Generic [T ], Sequence [T ]):
78- def __init__ (self , ctx : Context , parent : Optional [Active ] = None ):
79- """A sequence abstraction for any HTTP GET endpoint that returns a collection.
79+ """A sequence for any HTTP GET endpoint that returns a collection."""
80+
81+ _cache : Optional [List [T ]]
8082
81- It lazily fetches data on demand, caches the results, and allows for standard sequence operations like indexing and slicing.
83+ def __init__ (self , ctx : Context , path : str , uid : str = "guid" ):
84+ """A sequence abstraction for any HTTP GET endpoint that returns a collection.
8285
8386 Parameters
8487 ----------
8588 ctx : Context
86- The context object that holds the HTTP session used for sending the GET request.
87- parent : Optional[Active], optional
88- An optional parent resource to establish a nested relationship, by default None.
89+ The context object containing the session and URL for API interactions.
90+ path : str
91+ The HTTP path component for the collection endpoint
92+ uid : str, optional
93+ The field name of that uniquely identifiers an instance of T, by default "guid"
8994 """
9095 super ().__init__ ()
9196 self ._ctx = ctx
92- self ._parent = parent
93- self ._cache : Optional [List [T ]] = None
97+ self ._path = path
98+ self ._uid = uid
99+ self ._cache = None
94100
95- @property
96101 @abstractmethod
97- def _endpoint (self ) -> str :
102+ def _create_instance (self , path : str , / , ** kwargs : Any ) -> T :
103+ """Create an instance of 'T'."""
104+ raise NotImplementedError ()
105+
106+ def reload (self ) -> Self :
107+ """Reloads the collection from Connect.
108+
109+ Returns
110+ -------
111+ Self
98112 """
99- Abstract property to define the endpoint URL for the GET request.
113+ self ._cache = None
114+ return self
115+
116+ def _fetch (self ) -> List [T ]:
117+ """Fetch the collection.
100118
101- Subclasses must implement this property to return the API endpoint URL that will
102- be queried to fetch the data.
119+ Fetches the collection directly from Connect. This operation does not effect the cache state.
103120
104121 Returns
105122 -------
106- str
107- The API endpoint URL.
123+ List[T]
108124 """
109- raise NotImplementedError ()
125+ endpoint = self ._ctx .url + self ._path
126+ response = self ._ctx .session .get (endpoint )
127+ results = response .json ()
128+ return [self ._to_instance (result ) for result in results ]
129+
130+ def _to_instance (self , result : dict ) -> T :
131+ """Converts a result into an instance of T."""
132+ uid = result [self ._uid ]
133+ path = posixpath .join (self ._path , uid )
134+ return self ._create_instance (path , ** result )
110135
111136 @property
112137 def _data (self ) -> List [T ]:
113- """
114- Fetch and cache the data from the API.
138+ """Get the collection.
115139
116- This method sends a GET request to the `_endpoint` and parses the response as a list of JSON objects.
117- Each JSON object is used to instantiate an item of type `T` using the class specified by `_cls`.
118- The results are cached after the first request and reused for subsequent access unless reloaded.
140+ Fetches the collection from Connect and caches the result. Subsequent invocations return the cached results unless the cache is explicitly reset.
119141
120142 Returns
121143 -------
122144 List[T]
123- A list of items of type `T` representing the fetched data.
124- """
125- if self ._cache :
126- return self ._cache
127145
128- response = self ._ctx .session .get (self ._endpoint )
129- results = response .json ()
130- self ._cache = [self ._create_instance (** result ) for result in results ]
146+ See Also
147+ --------
148+ cached
149+ reload
150+ """
151+ if self ._cache is None :
152+ self ._cache = self ._fetch ()
131153 return self ._cache
132154
133155 @overload
@@ -148,52 +170,18 @@ def __str__(self) -> str:
148170 def __repr__ (self ) -> str :
149171 return repr (self ._data )
150172
151- @abstractmethod
152- def _create_instance (self , ** kwargs ) -> T :
153- """Create an instance of 'T'.
154173
155- Returns
156- -------
157- T
158- """
159- raise NotImplementedError ()
174+ class ActiveFinderMethods (ActiveSequence [T ], ABC ):
175+ """Finder methods.
160176
161- def reload (self ) -> Self :
162- """
163- Clear the cache and reload the data from the API on the next access.
164-
165- Returns
166- -------
167- ActiveSequence
168- The current instance with cleared cache, ready to reload data on next access.
169- """
170- self ._cache = None
171- return self
172-
173-
174- class ActiveFinderMethods (ActiveSequence [T ], ABC , Generic [T ]):
175- def __init__ (self , ctx : Context , parent : Optional [Active ] = None , uid : str = "guid" ):
176- """Finder methods.
177-
178- Provides various finder methods for locating records in any endpoint supporting HTTP GET requests.
179-
180- Parameters
181- ----------
182- ctx : Context
183- The context containing the HTTP session used to interact with the API.
184- parent : Optional[Active], optional
185- Optional parent resource for maintaining hierarchical relationships, by default None
186- uid : str, optional
187- The default field name used to uniquely identify records, by default "guid"
188- """
189- super ().__init__ (ctx , parent )
190- self ._uid = uid
177+ Provides various finder methods for locating records in any endpoint supporting HTTP GET requests.
178+ """
191179
192180 def find (self , uid ) -> T :
193181 """
194182 Find a record by its unique identifier.
195183
196- Fetches a record either by searching the cache or by making a GET request to the endpoint .
184+ Fetches the record from Connect by it's identifier .
197185
198186 Parameters
199187 ----------
@@ -203,26 +191,11 @@ def find(self, uid) -> T:
203191 Returns
204192 -------
205193 T
206-
207- Raises
208- ------
209- ValueError
210- If no record is found.
211194 """
212- # todo - add some more comments about this
213- if self ._cache :
214- conditions = {self ._uid : uid }
215- result = self .find_by (** conditions )
216- else :
217- endpoint = self ._endpoint + uid
218- response = self ._ctx .session .get (endpoint )
219- result = response .json ()
220- result = self ._create_instance (** result )
221-
222- if not result :
223- raise ValueError (f"Failed to find instance where { self ._uid } is '{ uid } '" )
224-
225- return result
195+ endpoint = self ._ctx .url + self ._path + uid
196+ response = self ._ctx .session .get (endpoint )
197+ result = response .json ()
198+ return self ._to_instance (result )
226199
227200 def find_by (self , ** conditions : Any ) -> Optional [T ]:
228201 """
0 commit comments