Skip to content

Tags

toggl_api.TagEndpoint

Bases: TogglCachedEndpoint[TogglTag]

Specific endpoints for retrieving and modifying tags.

Official Documentation

Examples:

>>> tag_endpoint = TagEndpoint(21341214, BasicAuth(...), JSONCache(Path("cache")))
>>> tag_endpoint.add("Eucalyptus")
TogglTag(213123132, "Eucalyptus")
>>> tag_endpoint.query(TogglQuery("name", "Eucalyptus"))
[TogglTag(213123132, "Eucalyptus")]
PARAMETER DESCRIPTION
workspace_id

The workspace the tags belong to.

TYPE: int | TogglWorkspace

auth

Authentication for the client.

TYPE: BasicAuth

cache

Cache object where tags are stored.

TYPE: TogglCache[TogglTag] | None DEFAULT: None

client

Optional client to be passed to be used for requests. Useful when a global client is used and needs to be recycled.

TYPE: Client | None DEFAULT: None

timeout

How long it takes for the client to timeout. Keyword Only. Defaults to 10 seconds.

TYPE: Timeout | int DEFAULT: 10

re_raise

Whether to raise all HTTPStatusError errors and not handle them internally. Keyword Only.

TYPE: bool DEFAULT: False

retries

Max retries to attempt if the server returns a 5xx status_code. Has no effect if re_raise is True. Keyword Only

TYPE: int DEFAULT: 3

METHOD DESCRIPTION
collect

Gather all tags.

add

Create a new tag.

edit

Set the name of the tag based on the tag object.

delete

Delete a tag based on its ID or model.

Source code in src/toggl_api/_tag.py
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
class TagEndpoint(TogglCachedEndpoint[TogglTag]):
    """Specific endpoints for retrieving and modifying tags.

    [Official Documentation](https://engineering.toggl.com/docs/api/tags)

    Examples:
        >>> tag_endpoint = TagEndpoint(21341214, BasicAuth(...), JSONCache(Path("cache")))
        >>> tag_endpoint.add("Eucalyptus")
        TogglTag(213123132, "Eucalyptus")

        >>> tag_endpoint.query(TogglQuery("name", "Eucalyptus"))
        [TogglTag(213123132, "Eucalyptus")]

    Params:
        workspace_id: The workspace the tags belong to.
        auth: Authentication for the client.
        cache: Cache object where tags are stored.
        client: Optional client to be passed to be used for requests. Useful
            when a global client is used and needs to be recycled.
        timeout: How long it takes for the client to timeout. Keyword Only.
            Defaults to 10 seconds.
        re_raise: Whether to raise all HTTPStatusError errors and not handle them
            internally. Keyword Only.
        retries: Max retries to attempt if the server returns a *5xx* status_code.
            Has no effect if re_raise is `True`. Keyword Only
    """

    MODEL = TogglTag

    def __init__(
        self,
        workspace_id: int | TogglWorkspace,
        auth: BasicAuth,
        cache: TogglCache[TogglTag] | None = None,
        *,
        client: Client | None = None,
        timeout: Timeout | int = 10,
        re_raise: bool = False,
        retries: int = 3,
    ) -> None:
        super().__init__(
            auth,
            cache,
            client=client,
            timeout=timeout,
            re_raise=re_raise,
            retries=retries,
        )
        self.workspace_id = workspace_id if isinstance(workspace_id, int) else workspace_id.id

    def get(
        self,
        tag: TogglTag | int,
        *,
        refresh: bool = False,
    ) -> TogglTag | None:
        """Get endpoint convenience method for querying single tags from cache.

        This endpoint doesn't exist on the API so it locally queries for tags
        instead.

        Examples:
            >>> toggl_endpoint.get(213123132)
            TogglTag(213123132, "Eucalyptus")

        Args:
            tag: Which tag to retrieve. Can be an existing model or its id.
            refresh: Whether to collect all tags from the API first.

        Raises:
            HTTPStatusError: If an error is raised and `re_raise` is True.

        Returns:
            A tag model if it was found otherwise None.
        """
        if self.cache is None:
            return None

        if refresh:
            try:
                self.collect(refresh=True)
            except HTTPStatusError:
                if self.re_raise:
                    raise
                log.exception("%s")

        if isinstance(tag, TogglTag):
            tag = tag.id

        query = self.query(TogglQuery("id", tag))
        if query:
            return query[0]

        return None

    def collect(self, *, refresh: bool = False) -> list[TogglTag]:
        """Gather all tags.

        [Official Documentation](https://engineering.toggl.com/docs/api/tags#get-tags)

        Raises:
            HTTPStatusError: If any issue happens with the Toggl API.

        Returns:
            A list of tags collected from the API or local cache.
        """
        return cast("list[TogglTag]", self.request(self.endpoint, refresh=refresh))

    def add(self, name: str) -> TogglTag:
        """Create a new tag.

        This endpoint always hit the external API in order to keep tags consistent.

        [Official Documentation](https://engineering.toggl.com/docs/api/tags#post-create-tag)

        Args:
            name: The name of the new tag.

        Raises:
            NamingError: IF the tag name is empty.
            HTTPStatusError: If a tag with the same name exists or any other
                none *ok* status code is returned.

        Returns:
            The newly created tag.
        """
        if not name:
            msg = "The tag name needs to be at least one character long."
            raise NamingError(msg)

        return cast(
            "TogglTag",
            self.request(
                self.endpoint,
                body={"name": name},
                method=RequestMethod.POST,
                refresh=True,
            ),
        )

    def edit(self, tag: TogglTag | int, name: str) -> TogglTag:
        """Set the name of the tag based on the tag object.

        This endpoint always hit the external API in order to keep tags consistent.

        [Official Documentation](https://engineering.toggl.com/docs/api/tags#put-update-tag)

        Examples:
            >>> tag = Tag(213123132, "Eucalyptus")
            >>> tag_endpoint.edit(tag)
            TogglTag(213123132, "Eucalyptus")

            >>> tag_endpoint.edit(213123132, "Eucalyptus")
            TogglTag(213123132, "Eucalyptus")

        Args:
            tag: TogglTag or integer as the id.
            name: New name for the tag.

        Raises:
            NamingError: If the name is not at the minimum length.
            HTTPStatusError: If any issue happens with the Toggl API.

        Returns:
            The edited tag.
        """
        if not name:
            msg = "The tag name needs to be at least one character long."
            raise NamingError(msg)

        return cast(
            "TogglTag",
            self.request(
                f"{self.endpoint}/{tag.id if isinstance(tag, TogglTag) else tag}",
                body={"name": name},
                method=RequestMethod.PUT,
                refresh=True,
            ),
        )

    def delete(self, tag: TogglTag | int) -> None:
        """Delete a tag based on its ID or model.

        This endpoint always hit the external API in order to keep tags consistent.

        [Official Documentation](https://engineering.toggl.com/docs/api/tags#delete-delete-tag)

        Args:
            tag: The tag to delete. Either the id or model.

        Raises:
            HTTPStatusError: For anything thats not an '2xx' or '404' code.
        """
        tag_id = tag if isinstance(tag, int) else tag.id
        try:
            self.request(
                f"{self.endpoint}/{tag_id}",
                method=RequestMethod.DELETE,
                refresh=True,
            )
        except HTTPStatusError as err:
            if self.re_raise or err.response.status_code != codes.NOT_FOUND:
                raise
            log.warning(
                "Tag with id %s was either already deleted or did not exist in the first place!",
                tag_id,
            )

        if self.cache is None:
            return

        if isinstance(tag, int):
            tag_model = self.cache.find({"id": tag})
            if not isinstance(tag_model, TogglTag):
                return
            tag = tag_model

        self.cache.delete(tag)
        self.cache.commit()

    @property
    def endpoint(self) -> str:
        return f"workspaces/{self.workspace_id}/tags"

collect

collect(*, refresh: bool = False) -> list[TogglTag]

Gather all tags.

Official Documentation

RAISES DESCRIPTION
HTTPStatusError

If any issue happens with the Toggl API.

RETURNS DESCRIPTION
list[TogglTag]

A list of tags collected from the API or local cache.

Source code in src/toggl_api/_tag.py
119
120
121
122
123
124
125
126
127
128
129
130
def collect(self, *, refresh: bool = False) -> list[TogglTag]:
    """Gather all tags.

    [Official Documentation](https://engineering.toggl.com/docs/api/tags#get-tags)

    Raises:
        HTTPStatusError: If any issue happens with the Toggl API.

    Returns:
        A list of tags collected from the API or local cache.
    """
    return cast("list[TogglTag]", self.request(self.endpoint, refresh=refresh))

add

add(name: str) -> TogglTag

Create a new tag.

This endpoint always hit the external API in order to keep tags consistent.

Official Documentation

PARAMETER DESCRIPTION
name

The name of the new tag.

TYPE: str

RAISES DESCRIPTION
NamingError

IF the tag name is empty.

HTTPStatusError

If a tag with the same name exists or any other none ok status code is returned.

RETURNS DESCRIPTION
TogglTag

The newly created tag.

Source code in src/toggl_api/_tag.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def add(self, name: str) -> TogglTag:
    """Create a new tag.

    This endpoint always hit the external API in order to keep tags consistent.

    [Official Documentation](https://engineering.toggl.com/docs/api/tags#post-create-tag)

    Args:
        name: The name of the new tag.

    Raises:
        NamingError: IF the tag name is empty.
        HTTPStatusError: If a tag with the same name exists or any other
            none *ok* status code is returned.

    Returns:
        The newly created tag.
    """
    if not name:
        msg = "The tag name needs to be at least one character long."
        raise NamingError(msg)

    return cast(
        "TogglTag",
        self.request(
            self.endpoint,
            body={"name": name},
            method=RequestMethod.POST,
            refresh=True,
        ),
    )

edit

edit(tag: TogglTag | int, name: str) -> TogglTag

Set the name of the tag based on the tag object.

This endpoint always hit the external API in order to keep tags consistent.

Official Documentation

Examples:

>>> tag = Tag(213123132, "Eucalyptus")
>>> tag_endpoint.edit(tag)
TogglTag(213123132, "Eucalyptus")
>>> tag_endpoint.edit(213123132, "Eucalyptus")
TogglTag(213123132, "Eucalyptus")
PARAMETER DESCRIPTION
tag

TogglTag or integer as the id.

TYPE: TogglTag | int

name

New name for the tag.

TYPE: str

RAISES DESCRIPTION
NamingError

If the name is not at the minimum length.

HTTPStatusError

If any issue happens with the Toggl API.

RETURNS DESCRIPTION
TogglTag

The edited tag.

Source code in src/toggl_api/_tag.py
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
def edit(self, tag: TogglTag | int, name: str) -> TogglTag:
    """Set the name of the tag based on the tag object.

    This endpoint always hit the external API in order to keep tags consistent.

    [Official Documentation](https://engineering.toggl.com/docs/api/tags#put-update-tag)

    Examples:
        >>> tag = Tag(213123132, "Eucalyptus")
        >>> tag_endpoint.edit(tag)
        TogglTag(213123132, "Eucalyptus")

        >>> tag_endpoint.edit(213123132, "Eucalyptus")
        TogglTag(213123132, "Eucalyptus")

    Args:
        tag: TogglTag or integer as the id.
        name: New name for the tag.

    Raises:
        NamingError: If the name is not at the minimum length.
        HTTPStatusError: If any issue happens with the Toggl API.

    Returns:
        The edited tag.
    """
    if not name:
        msg = "The tag name needs to be at least one character long."
        raise NamingError(msg)

    return cast(
        "TogglTag",
        self.request(
            f"{self.endpoint}/{tag.id if isinstance(tag, TogglTag) else tag}",
            body={"name": name},
            method=RequestMethod.PUT,
            refresh=True,
        ),
    )

delete

delete(tag: TogglTag | int) -> None

Delete a tag based on its ID or model.

This endpoint always hit the external API in order to keep tags consistent.

Official Documentation

PARAMETER DESCRIPTION
tag

The tag to delete. Either the id or model.

TYPE: TogglTag | int

RAISES DESCRIPTION
HTTPStatusError

For anything thats not an '2xx' or '404' code.

Source code in src/toggl_api/_tag.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
def delete(self, tag: TogglTag | int) -> None:
    """Delete a tag based on its ID or model.

    This endpoint always hit the external API in order to keep tags consistent.

    [Official Documentation](https://engineering.toggl.com/docs/api/tags#delete-delete-tag)

    Args:
        tag: The tag to delete. Either the id or model.

    Raises:
        HTTPStatusError: For anything thats not an '2xx' or '404' code.
    """
    tag_id = tag if isinstance(tag, int) else tag.id
    try:
        self.request(
            f"{self.endpoint}/{tag_id}",
            method=RequestMethod.DELETE,
            refresh=True,
        )
    except HTTPStatusError as err:
        if self.re_raise or err.response.status_code != codes.NOT_FOUND:
            raise
        log.warning(
            "Tag with id %s was either already deleted or did not exist in the first place!",
            tag_id,
        )

    if self.cache is None:
        return

    if isinstance(tag, int):
        tag_model = self.cache.find({"id": tag})
        if not isinstance(tag_model, TogglTag):
            return
        tag = tag_model

    self.cache.delete(tag)
    self.cache.commit()

toggl_api.asyncio.AsyncTagEndpoint

Bases: TogglAsyncCachedEndpoint[TogglTag]

Specific endpoints for retrieving and modifying tags.

Official Documentation

Examples:

>>> tag_endpoint = TagEndpoint(21341214, BasicAuth(...), AsyncSqliteCache(Path("cache")))
>>> await tag_endpoint.add("Eucalyptus")
TogglTag(213123132, "Eucalyptus")
>>> await tag_endpoint.get(213123132, refresh=True)
TogglTag(213123132, "Eucalyptus")
PARAMETER DESCRIPTION
workspace_id

The workspace the tags belong to.

TYPE: int | TogglWorkspace

auth

Authentication for the client.

TYPE: BasicAuth

cache

Cache object where tags are stored.

TYPE: AsyncSqliteCache[TogglTag] | None DEFAULT: None

client

Optional async client to be passed to be used for requests.

TYPE: AsyncClient | None DEFAULT: None

timeout

How long it takes for the client to timeout. Keyword Only. Defaults to 10 seconds.

TYPE: int DEFAULT: 10

re_raise

Whether to raise all HTTPStatusError errors and not handle them internally. Keyword Only.

TYPE: bool DEFAULT: False

retries

Max retries to attempt if the server returns a 5xx status_code. Has no effect if re_raise is True. Keyword Only

TYPE: int DEFAULT: 3

METHOD DESCRIPTION
get

Get endpoint convenience method for querying single tags from cache.

collect

Gather all tags.

add

Create a new tag.

edit

Rename an existing tag.

delete

Delete a tag based on its ID or model.

ATTRIBUTE DESCRIPTION
endpoint

Generic tag endpoint params with workspace id prefilled.

TYPE: str

endpoint property

endpoint: str

Generic tag endpoint params with workspace id prefilled.

get async

get(tag: TogglTag | int, *, refresh: bool = False) -> TogglTag | None

Get endpoint convenience method for querying single tags from cache.

This endpoint doesn't exist on the API so it locally queries for tags instead.

Examples:

>>> await toggl_endpoint.get(213123132)
TogglTag(213123132, "Eucalyptus")
PARAMETER DESCRIPTION
tag

Which tag to retrieve. Can be an existing model or its id.

TYPE: TogglTag | int

refresh

Whether to collect all tags from the API first.

TYPE: bool DEFAULT: False

RAISES DESCRIPTION
NoCacheAssignedError

If no cache has been assigned to the endpoint.

HTTPStatusError

If any error is raised and re_raise is True.

RETURNS DESCRIPTION
TogglTag | None

A tag model if it was found otherwise None.

collect async

collect(*, refresh: bool = False) -> list[TogglTag]

Gather all tags.

Official Documentation

RAISES DESCRIPTION
HTTPStatusError

If any issue happens with the Toggl API.

RETURNS DESCRIPTION
list[TogglTag]

A list of tags collected from the API or local cache.

add async

add(name: str) -> TogglTag

Create a new tag.

This endpoint always hit the external API in order to keep tags consistent.

Official Documentation

PARAMETER DESCRIPTION
name

The name of the new tag.

TYPE: str

RAISES DESCRIPTION
NamingError

IF the tag name is empty.

HTTPStatusError

If a tag with the same name exists or any other none ok status code is returned.

RETURNS DESCRIPTION
TogglTag

The newly created tag.

edit async

edit(tag: TogglTag | int, name: str) -> TogglTag

Rename an existing tag.

This endpoint always hit the external API in order to keep tags consistent.

Official Documentation

Examples:

>>> tag = Tag(213123132, "Eucalyptus")
>>> await tag_endpoint.edit(tag)
TogglTag(213123132, "Eucalyptus")
>>> await tag_endpoint.edit(213123132, "Eucalyptus")
TogglTag(213123132, "Eucalyptus")
PARAMETER DESCRIPTION
tag

TogglTag or integer as the id.

TYPE: TogglTag | int

name

New name for the tag.

TYPE: str

RAISES DESCRIPTION
NamingError

If the name is not at the minimum length.

HTTPStatusError

If any issue happens with the Toggl API.

RETURNS DESCRIPTION
TogglTag

The edited tag.

delete async

delete(tag: TogglTag | int) -> None

Delete a tag based on its ID or model.

This endpoint always hit the external API in order to keep tags consistent.

Official Documentation

PARAMETER DESCRIPTION
tag

The tag to delete. Either the id or model.

TYPE: TogglTag | int

RAISES DESCRIPTION
HTTPStatusError

For anything thats not an '2xx' or '404' code.