bugdantic 0.5.0__tar.gz → 0.5.2__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.5.0 → bugdantic-0.5.2}/PKG-INFO +4 -4
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic/bugzilla.py +98 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic.egg-info/PKG-INFO +4 -4
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic.egg-info/requires.txt +3 -3
- {bugdantic-0.5.0 → bugdantic-0.5.2}/pyproject.toml +4 -4
- {bugdantic-0.5.0 → bugdantic-0.5.2}/test/test_bugzilla.py +18 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/LICENSE +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/README.md +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic/__init__.py +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic/py.typed +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic/userstory.py +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic.egg-info/SOURCES.txt +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic.egg-info/dependency_links.txt +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/bugdantic.egg-info/top_level.txt +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/setup.cfg +0 -0
- {bugdantic-0.5.0 → bugdantic-0.5.2}/test/test_userstory.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bugdantic
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Bugzilla client based on pydantic
|
|
5
5
|
Author-email: James Graham <james@hoppipolla.co.uk>
|
|
6
6
|
License-Expression: MPL-2.0
|
|
@@ -11,9 +11,9 @@ License-File: LICENSE
|
|
|
11
11
|
Requires-Dist: httpx[http2]>=0.28.1
|
|
12
12
|
Requires-Dist: pydantic>=2.11.3
|
|
13
13
|
Provides-Extra: test
|
|
14
|
-
Requires-Dist: mypy==2.3.
|
|
15
|
-
Requires-Dist: ruff==0.16.
|
|
14
|
+
Requires-Dist: mypy==2.3.1; extra == "test"
|
|
15
|
+
Requires-Dist: ruff==0.16.6; extra == "test"
|
|
16
16
|
Requires-Dist: pytest==9.1.1; extra == "test"
|
|
17
17
|
Requires-Dist: pytest-ruff==0.5; extra == "test"
|
|
18
|
-
Requires-Dist: ty==0.0.
|
|
18
|
+
Requires-Dist: ty==0.0.78; extra == "test"
|
|
19
19
|
Dynamic: license-file
|
|
@@ -97,6 +97,7 @@ class BugComment(BaseModel):
|
|
|
97
97
|
is_private: Optional[bool] = None
|
|
98
98
|
is_markdown: Optional[bool] = None
|
|
99
99
|
tags: Optional[list[str]] = None
|
|
100
|
+
reactions: Optional[dict[str, int]] = None
|
|
100
101
|
|
|
101
102
|
model_config = ConfigDict(extra="allow")
|
|
102
103
|
|
|
@@ -422,6 +423,33 @@ class AttachmentsCreateResponse(BaseModel):
|
|
|
422
423
|
attachments: Mapping[str, AttachmentCreateResponse]
|
|
423
424
|
|
|
424
425
|
|
|
426
|
+
class CommentCreate(BaseModel):
|
|
427
|
+
comment: str
|
|
428
|
+
is_private: Optional[bool] = None
|
|
429
|
+
is_markdown: Optional[bool] = None
|
|
430
|
+
work_time: Optional[float] = None
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class CommentCreateResponse(BaseModel):
|
|
434
|
+
id: int
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
CommentType = TypeVar("CommentType", bound=BaseModel)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
class CommentsResponseGeneric(BaseModel, Generic[CommentType]):
|
|
441
|
+
comments: Mapping[str, CommentType]
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def comments_response_model(
|
|
445
|
+
comment_type: type[CommentType],
|
|
446
|
+
) -> type[CommentsResponseGeneric[CommentType]]:
|
|
447
|
+
return cast(
|
|
448
|
+
type[CommentsResponseGeneric[CommentType]],
|
|
449
|
+
CommentsResponseGeneric.__class_getitem__(comment_type),
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
|
|
425
453
|
class ErrorResponse(BaseModel):
|
|
426
454
|
code: int
|
|
427
455
|
message: str
|
|
@@ -644,6 +672,63 @@ class Bugzilla:
|
|
|
644
672
|
)
|
|
645
673
|
return results
|
|
646
674
|
|
|
675
|
+
def _comments(
|
|
676
|
+
self,
|
|
677
|
+
comment_ids: Sequence[int],
|
|
678
|
+
comment_type: type[CommentType],
|
|
679
|
+
include_fields: Optional[list[str]] = None,
|
|
680
|
+
exclude_fields: Optional[list[str]] = None,
|
|
681
|
+
page_size: int = 100,
|
|
682
|
+
) -> list[CommentType]:
|
|
683
|
+
"""Get comments specified by their ids.
|
|
684
|
+
|
|
685
|
+
The API accepts a list of comment ids with a single id in the path,
|
|
686
|
+
and the remainder are passed as repeated comment_ids parameters."""
|
|
687
|
+
results: list[CommentType] = []
|
|
688
|
+
for comment_ids_chunk in [
|
|
689
|
+
comment_ids[n : n + page_size]
|
|
690
|
+
for n in range(0, len(comment_ids), page_size)
|
|
691
|
+
]:
|
|
692
|
+
response = self.check_error(
|
|
693
|
+
self.request(
|
|
694
|
+
"GET",
|
|
695
|
+
f"bug/comment/{comment_ids_chunk[0]}",
|
|
696
|
+
include_fields=include_fields,
|
|
697
|
+
exclude_fields=exclude_fields,
|
|
698
|
+
params={
|
|
699
|
+
"comment_ids": [str(item) for item in comment_ids_chunk[1:]]
|
|
700
|
+
},
|
|
701
|
+
)
|
|
702
|
+
)
|
|
703
|
+
result = comments_response_model(comment_type).model_validate(response)
|
|
704
|
+
results.extend(result.comments.values())
|
|
705
|
+
return results
|
|
706
|
+
|
|
707
|
+
def comments(
|
|
708
|
+
self,
|
|
709
|
+
comment_ids: Sequence[int],
|
|
710
|
+
include_fields: Optional[list[str]] = None,
|
|
711
|
+
exclude_fields: Optional[list[str]] = None,
|
|
712
|
+
page_size: int = 100,
|
|
713
|
+
) -> list[BugComment]:
|
|
714
|
+
"""Get comments specified by their ids"""
|
|
715
|
+
return self._comments(
|
|
716
|
+
comment_ids, BugComment, include_fields, exclude_fields, page_size
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
def comments_as(
|
|
720
|
+
self,
|
|
721
|
+
comment_ids: Sequence[int],
|
|
722
|
+
comment_type: type[CommentType],
|
|
723
|
+
exclude_fields: Optional[list[str]] = None,
|
|
724
|
+
page_size: int = 100,
|
|
725
|
+
) -> list[CommentType]:
|
|
726
|
+
"""Get comments specified by their ids"""
|
|
727
|
+
include_fields = model_field_names(comment_type)
|
|
728
|
+
return self._comments(
|
|
729
|
+
comment_ids, comment_type, include_fields, exclude_fields, page_size
|
|
730
|
+
)
|
|
731
|
+
|
|
647
732
|
def bug_history(
|
|
648
733
|
self, bug_id: int, new_since: Optional[datetime] = None
|
|
649
734
|
) -> BugHistory:
|
|
@@ -787,3 +872,16 @@ class Bugzilla:
|
|
|
787
872
|
return list(create_result.attachments.values())
|
|
788
873
|
|
|
789
874
|
return []
|
|
875
|
+
|
|
876
|
+
def add_comment(self, bug_id: int, comment: CommentCreate) -> Optional[int]:
|
|
877
|
+
"""Add a comment to a bug, returning the id of the new comment"""
|
|
878
|
+
path = f"bug/{bug_id}/comment"
|
|
879
|
+
|
|
880
|
+
json_body = comment.model_dump(exclude_none=True)
|
|
881
|
+
|
|
882
|
+
response = self.check_error(self.request("POST", path, json_body=json_body))
|
|
883
|
+
|
|
884
|
+
if self.config.allow_writes:
|
|
885
|
+
return CommentCreateResponse.model_validate(response).id
|
|
886
|
+
|
|
887
|
+
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bugdantic
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Bugzilla client based on pydantic
|
|
5
5
|
Author-email: James Graham <james@hoppipolla.co.uk>
|
|
6
6
|
License-Expression: MPL-2.0
|
|
@@ -11,9 +11,9 @@ License-File: LICENSE
|
|
|
11
11
|
Requires-Dist: httpx[http2]>=0.28.1
|
|
12
12
|
Requires-Dist: pydantic>=2.11.3
|
|
13
13
|
Provides-Extra: test
|
|
14
|
-
Requires-Dist: mypy==2.3.
|
|
15
|
-
Requires-Dist: ruff==0.16.
|
|
14
|
+
Requires-Dist: mypy==2.3.1; extra == "test"
|
|
15
|
+
Requires-Dist: ruff==0.16.6; extra == "test"
|
|
16
16
|
Requires-Dist: pytest==9.1.1; extra == "test"
|
|
17
17
|
Requires-Dist: pytest-ruff==0.5; extra == "test"
|
|
18
|
-
Requires-Dist: ty==0.0.
|
|
18
|
+
Requires-Dist: ty==0.0.78; extra == "test"
|
|
19
19
|
Dynamic: license-file
|
|
@@ -5,7 +5,7 @@ authors = [
|
|
|
5
5
|
{name = "James Graham", email = "james@hoppipolla.co.uk"}
|
|
6
6
|
]
|
|
7
7
|
|
|
8
|
-
version = "0.5.
|
|
8
|
+
version = "0.5.2"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
license = "MPL-2.0"
|
|
11
11
|
classifiers = [
|
|
@@ -20,11 +20,11 @@ dependencies = [
|
|
|
20
20
|
|
|
21
21
|
[project.optional-dependencies]
|
|
22
22
|
test = [
|
|
23
|
-
"mypy==2.3.
|
|
24
|
-
"ruff==0.16.
|
|
23
|
+
"mypy==2.3.1",
|
|
24
|
+
"ruff==0.16.6",
|
|
25
25
|
"pytest==9.1.1",
|
|
26
26
|
"pytest-ruff==0.5",
|
|
27
|
-
"ty==0.0.
|
|
27
|
+
"ty==0.0.78",
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
[tool.mypy]
|
|
@@ -124,3 +124,21 @@ def test_bug_as_exclude(bugzilla):
|
|
|
124
124
|
assert result.id == 975444
|
|
125
125
|
assert result.attachments
|
|
126
126
|
assert all("data" not in item for item in result.attachments)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_comment(bugzilla):
|
|
130
|
+
result = bugzilla.comments([18109498, 18109500])
|
|
131
|
+
assert all(isinstance(item, BugComment) for item in result)
|
|
132
|
+
assert len(result) == 2
|
|
133
|
+
assert {item.id for item in result} == {18109498, 18109500}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_comment_as(bugzilla):
|
|
137
|
+
class CommentReactions(BaseModel):
|
|
138
|
+
id: int
|
|
139
|
+
reactions: dict[str, int]
|
|
140
|
+
|
|
141
|
+
result = bugzilla.comments_as([18109498, 18109500], CommentReactions)
|
|
142
|
+
assert all(isinstance(item, CommentReactions) for item in result)
|
|
143
|
+
assert {item.id for item in result} == {18109498, 18109500}
|
|
144
|
+
assert all(isinstance(item.reactions, dict) for item in result)
|
|
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
|