Feedback Request
- Is the manner in which I use
attrs
adequate (i.e. designed well)? - Should I not expect to be able to use argument ordering to order the joining of groups, given my current setup (see
def label(self):
below)? - Are there any general Pythonic suggestions for the code I have?
Context
I am working on creating labels for specimens in paleontological collections.
At the moment, I have a poetry
package called paleo_utils
. __init__.py
contains code that takes Label
, CollectionsLabel
(subclassed Label
), and SystematicsLabel
(subclassed Label
) from label.py
. For the sake of this question, the code in Label
and SystematicsLabel
does not matter.
I would prefer to not have to use __init__
while also using attrs
in the code below but at present I am not sure I am able to get {key: kwargs[key] for key in kwargs}
using just __attrs_post_init__
.
My wish is to be able to have these two cases work as follows:
import paleo_utils label = paleo_utils.CollectionsLabel( save_directory="../assets/saved_images/", id_number="3244", collection="AMNH", collector="Dr. Montague", location="North America", formation="Navesink", coordinates=(40.7128, -74.0060), date_found="2024-01-01", title_overrides={"collection": "Museum: "}, ) print(label.label()) # ID Number: 3244 # Museum: AMNH # Collector: Dr. Montague # Location: North America # Formation: Navesink # Coordinates: (40.7128, -74.006) # Date Found: 2024-01-01
and
import paleo_utils label = paleo_utils.CollectionsLabel( save_directory="../assets/saved_images/", date_found="2024-01-01", id_number="3244", formation="Navesink", collection="AMNH", collector="Dr. Montague", location="North America", coordinates=(40.7128, -74.0060), title_overrides={ "date_found": "Date Collected: ", "location": "Locality: "}, ) print(label.label()) # Date Collected: 2024-01-01 # ID Number: 3244 # Formation: Navesink # Collection: AMNH # Collector: Dr. Montague # Locality: North America # Coordinates: (40.7128, -74.006)
Code For CollectionsLabel
@attrs.define(kw_only=True) class CollectionsLabel(Label): collection: str | None = attrs.field( default=None ) id_number: str | None = attrs.field( default=None ) collector: str | None = attrs.field( default=None ) species: str | None = attrs.field( default=None ) species_author: str | None = attrs.field( default=None ) common_name: str | None = attrs.field( default=None ) location: str | None = attrs.field( default=None ) coordinates: tuple[float, float] | None = ( attrs.field(default=None) ) coordinates_separate: bool = attrs.field( default=False ) date_found: str | None = attrs.field( default=None ) date_cataloged: str | None = attrs.field( default=None ) formation: str | None = attrs.field( default=None ) formation_author: str | None = attrs.field( default=None ) chrono_age: str | None = attrs.field( default=None ) chrono_age_author: str | None = attrs.field( default=None ) size: str | None = attrs.field(default=None) link: str | None = attrs.field(default=None) default_titles = { "collection": "Collection: ", "id_number": "ID Number: ", "collector": "Collector: ", "species": "Scientific Name: ", "species_author": "Species Author: ", "common_name": "Common Name: ", "location": "Location: ", "coordinates": "Coordinates: ", "date_found": "Date Found: ", "date_cataloged": "Date Cataloged: ", "formation": "Formation: ", "formation_author": "Formation Author: ", "chrono_age": "Age: ", "chrono_age_author": "Age Author: ", "size": "Size: ", "link": "Link: ", } title_overrides: dict[str, str] = attrs.field( factory=dict ) # empty by default _ordered_kwargs: dict = attrs.field(init=False) def __init__(self, **kwargs): self._ordered_kwargs = {key: kwargs[key] for key in kwargs} def __attrs_post_init__(self): # update title_overrides with any user-provided overrides if self.title_overrides: # merge user-provided titles, overriding defaults for ( key, value, ) in self.title_overrides.items(): if key in self.default_titles: self.default_titles[key] = ( value ) def _get_collections_attrs(self): label_attrs = { attr.name for attr in Label.__attrs_attrs__ } # collections_attrs = { # attr.name: getattr(self, attr.name) # for attr in self.__attrs_attrs__ # if attr.name not in label_attrs # } # print(self.__attrs_attrs__) collections_attrs = { key: value for key, value in self._ordered_kwargs.items() if key not in label_attrs } return collections_attrs def label(self): # empty list for parts of the final label parts = [] # collections label exclusive attrs collections_attrs = ( self._get_collections_attrs() ) # iterative over collections attrs for ( key, value, ) in collections_attrs.items(): # for all non-None collections attrs, proceed if ( value is not None and not isinstance(value, dict) ): # edit title with spaces and capitalized title = self.default_titles.get( key, f"{key.replace('_', ' ').capitalize()}: ", ) # add the group parts.append(f"{title}{value}") # consolidate to multiline label return "\n".join(parts)
TypedDict
with a helper static class?\$\endgroup\$