#274 Support SQLAlchemy 2.0
Closed a year ago by kparal. Opened a year ago by kparal.

file modified
-3
@@ -6,7 +6,6 @@ 

  

  from flask import Flask, render_template

  from flask_sqlalchemy import SQLAlchemy

- from flask_sqlalchemy.model import DefaultMeta

  import sqlalchemy

  

  from . import config
@@ -127,8 +126,6 @@ 

      }

  )

  db: SQLAlchemy = SQLAlchemy(app=app, metadata=metadata)

- # https://stackoverflow.com/questions/63542818/mypy-and-inheriting-from-a-class-that-is-an-attribute-on-an-instance

- BaseModel: DefaultMeta = db.Model

  

  

  # === Infra tweaks ===

file modified
+12 -14
@@ -84,23 +84,22 @@ 

  

  

  def add_release(args):

-     number = args.release

+     number = int(args.release)

      existing_release = Release.query.filter_by(number=number).count()

      if existing_release > 0:

-         print("Release %s already exists, not adding" % number)

+         print("Release %d already exists, not adding" % number)

      else:

-         print("Adding release %s" % number)

-         release_num = int(number)

-         new_release = Release(release_num)

+         print("Adding release %d" % number)

+         new_release = Release(number)

          db.session.add(new_release)

          db.session.commit()

  

  

  def add_milestone(args):

-     number = args.release

+     number = int(args.release)

      version = args.milestone

-     blocker = args.blocker

-     fe = args.fe

+     blocker = int(args.blocker)

+     fe = int(args.fe)

  

      existing_milestone = Milestone.query.filter_by(version=version,

                                                     blocker_tracker=blocker,
@@ -108,17 +107,16 @@ 

  

      current_milestones = Milestone.query.filter_by(active=True, current=True).count()

      if existing_milestone > 0:

-         print("Milestone already exists, not adding: %s-%s (%s, %s)" % (number, version, blocker, fe))

+         print("Milestone already exists, not adding: %d-%s (%d, %d)" % (number, version, blocker, fe))

      else:

-         print("Adding milestone: %s-%s (%s, %s)" % (number, version, blocker, fe))

-         release_num = int(number)

-         release = Release.query.filter_by(number=release_num).first()

+         print("Adding milestone: %d-%s (%d, %d)" % (number, version, blocker, fe))

+         release = Release.query.filter_by(number=number).first()

          if not release:

              add_release(release)

-             release = Release.query.filter_by(number=release_num).first()

+             release = Release.query.filter_by(number=number).first()

  

          new_milestone = Milestone(release, version, int(blocker), int(fe),

-                                   '%d-%s' % (release_num, version))

+                                   '%d-%s' % (number, version))

  

          # only active releases are synced but since this version is being added,

          # it's a good assumption to make it active.

file modified
+1 -1
@@ -110,7 +110,7 @@ 

  def openshift_config(config_object, openshift_production):

      # First, get db and other mandatory details from env

      try:

-         config_object["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://%s:%s@%s:%s/%s" % (

+         config_object["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg://%s:%s@%s:%s/%s" % (

              os.environ["POSTGRESQL_USER"],

              os.environ["POSTGRESQL_PASSWORD"],

              os.environ["POSTGRESQL_SERVICE_HOST"],

@@ -19,12 +19,11 @@ 

  

  """Base model classes"""

  

- from typing import Any

- 

  from blockerbugs import db

  

- update_fixes: Any = db.Table(

+ update_fixes = db.Table(

      'update_fixes',

+     db.metadata,

      db.Column('update_id', db.Integer, db.ForeignKey('update.id'), primary_key=True),

      db.Column('bug_id', db.Integer, db.ForeignKey('bug.id'), primary_key=True),

  )

file modified
+57 -47
@@ -19,19 +19,18 @@ 

  

  """ORM class for bug information stored in the database"""

  

- import datetime

+ from datetime import datetime

  import json

- from typing import Any, Optional

+ from typing import Any, Optional, List

  

  from sqlalchemy import or_

  from sqlalchemy.ext.hybrid import hybrid_property

  

- from blockerbugs import db, BaseModel, models

+ from blockerbugs import db, models

  import blockerbugs.models.milestone as model_milestone

- import blockerbugs.models.update as model_update

  

  

- class Bug(BaseModel):

+ class Bug(db.Model):

      """A representation of a Bugzilla ticket, with some additional attributes.

  

      Note: While a particular bug (with a given `bugid`) can exist only once in Bugzilla, a matching
@@ -39,37 +38,49 @@ 

      `Milestone`. So e.g. there can only be a single `Bug` with `bugid=123456` under F35-Beta, but

      there can be another `Bug` with `bugid=123456` under F35-Final, or F36-Beta.

      """

+     __tablename__ = "bug"

  

-     id = db.Column(db.Integer, primary_key=True)

-     bugid = db.Column(db.Integer, unique=False)

+     id: db.Mapped[int] = db.mapped_column(primary_key=True)

+     bugid: db.Mapped[Optional[int]]

      """The bug number, e.g. 123456"""

-     url = db.Column(db.String(1024), unique=False)

-     summary = db.Column(db.String(2048), unique=False)

-     status = db.Column(db.String(80), unique=False)

+     url: db.Mapped[Optional[str]] = db.mapped_column(db.String(1024))

+     summary: db.Mapped[Optional[str]] = db.mapped_column(db.String(2048))

+     status: db.Mapped[Optional[str]] = db.mapped_column(db.String(80))

      """E.g. 'NEW' or 'ASSIGNED'"""

-     component = db.Column(db.String(80), unique=False)

-     active = db.Column(db.Boolean(create_constraint=True, name='active_bool'))

+     component: db.Mapped[Optional[str]] = db.mapped_column(db.String(80))

+     active: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='active_bool'))

      """An alias for 'open', i.e. `True` when open, `False` when closed"""

-     last_bug_sync = db.Column(db.DateTime)

-     needinfo = db.Column(db.Boolean(create_constraint=True, name='needinfo_bool'))

-     needinfo_requestee = db.Column(db.String(1024), unique=False)

-     last_whiteboard_change = db.Column(db.DateTime)

+     last_bug_sync: db.Mapped[Optional[datetime]]

+     needinfo: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='needinfo_bool'))

+     needinfo_requestee: db.Mapped[Optional[str]] = db.mapped_column(db.String(1024))

+     last_whiteboard_change: db.Mapped[Optional[datetime]]

      """The time when we detected a blocker/FE keyword change. It doesn't really mark *any*

      whiteboard change, just for those tracked keywords."""

-     proposed_blocker = db.Column(db.Boolean(create_constraint=True, name='proposed_blocker_bool'))

-     proposed_fe = db.Column(db.Boolean(create_constraint=True, name='proposed_fe_bool'))

-     rejected_blocker = db.Column(db.Boolean(create_constraint=True, name='rejected_blocker_bool'))

-     rejected_fe = db.Column(db.Boolean(create_constraint=True, name='rejected_fe_bool'))

-     accepted_blocker = db.Column(db.Boolean(create_constraint=True, name='accepted_blocker_bool'))

-     accepted_0day = db.Column(db.Boolean(create_constraint=True, name='accepted_0day_bool'))

-     accepted_prevrel = db.Column(db.Boolean(create_constraint=True, name='accepted_prevrel_bool'))

-     accepted_fe = db.Column(db.Boolean(create_constraint=True, name='accepted_fe_bool'))

-     prioritized = db.Column(db.Boolean(create_constraint=True, name='prioritized_bool'))

-     milestone_id = db.Column(db.Integer, db.ForeignKey('milestone.id'))

-     milestone: Optional['model_milestone.Milestone'] = db.relationship(

-         'Milestone', back_populates='bugs', cascade_backrefs=False)

-     discussion_link = db.Column(db.String, unique=False)

-     votes: str = db.Column(db.Text, default='{}', nullable=False)

+     proposed_blocker: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='proposed_blocker_bool'))

+     proposed_fe: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='proposed_fe_bool'))

+     rejected_blocker: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='rejected_blocker_bool'))

+     rejected_fe: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='rejected_fe_bool'))

+     accepted_blocker: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='accepted_blocker_bool'))

+     accepted_0day: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='accepted_0day_bool'))

+     accepted_prevrel: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='accepted_prevrel_bool'))

+     accepted_fe: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='accepted_fe_bool'))

+     prioritized: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='prioritized_bool'))

+     milestone_id: db.Mapped[Optional[int]] = db.mapped_column(db.ForeignKey('milestone.id'))

+     milestone: db.Mapped[Optional['Milestone']] = db.relationship(  # noqa: F821

+         back_populates='bugs', cascade_backrefs=False)

+     discussion_link: db.Mapped[Optional[str]]

+     votes: db.Mapped[str] = db.mapped_column(db.Text, default='{}')

      """A JSON representation of dict of all BugVoteTrackers and corresponding output of

      `BugVoteTracker.enumerate_votes()` with comment ids removed:

      ```
@@ -78,12 +89,11 @@ 

                        "+1": ["nick3"]}

       }

      ```"""

-     _depends_on: str = db.Column('depends_on', db.Text, default='[]', nullable=False)

+     _depends_on: db.Mapped[str] = db.mapped_column('depends_on', db.Text, default='[]')

      """A JSON list of bug numbers which this bug depends on"""

-     updates: list['model_update.Update'] = db.relationship(

-         'Update', secondary=models.update_fixes, back_populates='bugs', lazy='dynamic',

-         order_by=('[Update.status.desc(), Update.request.desc()]'), cascade_backrefs=False

-     )

+     updates: db.Mapped[List['Update']] = db.relationship(  # noqa: F821

+         secondary=models.update_fixes, back_populates='bugs', lazy='dynamic',

+         order_by='[Update.status.desc(), Update.request.desc()]', cascade_backrefs=False)

  

      def __init__(self,

                   bugid: Optional[int],
@@ -95,8 +105,8 @@ 

                   active: Optional[bool],

                   needinfo: Optional[bool],

                   needinfo_requestee: Optional[str],

-                  last_whiteboard_change: Optional[datetime.datetime] = datetime.datetime.utcnow(),

-                  last_bug_sync: Optional[datetime.datetime] = datetime.datetime.now(),

+                  last_whiteboard_change: Optional[datetime] = datetime.utcnow(),

+                  last_bug_sync: Optional[datetime] = datetime.now(),

                   depends_on: Optional[list[int]] = None) -> None:

          self.bugid = bugid

          self.url = url
@@ -144,18 +154,18 @@ 

                  self.prioritized)

  

      @is_proposed_accepted.expression  # type: ignore[no-redef]

-     def is_proposed_accepted(cls) -> bool:

+     def is_proposed_accepted(self) -> bool:

          """Return ``True`` if this bug is either proposed or accepted as a Blocker, FreezeException

          or Prioritized.

          """

          # The SQLAlchemy expression when using ``is_proposed_accepted`` in a query.

-         return or_(cls.proposed_blocker,

-                    cls.proposed_fe,

-                    cls.accepted_blocker,

-                    cls.accepted_0day,

-                    cls.accepted_prevrel,

-                    cls.accepted_fe,

-                    cls.prioritized)

+         return or_(self.proposed_blocker,

+                    self.proposed_fe,

+                    self.accepted_blocker,

+                    self.accepted_0day,

+                    self.accepted_prevrel,

+                    self.accepted_fe,

+                    self.prioritized)

  

      def __repr__(self):

          return '<bug %d: %s>' % (self.bugid, self.summary)
@@ -178,7 +188,7 @@ 

              if self.proposed_blocker != buginfo['proposed'] or \

                 self.accepted_blocker != buginfo['accepted'] or \

                 self.rejected_blocker != buginfo['rejected']:

-                 self.last_whiteboard_change = datetime.datetime.utcnow()

+                 self.last_whiteboard_change = datetime.utcnow()

              self.proposed_blocker = buginfo['proposed']

              self.accepted_0day = buginfo['0day']

              self.accepted_prevrel = buginfo['prevrel']
@@ -188,7 +198,7 @@ 

              if self.proposed_fe != buginfo['proposed'] or \

                 self.accepted_fe != buginfo['accepted'] or \

                 self.rejected_fe != buginfo['rejected']:

-                 self.last_whiteboard_change = datetime.datetime.utcnow()

+                 self.last_whiteboard_change = datetime.utcnow()

              self.proposed_fe = buginfo['proposed']

              self.accepted_fe = buginfo['accepted']

              self.rejected_fe = buginfo['rejected']

file modified
+28 -24
@@ -18,46 +18,50 @@ 

  #   Tim Flink <tflink@redhat.com>

  

  """ORM class for release milestone info stored in the database"""

+ from datetime import datetime

+ from typing import Any, Optional, List

  

- from typing import Any, Optional

- 

- from blockerbugs import db, BaseModel

- from blockerbugs.models import bug

+ from blockerbugs import db

  from blockerbugs.models import release as model_release

  

  

- class Milestone(BaseModel):

+ class Milestone(db.Model):

      """A `Milestone` represents e.g. a Beta or a Final milestone, in relation to a certain

      `Release` (like 35).

      """

+     __tablename__ = "milestone"

  

-     id = db.Column(db.Integer, primary_key=True)

-     release_id = db.Column(db.Integer, db.ForeignKey('release.id'))

-     release: 'Optional[model_release.Release]' = db.relationship(

-         'Release', back_populates='milestones', cascade_backrefs=False)

-     version = db.Column(db.String(80))

+     id: db.Mapped[int] = db.mapped_column(primary_key=True)

+     release_id: db.Mapped[Optional[int]] = db.mapped_column(db.ForeignKey('release.id'))

+     release: db.Mapped[Optional['Release']] = db.relationship(  # noqa: F821

+         back_populates='milestones', cascade_backrefs=False)

+     version: db.Mapped[Optional[str]] = db.mapped_column(db.String(80))

      """E.g. 'beta' or 'final'"""

-     name = db.Column(db.String(80), unique=True)

+     name: db.Mapped[Optional[str]] = db.mapped_column(db.String(80), unique=True)

      """A "pretty" name for the milestone, usually created together with the release number,

      e.g. '35-beta'"""

-     blocker_tracker = db.Column(db.Integer, unique=True)

+     blocker_tracker: db.Mapped[Optional[int]] = db.mapped_column(unique=True)

      """A bugzilla ticket number representing the tracker for blockers"""

-     fe_tracker = db.Column(db.Integer, unique=True)

+     fe_tracker: db.Mapped[Optional[int]] = db.mapped_column(unique=True)

      """A bugzilla ticket number representing the tracker for freeze exceptions"""

-     active = db.Column(db.Boolean(create_constraint=True, name='active_bool'))

+     active: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='active_bool'))

      """Only active milestones are synced and displayed"""

-     last_bug_sync = db.Column(db.DateTime)

-     current = db.Column(db.Boolean(create_constraint=True, name='current_bool'))

+     last_bug_sync: db.Mapped[Optional[datetime]]

+     current: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='current_bool'))

      """Current milestone is the most relevant one currently. Usually it is the nearest milestone

      in the future. There should be at most one milestone marked as current."""

-     bugs: list['bug.Bug'] = db.relationship('Bug', back_populates='milestone', lazy='dynamic',

-                                             cascade_backrefs=False)

-     succeeds_id = db.Column(db.Integer, db.ForeignKey('milestone.id'), nullable=True)

-     succeeds: 'Milestone' = db.relationship('Milestone', back_populates='succeeded_by',

-                                             lazy='dynamic', cascade_backrefs=False)

-     succeeded_by: 'Milestone' = db.relationship('Milestone', back_populates='succeeds',

-                                                 remote_side=[id], uselist=False,

-                                                 cascade_backrefs=False)

+     bugs: db.Mapped[List['Bug']] = db.relationship(  # noqa: F821

+         back_populates='milestone', lazy='dynamic', cascade_backrefs=False)

+     succeeds_id: db.Mapped[Optional[int]] = db.mapped_column(db.ForeignKey('milestone.id'))

+     # FIXME: `succeeds` and `succeeded_by` should have `db.Mapped['Milestone']` type, but if we add

+     # it, tests fail with: "On relationship Milestone.succeeds, 'dynamic' loaders cannot be used

+     # with many-to-one/one-to-one relationships and/or uselist=False".

+     succeeds = db.relationship('Milestone', back_populates='succeeded_by', lazy='dynamic',

+                                cascade_backrefs=False)

+     succeeded_by = db.relationship('Milestone', back_populates='succeeds', remote_side=[id],

+                                    uselist=False, cascade_backrefs=False)

  

      def __init__(self,

                   release: Optional['model_release.Release'],

file modified
+16 -15
@@ -20,29 +20,30 @@ 

  """Database model for releases"""

  

  from datetime import datetime

- from typing import Optional

+ from typing import Optional, List

  

- from blockerbugs import db, BaseModel

- from blockerbugs.models import milestone, update

+ from blockerbugs import db

  

  

- class Release(BaseModel):

+ class Release(db.Model):

      """This represents an OS release, primarily determined by its number."""

+     __tablename__ = "release"

  

-     id = db.Column(db.Integer, primary_key=True)

-     number = db.Column(db.Integer)

+     id: db.Mapped[int] = db.mapped_column(primary_key=True)

+     number: db.Mapped[Optional[int]]

      """E.g. 35 (for Fedora 35)"""

-     active = db.Column(db.Boolean(create_constraint=True, name='active_bool'))

+     active: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='active_bool'))

      """Only active releases are synced and displayed"""

-     discussions_closed = db.Column(db.Boolean(create_constraint=True,

-                                               name='discussions_closed_bool'))

+     discussions_closed: db.Mapped[Optional[bool]] = db.mapped_column(

+         db.Boolean(create_constraint=True, name='discussions_closed_bool'))

      """This is used for past (historical) releases. If this is `True`, all discussion tickets (as in

      `Bug.discussion_link`) have been closed ("cleaned up")."""

-     last_update_sync: datetime = db.Column(db.DateTime)

-     milestones: list['milestone.Milestone'] = db.relationship('Milestone', back_populates='release',

-                                                               lazy='dynamic', cascade_backrefs=False)

-     updates: list['update.Update'] = db.relationship('Update', back_populates='release',

-                                                      lazy='dynamic', cascade_backrefs=False)

+     last_update_sync: db.Mapped[Optional[datetime]]

+     milestones: db.Mapped[List['Milestone']] = db.relationship(  # noqa: F821

+         back_populates='release', lazy='dynamic', cascade_backrefs=False)

+     updates: db.Mapped[List['Update']] = db.relationship(  # noqa: F821

+         back_populates='release', lazy='dynamic', cascade_backrefs=False)

  

      def __init__(self, number: int, active: Optional[bool] = True,

                   discussions_closed: Optional[bool] = False) -> None:
@@ -53,4 +54,4 @@ 

          self.last_update_sync = datetime(1990, 1, 1, 1, 0, 0, 0)

  

      def __str__(self) -> str:

-         return 'release: %d' % (self.number)

+         return 'release: %d' % self.number

file modified
+22 -20
@@ -19,15 +19,15 @@ 

  

  """Database model for Bodhi updates"""

  

- from typing import Optional, Any

+ from typing import Optional, Any, List

  from datetime import datetime

  

- from blockerbugs import db, BaseModel, models

+ from blockerbugs import db, models

  from blockerbugs.models import bug

  from blockerbugs.models import release as model_release

  

  

- class Update(BaseModel):

+ class Update(db.Model):

      """A representation of a Bodhi update.

  

      Bodhi update states are documented here:
@@ -35,36 +35,38 @@ 

      And here's a JSON schema for the different fields:

      https://bodhi.fedoraproject.org/docs/server_api/messages/update.html#json-schemas

      """

-     id: int = db.Column(db.Integer, primary_key=True)

-     updateid: str = db.Column(db.Text, nullable=False, unique=True)

+     __tablename__ = "update"

+ 

+     id: db.Mapped[int] = db.mapped_column(primary_key=True)

+     updateid: db.Mapped[str] = db.mapped_column(db.Text, nullable=False, unique=True)

      """E.g. FEDORA-2021-5282b5cafd"""

-     release_id: int = db.Column(db.Integer, db.ForeignKey('release.id'), nullable=False)

-     release: 'model_release.Release' = db.relationship('Release', back_populates='updates',

-                                                        cascade_backrefs=False)

+     release_id: db.Mapped[int] = db.mapped_column(db.ForeignKey('release.id'))

+     release: db.Mapped['Release'] = db.relationship(  # noqa: F821

+         back_populates='updates', cascade_backrefs=False)

      """The release this update was created for in Bodhi"""

-     status: str = db.Column(db.Enum('stable', 'pending', 'testing', create_constraint=True,

-                                     name='update_status_enum'),

-                             nullable=False)

+     status: db.Mapped[str] = db.mapped_column(

+         db.Enum('stable', 'pending', 'testing', create_constraint=True, name='update_status_enum'))

      """One of: 'stable', 'pending', 'testing'. A Bodhi update can have additional values, but we

      only allow these three here. Because this is an enum, Updates can be sorted by this in the

      specified order (updates in a need of testing have higher value)."""

-     karma: int = db.Column(db.Integer, nullable=False)

+     karma: db.Mapped[int]

      """Current karma value"""

-     url: str = db.Column(db.Text, nullable=False)

+     url: db.Mapped[str] = db.mapped_column(db.Text)

      """E.g. https://bodhi.fedoraproject.org/updates/FEDORA-2021-5282b5cafd"""

-     date_submitted: datetime = db.Column(db.DateTime, nullable=False)

+     date_submitted: db.Mapped[datetime]

      """When the update was created"""

-     request: Optional[str] = db.Column(db.Enum('revoke', 'unpush', 'obsolete', 'stable', 'testing',

-                                                create_constraint=True, name='update_request_enum'))

+     request: db.Mapped[Optional[str]] = db.mapped_column(

+         db.Enum('revoke', 'unpush', 'obsolete', 'stable', 'testing',

+                 create_constraint=True, name='update_request_enum'))

      """One of: 'revoke', 'unpush', 'obsolete', 'stable', 'testing', None. Because this is an enum,

      Updates can be sorted by this in the specified order (updates in a need of testing have higher

      value)."""

-     title: Optional[str] = db.Column(db.Text)

+     title: db.Mapped[Optional[str]] = db.mapped_column(db.Text)

      """E.g. firewalld-0.9.4-1.fc34"""

-     stable_karma: Optional[int] = db.Column(db.Integer)

+     stable_karma: db.Mapped[Optional[int]]

      """Target karma value for allowing the update to go stable (via auto or manual push)."""

-     bugs: list['bug.Bug'] = db.relationship(

-         'Bug', secondary=models.update_fixes, back_populates='updates', cascade_backrefs=False)

+     bugs: db.Mapped[List['Bug']] = db.relationship(  # noqa: F821

+         secondary=models.update_fixes, back_populates='updates', cascade_backrefs=False)

      """A list of bugs this update claims to fix *and* we track them"""

  

      _tmpstr = 'A placeholder value when creating incomplete Update objects'

file modified
+1 -1
@@ -1,7 +1,7 @@ 

  # while you can use this as a template, we recommend that you use the blockerbugs

  # cli to generate a config file

  SECRET_KEY = 'replace-me-with-something-random'

- SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://dbuser:dbpassword@dbhost:dbport/dbname'

+ SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg://dbuser:dbpassword@dbhost:dbport/dbname'

  FAS_ENABLED = False

  FAS_ADMIN_GROUP = "magic-fas-group"

  BUGZILLA_URL = 'https://bugzilla.stage.redhat.com'

file modified
+1 -1
@@ -98,7 +98,7 @@ 

  

  To generate an initial config using a PostgreSQL database, run the following command from the project root::

  

-   ./run cli generate_config -d 'postgresql+psycopg2://postgres:your-password@localhost:5432/blockerbugs'

+   ./run cli generate_config -d 'postgresql+psycopg://postgres:your-password@localhost:5432/blockerbugs'

  

  The configuration file will be generated in the ``conf/`` directory. While you

  would copy this config file to ``/etc/blockerbugs`` in a production system, for

@@ -4,7 +4,6 @@ 

  mypy

  

  ## additional type hints for mypy

- sqlalchemy-stubs

  types-Flask

  munch-stubs

  types-requests

file modified
+2 -2
@@ -15,7 +15,7 @@ 

  koji

  mock

  munch

- psycopg2-binary

+ psycopg[binary,pool]

  py

  pycurl

  pytest-cov
@@ -27,7 +27,7 @@ 

  python-openid-cla

  python-openid-teams

  python3-openid

- SQLAlchemy ~= 1.4

+ SQLAlchemy ~= 2.0.0

  WTForms

  

  # openshift deployment dependency

Please review per commit for better readability. Note that manual adjustments in your dev env are needed in order to test it locally, see the description of one of the commits. Thanks.

@frantisekz This will require a config change when deploying it.

Fixes: #266

A side note: I wanted to also use shiny dataclasses as part of this change, but it's not yet possible due to Flask-SQLAlchemy. More info in #273.

1 new commit added

  • cli.py: explicit typecast
a year ago

Just to mention for the record:

@frantisekz This will require a config change when deploying it.

Checked, no deployment changes would be necessary, DB_URI is dynamically generated on deployment rollup from DB credentials.

I'd pin this to 2.0.Z. sqla has caused major breakages in past during the Y version bumps (eg. 1.3 > 1.4).

Double checked infra if our psql version is supported by the psycopg3, it is.

1 new commit added

  • requirements: require SQLAlchemy ~= 2.0.0
a year ago

Pull-Request has been closed by kparal

a year ago

Merged into develop.