bugdantic 0.4.2__tar.gz → 0.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bugdantic-0.4.2 → bugdantic-0.4.4}/PKG-INFO +1 -1
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic/bugzilla.py +33 -10
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic.egg-info/PKG-INFO +1 -1
- {bugdantic-0.4.2 → bugdantic-0.4.4}/pyproject.toml +1 -1
- {bugdantic-0.4.2 → bugdantic-0.4.4}/test/test_bugzilla.py +13 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/LICENSE +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/README.md +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic/__init__.py +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic/py.typed +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic/userstory.py +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic.egg-info/SOURCES.txt +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic.egg-info/dependency_links.txt +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic.egg-info/requires.txt +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/bugdantic.egg-info/top_level.txt +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/setup.cfg +0 -0
- {bugdantic-0.4.2 → bugdantic-0.4.4}/test/test_userstory.py +0 -0
|
@@ -2,8 +2,9 @@ import base64
|
|
|
2
2
|
import enum
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
+
import time
|
|
5
6
|
from collections.abc import Mapping, MutableMapping, Sequence
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
+
from dataclasses import dataclass, field
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from typing import (
|
|
9
10
|
Any,
|
|
@@ -436,6 +437,7 @@ class BugzillaConfig:
|
|
|
436
437
|
allow_writes: bool = False
|
|
437
438
|
# Number of times to retry a request if there's a 503 error
|
|
438
439
|
max_retries: int = 1
|
|
440
|
+
retry_status_codes: set[int] = field(default_factory=lambda: {502, 503})
|
|
439
441
|
|
|
440
442
|
|
|
441
443
|
BugType = TypeVar("BugType", bound=BaseModel)
|
|
@@ -453,10 +455,19 @@ def bug_search_model(bug_type: type[BugType]) -> type[BugSearchGeneric[BugType]]
|
|
|
453
455
|
|
|
454
456
|
|
|
455
457
|
def model_field_names(model: type[BaseModel]) -> list[str]:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
field_names = []
|
|
459
|
+
for name, field_obj in model.model_fields.items():
|
|
460
|
+
if field_obj.validation_alias is not None:
|
|
461
|
+
if not isinstance(field_obj.validation_alias, str):
|
|
462
|
+
raise ValueError(
|
|
463
|
+
"Only string values for validation_alias are supported"
|
|
464
|
+
)
|
|
465
|
+
field_names.append(field_obj.validation_alias)
|
|
466
|
+
elif field_obj.alias is not None:
|
|
467
|
+
field_names.append(field_obj.alias)
|
|
468
|
+
else:
|
|
469
|
+
field_names.append(name)
|
|
470
|
+
return field_names
|
|
460
471
|
|
|
461
472
|
|
|
462
473
|
class Bugzilla:
|
|
@@ -496,18 +507,30 @@ class Bugzilla:
|
|
|
496
507
|
path = path.removeprefix("/")
|
|
497
508
|
|
|
498
509
|
url = urljoin(self.config.base_url, f"/rest/{path}")
|
|
499
|
-
|
|
510
|
+
logging.debug("Fetching from bugzilla: %s", url)
|
|
500
511
|
if self.config.allow_writes or method in {"GET", "OPTIONS", "HEAD"}:
|
|
501
512
|
retry = 0
|
|
502
513
|
if self.config.max_retries < 0:
|
|
503
514
|
raise ValueError("max_retries must be at least 0")
|
|
504
515
|
response = None
|
|
505
516
|
while retry <= self.config.max_retries:
|
|
517
|
+
if retry != 0:
|
|
518
|
+
wait_time = 2**retry
|
|
519
|
+
logging.debug(
|
|
520
|
+
"Request failed, retrying %s/%s, sleeping %ss",
|
|
521
|
+
retry,
|
|
522
|
+
self.config.max_retries,
|
|
523
|
+
wait_time,
|
|
524
|
+
)
|
|
525
|
+
time.sleep(wait_time)
|
|
506
526
|
retry += 1
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
527
|
+
try:
|
|
528
|
+
response = self.client.request(
|
|
529
|
+
method, url, params=params, headers=headers, json=json_body
|
|
530
|
+
)
|
|
531
|
+
except httpx.ReadTimeout:
|
|
532
|
+
continue
|
|
533
|
+
if response.status_code not in self.config.retry_status_codes:
|
|
511
534
|
break
|
|
512
535
|
assert response is not None
|
|
513
536
|
try:
|
|
@@ -80,3 +80,16 @@ def test_bug_as_alias(bugzilla):
|
|
|
80
80
|
assert isinstance(result, BugData)
|
|
81
81
|
assert result.id == 975444
|
|
82
82
|
assert result.user_story is not None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_bug_as_validation_alias(bugzilla):
|
|
86
|
+
class BugData(BaseModel):
|
|
87
|
+
id: int
|
|
88
|
+
user_story: str = Field(
|
|
89
|
+
validation_alias="cf_user_story", alias="raw_user_story"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
result = bugzilla.bug_as(975444, BugData)
|
|
93
|
+
assert isinstance(result, BugData)
|
|
94
|
+
assert result.id == 975444
|
|
95
|
+
assert result.user_story is not None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|