Skip to content

LN Classes

pymoe.ln.get

artist(item_id)

Default get artist method from WLNUpdates

Source code in pymoe\ln\get\__init__.py
def artist(item_id: int):
    """
    Default get artist method from WLNUpdates
    """
    return wlnupdates.artist(item_id)

author(item_id)

Default get author method from WLNUpdates

Source code in pymoe\ln\get\__init__.py
def author(item_id: int):
    """
    Default get author method from WLNUpdates
    """
    return wlnupdates.author(item_id)

genre(item_id)

Default get genre method from WLNUpdates. NOTICE: This will return all items with that genre.

Source code in pymoe\ln\get\__init__.py
def genre(item_id: int):
    """
    Default get genre method from WLNUpdates.
    NOTICE: This will return all items with that genre.
    """
    return wlnupdates.genre(item_id)

group(item_id)

Default get group method from WLNUpdates

Source code in pymoe\ln\get\__init__.py
def group(item_id: int):
    """
    Default get group method from WLNUpdates
    """
    return wlnupdates.group(item_id)

publisher(item_id)

Default get publisher method from WLNUpdates

Source code in pymoe\ln\get\__init__.py
def publisher(item_id: int):
    """
    Default get publisher method from WLNUpdates
    """
    return wlnupdates.publisher(item_id)

series(item_id)

Default get series method from WLNUpdates

Source code in pymoe\ln\get\__init__.py
def series(item_id: int):
    """
    Default get series method from WLNUpdates
    """
    return wlnupdates.series(item_id)

tag(item_id)

Default get tag method from WLNUpdates. NOTICE: This will return all items with that tag.

Source code in pymoe\ln\get\__init__.py
def tag(item_id: int):
    """
    Default get tag method from WLNUpdates.
    NOTICE: This will return all items with that tag.
    """
    return wlnupdates.tag(item_id)

pymoe.ln.get.bakatsuki

settings = {'apiurl': 'https://www.baka-tsuki.org/project/api.php', 'header': {'User-Agent': 'Pymoe (github.com/ccubed/Pymoe)'}, 'active': 56132, 'compiledRegex': {'chapter': re.compile('volume|chapter', re.I), 'separate': re.compile('(volume|chapter) (?P<chapter>[0-9]{1,2})', re.I)}} module-attribute

active()

Get a list of active projects.

RETURNS DESCRIPTION

A list of tuples containing a title and pageid in that order.

Source code in pymoe\ln\get\bakatsuki.py
def active():
    """
    Get a list of active projects.

    :return list: A list of tuples containing a title and pageid in that order.
    """
    projects = []

    r = requests.get(
        settings["apiurl"],
        params={
            "action": "query",
            "list": "categorymembers",
            "cmpageid": settings["active"],
            "cmtype": "page",
            "cmlimit": "500",
            "format": "json",
        },
        headers=settings["header"],
    )

    if r.status_code == 200:
        jsd = ujson.loads(r.text)
        projects.append(
            [(x["title"], x["pageid"]) for x in jsd["query"]["categorymembers"]]
        )

        if "query-continue" in jsd:
            while True:
                r = requests.get(
                    settings["apiurl"],
                    params={
                        "action": "query",
                        "list": "categorymembers",
                        "cmpageid": settings["active"],
                        "cmtype": "page",
                        "cmlimit": "500",
                        "cmcontinue": jsd["query-continue"]["categorymembers"][
                            "cmcontinue"
                        ],
                        "format": "json",
                    },
                    headers=settings["header"],
                )

                if r.status_code == 200:

                    jsd = ujson.loads(r.text)
                    projects.append(
                        [
                            (x["title"], x["pageid"])
                            for x in jsd["query"]["categorymembers"]
                        ]
                    )

                    if "query-continue" not in jsd:
                        break

                else:
                    break

    return projects[0]

chapters(title)

Get a list of chapters for a visual novel. Keep in mind, this can be slow. I've certainly tried to make it as fast as possible, but it's still pulling text out of a webpage.

PARAMETER DESCRIPTION
title

The title of the novel you want chapters from

TYPE: str

RETURNS DESCRIPTION

An OrderedDict which contains the chapters found for the visual novel supplied

Source code in pymoe\ln\get\bakatsuki.py
def chapters(title: str):
    """
    Get a list of chapters for a visual novel. Keep in mind, this can be slow. I've certainly tried to make it as fast as possible, but it's still pulling text out of a webpage.

    :param str title: The title of the novel you want chapters from
    :return OrderedDict: An OrderedDict which contains the chapters found for the visual novel supplied
    """
    r = requests.get(
        "https://www.baka-tsuki.org/project/index.php?title={}".format(
            title.replace(" ", "_")
        ),
        headers=settings["header"],
    )

    if r.status_code != 200:
        raise serverError(r.text, r.status_code)
    else:
        parsed = soup(r.text, "html.parser")
        dd = parsed.find_all("a")

        volumes = []
        for link in dd:
            if "class" in link.attrs:
                if "image" in link.get("class"):
                    continue

            if "href" in link.attrs:
                if re.search(
                    settings["compiledRegex"]["chapter"], link.get("href")
                ) is not None and not link.get("href").startswith("#"):
                    volumes.append(link)

        seplist = OrderedDict()
        for item in volumes:
            if "title" in item.attrs:
                result = re.search(
                    settings["compiledRegex"]["separate"], item.get("title").lower()
                )
            else:
                result = re.search(
                    settings["compiledRegex"]["separate"], item.text.lower()
                )

            if result and result.groups():
                if result.group("chapter").lstrip("0") in seplist:
                    seplist[result.group("chapter").lstrip("0")].append(
                        [
                            item.get("href"),
                            item.get("title") if "title" in item.attrs else item.text,
                        ]
                    )
                else:
                    seplist[result.group("chapter").lstrip("0")] = [
                        [
                            item.get("href"),
                            item.get("title") if "title" in item.attrs else item.text,
                        ]
                    ]

        return seplist

cover(pageid)

Get a cover image given a page id.

PARAMETER DESCRIPTION
pageid

The pageid for the light novel you want a cover image for

TYPE: str

RETURNS DESCRIPTION

the image url or None

Source code in pymoe\ln\get\bakatsuki.py
def cover(pageid: str):
    """
    Get a cover image given a page id.

    :param str pageid: The pageid for the light novel you want a cover image for
    :return str: the image url or None
    """
    r = requests.get(
        settings["apiurl"],
        params={
            "action": "query",
            "prop": "pageimages",
            "pageids": pageid,
            "format": "json",
        },
        headers=settings["header"],
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        # pageid can be returned as an int
        if "pageimage" in jsd["query"]["pages"][str(pageid)]:
            image = "File:" + jsd["query"]["pages"][str(pageid)]["pageimage"]
            r = requests.get(
                settings["apiurl"],
                params={
                    "action": "query",
                    "prop": "imageinfo",
                    "iiprop": "url",
                    "titles": image,
                    "format": "json",
                },
                headers=settings["header"],
            )

            try:
                jsd = ujson.loads(r.text)
            except ValueError:
                return None
            else:
                return jsd["query"]["pages"][list(jsd["query"]["pages"].keys())[0]][
                    "imageinfo"
                ][0]["url"]
        else:
            return None

pymoe.ln.get.wlnupdates

settings = {'apiurl': 'https://www.wlnupdates.com/api', 'header': {'User-Agent': 'Pymoe (github.com/ccubed/Pymoe)', 'Content-Type': 'application/json', 'Accept': 'application/json'}} module-attribute

artist(item_id)

Given an item_id, get information about the artist with that item_id.

PARAMETER DESCRIPTION
item_id

The ID of the Artist we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def artist(item_id: int):
    """
    Given an item_id, get information about the artist with that item_id.

    :param item_id: The ID of the Artist we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-artist-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

author(item_id)

Given an item_id, get information about the author with that item_id.

PARAMETER DESCRIPTION
item_id

The ID of the Author we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def author(item_id: int):
    """
    Given an item_id, get information about the author with that item_id.

    :param item_id: The ID of the Author we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-author-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

genre(item_id)

Given an item_id, get information about the genre with that item_id. This actually returns all series with that genre along with the genre itself.

PARAMETER DESCRIPTION
item_id

The ID of the Genre we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def genre(item_id: int):
    """
    Given an item_id, get information about the genre with that item_id.
    This actually returns all series with that genre along with the genre itself.

    :param item_id: The ID of the Genre we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-genre-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

group(item_id)

Given an item_id, get information about the group with that item_id. This appears to be scanlators/translators.

PARAMETER DESCRIPTION
item_id

The ID of the Group we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def group(item_id: int):
    """
    Given an item_id, get information about the group with that item_id.
    This appears to be scanlators/translators.

    :param item_id: The ID of the Group we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-group-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

publisher(item_id)

Given an item_id, get information about the publisher with that item_id.

PARAMETER DESCRIPTION
item_id

The ID of the Publisher we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def publisher(item_id: int):
    """
    Given an item_id, get information about the publisher with that item_id.

    :param item_id: The ID of the Publisher we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-publisher-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

series(item_id)

Given an item_id, get information about the series with that item_id.

PARAMETER DESCRIPTION
item_id

The ID of the Series we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def series(item_id: int):
    """
    Given an item_id, get information about the series with that item_id.

    :param item_id: The ID of the Series we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-series-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

tag(item_id)

Given an item_id, get information about the tag with that item_id. This actually returns all series with that tag along with the tag itself.

PARAMETER DESCRIPTION
item_id

The ID of the Artist we want

TYPE: int

Source code in pymoe\ln\get\wlnupdates.py
def tag(item_id: int):
    """
    Given an item_id, get information about the tag with that item_id.
    This actually returns all series with that tag along with the tag itself.

    :param item_id: The ID of the Artist we want
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"id": item_id, "mode": "get-tag-id"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

pymoe.ln.search

series(title)

Return a title search for title against WLNUpdates

Source code in pymoe\ln\search\__init__.py
def series(title: str):
    """
    Return a title search for title against WLNUpdates
    """
    return wlnupdates.series(title)

pymoe.ln.search.bakatsuki

settings = {'apiurl': 'https://www.baka-tsuki.org/project/api.php', 'header': {'User-Agent': 'Pymoe (github.com/ccubed/Pymoe)'}} module-attribute

lightNovels(language='English')

Get a list of light novels under a certain language.

PARAMETER DESCRIPTION
language

Defaults to English. Replace with whatever language you want to query. You can check their site for the language attributes.

TYPE: str DEFAULT: 'English'

RETURNS DESCRIPTION

A list of tuples containing a title and pageid element in that order.

Source code in pymoe\ln\search\bakatsuki.py
def lightNovels(language: str = "English"):
    """
    Get a list of light novels under a certain language.

    :param str language: Defaults to English. Replace with whatever language you want to query. You can check their site for the language attributes.
    :return list: A list of tuples containing a title and pageid element in that order.
    """
    projects = []

    r = requests.get(
        settings["apiurl"],
        params={
            "action": "query",
            "list": "categorymembers",
            "cmtitle": "Category:Light_novel_({})".format(language.replace(" ", "_")),
            "cmtype": "page",
            "cmlimit": "500",
            "format": "json",
        },
    )

    if r.status_code != 200:
        raise serverError(r.text, r.status_code)
    else:
        try:
            jsd = ujson.loads(r.text)
        except ValueError:
            raise serializationFailed(r.text, r.status_code)
        else:
            projects.append(
                [(x["title"], x["pageid"]) for x in jsd["query"]["categorymembers"]]
            )

            if "query-continue" in jsd:
                while True:
                    r = requests.get(
                        settings["apiurl"],
                        params={
                            "action": "query",
                            "list": "categorymembers",
                            "cmtitle": "Category:Light_novel_({})".format(
                                language.replace(" ", "_")
                            ),
                            "cmtype": "page",
                            "cmlimit": "500",
                            "cmcontinue": jsd["query-continue"]["categorymembers"][
                                "cmcontinue"
                            ],
                            "format": "json",
                        },
                        headers=settings["header"],
                    )

                    if r.status_code != 200:
                        break
                    else:
                        try:
                            jsd = ujson.loads(r.text)
                        except ValueError:
                            break
                        else:
                            projects.append(
                                [
                                    (x["title"], x["pageid"])
                                    for x in jsd["query"]["categorymembers"]
                                ]
                            )
                            if "query-continue" not in jsd:
                                break

            return projects[0]

teasers(language='English')

Get a list of teaser projects under a certain language.

PARAMETER DESCRIPTION
language

Defaults to English. Replace with whatever language you want to query.

TYPE: str DEFAULT: 'English'

RETURNS DESCRIPTION

A list of tuples containing a title and pageid element in that order.

Source code in pymoe\ln\search\bakatsuki.py
def teasers(language: str = "English"):
    """
    Get a list of teaser projects under a certain language.

    :param str language: Defaults to English. Replace with whatever language you want to query.
    :return list: A list of tuples containing a title and pageid element in that order.
    """
    projects = []

    r = requests.get(
        settings["apiurl"],
        params={
            "action": "query",
            "list": "categorymembers",
            "cmtitle": "Category:Teaser_({})".format(language.replace(" ", "_")),
            "cmtype": "page",
            "cmlimit": "500",
            "format": "json",
        },
    )

    if r.status_code != 200:
        raise serverError(r.text, r.status_code)
    else:
        try:
            jsd = ujson.loads(r.text)
        except ValueError:
            raise serializationFailed(r.text, r.status_code)
        else:
            projects.append(
                [(x["title"], x["pageid"]) for x in jsd["query"]["categorymembers"]]
            )

            if "query-continue" in jsd:
                while True:
                    r = requests.get(
                        settings["apiurl"],
                        params={
                            "action": "query",
                            "list": "categorymembers",
                            "cmtitle": "Category:Teaser_({})".format(
                                language.replace(" ", "_")
                            ),
                            "cmtype": "page",
                            "cmlimit": "500",
                            "cmcontinue": jsd["query-continue"]["categorymembers"][
                                "cmcontinue"
                            ],
                            "format": "json",
                        },
                        headers=settings["header"],
                    )

                    if r.status_code != 200:
                        break
                    else:
                        try:
                            jsd = ujson.loads(r.text)
                        except ValueError:
                            break
                        else:
                            projects.append(
                                [
                                    (x["title"], x["pageid"])
                                    for x in jsd["query"]["categorymembers"]
                                ]
                            )
                            if "query-continue" not in jsd:
                                break

            return projects[0]

webNovels(language='English')

Get a list of web novels under a certain language.

PARAMETER DESCRIPTION
language

Defaults to English. Replace with whatever language you want to query.

TYPE: str DEFAULT: 'English'

RETURNS DESCRIPTION

A list of tuples containing a title and pageid element in that order.

Source code in pymoe\ln\search\bakatsuki.py
def webNovels(language: str = "English"):
    """
    Get a list of web novels under a certain language.

    :param str language: Defaults to English. Replace with whatever language you want to query.
    :return list: A list of tuples containing a title and pageid element in that order.
    """
    projects = []

    r = requests.get(
        settings["apiurl"],
        params={
            "action": "query",
            "list": "categorymembers",
            "cmtitle": "Category:Web_novel_({})".format(language.replace(" ", "_")),
            "cmtype": "page",
            "cmlimit": "500",
            "format": "json",
        },
    )

    if r.status_code != 200:
        raise serverError(r.text, r.status_code)
    else:
        try:
            jsd = ujson.loads(r.text)
        except ValueError:
            raise serializationFailed(r.text, r.status_code)
        else:
            projects.append(
                [(x["title"], x["pageid"]) for x in jsd["query"]["categorymembers"]]
            )

            if "query-continue" in jsd:
                while True:
                    r = requests.get(
                        settings["apiurl"],
                        params={
                            "action": "query",
                            "list": "categorymembers",
                            "cmtitle": "Category:Web_novel_({})".format(
                                language.replace(" ", "_")
                            ),
                            "cmtype": "page",
                            "cmlimit": "500",
                            "cmcontinue": jsd["query-continue"]["categorymembers"][
                                "cmcontinue"
                            ],
                            "format": "json",
                        },
                        headers=settings["header"],
                    )

                    if r.status_code != 200:
                        break
                    else:
                        try:
                            jsd = ujson.loads(r.text)
                        except ValueError:
                            break
                        else:
                            projects.append(
                                [
                                    (x["title"], x["pageid"])
                                    for x in jsd["query"]["categorymembers"]
                                ]
                            )
                            if "query-continue" not in jsd:
                                break

            return projects[0]

pymoe.ln.search.wlnupdates

settings = {'apiurl': 'https://www.wlnupdates.com/api', 'header': {'User-Agent': 'Pymoe (github.com/ccubed/Pymoe)', 'Content-Type': 'application/json', 'Accept': 'application/json'}} module-attribute

genres()

This simply returns a list of all genres along with their IDs. These are the genres you can use in Parametric search. You can also use these in pymoe.ln.get.wlnupdates.genre

Source code in pymoe\ln\search\wlnupdates.py
def genres():
    """
    This simply returns a list of all genres along with their IDs.
    These are the genres you can use in Parametric search.
    You can also use these in pymoe.ln.get.wlnupdates.genre
    """
    r = requests.post(
        settings["apiurl"], headers=settings["header"], json={"mode": "enumerate-genres"}
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

parametric(title_search_text=None, tag_category=None, genre_category=None, chapter_limits=None, series_type=None, sort_mode='name', include_results=None)

Perform a Parametric search. This is the search-advanced route. You have to pass at least one of tags or genres. If you don't, this function will refer your search to title search. If you don't need to search by tags or genres, title search is a better option per the api documentation. The parameters have the same name as the API due to how the query is built.

PARAMETER DESCRIPTION
title-search-text

Optional title to search by

tags

A dictionary consisting of pairs of 'tag' keys and then 'included' or 'excluded'

genres

A dictionary consisting of pairs of 'genre' keys and then 'included' or 'excluded'

chapter_limit

A tuple consisting of (minimum,maximum) to limit by chapter count. Passing 0 disables the limit it was passed for.

series_type

A dictionary consisting of the keys 'Translated' and 'Original English Language' along with Included or Excluded as the value for each.

TYPE: Dict DEFAULT: None

sort_mode

One of update, chapter-count, or name. Defaults to name.

TYPE: str DEFAULT: 'name'

include_results

A list of strings to represent what additional information to return. Only accepts description, covers, tags, genres.

TYPE: Dict DEFAULT: None

Source code in pymoe\ln\search\wlnupdates.py
def parametric(
    title_search_text: str = None,
    tag_category=None,
    genre_category: Dict = None,
    chapter_limits: tuple = None,
    series_type: Dict = None,
    sort_mode: str = "name",
    include_results: Dict = None,
):
    """
    Perform a Parametric search. This is the search-advanced route.
    You have to pass at least one of tags or genres. If you don't, this function will refer your search to title search.
    If you don't need to search by tags or genres, title search is a better option per the api documentation.
    The parameters have the same name as the API due to how the query is built.

    :param title-search-text: Optional title to search by
    :param tags: A dictionary consisting of pairs of 'tag' keys and then 'included' or 'excluded'
    :param genres: A dictionary consisting of pairs of 'genre' keys and then 'included' or 'excluded'
    :param chapter_limit: A tuple consisting of (minimum,maximum) to limit by chapter count. Passing 0 disables the limit it was passed for.
    :param series_type: A dictionary consisting of the keys 'Translated' and 'Original English Language' along with Included or Excluded as the value for each.
    :param sort_mode: One of update, chapter-count, or name. Defaults to name.
    :param include_results: A list of strings to represent what additional information to return. Only accepts description, covers, tags, genres.
    """
    if not (tag_category or genre_category):
        if title_search_text:
            return series(title_search_text)
        else:
            raise ValueError(
                "pymoe.ln.search.wlnupdates.parametric: Requires one of tag_category or genre_category."
            )

    json_data = {"mode": "search-advanced"}

    args, _, _, values = getargvalues(currentframe())

    for item in args:
        if values[item]:
            json_data[item.replace("_", "-")] = values[item]

    r = requests.post(settings["apiurl"], headers=settings["header"], json=json_data)

    print(r.text)

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

series(title_text)

Given the title_text to search by, return a list of results. This is the best method to find a title by name.

PARAMETER DESCRIPTION
title_text

The title to search for.

TYPE: str

Source code in pymoe\ln\search\wlnupdates.py
def series(title_text: str):
    """
    Given the title_text to search by, return a list of results.
    This is the best method to find a title by name.

    :param title_text: The title to search for.
    """
    r = requests.post(
        settings["apiurl"],
        headers=settings["header"],
        json={"title": title_text, "mode": "search-title"},
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]

tags()

This simply returns a list of all tags along with their IDs. These are the tags you can use in Parametric search. You can also use these in pymoe.ln.get.wlnupdates.tag

Source code in pymoe\ln\search\wlnupdates.py
def tags():
    """
    This simply returns a list of all tags along with their IDs.
    These are the tags you can use in Parametric search.
    You can also use these in pymoe.ln.get.wlnupdates.tag
    """
    r = requests.post(
        settings["apiurl"], headers=settings["header"], json={"mode": "enumerate-tags"}
    )

    try:
        jsd = ujson.loads(r.text)
    except ValueError:
        raise serializationFailed(r.text, r.status_code)
    else:
        if jsd["error"]:
            raise serverError(jsd["message"], r.status_code)
        else:
            return jsd["data"]