Skip to content

Commit a3eafab

Browse files
authored
Merge pull request #1773 from python-gitlab/jlvillal/pagination
fix: handle situation where gitlab.com does not return values
2 parents 501f9a1 + cb824a4 commit a3eafab

File tree

5 files changed

+35
-23
lines changed

5 files changed

+35
-23
lines changed

docs/api-usage.rst

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,17 @@ The generator exposes extra listing information as received from the server:
265265
* ``prev_page``: if ``None`` the current page is the first one
266266
* ``next_page``: if ``None`` the current page is the last one
267267
* ``per_page``: number of items per page
268-
* ``total_pages``: total number of pages available
269-
* ``total``: total number of items in the list
268+
* ``total_pages``: total number of pages available. This may be a ``None`` value.
269+
* ``total``: total number of items in the list. This may be a ``None`` value.
270+
271+
.. note::
272+
273+
For performance reasons, if a query returns more than 10,000 records, GitLab
274+
does not return the ``total_pages`` or ``total`` headers. In this case,
275+
``total_pages`` and ``total`` will have a value of ``None``.
276+
277+
For more information see:
278+
https://docs.gitlab.com/ee/user/gitlab_com/index.html#pagination-response-headers
270279

271280
Sudo
272281
====

gitlab/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,12 +288,12 @@ def per_page(self) -> int:
288288
return self._list.per_page
289289

290290
@property
291-
def total_pages(self) -> int:
291+
def total_pages(self) -> Optional[int]:
292292
"""The total number of pages."""
293293
return self._list.total_pages
294294

295295
@property
296-
def total(self) -> int:
296+
def total(self) -> Optional[int]:
297297
"""The total number of items."""
298298
return self._list.total
299299

gitlab/client.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -917,14 +917,12 @@ def _query(
917917
self._next_url = next_url
918918
except KeyError:
919919
self._next_url = None
920-
self._current_page: Optional[Union[str, int]] = result.headers.get("X-Page")
921-
self._prev_page: Optional[Union[str, int]] = result.headers.get("X-Prev-Page")
922-
self._next_page: Optional[Union[str, int]] = result.headers.get("X-Next-Page")
923-
self._per_page: Optional[Union[str, int]] = result.headers.get("X-Per-Page")
924-
self._total_pages: Optional[Union[str, int]] = result.headers.get(
925-
"X-Total-Pages"
926-
)
927-
self._total: Optional[Union[str, int]] = result.headers.get("X-Total")
920+
self._current_page: Optional[str] = result.headers.get("X-Page")
921+
self._prev_page: Optional[str] = result.headers.get("X-Prev-Page")
922+
self._next_page: Optional[str] = result.headers.get("X-Next-Page")
923+
self._per_page: Optional[str] = result.headers.get("X-Per-Page")
924+
self._total_pages: Optional[str] = result.headers.get("X-Total-Pages")
925+
self._total: Optional[str] = result.headers.get("X-Total")
928926

929927
try:
930928
self._data: List[Dict[str, Any]] = result.json()
@@ -965,19 +963,22 @@ def per_page(self) -> int:
965963
assert self._per_page is not None
966964
return int(self._per_page)
967965

966+
# NOTE(jlvillal): When a query returns more than 10,000 items, GitLab doesn't return
967+
# the headers 'x-total-pages' and 'x-total'. In those cases we return None.
968+
# https://docs.gitlab.com/ee/user/gitlab_com/index.html#pagination-response-headers
968969
@property
969-
def total_pages(self) -> int:
970+
def total_pages(self) -> Optional[int]:
970971
"""The total number of pages."""
971-
if TYPE_CHECKING:
972-
assert self._total_pages is not None
973-
return int(self._total_pages)
972+
if self._total_pages is not None:
973+
return int(self._total_pages)
974+
return None
974975

975976
@property
976-
def total(self) -> int:
977+
def total(self) -> Optional[int]:
977978
"""The total number of items."""
978-
if TYPE_CHECKING:
979-
assert self._total is not None
980-
return int(self._total)
979+
if self._total is not None:
980+
return int(self._total)
981+
return None
981982

982983
def __iter__(self) -> "GitlabList":
983984
return self

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,6 @@ disable = [
8787
"useless-object-inheritance",
8888

8989
]
90+
91+
[tool.pytest.ini_options]
92+
xfail_strict = true

tests/unit/test_gitlab.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
# You should have received a copy of the GNU Lesser General Public License
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818

19+
import copy
1920
import pickle
2021
import warnings
21-
from copy import deepcopy
2222

2323
import pytest
2424
import responses
@@ -109,15 +109,14 @@ def _strip_pagination_headers(response):
109109
"""
110110
https://docs.gitlab.com/ee/user/gitlab_com/index.html#pagination-response-headers
111111
"""
112-
stripped = deepcopy(response)
112+
stripped = copy.deepcopy(response)
113113

114114
del stripped["headers"]["X-Total-Pages"]
115115
del stripped["headers"]["X-Total"]
116116

117117
return stripped
118118

119119

120-
@pytest.mark.xfail(reason="See #1686")
121120
@responses.activate
122121
def test_gitlab_build_list_missing_headers(gl, resp_page_1, resp_page_2):
123122
stripped_page_1 = _strip_pagination_headers(resp_page_1)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy