refactoring equals for api objects

adding access to repository files (non-gitea objects in general) requires a more granular comparison of api objects than the old hope that there is an id approach
pull/10/head
Langenfeld 2021-11-11 10:18:23 +01:00
rodzic a0d1b6f80a
commit 53410b79e7
5 zmienionych plików z 78 dodań i 43 usunięć

Wyświetl plik

@ -1,24 +1,22 @@
from .exceptions import ObjectIsInvalid from .exceptions import ObjectIsInvalid, MissiongEqualyImplementation
class BasicGiteaApiObject: class BasicGiteaApiObject:
GET_API_OBJECT = "FORMAT/STINING/{argument}" GET_API_OBJECT = "FORMAT/STINING/{argument}"
PATCH_API_OBJECT = "FORMAT/STINING/{argument}" PATCH_API_OBJECT = "FORMAT/STINING/{argument}"
def __init__(self, gitea, id): def __init__(self, gitea):
self.__id = id
self.gitea = gitea self.gitea = gitea
self.deleted = False # set if .delete was called, so that an exception is risen self.deleted = False # set if .delete was called, so that an exception is risen
self.dirty_fields = set() self.dirty_fields = set()
def __eq__(self, other):
return other.id == self.id if isinstance(other, type(self)) else False
def __str__(self): def __str__(self):
return "GiteaAPIObject (%s) id: %s" % (type(self), self.id) return "GiteaAPIObject (%s):" % (type(self))
def __eq__(self, other):
"""Compare only fields that are part of the gitea-data"""
raise MissiongEqualyImplementation()
def __hash__(self):
return self.id
fields_to_parsers = {} fields_to_parsers = {}
@ -30,12 +28,8 @@ class BasicGiteaApiObject:
@classmethod @classmethod
def parse_response(cls, gitea, result) -> "BasicGiteaApiObject": def parse_response(cls, gitea, result) -> "BasicGiteaApiObject":
if "id" in result:
id = int(result["id"])
else:
id = hash(result.items)
# gitea.logger.debug("Found api object of type %s (id: %s)" % (type(cls), id)) # gitea.logger.debug("Found api object of type %s (id: %s)" % (type(cls), id))
api_object = cls(gitea, id=id) api_object = cls(gitea)
cls._initialize(gitea, api_object, result) cls._initialize(gitea, api_object, result)
return api_object return api_object
@ -56,7 +50,7 @@ class BasicGiteaApiObject:
cls._add_property(name, value, api_object) cls._add_property(name, value, api_object)
else: else:
cls._add_readonly_property(name,value,api_object) cls._add_readonly_property(name,value,api_object)
# add all patchable fields to be watched if changed # add all patchable fields missing in the request to be writable
for name in cls.patchable_fields: for name in cls.patchable_fields:
if not hasattr(api_object,name): if not hasattr(api_object,name):
cls._add_property(name, None, api_object) cls._add_property(name, None, api_object)

Wyświetl plik

@ -12,3 +12,10 @@ class ObjectIsInvalid(Exception):
class ConflictException(Exception): class ConflictException(Exception):
pass pass
class MissiongEqualyImplementation(Exception):
"""
Each Object obtained from the gitea api must be able to check itself for equality in relation to its
fields obtained from gitea. Risen if an api object is lacking the proper implementation.
"""
pass

Wyświetl plik

@ -24,8 +24,12 @@ class Organization(GiteaApiObject):
ORG_DELETE = """/orgs/%s""" # <org> ORG_DELETE = """/orgs/%s""" # <org>
ORG_HEATMAP = """/users/%s/heatmap""" # <username> ORG_HEATMAP = """/users/%s/heatmap""" # <username>
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Organization, self).__init__(gitea, id=id) super(Organization, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Organization): return False
return self.gitea == other.gitea and self.name == other.name
@classmethod @classmethod
def request(cls, gitea, name): def request(cls, gitea, name):
@ -118,10 +122,14 @@ class User(GiteaApiObject):
ADMIN_EDIT_USER = """/admin/users/{username}""" # <username> ADMIN_EDIT_USER = """/admin/users/{username}""" # <username>
USER_HEATMAP = """/users/%s/heatmap""" # <username> USER_HEATMAP = """/users/%s/heatmap""" # <username>
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(User, self).__init__(gitea, id=id) super(User, self).__init__(gitea)
self._emails = [] self._emails = []
def __eq__(self, other):
if not isinstance(other, User): return False
return self.gitea == other.gitea and self.id == other.id
@property @property
def emails(self): def emails(self):
self.__request_emails() self.__request_emails()
@ -212,8 +220,12 @@ class User(GiteaApiObject):
class Branch(GiteaApiObject): class Branch(GiteaApiObject):
GET_API_OBJECT = """/repos/%s/%s/branches/%s""" # <owner>, <repo>, <ref> GET_API_OBJECT = """/repos/%s/%s/branches/%s""" # <owner>, <repo>, <ref>
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Branch, self).__init__(gitea, id=id) super(Branch, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Branch): return False
return self.gitea == other.gitea and self.repo == other.repo and self.name == other.name
fields_to_parsers = { fields_to_parsers = {
"commit": lambda gitea, c: Commit.parse_response(gitea, c) "commit": lambda gitea, c: Commit.parse_response(gitea, c)
@ -239,8 +251,12 @@ class Repository(GiteaApiObject):
REPO_TRANSFER = "/repos/{owner}/{repo}/transfer" REPO_TRANSFER = "/repos/{owner}/{repo}/transfer"
REPO_CONTENTS = "/repos/{owner}/{repo}/contents" REPO_CONTENTS = "/repos/{owner}/{repo}/contents"
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Repository, self).__init__(gitea, id=id) super(Repository, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Repository): return False
return self.gitea == other.gitea and self.owner == other.owner and self.name == other.name
fields_to_parsers = { fields_to_parsers = {
# dont know how to tell apart user and org as owner except form email being empty. # dont know how to tell apart user and org as owner except form email being empty.
@ -430,11 +446,15 @@ class Repository(GiteaApiObject):
class Milestone(GiteaApiObject): class Milestone(GiteaApiObject):
GET_API_OBJECT = ( GET_API_OBJECT = (
"""/repos/{owner}/{repo}/milestones/{number}""" # <owner, repo, id> """/repos/{owner}/{repo}/milestones/{number}""" # <owner, repo>
) )
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Milestone, self).__init__(gitea, id=id) super(Milestone, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Milestone): return False
return self.gitea == other.gitea and self.repo == other.repo and self.id == other.id
fields_to_parsers = { fields_to_parsers = {
"closed_at": lambda gitea, t: Util.convert_time(t), "closed_at": lambda gitea, t: Util.convert_time(t),
@ -466,8 +486,12 @@ class Milestone(GiteaApiObject):
class Comment(BasicGiteaApiObject): class Comment(BasicGiteaApiObject):
PATCH_API_OBJECT = "/repos/{owner}/{repo}/issues/comments/{id}" PATCH_API_OBJECT = "/repos/{owner}/{repo}/issues/comments/{id}"
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Comment, self).__init__(gitea, id=id) super(Comment, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Comment): return False
return self.gitea == other.gitea and self.repo == other.repo and self.id == other.id
fields_to_parsers = { fields_to_parsers = {
"user": lambda gitea, r: User.parse_response(gitea, r), "user": lambda gitea, r: User.parse_response(gitea, r),
@ -479,14 +503,18 @@ class Comment(BasicGiteaApiObject):
class Commit(GiteaApiObject): class Commit(GiteaApiObject):
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Commit, self).__init__(gitea, id=id) super(Commit, self).__init__(gitea)
fields_to_parsers = { fields_to_parsers = {
# NOTE: do not try to parse gitea-users from git-committers/authors, as # NOTE: do not try to parse gitea-users from git-committers/authors, as
# they are not necessarily users of gitea as well # they are not necessarily users of gitea as well
} }
def __eq__(self, other):
if not isinstance(other, Commit): return False
return self.gitea == other.gitea and self.repo == other.repo and self.ref == other.ref
@classmethod @classmethod
def request(cls, gitea, owner, repo): def request(cls, gitea, owner, repo):
api_object = cls._request(gitea, {"owner": owner, "repo": repo}) api_object = cls._request(gitea, {"owner": owner, "repo": repo})
@ -494,9 +522,7 @@ class Commit(GiteaApiObject):
@classmethod @classmethod
def parse_response(cls, gitea, result): def parse_response(cls, gitea, result):
id = result["id"] #``sha`` is now called ``id`` api_object = cls(gitea)
# gitea.logger.debug("Found api object of type %s (id: %s)" % (type(cls), id))
api_object = cls(gitea, id=id)
cls._initialize(gitea, api_object, result) cls._initialize(gitea, api_object, result)
return api_object return api_object
@ -510,8 +536,12 @@ class Issue(GiteaApiObject):
OPENED = "open" OPENED = "open"
CLOSED = "closed" CLOSED = "closed"
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Issue, self).__init__(gitea, id=id) super(Issue, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Issue): return False
return self.gitea == other.gitea and self.repo == other.repo and self.id == other.id
fields_to_parsers = { fields_to_parsers = {
"milestone": lambda gitea, m: Milestone.parse_response(gitea, m), "milestone": lambda gitea, m: Milestone.parse_response(gitea, m),
@ -593,8 +623,12 @@ class Team(GiteaApiObject):
GET_MEMBERS = """/teams/%s/members""" # <id> GET_MEMBERS = """/teams/%s/members""" # <id>
GET_REPOS = """/teams/%s/repos""" # <id> GET_REPOS = """/teams/%s/repos""" # <id>
def __init__(self, gitea, id: int): def __init__(self, gitea):
super(Team, self).__init__(gitea, id=id) super(Team, self).__init__(gitea)
def __eq__(self, other):
if not isinstance(other, Team): return False
return self.gitea == other.gitea and self.organization == other.organization and self.id == other.id
fields_to_parsers = { fields_to_parsers = {
"organization": lambda gitea, o: Organization.parse_response(gitea, o) "organization": lambda gitea, o: Organization.parse_response(gitea, o)

Wyświetl plik

@ -2,17 +2,17 @@ from .basicGiteaApiObject import BasicGiteaApiObject
class GiteaApiObject(BasicGiteaApiObject): class GiteaApiObject(BasicGiteaApiObject):
GET_API_OBJECT = "FORMAT/STINING/{argument}" GET_API_OBJECT = "FORMAT/STRING/{argument}"
PATCH_API_OBJECT = "FORMAT/STINING/{argument}" PATCH_API_OBJECT = "FORMAT/STRING/{argument}"
def __init__(self, gitea, id): def __init__(self, gitea):
super(GiteaApiObject, self).__init__(gitea, id) super(GiteaApiObject, self).__init__(gitea)
@classmethod @classmethod
def request(cls, gitea, id): def request(cls, gitea, id):
"""Use for giving a nice e.g. 'request(gita, orgname, repo, ticket)'. """Use for giving a nice e.g. 'request(gita, orgname, repo, ticket)'.
All args are put into an args tuple for passing around""" All args are put into an args tuple for passing around"""
return cls._request(gitea, {"id": id}) return cls._request(gitea)
@classmethod @classmethod
def _request(cls, gitea, args): def _request(cls, gitea, args):

Wyświetl plik

@ -79,7 +79,7 @@ def test_change_user(instance):
def test_create_org(instance): def test_create_org(instance):
user = instance.get_user() user = instance.get_user()
org = instance.create_org(user, test_org, "some-desc", "loc") org = instance.create_org(user, test_org, "some-desc", "loc")
assert org.get_members() == [user] assert org.get_members()[0] == user
assert org.description == "some-desc" assert org.description == "some-desc"
assert org.username == test_org assert org.username == test_org
assert org.location == "loc" assert org.location == "loc"