bugdantic 0.4.3__tar.gz → 0.5.0__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.3
3
+ Version: 0.5.0
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
@@ -455,10 +455,19 @@ def bug_search_model(bug_type: type[BugType]) -> type[BugSearchGeneric[BugType]]
455
455
 
456
456
 
457
457
  def model_field_names(model: type[BaseModel]) -> list[str]:
458
- return [
459
- field.alias if field.alias else name
460
- for name, field in model.model_fields.items()
461
- ]
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
462
471
 
463
472
 
464
473
  class Bugzilla:
@@ -555,11 +564,17 @@ class Bugzilla:
555
564
  bug_id: int,
556
565
  bug_type: type[BugType],
557
566
  include_fields: Optional[list[str]] = None,
567
+ exclude_fields: Optional[list[str]] = None,
558
568
  ) -> Optional[BugType]:
559
569
  """Get a single bug specified by id"""
560
570
 
561
571
  data = self.check_error(
562
- self.request("GET", f"bug/{bug_id}", include_fields=include_fields)
572
+ self.request(
573
+ "GET",
574
+ f"bug/{bug_id}",
575
+ include_fields=include_fields,
576
+ exclude_fields=exclude_fields,
577
+ )
563
578
  )
564
579
  search_result = bug_search_model(bug_type).model_validate(data)
565
580
  if search_result.faults:
@@ -571,18 +586,27 @@ class Bugzilla:
571
586
  return bugs[0]
572
587
 
573
588
  def bug(
574
- self, bug_id: int, include_fields: Optional[list[str]] = None
589
+ self,
590
+ bug_id: int,
591
+ include_fields: Optional[list[str]] = None,
592
+ exclude_fields: Optional[list[str]] = None,
575
593
  ) -> Optional[Bug]:
576
- return self._bug(bug_id, Bug, include_fields)
594
+ return self._bug(bug_id, Bug, include_fields, exclude_fields)
577
595
 
578
- def bug_as(self, bug_id: int, bug_type: type[BugType]) -> Optional[BugType]:
596
+ def bug_as(
597
+ self,
598
+ bug_id: int,
599
+ bug_type: type[BugType],
600
+ exclude_fields: Optional[list[str]] = None,
601
+ ) -> Optional[BugType]:
579
602
  include_fields = model_field_names(bug_type)
580
- return self._bug(bug_id, bug_type, include_fields)
603
+ return self._bug(bug_id, bug_type, include_fields, exclude_fields)
581
604
 
582
605
  def bugs(
583
606
  self,
584
607
  bug_ids: Sequence[int],
585
608
  include_fields: Optional[list[str]] = None,
609
+ exclude_fields: Optional[list[str]] = None,
586
610
  page_size: int = 100,
587
611
  ) -> list[Bug]:
588
612
  """Get multiple bugs specified by id"""
@@ -594,6 +618,7 @@ class Bugzilla:
594
618
  self.search(
595
619
  {"id": ",".join(str(id) for id in bug_ids_chunk)},
596
620
  include_fields=include_fields,
621
+ exclude_fields=exclude_fields,
597
622
  )
598
623
  )
599
624
  return results
@@ -602,6 +627,7 @@ class Bugzilla:
602
627
  self,
603
628
  bug_ids: Sequence[int],
604
629
  bug_type: type[BugType],
630
+ exclude_fields: Optional[list[str]] = None,
605
631
  page_size: int = 100,
606
632
  ) -> list[BugType]:
607
633
  """Get multiple bugs specified by id"""
@@ -613,6 +639,7 @@ class Bugzilla:
613
639
  self.search_as(
614
640
  {"id": ",".join(str(id) for id in bug_ids_chunk)},
615
641
  bug_type,
642
+ exclude_fields,
616
643
  )
617
644
  )
618
645
  return results
@@ -641,6 +668,7 @@ class Bugzilla:
641
668
  bug_type: type[BugType],
642
669
  query: QueryParams,
643
670
  include_fields: Optional[list[str]] = None,
671
+ exclude_fields: Optional[list[str]] = None,
644
672
  page_size: int = 100,
645
673
  ) -> list[BugType]:
646
674
  """Search for bugs using the bugzilla query API"""
@@ -656,7 +684,13 @@ class Bugzilla:
656
684
  results: list[BugType] = []
657
685
  while True:
658
686
  response = self.check_error(
659
- self.request("GET", "bug", params=query, include_fields=include_fields)
687
+ self.request(
688
+ "GET",
689
+ "bug",
690
+ params=query,
691
+ include_fields=include_fields,
692
+ exclude_fields=exclude_fields,
693
+ )
660
694
  )
661
695
  search_result = bug_search_model(bug_type).model_validate(response)
662
696
  if search_result.faults:
@@ -680,15 +714,20 @@ class Bugzilla:
680
714
  self,
681
715
  query: QueryParams,
682
716
  include_fields: Optional[list[str]] = None,
717
+ exclude_fields: Optional[list[str]] = None,
683
718
  page_size: int = 100,
684
719
  ) -> list[Bug]:
685
- return self._search(Bug, query, include_fields, page_size)
720
+ return self._search(Bug, query, include_fields, exclude_fields, page_size)
686
721
 
687
722
  def search_as(
688
- self, query: QueryParams, bug_type: type[BugType], page_size: int = 100
723
+ self,
724
+ query: QueryParams,
725
+ bug_type: type[BugType],
726
+ exclude_fields: Optional[list[str]] = None,
727
+ page_size: int = 100,
689
728
  ) -> list[BugType]:
690
729
  include_fields = model_field_names(bug_type)
691
- return self._search(bug_type, query, include_fields, page_size)
730
+ return self._search(bug_type, query, include_fields, exclude_fields, page_size)
692
731
 
693
732
  def update_bugs(
694
733
  self, update_params: BugUpdate, bug_id: Optional[int] = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bugdantic
3
- Version: 0.4.3
3
+ Version: 0.5.0
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.3"
8
+ version = "0.5.0"
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):
@@ -80,3 +99,28 @@ def test_bug_as_alias(bugzilla):
80
99
  assert isinstance(result, BugData)
81
100
  assert result.id == 975444
82
101
  assert result.user_story is not None
102
+
103
+
104
+ def test_bug_as_validation_alias(bugzilla):
105
+ class BugData(BaseModel):
106
+ id: int
107
+ user_story: str = Field(
108
+ validation_alias="cf_user_story", alias="raw_user_story"
109
+ )
110
+
111
+ result = bugzilla.bug_as(975444, BugData)
112
+ assert isinstance(result, BugData)
113
+ assert result.id == 975444
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