1- """The classlist module. Contains the ClassList class, which defines a list containing instances of a particular class.
1+ """The classlist module. Contains the ClassList class, which defines a list containing instances of a particular
2+ class.
23"""
34
45import collections
5- from collections .abc import Iterable , Sequence
66import contextlib
7- import prettytable
8- from typing import Any , Union
97import warnings
8+ from collections .abc import Iterable , Sequence
9+ from typing import Any , Union
10+
11+ import prettytable
1012
1113
1214class ClassList (collections .UserList ):
@@ -31,7 +33,9 @@ class ClassList(collections.UserList):
3133 An instance, or list of instance(s), of the class to be used in this ClassList.
3234 name_field : str, optional
3335 The field used to define unique objects in the ClassList (default is "name").
36+
3437 """
38+
3539 def __init__ (self , init_list : Union [Sequence [object ], object ] = None , name_field : str = "name" ) -> None :
3640 self .name_field = name_field
3741
@@ -56,7 +60,7 @@ def __repr__(self):
5660 else :
5761 if any (model .__dict__ for model in self .data ):
5862 table = prettytable .PrettyTable ()
59- table .field_names = [' index' ] + [key .replace ('_' , ' ' ) for key in self .data [0 ].__dict__ . keys () ]
63+ table .field_names = [" index" ] + [key .replace ("_" , " " ) for key in self .data [0 ].__dict__ ]
6064 table .add_rows ([[index ] + list (model .__dict__ .values ()) for index , model in enumerate (self .data )])
6165 output = table .get_string ()
6266 else :
@@ -81,15 +85,15 @@ def _delitem(self, index: int) -> None:
8185 """Auxiliary routine of "__delitem__" used to enable wrapping."""
8286 del self .data [index ]
8387
84- def __iadd__ (self , other : Sequence [object ]) -> ' ClassList' :
88+ def __iadd__ (self , other : Sequence [object ]) -> " ClassList" :
8589 """Define in-place addition using the "+=" operator."""
8690 return self ._iadd (other )
8791
88- def _iadd (self , other : Sequence [object ]) -> ' ClassList' :
92+ def _iadd (self , other : Sequence [object ]) -> " ClassList" :
8993 """Auxiliary routine of "__iadd__" used to enable wrapping."""
9094 if other and not (isinstance (other , Sequence ) and not isinstance (other , str )):
9195 other = [other ]
92- if not hasattr (self , ' _class_handle' ):
96+ if not hasattr (self , " _class_handle" ):
9397 self ._class_handle = self ._determine_class_handle (self + other )
9498 self ._check_classes (self + other )
9599 self ._check_unique_name_fields (self + other )
@@ -129,20 +133,27 @@ def append(self, obj: object = None, **kwargs) -> None:
129133 SyntaxWarning
130134 Raised if the input arguments contain BOTH an object and keyword arguments. In this situation the object is
131135 appended to the ClassList and the keyword arguments are discarded.
136+
132137 """
133138 if obj and kwargs :
134- warnings .warn ('ClassList.append() called with both an object and keyword arguments. '
135- 'The keyword arguments will be ignored.' , SyntaxWarning )
139+ warnings .warn (
140+ "ClassList.append() called with both an object and keyword arguments. "
141+ "The keyword arguments will be ignored." ,
142+ SyntaxWarning ,
143+ stacklevel = 2 ,
144+ )
136145 if obj :
137- if not hasattr (self , ' _class_handle' ):
146+ if not hasattr (self , " _class_handle" ):
138147 self ._class_handle = type (obj )
139148 self ._check_classes (self + [obj ])
140149 self ._check_unique_name_fields (self + [obj ])
141150 self .data .append (obj )
142151 else :
143- if not hasattr (self , '_class_handle' ):
144- raise TypeError ('ClassList.append() called with keyword arguments for a ClassList without a class '
145- 'defined. Call ClassList.append() with an object to define the class.' )
152+ if not hasattr (self , "_class_handle" ):
153+ raise TypeError (
154+ "ClassList.append() called with keyword arguments for a ClassList without a class "
155+ "defined. Call ClassList.append() with an object to define the class." ,
156+ )
146157 self ._validate_name_field (kwargs )
147158 self .data .append (self ._class_handle (** kwargs ))
148159
@@ -169,20 +180,27 @@ def insert(self, index: int, obj: object = None, **kwargs) -> None:
169180 SyntaxWarning
170181 Raised if the input arguments contain both an object and keyword arguments. In this situation the object is
171182 inserted into the ClassList and the keyword arguments are discarded.
183+
172184 """
173185 if obj and kwargs :
174- warnings .warn ('ClassList.insert() called with both an object and keyword arguments. '
175- 'The keyword arguments will be ignored.' , SyntaxWarning )
186+ warnings .warn (
187+ "ClassList.insert() called with both an object and keyword arguments. "
188+ "The keyword arguments will be ignored." ,
189+ SyntaxWarning ,
190+ stacklevel = 2 ,
191+ )
176192 if obj :
177- if not hasattr (self , ' _class_handle' ):
193+ if not hasattr (self , " _class_handle" ):
178194 self ._class_handle = type (obj )
179195 self ._check_classes (self + [obj ])
180196 self ._check_unique_name_fields (self + [obj ])
181197 self .data .insert (index , obj )
182198 else :
183- if not hasattr (self , '_class_handle' ):
184- raise TypeError ('ClassList.insert() called with keyword arguments for a ClassList without a class '
185- 'defined. Call ClassList.insert() with an object to define the class.' )
199+ if not hasattr (self , "_class_handle" ):
200+ raise TypeError (
201+ "ClassList.insert() called with keyword arguments for a ClassList without a class "
202+ "defined. Call ClassList.insert() with an object to define the class." ,
203+ )
186204 self ._validate_name_field (kwargs )
187205 self .data .insert (index , self ._class_handle (** kwargs ))
188206
@@ -209,7 +227,7 @@ def extend(self, other: Sequence[object]) -> None:
209227 """Extend the ClassList by adding another sequence."""
210228 if other and not (isinstance (other , Sequence ) and not isinstance (other , str )):
211229 other = [other ]
212- if not hasattr (self , ' _class_handle' ):
230+ if not hasattr (self , " _class_handle" ):
213231 self ._class_handle = self ._determine_class_handle (self + other )
214232 self ._check_classes (self + other )
215233 self ._check_unique_name_fields (self + other )
@@ -229,6 +247,7 @@ def get_names(self) -> list[str]:
229247 -------
230248 names : list [str]
231249 The value of the name_field attribute of each object in the ClassList.
250+
232251 """
233252 return [getattr (model , self .name_field ) for model in self .data if hasattr (model , self .name_field )]
234253
@@ -244,9 +263,14 @@ def get_all_matches(self, value: Any) -> list[tuple]:
244263 -------
245264 : list [tuple]
246265 A list of (index, field) tuples matching the given value.
266+
247267 """
248- return [(index , field ) for index , element in enumerate (self .data ) for field in vars (element )
249- if getattr (element , field ) == value ]
268+ return [
269+ (index , field )
270+ for index , element in enumerate (self .data )
271+ for field in vars (element )
272+ if getattr (element , field ) == value
273+ ]
250274
251275 def _validate_name_field (self , input_args : dict [str , Any ]) -> None :
252276 """Raise a ValueError if the name_field attribute is passed as an object parameter, and its value is already
@@ -261,12 +285,15 @@ def _validate_name_field(self, input_args: dict[str, Any]) -> None:
261285 ------
262286 ValueError
263287 Raised if the input arguments contain a name_field value already defined in the ClassList.
288+
264289 """
265290 names = self .get_names ()
266291 with contextlib .suppress (KeyError ):
267292 if input_args [self .name_field ] in names :
268- raise ValueError (f"Input arguments contain the { self .name_field } '{ input_args [self .name_field ]} ', "
269- f"which is already specified in the ClassList" )
293+ raise ValueError (
294+ f"Input arguments contain the { self .name_field } '{ input_args [self .name_field ]} ', "
295+ f"which is already specified in the ClassList" ,
296+ )
270297
271298 def _check_unique_name_fields (self , input_list : Iterable [object ]) -> None :
272299 """Raise a ValueError if any value of the name_field attribute is used more than once in a list of class
@@ -281,6 +308,7 @@ def _check_unique_name_fields(self, input_list: Iterable[object]) -> None:
281308 ------
282309 ValueError
283310 Raised if the input list defines more than one object with the same value of name_field.
311+
284312 """
285313 names = [getattr (model , self .name_field ) for model in input_list if hasattr (model , self .name_field )]
286314 if len (set (names )) != len (names ):
@@ -298,6 +326,7 @@ def _check_classes(self, input_list: Iterable[object]) -> None:
298326 ------
299327 ValueError
300328 Raised if the input list defines objects of different types.
329+
301330 """
302331 if not (all (isinstance (element , self ._class_handle ) for element in input_list )):
303332 raise ValueError (f"Input list contains elements of type other than '{ self ._class_handle .__name__ } '" )
@@ -315,6 +344,7 @@ def _get_item_from_name_field(self, value: Union[object, str]) -> Union[object,
315344 instance : object or str
316345 Either the object with the value of the name_field attribute given by value, or the input value if an
317346 object with that value of the name_field attribute cannot be found.
347+
318348 """
319349 return next ((model for model in self .data if getattr (model , self .name_field ) == value ), value )
320350
@@ -333,6 +363,7 @@ def _determine_class_handle(input_list: Sequence[object]):
333363 class_handle : type
334364 The type object of the element fulfilling the condition of satisfying "issubclass" for all of the other
335365 elements.
366+
336367 """
337368 for this_element in input_list :
338369 if all ([issubclass (type (instance ), type (this_element )) for instance in input_list ]):
0 commit comments