pkgcore.bugzilla package¶
Submodules¶
- pkgcore.bugzilla.apikey module
- pkgcore.bugzilla.bug module
BugBug.aliasBug.arches()Bug.assigned_toBug.blocksBug.categoryBug.ccBug.componentBug.creation_timeBug.creatorBug.deadlineBug.depends_onBug.flag()Bug.flagsBug.groupsBug.idBug.keywordsBug.last_change_timeBug.package_listBug.priorityBug.productBug.resolutionBug.resolvedBug.runtime_testing_requiredBug.sanity_checkBug.securityBug.see_alsoBug.severityBug.statusBug.summaryBug.tagsBug.urlBug.versionBug.whiteboard
BugChangesCommentFieldChangeFlagUserparse_bug()parse_changes()parse_comment()parse_user()
- pkgcore.bugzilla.changes module
BugUpdateBugUpdate.assigned_toBugUpdate.blocksBugUpdate.ccBugUpdate.commentBugUpdate.deadlineBugUpdate.depends_onBugUpdate.dupe_ofBugUpdate.flagsBugUpdate.groupsBugUpdate.keywordsBugUpdate.obsoleted_by()BugUpdate.package_listBugUpdate.resolutionBugUpdate.resolve()BugUpdate.runtime_testing_requiredBugUpdate.sanity_check()BugUpdate.see_alsoBugUpdate.statusBugUpdate.summaryBugUpdate.to_wire()BugUpdate.whiteboard
FlagChangeListChangeNewBugNewBug.arch_request()NewBug.assigned_toNewBug.blocksNewBug.ccNewBug.componentNewBug.deadlineNewBug.depends_onNewBug.descriptionNewBug.keywordsNewBug.package_listNewBug.package_mask()NewBug.productNewBug.runtime_testing_requiredNewBug.see_alsoNewBug.severityNewBug.summaryNewBug.to_wire()NewBug.version
NewCommentsummarise()
- pkgcore.bugzilla.client module
- pkgcore.bugzilla.enums module
BugCategoryChartOpChartOp.ALL_WORDSChartOp.ALL_WORDS_SUBSTRChartOp.ANY_EXACTChartOp.ANY_WORDSChartOp.ANY_WORDS_SUBSTRChartOp.CASE_SUBSTRINGChartOp.CHANGED_AFTERChartOp.CHANGED_BEFOREChartOp.CHANGED_BYChartOp.CHANGED_FROMChartOp.CHANGED_TOChartOp.EQUALSChartOp.GREATER_THANChartOp.GREATER_THAN_EQChartOp.IS_EMPTYChartOp.IS_NOT_EMPTYChartOp.LESS_THANChartOp.LESS_THAN_EQChartOp.MATCHESChartOp.NOT_EQUALSChartOp.NOT_MATCHESChartOp.NOT_REGEXPChartOp.NOT_SUBSTRINGChartOp.NO_WORDSChartOp.NO_WORDS_SUBSTRChartOp.REGEXPChartOp.SUBSTRING
ComponentFlagStatusJoinProductResolutionRuntimeTestingSeverityStatus
- pkgcore.bugzilla.errors module
- pkgcore.bugzilla.pkglist module
- pkgcore.bugzilla.query module
BugQueryBugQuery.any_of()BugQuery.assigned_to()BugQuery.batches()BugQuery.category()BugQuery.cc()BugQuery.chartsBugQuery.component()BugQuery.flag()BugQuery.ids()BugQuery.keywords()BugQuery.limitBugQuery.offsetBugQuery.orderBugQuery.package_list_any()BugQuery.paged()BugQuery.params()BugQuery.product()BugQuery.resolution()BugQuery.simpleBugQuery.status()BugQuery.unresolved()BugQuery.without_tags()
ChartGroupCriterion
- pkgcore.bugzilla.testing module
CallCassetteCassette.always()Cassette.assert_drained()Cassette.callsCassette.client()Cassette.creates_bugs()Cassette.expect()Cassette.expect_bugs()Cassette.expect_changed()Cassette.expect_created()Cassette.expect_error()Cassette.expect_whoami()Cassette.fallbackCassette.installed()Cassette.pendingCassette.transport()
RecordingReplayHandlerresponse()
- pkgcore.bugzilla.transport module
- pkgcore.bugzilla.wire module
JSONValueRawBugRawBug.aliasRawBug.assigned_toRawBug.blocksRawBug.ccRawBug.cf_runtime_testing_requiredRawBug.cf_stabilisation_atomsRawBug.componentRawBug.creation_timeRawBug.creatorRawBug.deadlineRawBug.depends_onRawBug.flagsRawBug.groupsRawBug.idRawBug.keywordsRawBug.last_change_timeRawBug.priorityRawBug.productRawBug.resolutionRawBug.see_alsoRawBug.severityRawBug.statusRawBug.summaryRawBug.tagsRawBug.versionRawBug.whiteboard
RawBugUpdateRawBugUpdate.assigned_toRawBugUpdate.blocksRawBugUpdate.ccRawBugUpdate.cf_runtime_testing_requiredRawBugUpdate.cf_stabilisation_atomsRawBugUpdate.commentRawBugUpdate.deadlineRawBugUpdate.depends_onRawBugUpdate.dupe_ofRawBugUpdate.flagsRawBugUpdate.groupsRawBugUpdate.idsRawBugUpdate.keywordsRawBugUpdate.resolutionRawBugUpdate.see_alsoRawBugUpdate.statusRawBugUpdate.summaryRawBugUpdate.whiteboard
RawChangesRawCommentRawCommentsRawCommentsResponseRawCreateResponseRawErrorRawFieldChangeRawFlagRawFlagChangeRawGetResponseRawListChangeRawNewBugRawNewBug.assigned_toRawNewBug.blocksRawNewBug.ccRawNewBug.cf_runtime_testing_requiredRawNewBug.cf_stabilisation_atomsRawNewBug.componentRawNewBug.deadlineRawNewBug.depends_onRawNewBug.descriptionRawNewBug.keywordsRawNewBug.productRawNewBug.see_alsoRawNewBug.severityRawNewBug.summaryRawNewBug.version
RawNewCommentRawSearchResponseRawUpdateResponseRawWhoamiRequestBody
Module contents¶
Typed client for the bugs.gentoo.org Bugzilla REST API.
The public surface is re-exported here; the implementation is split across
submodules so that pkgcore.bugzilla.wire and friends can be imported
without dragging in the HTTP transport.
>>> from pkgcore.bugzilla import Bugzilla, BugQuery, Component, FlagStatus
>>> bz = Bugzilla()
>>> query = (BugQuery.component(Component.STABILIZATION)
... & BugQuery.unresolved()
... & BugQuery.flag("sanity-check", FlagStatus.GRANTED))
>>> bugs = bz.search(query)
- class pkgcore.bugzilla.AuthMode(*values)[source]¶
Bases:
StrEnumWhere the api key is placed.
QUERYis the only mode bugs.gentoo.org honours today;HEADERexists for instances running Bugzilla 6.- HEADER = 'header'¶
- QUERY = 'query'¶
- class pkgcore.bugzilla.Bug(*, id: BugId = 0, summary: str = '', product: str = '', component: str = '', version: str = '', status: str = '', resolution: str = '', severity: str = '', priority: str = '', assigned_to: str = '', creator: str = '', cc: tuple[str, ...]=(), keywords: tuple[str, ...]=(), whiteboard: str = '', alias: tuple[str, ...]=(), tags: tuple[str, ...]=(), depends_on: tuple[~pkgcore.bugzilla.wire.BugId, ...]=(), blocks: tuple[~pkgcore.bugzilla.wire.BugId, ...]=(), see_also: tuple[str, ...]=(), groups: tuple[str, ...]=(), flags: tuple[~pkgcore.bugzilla.bug.Flag, ...]=(), deadline: date | None = None, creation_time: datetime = datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), last_change_time: datetime = datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), package_list: PackageList = <PackageList ''>, runtime_testing_required: RuntimeTesting = RuntimeTesting.UNSET)[source]¶
Bases:
objectAn immutable snapshot of a bug.
Anonymous requests get every email address truncated at the
@, soassigned_to,creatorandcconly hold full addresses when the client was given an api key.- arches(known_arches: Container[str]) tuple[str, ...][source]¶
Arch names found in CC, tolerating truncated anonymous addresses
- property category: BugCategory | None¶
- id: BugId¶
- package_list: PackageList¶
- runtime_testing_required: RuntimeTesting¶
- class pkgcore.bugzilla.BugCategory(*values)[source]¶
Bases:
StrEnumGentoo arch team bug categories, valued by their Bugzilla component
- KEYWORDREQ = 'Keywording'¶
- STABLEREQ = 'Stabilization'¶
- class pkgcore.bugzilla.BugChanges(id: BugId, last_change_time: datetime, changes: dict[str, ~pkgcore.bugzilla.bug.FieldChange]=<factory>, alias: tuple[str, ...]=())[source]¶
Bases:
objectThe result of updating a bug
- changes: dict[str, FieldChange]¶
- id: BugId¶
- class pkgcore.bugzilla.BugQuery(simple: tuple[tuple[str, tuple[str, ...]], ...] = (), charts: tuple[Criterion | ChartGroup, ...] = (), limit: int | None = None, offset: int | None = None, order: str | None = None)[source]¶
Bases:
objectA search, built from named constructors and combined with
&- classmethod any_of(*queries: BugQuery) BugQuery[source]¶
OR several chart-only queries together.
Simple parameters can’t take part in a chart group, so a query holding any is rejected rather than silently ANDed in.
- batches(base_length: int = 0, max_length: int = 6000) Iterator[BugQuery][source]¶
Split into sub-queries whose encoded parameters each fit the budget.
Only the largest splittable axis is divided, either the
idsimple parameter or aCriterionmarked splittable; everything else is repeated in every batch. Sizing uses the encoded length rather than a count, so it adapts to long atoms instead of guessing.
- classmethod category(*categories: BugCategory) BugQuery[source]¶
Restrict to keywordreqs and/or stablereqs
- charts: tuple[Criterion | ChartGroup, ...]¶
- classmethod flag(name: str, *statuses: FlagStatus | str) BugQuery[source]¶
Match a flag by status.
Bugzilla can’t express “flag is absent”; those bugs have to be fetched and filtered client side.
- classmethod package_list_any(packages: Iterable[object]) BugQuery[source]¶
Match bugs whose package list mentions any of these packages
- paged(limit: int, offset: int = 0) BugQuery[source]¶
Return a copy with explicit paging.
Bugzilla rejects an offset without a limit, and treats
limit=0as unlimited while silently discarding the offset, so both are refused.
- params() list[tuple[str, str]][source]¶
Render to ordered query parameters.
Ordered pairs rather than a mapping, since chart slots are positional and duplicate keys are meaningful.
- class pkgcore.bugzilla.BugUpdate(*, status: Status | None = None, resolution: Resolution | None = None, dupe_of: BugId | None = None, summary: str | None = None, assigned_to: str | None = None, whiteboard: str | None = None, deadline: date | None = None, cc: ListChange[str] = ListChange(add=(), remove=(), replace=None), keywords: ListChange[str] = ListChange(add=(), remove=(), replace=None), blocks: ListChange[BugId] = ListChange(add=(), remove=(), replace=None), depends_on: ListChange[BugId] = ListChange(add=(), remove=(), replace=None), see_also: ListChange[str] = ListChange(add=(), remove=(), replace=None), groups: ListChange[str] = ListChange(add=(), remove=(), replace=None), flags: tuple[FlagChange, ...] = (), comment: NewComment | None = None, package_list: PackageList | None = None, runtime_testing_required: RuntimeTesting | None = None)[source]¶
Bases:
objectA patch to apply to one or more bugs.
Every field defaults to leaving the bug alone. List valued fields only accept a
ListChange, so thecc_addshape Bugzilla ignores is both a static and a runtime error.- blocks: ListChange[BugId]¶
- cc: ListChange[str]¶
- comment: NewComment | None¶
- depends_on: ListChange[BugId]¶
- flags: tuple[FlagChange, ...]¶
- groups: ListChange[str]¶
- keywords: ListChange[str]¶
- classmethod obsoleted_by(bug: BugId | int, **kwargs: Any) BugUpdate[source]¶
Close as OBSOLETE, pointing at the bug that supersedes this one
- package_list: PackageList | None¶
- resolution: Resolution | None¶
- classmethod resolve(resolution: Resolution = Resolution.FIXED, *, comment: str | None = None, **kwargs: Any) BugUpdate[source]¶
- runtime_testing_required: RuntimeTesting | None¶
- classmethod sanity_check(status: bool | None, *, comment: str | None = None, **kwargs: Any) BugUpdate[source]¶
Set the sanity-check flag, None clearing it
- see_also: ListChange[str]¶
- to_wire(ids: Sequence[BugId | int]) RawBugUpdate[source]¶
Render the payload.
The complete id list is always sent, since Bugzilla lets the body override the id in the request path rather than the other way around.
- class pkgcore.bugzilla.Bugzilla(api_key: str | None = None, *, base_url: str = 'https://bugs.gentoo.org', timeout: float = 30.0, retries: int = 3, auth_mode: AuthMode = AuthMode.QUERY, retry_writes: bool = False, user_agent: str | None = None, opener: OpenerDirector | None = None, transport: Transport | None = None)[source]¶
Bases:
objectA Bugzilla instance, defaulting to bugs.gentoo.org.
Without an api key the client is read only, and Bugzilla truncates every email address it returns at the
@, so anything matching on addresses needs one.user_agentnames the calling tool; it is prepended to pkgcore’s own token rather than replacing it.- base_url¶
- create(bug: NewBug, /) BugId[source]¶
File a bug and return its id.
Never retried, since a retry after a timeout files a duplicate.
- get(bugs: BugId | int, /) Bug[source]¶
- get(bugs: Iterable[BugId | int], /) dict[BugId, Bug]
Fetch one bug, or a mapping for several.
- Raises:
BugzillaNotFound – when a single requested bug doesn’t exist
- latest_comment(bug: BugId | int, /, *, creator: str | None = None) Comment | None[source]¶
The newest comment, optionally restricted to one author.
creatordefaults to the authenticated account.
- mark_own_comments_obsolete(bug: BugId | int, /) int[source]¶
Tag the authenticated user’s comments obsolete, returning the count.
Deliberately separate from
update(), so a failed update doesn’t leave a bug with every comment obsoleted and no replacement.
- raw_search(query: BugQuery = BugQuery(simple=(), charts=(), limit=None, offset=None, order=None), /, *, fields: Sequence[str] = ('id', 'summary', 'product', 'component', 'version', 'status', 'resolution', 'severity', 'priority', 'assigned_to', 'creator', 'cc', 'keywords', 'whiteboard', 'alias', 'tags', 'depends_on', 'blocks', 'see_also', 'groups', 'flags', 'deadline', 'creation_time', 'last_change_time', 'cf_stabilisation_atoms', 'cf_runtime_testing_required')) tuple[RawBug, ...][source]¶
Run a search, returning the wire dicts rather than
Bug.Use this for the narrow projections a full
Bugdoesn’t need; anything left out offieldsis simply absent from the results.
- resolve_dependencies(bugs: dict[BugId, Bug]) dict[BugId, Bug][source]¶
Fetch the transitive closure of everything
bugsdepends on.Dependencies that can’t be fetched, because they were deleted or are behind a security group, are logged and dropped rather than looping.
- search(query: BugQuery = BugQuery(simple=(), charts=(), limit=None, offset=None, order=None), /) dict[BugId, Bug][source]¶
Run a search, batching and paging as needed
- tag_comments(comments: Iterable[CommentId | int], /, tags: ListChange[str]) None[source]¶
Add or remove tags on comments, one request per comment
- update(bugs: BugId | int, /, update: BugUpdate) BugChanges[source]¶
- update(bugs: Iterable[BugId | int], /, update: BugUpdate) tuple[BugChanges, ...]
Apply an update to one or more bugs.
The full id list always goes in the body, because Bugzilla lets the body override the id in the request path rather than the other way around.
- exception pkgcore.bugzilla.BugzillaError(msg, verbosity=None)[source]¶
Bases:
PkgcoreUserExceptionBase for every failure raised by pkgcore.bugzilla
- class pkgcore.bugzilla.Comment(id: CommentId, bug_id: BugId, count: int, text: str, creator: str, creation_time: datetime, is_private: bool = False, tags: tuple[str, ...] = ())[source]¶
Bases:
objectA single comment on a bug
- bug_id: BugId¶
- id: CommentId¶
- class pkgcore.bugzilla.Component(*values)[source]¶
Bases:
StrEnumComponents of Gentoo Linux, plus the security one that matters
- CURRENT_PACKAGES = 'Current packages'¶
- ECLASSES = 'Eclasses'¶
- KEYWORDING = 'Keywording'¶
- NEW_PACKAGES = 'New packages'¶
- PROFILES = 'Profiles'¶
- STABILIZATION = 'Stabilization'¶
- VULNERABILITIES = 'Vulnerabilities'¶
- class pkgcore.bugzilla.Criterion(field: str, op: ChartOp, values: tuple[str, ...] = (), negate: bool = False, splittable: bool = False)[source]¶
Bases:
objectOne boolean chart condition
- class pkgcore.bugzilla.Flag(name: str, status: FlagStatus, id: FlagId = 0, type_id: FlagTypeId = 0, setter: str = '', requestee: str = '')[source]¶
Bases:
objectA flag set on a bug
- id: FlagId¶
- status: FlagStatus¶
- type_id: FlagTypeId¶
- class pkgcore.bugzilla.FlagChange(name: str, status: FlagStatus, requestee: str | None = None)[source]¶
Bases:
objectSet or clear a flag
- status: FlagStatus¶
- to_wire() RawFlagChange[source]¶
- class pkgcore.bugzilla.FlagStatus(*values)[source]¶
Bases:
StrEnumStatus of a Bugzilla flag, CLEARED being write only
- CLEARED = 'X'¶
- DENIED = '-'¶
- GRANTED = '+'¶
- REQUESTED = '?'¶
- class pkgcore.bugzilla.ListChange(add: tuple[T, ...] = (), remove: tuple[T, ...] = (), replace: tuple[T, ...] | None = None)[source]¶
Bases:
GenericAn add/remove/set mutation of a list valued field
- classmethod adding(*values: T) ListChange[T][source]¶
- classmethod removing(*values: T) ListChange[T][source]¶
- classmethod setting(*values: T) ListChange[T][source]¶
Replace the field wholesale, Bugzilla’s
set
- to_wire() RawListChange[source]¶
- class pkgcore.bugzilla.NewBug(*, summary: str, description: str, component: Component | str, product: Product | str = Product.GENTOO_LINUX, version: str = 'unspecified', severity: Severity | str = Severity.NORMAL, assigned_to: str | None = None, cc: tuple[str, ...] = (), keywords: tuple[str, ...] = (), depends_on: tuple[BugId, ...] = (), blocks: tuple[BugId, ...] = (), see_also: tuple[str, ...] = (), deadline: date | None = None, package_list: PackageList | None = None, runtime_testing_required: RuntimeTesting | None = None)[source]¶
Bases:
objectA bug to file
- classmethod arch_request(category: BugCategory, package_list: PackageList, *, maintainers: Sequence[str] = (), cc_arches: bool = False, summary: str | None = None, description: str | None = None, **kwargs: Any) NewBug[source]¶
A keywordreq or stablereq, with the bgo conventions applied
- package_list: PackageList | None¶
- classmethod package_mask(summary: str, description: str, *, rites: int, maintainers: Sequence[str] = (), today: date | None = None, **kwargs: Any) NewBug[source]¶
A last rites tracker, masked for
ritesdays
- runtime_testing_required: RuntimeTesting | None¶
- class pkgcore.bugzilla.NewComment(body: str, is_private: bool = False)[source]¶
Bases:
objectA comment to leave alongside an update
- to_wire() RawNewComment[source]¶
- class pkgcore.bugzilla.PackageList(text: str = '', *, bug_id: BugId | None = None)[source]¶
Bases:
SimpleA lazily parsed view of a bug’s package list.
Parsing is deferred so fetching a bug with a malformed list never fails; only code that looks at the list does.
- bug_id¶
- classmethod build(entries: Iterable[tuple[atom, Iterable[str]]]) PackageList[source]¶
Construct a fresh list from atoms and their keywords
- entries¶
Every line of the list, blanks and comments included
- expand(suggest: Callable[[atom], Sequence[str]]) PackageList[source]¶
Resolve the
*and^sentinels.suggestreturns the keywords a package should be requested for, in the order they should be written; returning nothing collapses the line to-.- Raises:
PackageListError – on
^with nothing above it to copy
- text¶
- class pkgcore.bugzilla.PackageListEntry(lineno: int, raw: str, pkg: atom | None, keywords: tuple[str, ...] = (), comment: str = '', eol: str = '')[source]¶
Bases:
objectA single line of a package list
- with_keywords(keywords: Iterable[str]) PackageListEntry[source]¶
Return a copy with new keywords, keeping indentation and comment
- class pkgcore.bugzilla.Product(*values)[source]¶
Bases:
StrEnumThe bugs.gentoo.org products this module knows about
- GENTOO_LINUX = 'Gentoo Linux'¶
- GENTOO_SECURITY = 'Gentoo Security'¶
- class pkgcore.bugzilla.Resolution(*values)[source]¶
Bases:
StrEnumResolutions enabled on bugs.gentoo.org.
LATER and REMIND are legacy values still set on old bugs, listed so parsing round-trips rather than because anything should write them.
- CANTFIX = 'CANTFIX'¶
- DUPLICATE = 'DUPLICATE'¶
- FIXED = 'FIXED'¶
- INVALID = 'INVALID'¶
- LATER = 'LATER'¶
- NEEDINFO = 'NEEDINFO'¶
- OBSOLETE = 'OBSOLETE'¶
- PKGREMOVED = 'PKGREMOVED'¶
- REMIND = 'REMIND'¶
- TEST_REQUEST = 'TEST-REQUEST'¶
- UPSTREAM = 'UPSTREAM'¶
- WONTFIX = 'WONTFIX'¶
- WORKSFORME = 'WORKSFORME'¶
- class pkgcore.bugzilla.RuntimeTesting(*values)[source]¶
Bases:
StrEnumValues of cf_runtime_testing_required.
The field only exists on the Keywording and Stabilization components, and reads back as UNSET everywhere else.
- MANUAL = 'Manual'¶
- NO = 'No'¶
- UNSET = '---'¶
- YES = 'Yes'¶
- class pkgcore.bugzilla.Severity(*values)[source]¶
Bases:
StrEnumBug severities, QA being Gentoo specific
- BLOCKER = 'blocker'¶
- CRITICAL = 'critical'¶
- ENHANCEMENT = 'enhancement'¶
- MAJOR = 'major'¶
- MINOR = 'minor'¶
- NORMAL = 'normal'¶
- QA = 'QA'¶
- TRIVIAL = 'trivial'¶