pdoo


Namepdoo JSON
Version 0.1.7 PyPI version JSON
download
home_pageNone
SummaryNone
upload_time2024-04-03 15:38:58
maintainerNone
docs_urlNone
authortlonny
requires_python<4.0,>=3.11
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # PDOO

PDOO, short for "**P**ython **DO**M **O**rchestrator," is a lightweight, dependency-free library designed for effortlessly crafting styled HTML documents solely with Python. Drawing inspiration from robust alternatives like [dominate](https://github.com/Knio/dominate), PDOO emphasizes simplicity and ease of use.

With PDOO, you sidestep the need for clunky templating languages like Jinja or Mustache. Styling becomes a breeze using Python alone — no separate CSS files to juggle, just straightforward dynamic styling with f-strings.

Below is an example of the library in action. Note, the example below demonstrates **all** the concepts provided by PDOO. Scroll down below for a _gentler_ introduction to the library...

### Python
```python
from pdoo import Document, style

# Create the HTML document object
doc = Document()

# Create a dynamic CSS class that is parameterized by
# border_radius and background_color arguments.
@style
def style_fn(*, background_color, border_radius = 0):
    return lambda clsname: f"""
        .{clsname} {{
            background-color: {background_color};
            border-radius: {border_radius}px;
        }}
    """

# Begin defining the contents of the <head> tag.
with doc.head:
    # Create a <title> tag.
    with doc.tag("title"):
        # Inside the title tag, add the actual title text.
        doc.text("PDOO isn't too bad")

    # Now lets create a <script> tag.
    with doc.tag("script"):
        # As before, we want to include this JS code inside the script tag
        # however, we use "doc.raw" instead of "doc.text" to prevent escaping
        # of any HTML characters (i.e. "<" or ">").
        doc.raw("console.log(\"<hello world>\");")

# Now lets work on the <body>.
with doc.body:
    # As a shortcut, text can be provided directly as an argument
    # after the tag attributes...
    doc.tag("h1", {}, "Here are some custom labels")

    # Create a green label with square borders
    div_cls = doc.style(style_fn(background_color = "green"))
    with doc.tag("div", {"class": div_cls}):
        doc.text("This is green with square borders")

    # Create a blue label with round borders
    div_cls = doc.style(style_fn(background_color = "blue", border_radius = 4))
    with doc.tag("div", {"class": div_cls}):
        doc.text("This is blue with round borders")

    # Create a blue label with round borders
    div_cls = doc.style(style_fn(background_color = "blue", border_radius = 4))
    with doc.tag("div", {"class": div_cls}):
        doc.text("This is blue with round borders")

# Spit out the HTML!
print(str(doc))
```

### Output

```html
<!DOCTYPE html>
<html>
    <head>
        <style>
            .cls-__main__-style_fn-0 {
                background-color: green;
                border-radius: 0px;
            }
            .cls-__main__-style_fn-1 {
                background-color: blue;
                border-radius: 4px;
            }
        </style>
        <title>
            PDOO isn&#x27;t too bad
        </title>
        <script>
            console.log("<hello world>");
        </script>
    </head>
    <body>
        <h1>
            Here are some custom labels
        </h1>
        <div class="cls-__main__-style_fn-0">
            This is green with square borders
        </div>
        <div class="cls-__main__-style_fn-1">
            This is blue with round borders
        </div>
        <div class="cls-__main__-style_fn-1">
            This is blue with round borders
        </div>
    </body>
</html>
```

# Installation

You can install pdoo using `pip` via:

```bash
pip install pdoo
```

## Testing

You can test pdoo via:

```bash
python -m unittest discover -s test
```

# Usage

All code snippets below assume that both `Document` and `style` have been imported from `pdoo`:

```python
from pdoo import Document, style
```

## Getting started

To begin our journey with PDOO, we must first create an HTML Document. This is as simple as doing:

```python
# By default, PDOO will indent HTML by 4 spaces.
doc = Document(indent_prefix = 4)
print(str(doc))
```

This will generate a bare-bones empty HTML document with empty `<head>` and `<body>` tags:

```html
<!DOCTYPE html>
<html>
    <head>
        <style>
        </style>
    </head>
    <body>
    </body>
</html>
```

## Tags

Lets start adding to the `<body>` tag of our document. Adding content to a tag is as simple as "binding" it using python's `with` statement and then calling either:
  - `doc.tag` to append an HTML tag.
  - `doc.text` to append HTML-escaped text to the node.
  - `doc.raw` to append un-escaped HTML to the node

As we can see in the example below, tags created by `doc.tag` can themselves be bound using the `with` statement.

```python
doc = Document()
with doc.body:
    with doc.tag("div"):
        doc.text("Hello, World")
print(str(doc))
```

The above code generates the following HTML:

```html
<!DOCTYPE html>
<html>
    <head>
        <style>
        </style>
    </head>
    <body>
        <div>
            Hello, World
        </div>
    </body>
</html>
```

## Attributes

Similar to how tags, text and raw HTML can be added to a node, we can also add attributes. This can be done in two ways. First, we can pass a dictionary of `attribute_name : attribute_value` pairs as the second argument to `doc.tag`:

```python
doc.tag("div", {"id": "foobar", "class": "my-class" })
```

Alternatively, we can insert attributes to the currently bound tag by using the `doc.attr` method:
```python
with doc.tag("div"):
    doc.attr("id", "foobar")
    doc.attr("class", "my-class")
```

## Text

As seen in the "Tags" section above, text can be added to the currently bound tag by calling `doc.text`. Alternatively, we can pass in text as the third argument to `doc.tag` (after the attributes dictionary):

```python
doc.tag("div", {}, "Hello, World")
```

## Styling

PDOO allows us to remain in python even when styling our HTML components. PDOO keeps track of defined styles and generates unique class names that are guaranteed not to collide. PDOO also ensures that styles aren't redundantly redefined multiple times, ensuring file sizes are kept as small as possible!

To start styling with PDOO, lets first create a styling function:

```python
@style
def padding(padding_amount):
    return lambda cls: f"""
        .{cls} {{ padding: {padding_amount}px; }}
    """
```

A styling function takes some set of arguments and returns a **lambda** that itself generates CSS. This lambda is then passed the class name that PDOO generates for us to render a valid fragment of CSS that is included within an in-line `<style>` tag inside our `<head>`.

The reason why we use the approach of explicitly passing the class name into a lambda is that it makes more complex CSS a breeze to implement as shown below:

```python
@style
def responsive_padding(padding_amount, breakpoint):
    return lambda cls: f"""
        .{cls} {{ padding: {padding_amount}px; }}
        .{cls}:hover {{ color: red; }}
        @media (max-width: {breakpoint}px) {{
            .{cls} {{ display: none; }}
        }}
    """
```

To use a style function, we simply call it and pass the result to `doc.style`. We can then style a tag by assigning the result to the class attribute of a tag:

```python
class_name = doc.style(padding(6))
doc.text("div", {"class": class_name}, "I am a styled tag!" )
```

N.B. the `@style` decorator is required when creating a styling function as this facilitates the caching of identical styles, preventing the same styles being created multiple times under different class names.

## Components

If you've made it this far, congratulations! You understand _all_ of what PDOO has to offer. This last chapter doesn't introduce any new concepts, but instead demonstrates a powerful usage pattern that allows the creation of modular, re-usable components (A familiarity with `contextlib.contextmanager` is helpful).

Lets pretend we have a bunch of content on our website that we want to pad. One way we could do this is by styling each bit of content explicitly using a styling function. This is a bit of a faff - lets instead create a re-usable `padding` component which will automatically wrap any content in some padding.

First, lets create the styling function. We might want to pad the content by a variable amount so lets leave the padding amount as an input variable vs. hardcoding it:

```python
@style
def padding_style(padding_amount):
    return lambda cls: f"""
        .{cls} {{ padding: {padding_amount}px; }}
    """
```

Now lets create our padding component. All we must do is:

```python
@contextmanager
def padding_component(doc, *, padding_amount):
    cls = doc.style(padding_style(padding_amount))
    with doc.tag("div", {"class": cls}):
        yield
```

By constructing the component using the `@contextmanager` decorator, we can "bind" it in the same way we bind regular tags. Lets see the whole code in action:

```python
from pdoo import Document, style
from contextlib import contextmanager

@style
def padding_style(padding_amount):
    return lambda cls: f"""
        .{cls} {{ padding: {padding_amount}px; }}
    """

@contextmanager
def padding_component(doc, *, padding_amount):
    cls = doc.style(padding_style(padding_amount))
    with doc.tag("div", {"class": cls}):
        yield

# Create the HTML document object
doc = Document()
with doc.body:
    with padding_component(doc, padding_amount = 5):
        doc.text("Hello - I am padded by 5 pixels")
    with padding_component(doc, padding_amount = 5):
        with padding_component(doc, padding_amount = 5):
            doc.text("Hello - I am padded by 10 pixels")

print(str(doc))
```

This generates the following HTML:

```html
<!DOCTYPE html>
<html>
    <head>
        <style>
            .cls-__main__-padding_style-0 { padding: 5px; }
        </style>
    </head>
    <body>
        <div class="cls-__main__-padding_style-0">
            Hello - I am padded by 5 pixels
        </div>
        <div class="cls-__main__-padding_style-0">
            <div class="cls-__main__-padding_style-0">
                Hello - I am padded by 10 pixels
            </div>
        </div>
    </body>
</html>
```

As you can see, its quite straight-forward to create modular components that can be re-used and composed together across your code-base!

## Appendix: Asynchronous python

_tl;dr this library works well with async web frameworks_

This library requires tags, text and raw HTML to be created via methods on the `Document` object. As a result, the document (Usually named `doc`) needs to be explicitly passed around. This might feel like sub-par UX however it was a conscious choice - it means that currently bound tags are not stored under global variables but instead are stored in the document.

This means that this library plays nice with asynchronous web frameworks like [sanic](https://github.com/sanic-org/sanic), as concurrent requests won't interfere with one another - one request can't affect the currently bound tag of another. 

An alternate approach might be to use a `contextlib.ContextVar` to store currently bound tags. This would free us from having to pass `doc` everywhere - However, I want to avoid "magic" as much as possible. Although the current UX is slightly clunkier then it needs to be, its dead simple to understand and I intend to keep it as such.

## Thanks

Thanks for reading fellas! If you have any questions/suggestions, please reach out. My details are as follows:

  - Email: [t@lonny.io](mailto:t@lonny.io)
  - Website: [The Lonny Corporation](https://lonny.io)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pdoo",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.11",
    "maintainer_email": null,
    "keywords": null,
    "author": "tlonny",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/53/fc/25af84447cbc2d85d20a70b4fd2a21f0fe4b3da2393dc26401b29f689b83/pdoo-0.1.7.tar.gz",
    "platform": null,
    "description": "# PDOO\n\nPDOO, short for \"**P**ython **DO**M **O**rchestrator,\" is a lightweight, dependency-free library designed for effortlessly crafting styled HTML documents solely with Python. Drawing inspiration from robust alternatives like [dominate](https://github.com/Knio/dominate), PDOO emphasizes simplicity and ease of use.\n\nWith PDOO, you sidestep the need for clunky templating languages like Jinja or Mustache. Styling becomes a breeze using Python alone \u2014 no separate CSS files to juggle, just straightforward dynamic styling with f-strings.\n\nBelow is an example of the library in action. Note, the example below demonstrates **all** the concepts provided by PDOO. Scroll down below for a _gentler_ introduction to the library...\n\n### Python\n```python\nfrom pdoo import Document, style\n\n# Create the HTML document object\ndoc = Document()\n\n# Create a dynamic CSS class that is parameterized by\n# border_radius and background_color arguments.\n@style\ndef style_fn(*, background_color, border_radius = 0):\n    return lambda clsname: f\"\"\"\n        .{clsname} {{\n            background-color: {background_color};\n            border-radius: {border_radius}px;\n        }}\n    \"\"\"\n\n# Begin defining the contents of the <head> tag.\nwith doc.head:\n    # Create a <title> tag.\n    with doc.tag(\"title\"):\n        # Inside the title tag, add the actual title text.\n        doc.text(\"PDOO isn't too bad\")\n\n    # Now lets create a <script> tag.\n    with doc.tag(\"script\"):\n        # As before, we want to include this JS code inside the script tag\n        # however, we use \"doc.raw\" instead of \"doc.text\" to prevent escaping\n        # of any HTML characters (i.e. \"<\" or \">\").\n        doc.raw(\"console.log(\\\"<hello world>\\\");\")\n\n# Now lets work on the <body>.\nwith doc.body:\n    # As a shortcut, text can be provided directly as an argument\n    # after the tag attributes...\n    doc.tag(\"h1\", {}, \"Here are some custom labels\")\n\n    # Create a green label with square borders\n    div_cls = doc.style(style_fn(background_color = \"green\"))\n    with doc.tag(\"div\", {\"class\": div_cls}):\n        doc.text(\"This is green with square borders\")\n\n    # Create a blue label with round borders\n    div_cls = doc.style(style_fn(background_color = \"blue\", border_radius = 4))\n    with doc.tag(\"div\", {\"class\": div_cls}):\n        doc.text(\"This is blue with round borders\")\n\n    # Create a blue label with round borders\n    div_cls = doc.style(style_fn(background_color = \"blue\", border_radius = 4))\n    with doc.tag(\"div\", {\"class\": div_cls}):\n        doc.text(\"This is blue with round borders\")\n\n# Spit out the HTML!\nprint(str(doc))\n```\n\n### Output\n\n```html\n<!DOCTYPE html>\n<html>\n    <head>\n        <style>\n            .cls-__main__-style_fn-0 {\n                background-color: green;\n                border-radius: 0px;\n            }\n            .cls-__main__-style_fn-1 {\n                background-color: blue;\n                border-radius: 4px;\n            }\n        </style>\n        <title>\n            PDOO isn&#x27;t too bad\n        </title>\n        <script>\n            console.log(\"<hello world>\");\n        </script>\n    </head>\n    <body>\n        <h1>\n            Here are some custom labels\n        </h1>\n        <div class=\"cls-__main__-style_fn-0\">\n            This is green with square borders\n        </div>\n        <div class=\"cls-__main__-style_fn-1\">\n            This is blue with round borders\n        </div>\n        <div class=\"cls-__main__-style_fn-1\">\n            This is blue with round borders\n        </div>\n    </body>\n</html>\n```\n\n# Installation\n\nYou can install pdoo using `pip` via:\n\n```bash\npip install pdoo\n```\n\n## Testing\n\nYou can test pdoo via:\n\n```bash\npython -m unittest discover -s test\n```\n\n# Usage\n\nAll code snippets below assume that both `Document` and `style` have been imported from `pdoo`:\n\n```python\nfrom pdoo import Document, style\n```\n\n## Getting started\n\nTo begin our journey with PDOO, we must first create an HTML Document. This is as simple as doing:\n\n```python\n# By default, PDOO will indent HTML by 4 spaces.\ndoc = Document(indent_prefix = 4)\nprint(str(doc))\n```\n\nThis will generate a bare-bones empty HTML document with empty `<head>` and `<body>` tags:\n\n```html\n<!DOCTYPE html>\n<html>\n    <head>\n        <style>\n        </style>\n    </head>\n    <body>\n    </body>\n</html>\n```\n\n## Tags\n\nLets start adding to the `<body>` tag of our document. Adding content to a tag is as simple as \"binding\" it using python's `with` statement and then calling either:\n  - `doc.tag` to append an HTML tag.\n  - `doc.text` to append HTML-escaped text to the node.\n  - `doc.raw` to append un-escaped HTML to the node\n\nAs we can see in the example below, tags created by `doc.tag` can themselves be bound using the `with` statement.\n\n```python\ndoc = Document()\nwith doc.body:\n    with doc.tag(\"div\"):\n        doc.text(\"Hello, World\")\nprint(str(doc))\n```\n\nThe above code generates the following HTML:\n\n```html\n<!DOCTYPE html>\n<html>\n    <head>\n        <style>\n        </style>\n    </head>\n    <body>\n        <div>\n            Hello, World\n        </div>\n    </body>\n</html>\n```\n\n## Attributes\n\nSimilar to how tags, text and raw HTML can be added to a node, we can also add attributes. This can be done in two ways. First, we can pass a dictionary of `attribute_name : attribute_value` pairs as the second argument to `doc.tag`:\n\n```python\ndoc.tag(\"div\", {\"id\": \"foobar\", \"class\": \"my-class\" })\n```\n\nAlternatively, we can insert attributes to the currently bound tag by using the `doc.attr` method:\n```python\nwith doc.tag(\"div\"):\n    doc.attr(\"id\", \"foobar\")\n    doc.attr(\"class\", \"my-class\")\n```\n\n## Text\n\nAs seen in the \"Tags\" section above, text can be added to the currently bound tag by calling `doc.text`. Alternatively, we can pass in text as the third argument to `doc.tag` (after the attributes dictionary):\n\n```python\ndoc.tag(\"div\", {}, \"Hello, World\")\n```\n\n## Styling\n\nPDOO allows us to remain in python even when styling our HTML components. PDOO keeps track of defined styles and generates unique class names that are guaranteed not to collide. PDOO also ensures that styles aren't redundantly redefined multiple times, ensuring file sizes are kept as small as possible!\n\nTo start styling with PDOO, lets first create a styling function:\n\n```python\n@style\ndef padding(padding_amount):\n    return lambda cls: f\"\"\"\n        .{cls} {{ padding: {padding_amount}px; }}\n    \"\"\"\n```\n\nA styling function takes some set of arguments and returns a **lambda** that itself generates CSS. This lambda is then passed the class name that PDOO generates for us to render a valid fragment of CSS that is included within an in-line `<style>` tag inside our `<head>`.\n\nThe reason why we use the approach of explicitly passing the class name into a lambda is that it makes more complex CSS a breeze to implement as shown below:\n\n```python\n@style\ndef responsive_padding(padding_amount, breakpoint):\n    return lambda cls: f\"\"\"\n        .{cls} {{ padding: {padding_amount}px; }}\n        .{cls}:hover {{ color: red; }}\n        @media (max-width: {breakpoint}px) {{\n            .{cls} {{ display: none; }}\n        }}\n    \"\"\"\n```\n\nTo use a style function, we simply call it and pass the result to `doc.style`. We can then style a tag by assigning the result to the class attribute of a tag:\n\n```python\nclass_name = doc.style(padding(6))\ndoc.text(\"div\", {\"class\": class_name}, \"I am a styled tag!\" )\n```\n\nN.B. the `@style` decorator is required when creating a styling function as this facilitates the caching of identical styles, preventing the same styles being created multiple times under different class names.\n\n## Components\n\nIf you've made it this far, congratulations! You understand _all_ of what PDOO has to offer. This last chapter doesn't introduce any new concepts, but instead demonstrates a powerful usage pattern that allows the creation of modular, re-usable components (A familiarity with `contextlib.contextmanager` is helpful).\n\nLets pretend we have a bunch of content on our website that we want to pad. One way we could do this is by styling each bit of content explicitly using a styling function. This is a bit of a faff - lets instead create a re-usable `padding` component which will automatically wrap any content in some padding.\n\nFirst, lets create the styling function. We might want to pad the content by a variable amount so lets leave the padding amount as an input variable vs. hardcoding it:\n\n```python\n@style\ndef padding_style(padding_amount):\n    return lambda cls: f\"\"\"\n        .{cls} {{ padding: {padding_amount}px; }}\n    \"\"\"\n```\n\nNow lets create our padding component. All we must do is:\n\n```python\n@contextmanager\ndef padding_component(doc, *, padding_amount):\n    cls = doc.style(padding_style(padding_amount))\n    with doc.tag(\"div\", {\"class\": cls}):\n        yield\n```\n\nBy constructing the component using the `@contextmanager` decorator, we can \"bind\" it in the same way we bind regular tags. Lets see the whole code in action:\n\n```python\nfrom pdoo import Document, style\nfrom contextlib import contextmanager\n\n@style\ndef padding_style(padding_amount):\n    return lambda cls: f\"\"\"\n        .{cls} {{ padding: {padding_amount}px; }}\n    \"\"\"\n\n@contextmanager\ndef padding_component(doc, *, padding_amount):\n    cls = doc.style(padding_style(padding_amount))\n    with doc.tag(\"div\", {\"class\": cls}):\n        yield\n\n# Create the HTML document object\ndoc = Document()\nwith doc.body:\n    with padding_component(doc, padding_amount = 5):\n        doc.text(\"Hello - I am padded by 5 pixels\")\n    with padding_component(doc, padding_amount = 5):\n        with padding_component(doc, padding_amount = 5):\n            doc.text(\"Hello - I am padded by 10 pixels\")\n\nprint(str(doc))\n```\n\nThis generates the following HTML:\n\n```html\n<!DOCTYPE html>\n<html>\n    <head>\n        <style>\n            .cls-__main__-padding_style-0 { padding: 5px; }\n        </style>\n    </head>\n    <body>\n        <div class=\"cls-__main__-padding_style-0\">\n            Hello - I am padded by 5 pixels\n        </div>\n        <div class=\"cls-__main__-padding_style-0\">\n            <div class=\"cls-__main__-padding_style-0\">\n                Hello - I am padded by 10 pixels\n            </div>\n        </div>\n    </body>\n</html>\n```\n\nAs you can see, its quite straight-forward to create modular components that can be re-used and composed together across your code-base!\n\n## Appendix: Asynchronous python\n\n_tl;dr this library works well with async web frameworks_\n\nThis library requires tags, text and raw HTML to be created via methods on the `Document` object. As a result, the document (Usually named `doc`) needs to be explicitly passed around. This might feel like sub-par UX however it was a conscious choice - it means that currently bound tags are not stored under global variables but instead are stored in the document.\n\nThis means that this library plays nice with asynchronous web frameworks like [sanic](https://github.com/sanic-org/sanic), as concurrent requests won't interfere with one another - one request can't affect the currently bound tag of another. \n\nAn alternate approach might be to use a `contextlib.ContextVar` to store currently bound tags. This would free us from having to pass `doc` everywhere - However, I want to avoid \"magic\" as much as possible. Although the current UX is slightly clunkier then it needs to be, its dead simple to understand and I intend to keep it as such.\n\n## Thanks\n\nThanks for reading fellas! If you have any questions/suggestions, please reach out. My details are as follows:\n\n  - Email: [t@lonny.io](mailto:t@lonny.io)\n  - Website: [The Lonny Corporation](https://lonny.io)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": null,
    "version": "0.1.7",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "534dc6267b059a64f4b2e0795b7190a9897df60222303a507500cc5b2f0e84b4",
                "md5": "a867d4b1df733df74299629a473788fb",
                "sha256": "291f346db34b877f24564037dce7e9c288cd6f4a330ed690faee1957884f89c6"
            },
            "downloads": -1,
            "filename": "pdoo-0.1.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a867d4b1df733df74299629a473788fb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.11",
            "size": 8321,
            "upload_time": "2024-04-03T15:38:57",
            "upload_time_iso_8601": "2024-04-03T15:38:57.397829Z",
            "url": "https://files.pythonhosted.org/packages/53/4d/c6267b059a64f4b2e0795b7190a9897df60222303a507500cc5b2f0e84b4/pdoo-0.1.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "53fc25af84447cbc2d85d20a70b4fd2a21f0fe4b3da2393dc26401b29f689b83",
                "md5": "a21f8c48f2457d5448210202a024b496",
                "sha256": "8c9b02bd9e516ad142d1c69dd38bf38c7c82e7c92feab3e7151fe49c12e5a634"
            },
            "downloads": -1,
            "filename": "pdoo-0.1.7.tar.gz",
            "has_sig": false,
            "md5_digest": "a21f8c48f2457d5448210202a024b496",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.11",
            "size": 7087,
            "upload_time": "2024-04-03T15:38:58",
            "upload_time_iso_8601": "2024-04-03T15:38:58.768352Z",
            "url": "https://files.pythonhosted.org/packages/53/fc/25af84447cbc2d85d20a70b4fd2a21f0fe4b3da2393dc26401b29f689b83/pdoo-0.1.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-03 15:38:58",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pdoo"
}
        
Elapsed time: 0.39090s