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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bugdantic
3
- Version: 0.4.4
3
+ Version: 0.5.1
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
@@ -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("GET", f"bug/{bug_id}", include_fields=include_fields)
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, bug_id: int, include_fields: Optional[list[str]] = None
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(self, bug_id: int, bug_type: type[BugType]) -> Optional[BugType]:
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("GET", "bug", params=query, include_fields=include_fields)
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, query: QueryParams, bug_type: type[BugType], page_size: int = 100
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bugdantic
3
- Version: 0.4.4
3
+ Version: 0.5.1
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
@@ -5,7 +5,7 @@ authors = [
5
5
  {name = "James Graham", email = "james@hoppipolla.co.uk"}
6
6
  ]
7
7
 
8
- version = "0.4.4"
8
+ version = "0.5.1"
9
9
  requires-python = ">=3.11"
10
10
  license = "MPL-2.0"
11
11
  classifiers = [
@@ -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