Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typing: Add ProjectModel dataclass #7658

Merged
merged 3 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions master/buildbot/data/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,27 @@
#
# Copyright Buildbot Team Members

from __future__ import annotations

from typing import TYPE_CHECKING

from twisted.internet import defer

from buildbot.data import base
from buildbot.data import types

if TYPE_CHECKING:
from buildbot.db.projects import ProjectModel


def project_db_to_data(dbdict, active=None):
def project_db_to_data(model: ProjectModel, active=None):
return {
"projectid": dbdict["id"],
"name": dbdict["name"],
"slug": dbdict["slug"],
"description": dbdict["description"],
"description_format": dbdict["description_format"],
"description_html": dbdict["description_html"],
"projectid": model.id,
"name": model.name,
"slug": model.slug,
"description": model.description,
"description_format": model.description_format,
"description_html": model.description_html,
"active": active,
}

Expand Down Expand Up @@ -69,8 +75,8 @@ def get(self, result_spec, kwargs):
# This is not optimized case which is assumed to be infrequently required
dbdicts_all = yield self.master.db.projects.get_projects()
dbdicts_active = yield self.master.db.projects.get_active_projects()
ids_active = set(dbdict["id"] for dbdict in dbdicts_active)
dbdicts = [dbdict for dbdict in dbdicts_all if dbdict["id"] not in ids_active]
ids_active = set(dbdict.id for dbdict in dbdicts_active)
dbdicts = [dbdict for dbdict in dbdicts_all if dbdict.id not in ids_active]

return [project_db_to_data(dbdict, active=active) for dbdict in dbdicts]

Expand Down
85 changes: 59 additions & 26 deletions master/buildbot/db/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,45 @@
#
# Copyright Buildbot Team Members

from __future__ import annotations

from dataclasses import dataclass

from twisted.internet import defer

from buildbot.db import base
from buildbot.warnings import warn_deprecated


@dataclass
class ProjectModel:
id: int
name: str
slug: str
description: str | None
description_format: str | None
description_html: str | None

# For backward compatibility
def __getitem__(self, key: str):
warn_deprecated(
'4.1.0',
(
'ProjectsConnectorComponent '
'get_project, get_projects, and get_active_projects '
'no longer return Project as dictionnaries. '
'Usage of [] accessor is deprecated: please access the member directly'
),
)

if hasattr(self, key):
return getattr(self, key)

raise KeyError(key)


class ProjectsConnectorComponent(base.DBConnectorComponent):
def find_project_id(self, name, auto_create=True):
def find_project_id(self, name: str, auto_create: bool = True) -> defer.Deferred[int | None]:
name_hash = self.hashColumns(name)
return self.findSomethingId(
tbl=self.db.model.projects,
Expand All @@ -33,9 +64,8 @@ def find_project_id(self, name, auto_create=True):
autoCreate=auto_create,
)

@defer.inlineCallbacks
def get_project(self, projectid):
def thd(conn):
def get_project(self, projectid: int) -> defer.Deferred[ProjectModel | None]:
def thd(conn) -> ProjectModel | None:
q = self.db.model.projects.select().where(
self.db.model.projects.c.id == projectid,
)
Expand All @@ -44,41 +74,44 @@ def thd(conn):

rv = None
if row:
rv = self._project_dict_from_row(row)
rv = self._model_from_row(row)
res.close()
return rv

return (yield self.db.pool.do(thd))
return self.db.pool.do(thd)

# returns a Deferred that returns a value
def get_projects(self):
def thd(conn):
def get_projects(self) -> defer.Deferred[list[ProjectModel]]:
def thd(conn) -> list[ProjectModel]:
tbl = self.db.model.projects
q = tbl.select()
q = q.order_by(tbl.c.name)
res = conn.execute(q)
return [self._project_dict_from_row(row) for row in res.fetchall()]
return [self._model_from_row(row) for row in res.fetchall()]

return self.db.pool.do(thd)

# returns a Deferred that returns a value
def get_active_projects(self):
def thd(conn):
def get_active_projects(self) -> defer.Deferred[list[ProjectModel]]:
def thd(conn) -> list[ProjectModel]:
projects_tbl = self.db.model.projects
builders_tbl = self.db.model.builders
bm_tbl = self.db.model.builder_masters

q = projects_tbl.select().join(builders_tbl).join(bm_tbl).order_by(projects_tbl.c.name)
res = conn.execute(q)
return [self._project_dict_from_row(row) for row in res.fetchall()]
return [self._model_from_row(row) for row in res.fetchall()]

return self.db.pool.do(thd)

# returns a Deferred that returns a value
def update_project_info(
self, projectid, slug, description, description_format, description_html
):
def thd(conn):
self,
projectid: int,
slug: str,
description: str | None,
description_format: str | None,
description_html: str | None,
) -> defer.Deferred[None]:
def thd(conn) -> None:
q = self.db.model.projects.update().where(self.db.model.projects.c.id == projectid)
conn.execute(
q.values(
Expand All @@ -91,12 +124,12 @@ def thd(conn):

return self.db.pool.do(thd)

def _project_dict_from_row(self, row):
return {
"id": row.id,
"name": row.name,
"slug": row.slug,
"description": row.description,
"description_format": row.description_format,
"description_html": row.description_html,
}
def _model_from_row(self, row):
return ProjectModel(
id=row.id,
name=row.name,
slug=row.slug,
description=row.description,
description_format=row.description_format,
description_html=row.description_html,
)
37 changes: 25 additions & 12 deletions master/buildbot/test/fakedb/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
#
# Copyright Buildbot Team Members

from __future__ import annotations

from twisted.internet import defer

from buildbot.db.projects import ProjectModel
from buildbot.test.fakedb.base import FakeDBComponent
from buildbot.test.fakedb.row import Row

Expand Down Expand Up @@ -65,8 +67,7 @@ def insert_test_data(self, rows):
"description_html": row.description_html,
}

# Returns Deferred that yields a number
def find_project_id(self, name, auto_create=True):
def find_project_id(self, name: str, auto_create: bool = True) -> defer.Deferred[int | None]:
for m in self.projects.values():
if m['name'] == name:
return defer.succeed(m['id'])
Expand All @@ -83,18 +84,18 @@ def find_project_id(self, name, auto_create=True):
}
return defer.succeed(id)

def get_project(self, projectid):
def get_project(self, projectid: int) -> defer.Deferred[ProjectModel | None]:
if projectid in self.projects:
return defer.succeed(self._row2dict(self.projects[projectid]))
return defer.succeed(self._model_from_row(self.projects[projectid]))
return defer.succeed(None)

def get_projects(self):
def get_projects(self) -> list[ProjectModel]:
rv = []
for project in self.projects.values():
rv.append(self._row2dict(project))
rv.append(self._model_from_row(project))
return rv

def get_active_projects(self):
def get_active_projects(self) -> list[ProjectModel]:
rv = []

active_builderids = {
Expand All @@ -110,12 +111,17 @@ def get_active_projects(self):
for id, project in self.projects.items():
if id not in active_projectids:
continue
rv.append(self._row2dict(project))
rv.append(self._model_from_row(project))
return rv

def update_project_info(
self, projectid, slug, description, description_format, description_html
):
self,
projectid: int,
slug: str,
description: str | None,
description_format: str | None,
description_html: str | None,
) -> defer.Deferred[None]:
if projectid not in self.projects:
return defer.succeed(None)
project = self.projects[projectid]
Expand All @@ -125,5 +131,12 @@ def update_project_info(
project["description_html"] = description_html
return defer.succeed(None)

def _row2dict(self, row):
return row.copy()
def _model_from_row(self, row):
return ProjectModel(
id=row['id'],
name=row['name'],
slug=row['slug'],
description=row['description'],
description_format=row['description_format'],
description_html=row['description_html'],
)
17 changes: 9 additions & 8 deletions master/buildbot/test/unit/data/test_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from buildbot.data import projects
from buildbot.data import resultspec
from buildbot.db.projects import ProjectModel
from buildbot.test import fakedb
from buildbot.test.fake import fakemaster
from buildbot.test.reactor import TestReactorMixin
Expand Down Expand Up @@ -155,13 +156,13 @@ def test_update_project_info(self):
self.assertEqual(
projects,
[
{
"id": 13,
"name": "fake_project",
"slug": "slug13",
"description": "project13 desc",
"description_format": "format",
"description_html": "html desc",
}
ProjectModel(
id=13,
name="fake_project",
slug="slug13",
description="project13 desc",
description_format="format",
description_html="html desc",
)
],
)
Loading
Loading