bugdantic 0.4.4__tar.gz → 0.5.1__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.4 → bugdantic-0.5.1}/PKG-INFO +1 -1
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic/bugzilla.py +63 -9
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic.egg-info/PKG-INFO +1 -1
- {bugdantic-0.4.4 → bugdantic-0.5.1}/pyproject.toml +1 -1
- {bugdantic-0.4.4 → bugdantic-0.5.1}/test/test_bugzilla.py +31 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/LICENSE +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/README.md +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic/__init__.py +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic/py.typed +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic/userstory.py +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic.egg-info/SOURCES.txt +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic.egg-info/dependency_links.txt +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic.egg-info/requires.txt +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/bugdantic.egg-info/top_level.txt +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/setup.cfg +0 -0
- {bugdantic-0.4.4 → bugdantic-0.5.1}/test/test_userstory.py +0 -0
|
@@ -422,6 +422,17 @@ class AttachmentsCreateResponse(BaseModel):
|
|
|
422
422
|
attachments: Mapping[str, AttachmentCreateResponse]
|
|
423
423
|
|
|
424
424
|
|
|
425
|
+
class CommentCreate(BaseModel):
|
|
426
|
+
comment: str
|
|
427
|
+
is_private: Optional[bool] = None
|
|
428
|
+
is_markdown: Optional[bool] = None
|
|
429
|
+
work_time: Optional[float] = None
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class CommentCreateResponse(BaseModel):
|
|
433
|
+
id: int
|
|
434
|
+
|
|
435
|
+
|
|
425
436
|
class ErrorResponse(BaseModel):
|
|
426
437
|
code: int
|
|
427
438
|
message: str
|
|
@@ -564,11 +575,17 @@ class Bugzilla:
|
|
|
564
575
|
bug_id: int,
|
|
565
576
|
bug_type: type[BugType],
|
|
566
577
|
include_fields: Optional[list[str]] = None,
|
|
578
|
+
exclude_fields: Optional[list[str]] = None,
|
|
567
579
|
) -> Optional[BugType]:
|
|
568
580
|
"""Get a single bug specified by id"""
|
|
569
581
|
|
|
570
582
|
data = self.check_error(
|
|
571
|
-
self.request(
|
|
583
|
+
self.request(
|
|
584
|
+
"GET",
|
|
585
|
+
f"bug/{bug_id}",
|
|
586
|
+
include_fields=include_fields,
|
|
587
|
+
exclude_fields=exclude_fields,
|
|
588
|
+
)
|
|
572
589
|
)
|
|
573
590
|
search_result = bug_search_model(bug_type).model_validate(data)
|
|
574
591
|
if search_result.faults:
|
|
@@ -580,18 +597,27 @@ class Bugzilla:
|
|
|
580
597
|
return bugs[0]
|
|
581
598
|
|
|
582
599
|
def bug(
|
|
583
|
-
self,
|
|
600
|
+
self,
|
|
601
|
+
bug_id: int,
|
|
602
|
+
include_fields: Optional[list[str]] = None,
|
|
603
|
+
exclude_fields: Optional[list[str]] = None,
|
|
584
604
|
) -> Optional[Bug]:
|
|
585
|
-
return self._bug(bug_id, Bug, include_fields)
|
|
605
|
+
return self._bug(bug_id, Bug, include_fields, exclude_fields)
|
|
586
606
|
|
|
587
|
-
def bug_as(
|
|
607
|
+
def bug_as(
|
|
608
|
+
self,
|
|
609
|
+
bug_id: int,
|
|
610
|
+
bug_type: type[BugType],
|
|
611
|
+
exclude_fields: Optional[list[str]] = None,
|
|
612
|
+
) -> Optional[BugType]:
|
|
588
613
|
include_fields = model_field_names(bug_type)
|
|
589
|
-
return self._bug(bug_id, bug_type, include_fields)
|
|
614
|
+
return self._bug(bug_id, bug_type, include_fields, exclude_fields)
|
|
590
615
|
|
|
591
616
|
def bugs(
|
|
592
617
|
self,
|
|
593
618
|
bug_ids: Sequence[int],
|
|
594
619
|
include_fields: Optional[list[str]] = None,
|
|
620
|
+
exclude_fields: Optional[list[str]] = None,
|
|
595
621
|
page_size: int = 100,
|
|
596
622
|
) -> list[Bug]:
|
|
597
623
|
"""Get multiple bugs specified by id"""
|
|
@@ -603,6 +629,7 @@ class Bugzilla:
|
|
|
603
629
|
self.search(
|
|
604
630
|
{"id": ",".join(str(id) for id in bug_ids_chunk)},
|
|
605
631
|
include_fields=include_fields,
|
|
632
|
+
exclude_fields=exclude_fields,
|
|
606
633
|
)
|
|
607
634
|
)
|
|
608
635
|
return results
|
|
@@ -611,6 +638,7 @@ class Bugzilla:
|
|
|
611
638
|
self,
|
|
612
639
|
bug_ids: Sequence[int],
|
|
613
640
|
bug_type: type[BugType],
|
|
641
|
+
exclude_fields: Optional[list[str]] = None,
|
|
614
642
|
page_size: int = 100,
|
|
615
643
|
) -> list[BugType]:
|
|
616
644
|
"""Get multiple bugs specified by id"""
|
|
@@ -622,6 +650,7 @@ class Bugzilla:
|
|
|
622
650
|
self.search_as(
|
|
623
651
|
{"id": ",".join(str(id) for id in bug_ids_chunk)},
|
|
624
652
|
bug_type,
|
|
653
|
+
exclude_fields,
|
|
625
654
|
)
|
|
626
655
|
)
|
|
627
656
|
return results
|
|
@@ -650,6 +679,7 @@ class Bugzilla:
|
|
|
650
679
|
bug_type: type[BugType],
|
|
651
680
|
query: QueryParams,
|
|
652
681
|
include_fields: Optional[list[str]] = None,
|
|
682
|
+
exclude_fields: Optional[list[str]] = None,
|
|
653
683
|
page_size: int = 100,
|
|
654
684
|
) -> list[BugType]:
|
|
655
685
|
"""Search for bugs using the bugzilla query API"""
|
|
@@ -665,7 +695,13 @@ class Bugzilla:
|
|
|
665
695
|
results: list[BugType] = []
|
|
666
696
|
while True:
|
|
667
697
|
response = self.check_error(
|
|
668
|
-
self.request(
|
|
698
|
+
self.request(
|
|
699
|
+
"GET",
|
|
700
|
+
"bug",
|
|
701
|
+
params=query,
|
|
702
|
+
include_fields=include_fields,
|
|
703
|
+
exclude_fields=exclude_fields,
|
|
704
|
+
)
|
|
669
705
|
)
|
|
670
706
|
search_result = bug_search_model(bug_type).model_validate(response)
|
|
671
707
|
if search_result.faults:
|
|
@@ -689,15 +725,20 @@ class Bugzilla:
|
|
|
689
725
|
self,
|
|
690
726
|
query: QueryParams,
|
|
691
727
|
include_fields: Optional[list[str]] = None,
|
|
728
|
+
exclude_fields: Optional[list[str]] = None,
|
|
692
729
|
page_size: int = 100,
|
|
693
730
|
) -> list[Bug]:
|
|
694
|
-
return self._search(Bug, query, include_fields, page_size)
|
|
731
|
+
return self._search(Bug, query, include_fields, exclude_fields, page_size)
|
|
695
732
|
|
|
696
733
|
def search_as(
|
|
697
|
-
self,
|
|
734
|
+
self,
|
|
735
|
+
query: QueryParams,
|
|
736
|
+
bug_type: type[BugType],
|
|
737
|
+
exclude_fields: Optional[list[str]] = None,
|
|
738
|
+
page_size: int = 100,
|
|
698
739
|
) -> list[BugType]:
|
|
699
740
|
include_fields = model_field_names(bug_type)
|
|
700
|
-
return self._search(bug_type, query, include_fields, page_size)
|
|
741
|
+
return self._search(bug_type, query, include_fields, exclude_fields, page_size)
|
|
701
742
|
|
|
702
743
|
def update_bugs(
|
|
703
744
|
self, update_params: BugUpdate, bug_id: Optional[int] = None
|
|
@@ -757,3 +798,16 @@ class Bugzilla:
|
|
|
757
798
|
return list(create_result.attachments.values())
|
|
758
799
|
|
|
759
800
|
return []
|
|
801
|
+
|
|
802
|
+
def add_comment(self, bug_id: int, comment: CommentCreate) -> Optional[int]:
|
|
803
|
+
"""Add a comment to a bug, returning the id of the new comment"""
|
|
804
|
+
path = f"bug/{bug_id}/comment"
|
|
805
|
+
|
|
806
|
+
json_body = comment.model_dump(exclude_none=True)
|
|
807
|
+
|
|
808
|
+
response = self.check_error(self.request("POST", path, json_body=json_body))
|
|
809
|
+
|
|
810
|
+
if self.config.allow_writes:
|
|
811
|
+
return CommentCreateResponse.model_validate(response).id
|
|
812
|
+
|
|
813
|
+
return None
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
from pydantic import BaseModel, Field
|
|
3
5
|
|
|
@@ -45,6 +47,23 @@ def test_search_include_comments_and_attachments(bugzilla):
|
|
|
45
47
|
assert bug.id == expected_id
|
|
46
48
|
assert isinstance(bug.comments, list)
|
|
47
49
|
assert isinstance(bug.attachments, list)
|
|
50
|
+
for item in bug.attachments:
|
|
51
|
+
assert "data" not in item
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_search_include_attachments_exclude_data(bugzilla):
|
|
55
|
+
bugs = [423488, 1749533]
|
|
56
|
+
result = bugzilla.search(
|
|
57
|
+
{"id": bugs},
|
|
58
|
+
include_fields=["id", "comments", "attachments"],
|
|
59
|
+
exclude_fields=["attachments.data"],
|
|
60
|
+
)
|
|
61
|
+
for expected_id, bug in zip(bugs, sorted(result, key=lambda x: x.id)):
|
|
62
|
+
assert bug.id == expected_id
|
|
63
|
+
assert isinstance(bug.comments, list)
|
|
64
|
+
assert isinstance(bug.attachments, list)
|
|
65
|
+
for item in bug.attachments:
|
|
66
|
+
assert "data" not in item
|
|
48
67
|
|
|
49
68
|
|
|
50
69
|
def test_bug_as(bugzilla):
|
|
@@ -93,3 +112,15 @@ def test_bug_as_validation_alias(bugzilla):
|
|
|
93
112
|
assert isinstance(result, BugData)
|
|
94
113
|
assert result.id == 975444
|
|
95
114
|
assert result.user_story is not None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_bug_as_exclude(bugzilla):
|
|
118
|
+
class BugData(BaseModel):
|
|
119
|
+
id: int
|
|
120
|
+
attachments: list[dict[str, Any]]
|
|
121
|
+
|
|
122
|
+
result = bugzilla.bug_as(975444, BugData, exclude_fields=["attachments.data"])
|
|
123
|
+
assert isinstance(result, BugData)
|
|
124
|
+
assert result.id == 975444
|
|
125
|
+
assert result.attachments
|
|
126
|
+
assert all("data" not in item for item in result.attachments)
|
|
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
|