11from __future__ import annotations
22
3- from typing import TYPE_CHECKING , Optional
3+ from typing import TYPE_CHECKING , Optional , overload
44
55from typing_extensions import NotRequired , TypedDict , Unpack
66
@@ -266,42 +266,37 @@ def get(self, tag_id: str) -> Tag:
266266 response = self ._ctx .session .get (url )
267267 return Tag (self ._ctx , path , ** response .json ())
268268
269- class _NameParentAttrs (TypedDict , total = False ):
270- name : str
271- """
272- The name of the tag.
273-
274- Note: tag names are only unique within the scope of a parent, which
275- means that it is possible to have multiple results when querying by
276- name; however, querying by both `name` and `parent` ensures a single
277- result.
278- """
279- parent : NotRequired [str | Tag | None ]
280- """The identifier for the parent tag. If there is no parent, the tag is a top-level tag."""
281-
282269 def _update_parent_kwargs (self , kwargs : dict ) -> dict :
283270 parent = kwargs .get ("parent" , None )
284271 if parent is None :
272+ # No parent to upgrade, return the kwargs as is
285273 return kwargs
286274
275+ if not isinstance (parent , Tag ):
276+ raise TypeError (
277+ "`parent=` must be a Tag instance. If using a string, please use `parent_id=`"
278+ )
279+
280+ parent_id = kwargs .get ("parent_id" , None )
281+ if parent_id :
282+ raise ValueError ("Cannot provide both `parent=` and `parent_id=`" )
283+
287284 ret_kwargs = {** kwargs }
288285
289286 # Remove `parent` from ret_kwargs
290287 # and store the `parent_id` in the ret_kwargs below
291288 del ret_kwargs ["parent" ]
292289
293- if isinstance ( parent , Tag ):
294- parent : str = parent [ "id" ]
290+ ret_kwargs [ "parent_id" ] = parent [ "id" ]
291+ return ret_kwargs
295292
296- if isinstance ( parent , str ):
297- if parent == "" :
298- raise ValueError ( " Tag `parent` cannot be an empty string" )
299- ret_kwargs [ "parent_id" ] = parent
300- return ret_kwargs
293+ # Allow for every combination of `name` and (` parent` or `parent_id`)
294+ @ overload
295+ def find ( self , / , * , name : str = ..., parent : Tag = ...) -> list [ Tag ]: ...
296+ @ overload
297+ def find ( self , / , * , name : str = ..., parent_id : str = ...) -> list [ Tag ]: ...
301298
302- raise TypeError ("`parent=` must be a string or Tag instance" )
303-
304- def find (self , / , ** kwargs : Unpack [Tags ._NameParentAttrs ]) -> list [Tag ]:
299+ def find (self , / , ** kwargs ) -> list [Tag ]:
305300 """
306301 Find tags by name and/or parent.
307302
@@ -313,7 +308,10 @@ def find(self, /, **kwargs: Unpack[Tags._NameParentAttrs]) -> list[Tag]:
313308 ----------
314309 name : str, optional
315310 The name of the tag.
316- parent : str, Tag, optional
311+ parent : Tag, optional
312+ The parent `Tag` object. If there is no parent, the tag is a top-level tag. Only one of
313+ `parent` or `parent_id` can be provided.
314+ parent_id : str, optional
317315 The identifier for the parent tag. If there is no parent, the tag is a top-level tag.
318316
319317 Returns
@@ -348,15 +346,25 @@ def find(self, /, **kwargs: Unpack[Tags._NameParentAttrs]) -> list[Tag]:
348346 results = response .json ()
349347 return [Tag (self ._ctx , f"{ self ._path } /{ result ['id' ]} " , ** result ) for result in results ]
350348
351- def create (self , / , ** kwargs : Unpack [Tags ._NameParentAttrs ]) -> Tag :
349+ @overload
350+ def create (self , / , * , name : str ) -> Tag : ...
351+ @overload
352+ def create (self , / , * , name : str , parent : Tag ) -> Tag : ...
353+ @overload
354+ def create (self , / , * , name : str , parent_id : str ) -> Tag : ...
355+
356+ def create (self , / , ** kwargs ) -> Tag :
352357 """
353358 Create a tag.
354359
355360 Parameters
356361 ----------
357362 name : str
358363 The name of the tag.
359- parent : str, Tag, optional
364+ parent : Tag, optional
365+ The parent `Tag` object. If there is no parent, the tag is a top-level tag. Only one of
366+ `parent` or `parent_id` can be provided.
367+ parent_id : str, optional
360368 The identifier for the parent tag. If there is no parent, the tag is a top-level tag.
361369
362370 Returns
@@ -456,8 +464,7 @@ def add(self, *tags: str | Tag) -> None:
456464
457465 url = self ._ctx .url + self ._path
458466 for tag_id in tag_ids :
459- _ = self ._ctx .session .post (url , json = {"tag_id" : tag_id })
460- return
467+ self ._ctx .session .post (url , json = {"tag_id" : tag_id })
461468
462469 def delete (self , * tags : str | Tag ) -> None :
463470 """
@@ -481,4 +488,3 @@ def delete(self, *tags: str | Tag) -> None:
481488 for tag_id in tag_ids :
482489 tag_url = f"{ url } /{ tag_id } "
483490 self ._ctx .session .delete (tag_url )
484- return
0 commit comments