Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit387e59f

Browse files
authored
Merge pull request#1702 from python-gitlab/jlvillal/attribute_help
chore: attempt to be more informative for missing attributes
2 parentse6582a3 +1839c9e commit387e59f

File tree

4 files changed

+71
-5
lines changed

4 files changed

+71
-5
lines changed

‎docs/faq.rst‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ I cannot edit the merge request / issue I've just retrieved
1616
See the:ref:`merge requests example<merge_requests_examples>` and the
1717
:ref:`issues examples<issues_examples>`.
1818

19+
.. _attribute_error_list:
20+
21+
I get an ``AttributeError`` when accessing attributes of an object retrieved via a ``list()`` call.
22+
Fetching a list of objects, doesn’t always include all attributes in the
23+
objects. To retrieve an object with all attributes use a ``get()`` call.
24+
25+
Example with projects::
26+
27+
for projects in gl.projects.list():
28+
# Retrieve project object with all attributes
29+
project = gl.projects.get(project.id)
30+
1931
How can I clone the repository of a project?
2032
python-gitlab doesn't provide an API to clone a project. You have to use a
2133
git library or call the ``git`` command.

‎gitlab/base.py‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

1818
importimportlib
19+
importtextwrap
1920
fromtypesimportModuleType
2021
fromtypingimportAny,Dict,Iterable,NamedTuple,Optional,Tuple,Type
2122

23+
importgitlab
2224
fromgitlabimporttypesasg_types
2325
fromgitlab.exceptionsimportGitlabParsingError
2426

@@ -32,6 +34,12 @@
3234
]
3335

3436

37+
_URL_ATTRIBUTE_ERROR= (
38+
f"https://python-gitlab.readthedocs.io/en/{gitlab.__version__}/"
39+
f"faq.html#attribute-error-list"
40+
)
41+
42+
3543
classRESTObject(object):
3644
"""Represents an object built from server data.
3745
@@ -45,13 +53,20 @@ class RESTObject(object):
4553

4654
_id_attr:Optional[str]="id"
4755
_attrs:Dict[str,Any]
56+
_created_from_list:bool# Indicates if object was created from a list() action
4857
_module:ModuleType
4958
_parent_attrs:Dict[str,Any]
5059
_short_print_attr:Optional[str]=None
5160
_updated_attrs:Dict[str,Any]
5261
manager:"RESTManager"
5362

54-
def__init__(self,manager:"RESTManager",attrs:Dict[str,Any])->None:
63+
def__init__(
64+
self,
65+
manager:"RESTManager",
66+
attrs:Dict[str,Any],
67+
*,
68+
created_from_list:bool=False,
69+
)->None:
5570
ifnotisinstance(attrs,dict):
5671
raiseGitlabParsingError(
5772
"Attempted to initialize RESTObject with a non-dictionary value: "
@@ -64,6 +79,7 @@ def __init__(self, manager: "RESTManager", attrs: Dict[str, Any]) -> None:
6479
"_attrs":attrs,
6580
"_updated_attrs": {},
6681
"_module":importlib.import_module(self.__module__),
82+
"_created_from_list":created_from_list,
6783
}
6884
)
6985
self.__dict__["_parent_attrs"]=self.manager.parent_attrs
@@ -106,8 +122,22 @@ def __getattr__(self, name: str) -> Any:
106122
exceptKeyError:
107123
try:
108124
returnself.__dict__["_parent_attrs"][name]
109-
exceptKeyError:
110-
raiseAttributeError(name)
125+
exceptKeyErrorasexc:
126+
message= (
127+
f"{type(self).__name__!r} object has no attribute{name!r}"
128+
)
129+
ifself._created_from_list:
130+
message= (
131+
f"{message}\n\n"
132+
+textwrap.fill(
133+
f"{self.__class__!r} was created via a list() call and "
134+
f"only a subset of the data may be present. To ensure "
135+
f"all data is present get the object using a "
136+
f"get(object.id) call. For more details, see:"
137+
)
138+
+f"\n\n{_URL_ATTRIBUTE_ERROR}"
139+
)
140+
raiseAttributeError(message)fromexc
111141

112142
def__setattr__(self,name:str,value:Any)->None:
113143
self.__dict__["_updated_attrs"][name]=value
@@ -229,7 +259,7 @@ def __next__(self) -> RESTObject:
229259

230260
defnext(self)->RESTObject:
231261
data=self._list.next()
232-
returnself._obj_cls(self.manager,data)
262+
returnself._obj_cls(self.manager,data,created_from_list=True)
233263

234264
@property
235265
defcurrent_page(self)->int:

‎gitlab/mixins.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def list(self, **kwargs: Any) -> Union[base.RESTObjectList, List[base.RESTObject
240240
assertself._obj_clsisnotNone
241241
obj=self.gitlab.http_list(path,**data)
242242
ifisinstance(obj,list):
243-
return [self._obj_cls(self,item)foriteminobj]
243+
return [self._obj_cls(self,item,created_from_list=True)foriteminobj]
244244
else:
245245
returnbase.RESTObjectList(self,self._obj_cls,obj)
246246

‎tests/unit/test_base.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,30 @@ def test_instantiate_non_dict(self, fake_gitlab, fake_manager):
9090
withpytest.raises(gitlab.exceptions.GitlabParsingError):
9191
FakeObject(fake_manager, ["a","list","fails"])
9292

93+
deftest_missing_attribute_does_not_raise_custom(self,fake_gitlab,fake_manager):
94+
"""Ensure a missing attribute does not raise our custom error message
95+
if the RESTObject was not created from a list"""
96+
obj=FakeObject(manager=fake_manager,attrs={"foo":"bar"})
97+
withpytest.raises(AttributeError)asexcinfo:
98+
obj.missing_attribute
99+
exc_str=str(excinfo.value)
100+
assert"missing_attribute"inexc_str
101+
assert"was created via a list()"notinexc_str
102+
assertbase._URL_ATTRIBUTE_ERRORnotinexc_str
103+
104+
deftest_missing_attribute_from_list_raises_custom(self,fake_gitlab,fake_manager):
105+
"""Ensure a missing attribute raises our custom error message if the
106+
RESTObject was created from a list"""
107+
obj=FakeObject(
108+
manager=fake_manager,attrs={"foo":"bar"},created_from_list=True
109+
)
110+
withpytest.raises(AttributeError)asexcinfo:
111+
obj.missing_attribute
112+
exc_str=str(excinfo.value)
113+
assert"missing_attribute"inexc_str
114+
assert"was created via a list()"inexc_str
115+
assertbase._URL_ATTRIBUTE_ERRORinexc_str
116+
93117
deftest_picklability(self,fake_manager):
94118
obj=FakeObject(fake_manager, {"foo":"bar"})
95119
original_obj_module=obj._module

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp