diff --git a/devops.py b/devops.py index ae27e1b..7de8a74 100644 --- a/devops.py +++ b/devops.py @@ -6,26 +6,49 @@ DEVOPS_SCOPE = "https://app.vssps.visualstudio.com/.default" DEVOPS_API_VERSION = "7.1" # Define a class decorator -def auto_properties(names=None): - names = names or [] +def auto_properties(mapping: dict[str,str] | None = None): - def make_property(name): + def make_property(name: str): private_var = f"_{name}" def getter(self): - i = getattr(self, private_var) - if i is not None: - return i - # Fetch repository details from the API + try: + i = getattr(self, private_var) + if i is not None: + return i + except AttributeError: + pass + + # Fetch repository details from the API if it is set to None or not existing self._get(getattr(self, "_id")) return getattr(self, private_var) - return property(getter) + return property(fget=getter) + + def set_auto_properties(self, **kwargs): + allowed = set(self.__class__.__auto_properties__) + unknown = [k for k in kwargs if k not in allowed] + if unknown: + raise ValueError(f"Unknown properties for {self.__class__.__name__}: {', '.join(unknown)}") + for k, v in kwargs.items(): + setattr(self, f"_{k}", v) + return self + + def from_json(self, json_data: dict): + for name in self.__class__.__auto_properties__: + setattr(self, f"_{name}", json_data.get(self.__class__.__auto_properties__[name], None)) + return self def decorator(cls): - cls.__auto_properties__ = names - for name in names: + cls.__auto_properties__ = mapping # Make a copy of the mapping + + # Create properties dynamically + for name in mapping: setattr(cls, name, make_property(name)) + + setattr(cls, "set_auto_properties", set_auto_properties) + setattr(cls, "from_json", from_json) + return cls return decorator