Skip to content

Commit e5dff0f

Browse files
authored
Merge pull request #1 from evrone/feature/ERP-1353/report-time-entry-pagination
Added response meta to report entries list.
2 parents d49bff0 + 0d130ab commit e5dff0f

File tree

9 files changed

+153
-10
lines changed

9 files changed

+153
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,4 @@ ENV/
104104
# IDE settings
105105
.vscode/
106106
local_*.py
107+
.idea/

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "toggl_python"
3-
version = "0.2.5"
3+
version = "0.2.6"
44
description = "Python wraper for Toggl API."
55
authors = ["Ivlev Denis <[email protected]>"]
66
readme = "README.md"

tests/conftest.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
3+
from tests.fixtures import REPORT_TIME_ENTRIES_RESPONSE, TIME_ENTRIES_RESPONSE
4+
from toggl_python import ReportTimeEntries, TimeEntries
5+
6+
7+
@pytest.fixture
8+
def patch_report_time_entries(monkeypatch):
9+
class MockResponse:
10+
def __init__(self, *args, **kwargs):
11+
pass
12+
13+
@staticmethod
14+
def json():
15+
return REPORT_TIME_ENTRIES_RESPONSE
16+
17+
monkeypatch.setattr(ReportTimeEntries, "get", MockResponse, raising=False)
18+
19+
20+
@pytest.fixture
21+
def patch_time_entries(monkeypatch):
22+
class MockResponse:
23+
def __init__(self, *args, **kwargs):
24+
pass
25+
26+
@staticmethod
27+
def json():
28+
return TIME_ENTRIES_RESPONSE
29+
30+
monkeypatch.setattr(TimeEntries, "get", MockResponse, raising=False)

tests/fixtures.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
REPORT_TIME_ENTRIES_RESPONSE = {
2+
"total_grand": 0,
3+
"total_billable": None,
4+
"total_currencies": [{"currency": None, "amount": None}],
5+
"total_count": 1,
6+
"per_page": 50,
7+
"data": [
8+
{
9+
"id": 45675345,
10+
"pid": 44556545,
11+
"tid": None,
12+
"uid": 123456,
13+
"description": "",
14+
"start": "2020-08-24T15:43:11+03:00",
15+
"end": "2020-08-24T15:43:19+03:00",
16+
"updated": "2020-08-24T15:43:19+03:00",
17+
"dur": 8000,
18+
"user": "Test User",
19+
"use_stop": True,
20+
"client": "test-client",
21+
"project": "test project",
22+
"project_color": "0",
23+
"project_hex_color": "#990099",
24+
"task": None,
25+
"billable": None,
26+
"is_billable": False,
27+
"cur": None,
28+
"tags": [],
29+
}
30+
],
31+
}
32+
33+
TIME_ENTRIES_RESPONSE = [
34+
{
35+
"id": 45675345,
36+
"guid": "3ab9166aac16cbf1374edda1cb652f69",
37+
"wid": 4581172,
38+
"pid": 44556545,
39+
"billable": False,
40+
"start": "2020-08-24T12:43:11+00:00",
41+
"stop": "2020-08-24T12:43:19+00:00",
42+
"duration": 8,
43+
"duronly": False,
44+
"at": "2020-08-24T12:43:19+00:00",
45+
"uid": 123456,
46+
},
47+
]

tests/test_repositories.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from toggl_python import (
2+
ReportTimeEntries,
3+
TokenAuth,
4+
ReportTimeEntry,
5+
TimeEntries,
6+
TimeEntry,
7+
)
8+
from tests.fixtures import REPORT_TIME_ENTRIES_RESPONSE, TIME_ENTRIES_RESPONSE
9+
10+
11+
def test_report_time_entries_pagination(patch_report_time_entries):
12+
auth = TokenAuth("token")
13+
report_time_entries = ReportTimeEntries(auth=auth).list()
14+
total_count = REPORT_TIME_ENTRIES_RESPONSE["total_count"]
15+
per_page = REPORT_TIME_ENTRIES_RESPONSE["per_page"]
16+
assert report_time_entries.total_count == total_count
17+
assert report_time_entries.per_page == per_page
18+
assert len(report_time_entries) == len(REPORT_TIME_ENTRIES_RESPONSE["data"])
19+
for report_time_entry in report_time_entries:
20+
assert isinstance(report_time_entry, ReportTimeEntry)
21+
22+
23+
def test_time_entries_no_pagination(patch_time_entries):
24+
auth = TokenAuth("token")
25+
time_entries = TimeEntries(auth=auth).list()
26+
assert not hasattr(time_entries, "total_count")
27+
assert not hasattr(time_entries, "per_page")
28+
assert len(time_entries) == len(TIME_ENTRIES_RESPONSE)
29+
for time_entry in time_entries:
30+
assert isinstance(time_entry, TimeEntry)

toggl_python/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.2.5"
1+
__version__ = "0.2.6"
22

33
from .auth import BasicAuth, TokenAuth # noqa: F401
44
from .entities import Dashboard # noqa: F401
@@ -10,6 +10,7 @@
1010
MostActiveUser,
1111
Project,
1212
ProjectUser,
13+
ReportTimeEntry,
1314
Tag,
1415
Task,
1516
TimeEntry,
@@ -23,6 +24,7 @@
2324
Dashboards,
2425
Groups,
2526
ProjectUsers,
27+
ReportTimeEntries,
2628
Tags,
2729
Tasks,
2830
TimeEntries,
@@ -46,6 +48,8 @@
4648
"Projects",
4749
"ProjectUser",
4850
"ProjectUsers",
51+
"ReportTimeEntry",
52+
"ReportTimeEntries",
4953
"Tag",
5054
"Tags",
5155
"Task",

toggl_python/exceptions.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1-
class BadRequest(Exception):
1+
class TogglException(Exception):
22
pass
33

44

5-
class Unauthorized(Exception):
5+
class BadRequest(TogglException):
66
pass
77

88

9-
class Forbidden(Exception):
9+
class Unauthorized(TogglException):
1010
pass
1111

1212

13-
class NotFound(Exception):
13+
class Forbidden(TogglException):
1414
pass
1515

1616

17-
class MethodNotAllowed(Exception):
17+
class NotFound(TogglException):
1818
pass
1919

2020

21-
class NotSupported(Exception):
21+
class MethodNotAllowed(TogglException):
22+
pass
23+
24+
25+
class NotSupported(TogglException):
2226
pass
2327

2428

toggl_python/repository.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
ReportTimeEntry,
2020
)
2121
from .exceptions import MethodNotAllowed, NotSupported
22+
from .response import ReportTimeEntriesList
2223

2324

2425
class BaseRepository(Api):
@@ -29,6 +30,7 @@ class BaseRepository(Api):
2930
EXCLUDED_METHODS = ()
3031
ADDITIONAL_PARAMS = {}
3132
DATA_CONTAINER = {}
33+
LIST_RESPONSE = None
3234

3335
def __init__(self, base_url=None, auth=None):
3436
super().__init__(base_url=base_url, auth=auth)
@@ -109,12 +111,17 @@ def _list(self, _url, entity_class, data_key: str = None, **kwargs):
109111
params.update(self.ADDITIONAL_PARAMS.get("list", {}))
110112

111113
response = self.get(_url, params=params)
112-
data = response.json()
114+
response_body = response.json()
115+
116+
data = response_body
113117
data_key = data_key or self.DATA_CONTAINER.get("list", None)
114118
if data_key:
115119
data = data[data_key]
116120
if data:
117-
return [entity_class(**entity) for entity in data]
121+
value = [entity_class(**entity) for entity in data]
122+
if self.LIST_RESPONSE:
123+
value = self.LIST_RESPONSE(value, response_body)
124+
return value
118125

119126
def list(self, **kwargs):
120127
if "list" in self.EXCLUDED_METHODS:
@@ -185,6 +192,7 @@ class ReportTimeEntries(BaseRepository):
185192
DATA_CONTAINER = {"list": "data"}
186193
LIST_URL = "details"
187194
ENTITY_CLASS = ReportTimeEntry
195+
LIST_RESPONSE = ReportTimeEntriesList
188196

189197

190198
class Users(BaseRepository):

toggl_python/response.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class ListResponse(list):
2+
response_parameters = ()
3+
4+
def __init__(self, value, response_body):
5+
super(ListResponse, self).__init__(value)
6+
7+
for parameter in self.response_parameters:
8+
if parameter in response_body:
9+
setattr(self, parameter, response_body[parameter])
10+
11+
12+
class ReportTimeEntriesList(ListResponse):
13+
response_parameters = (
14+
"total_count",
15+
"per_page",
16+
"total_grand",
17+
"total_billable",
18+
"total_currencies",
19+
)

0 commit comments

Comments
 (0)