DSD-DBS / polarion-rest-api-client

An API Client for the Polarion REST API.
1 stars 0 forks source link

Enable users to implement their own, custom WorkItem classes #2

Closed micha91 closed 1 year ago

micha91 commented 1 year ago

The Client is now generic and enables the use to define a custom WorkItem class implementation. The custom WorkItem implementation must be derived from WorkItem and match the constructor of WorkItem. E.g.

import polarion_rest_api_client as polarion_api

class CustomWorkItem(polarion_api.WorkItem):
    capella_uuid: str | None

client = polarion_api.OpenAPIPolarionProjectClient(
    project_id="PROJ",
    delete_polarion_work_items=False,
    polarion_api_endpoint="http://127.0.0.1/api",
    polarion_access_token="PAT123",
    custom_work_item=CustomWorkItem,
)

In addition, it is now possible to add default fields values for work items and linked work items. These will be used, whenever an API-call is performed to get a list of items, but the user did not provide the fields value. So if we want to ensure in the example above that capella_uuid is requested from polarion without adding it to fields on every API-Call, we have to adjust the client:

client.default_fields.workitems = "@basic,capella_uuid"
Wuestengecko commented 1 year ago
class CustomWorkItem(polarion_api.WorkItem):
    @property
    def capella_uuid(self):
        return self.additional_attributes["capella_uuid"]

    @capella_uuid.setter
    def capella_uuid(self, value):
        self.additional_attributes["capella_uuid"] = value

If this is the intended use case, have you thought about letting the base class automatically map all these additional attributes into the additional_attributes dict? This could be achieved relatively easily by overriding __getattr__ and __setattr__ (although we'd need to take care so we don't accidentally put "normal" attributes in the "additional" attributes dict). The major downside I suppose would be that it loses (some of) the intelligence of IDEs and static typing (as they don't know anything about these attributes, like which ones exist in the first place). On the other hand, an API user doesn't have to deal with defining any custom classes and passing those around.

Ultimately it comes down to personal preference (yet again), I guess.

micha91 commented 1 year ago
class CustomWorkItem(polarion_api.WorkItem):
    @property
    def capella_uuid(self):
        return self.additional_attributes["capella_uuid"]

    @capella_uuid.setter
    def capella_uuid(self, value):
        self.additional_attributes["capella_uuid"] = value

If this is the intended use case, have you thought about letting the base class automatically map all these additional attributes into the additional_attributes dict? This could be achieved relatively easily by overriding __getattr__ and __setattr__ (although we'd need to take care so we don't accidentally put "normal" attributes in the "additional" attributes dict). The major downside I suppose would be that it loses (some of) the intelligence of IDEs and static typing (as they don't know anything about these attributes, like which ones exist in the first place). On the other hand, an API user doesn't have to deal with defining any custom classes and passing those around.

Ultimately it comes down to personal preference (yet again), I guess.

Yes, I thought about that, too. From my perspective avoiding typos and having typing are the only benefits of this approach. If a user does not want to implement custom classes, it's possible to work with the additional_attributes dict directly without implementing a custom class. But we could also combine the 2 options and make implementing a custom class even easier while also supporting access to additional attributes without implementing a custom class.