Skip to main content

DivKit python library

Project description

PyDIVKit examples

This library is designed to work with DivKit with python.

Features:

  • Declarative and imperative DivKit blocks definition
  • Native Type-hints support
  • Complete object-oriented API
  • IDE type checks and suggestions

Object construction

The main idea is to provide a tool for creating blocks using Python objects.

import json
import pydivkit as dk

container = dk.DivContainer(
    items=[
        dk.DivGallery(
            items=[
                dk.DivText(text="Hello from pydivkit")
            ]
        )
    ]
)

print(json.dumps(container.dict(), indent=1))
# {
#  "type": "container",
#  "items": [
#   {
#    "type": "gallery",
#    "items": [
#     {
#      "type": "text",
#      "text": "Hello from pydivkit"
#     }
#    ]
#   }
#  ]
# }

Slider example

Following code is a rewritten slider example using pydivkit.

import pydivkit as dk


slider = dk.DivData(
    log_id="sample_card",
    states=[
        dk.DivDataState(
            state_id=0,
            div=dk.DivSlider(
                width=dk.DivMatchParentSize(),
                max_value=10,
                min_value=1,
                thumb_style=dk.DivShapeDrawable(
                    color="#00b300",
                    stroke=dk.DivStroke(
                        color="#ffffff",
                        width=3,
                    ),
                    shape=dk.DivRoundedRectangleShape(
                        item_width=dk.DivFixedSize(value=32),
                        item_height=dk.DivFixedSize(value=32),
                        corner_radius=dk.DivFixedSize(value=100)
                    ),
                ),
                track_active_style=dk.DivShapeDrawable(
                    color="#00b300",
                    shape=dk.DivRoundedRectangleShape(
                        item_height=dk.DivFixedSize(value=6)
                    )
                ),
                track_inactive_style=dk.DivShapeDrawable(
                    color="#20000000",
                    shape=dk.DivRoundedRectangleShape(
                        item_height=dk.DivFixedSize(value=6)
                    )
                )
            )
        )
    ]
)

This example might be serialised like this:

import json

print(json.dumps(slider.dict(), indent=1))
# {
#  "log_id": "sample_card",
#  "states": [
#   {
#    "div": {
#     "type": "slider",
#     "max_value": 10,
#     "min_value": 1,
#     "thumb_style": {
#      "type": "shape_drawable",
#      "color": "#00b300",
#      "shape": {
#       "type": "rounded_rectangle",
#       "corner_radius": {
#        "type": "fixed",
#        "value": 100
#       },
#       "item_height": {
#        "type": "fixed",
#        "value": 32
#       },
#       "item_width": {
#        "type": "fixed",
#        "value": 32
#       }
#      },
#      "stroke": {
#       "color": "#ffffff",
#       "width": 3
#      }
#     },
#     "track_active_style": {
#      "type": "shape_drawable",
#      "color": "#00b300",
#      "shape": {
#       "type": "rounded_rectangle",
#       "item_height": {
#        "type": "fixed",
#        "value": 6
#       }
#      }
#     },
#     "track_inactive_style": {
#      "type": "shape_drawable",
#      "color": "#20000000",
#      "shape": {
#       "type": "rounded_rectangle",
#       "item_height": {
#        "type": "fixed",
#        "value": 6
#       }
#      }
#     },
#     "width": {
#      "type": "match_parent"
#     }
#    },
#    "state_id": 0
#   }
#  ]
# }

Templating and DRY

Of course, manually building blocks from your code every time is boring. So, the first idea is to move the initialization of DivKit objects into functions.

# Naive DRY example which strictly non-recommended
import pydivkit as dk


def get_size(value: int = 32) -> dk.DivFixedSize:
    return dk.DivFixedSize(value=value)


def get_shape() -> dk.DivShape:
    return dk.DivShape(
        item_width=get_size(),
        item_height=get_size(),
        corner_radius=get_size(100)
    )

    
slider_shape = get_shape()

slider = dk.DivData(
    log_id="sample_card",
    states=[
        dk.DivDataState(
            # other arguments
            div=dk.DivSlider(
                thumb_style=dk.DivShapeDrawable(
                    shape=slider_shape,
                    # other arguments
                ),
                # other arguments
            )
        )
    ]
)

Looks a little better, but this approach doesn't scale well. To simplify layout and save traffic, DivKit has templates. This is a way to layout similar elements without having to declare the complete json, but just declare a template and use this many times in similar items.

PyDivKit supports defining templates through the inheritance.

Let's define an example card:

import json

import pydivkit as dk


class CategoriesItem(dk.DivContainer):
    """
    Class inherited from dk.DivContainer will have a template
    """

    # Special object for mark this fields a DivKit field in template
    icon_url: str = dk.Field()
    text: str = dk.Field()

    # Set defaults layout for in the template
    width = dk.DivWrapContentSize()
    background = [dk.DivSolidBackground(color="#f0f0f0")]
    content_alignment_vertical = dk.DivAlignmentVertical.CENTER
    orientation = dk.DivContainerOrientation.HORIZONTAL
    paddings = dk.DivEdgeInsets(left=12, right=12, top=10, bottom=10)
    border = dk.DivBorder(corner_radius=12)
    items = [
        dk.DivImage(
            width=dk.DivFixedSize(value=20),
            height=dk.DivFixedSize(value=20),
            margins=dk.DivEdgeInsets(right=6),

            # Special object Ref it's a reference for Field property
            image_url=dk.Ref(icon_url),
        ),
        dk.DivText(
            width=dk.DivWrapContentSize(),
            max_lines=1,

            # Special object Ref it's a reference for Field property
            text=dk.Ref(text),
        ),
    ]


BASE_URL = "https://leonardo.edadeal.io/dyn/re/segments/level1/96"


# So after class definition you might use all the `Field` marked property
# names as an argument.

gallery = dk.DivGallery(
    items=[
        CategoriesItem(
            text="Food", icon_url=f"{BASE_URL}/food.png",
        ),
        CategoriesItem(
            text="Alcohol", icon_url=f"{BASE_URL}/alcohol.png",
        ),
        CategoriesItem(
            text="Household", icon_url=f"{BASE_URL}/household.png",
        ),
    ]
)

print(json.dumps(dk.make_div(gallery), indent=1, ensure_ascii=False))
# {
#  "templates": {
#   "__main__.CategoriesItem": {
#    "type": "container",
#    "background": [
#     {
#      "type": "solid",
#      "color": "#f0f0f0"
#     }
#    ],
#    "border": {
#     "corner_radius": 12
#    },
#    "content_alignment_vertical": "center",
#    "items": [
#     {
#      "type": "image",
#      "height": {
#       "type": "fixed",
#       "value": 20
#      },
#      "$image_url": "icon_url",
#      "margins": {
#       "right": 6
#      },
#      "width": {
#       "type": "fixed",
#       "value": 20
#      }
#     },
#     {
#      "type": "text",
#      "max_lines": 1,
#      "$text": "text",
#      "width": {
#       "type": "wrap_content"
#      }
#     }
#    ],
#    "orientation": "horizontal",
#    "paddings": {
#     "bottom": 10,
#     "left": 12,
#     "right": 12,
#     "top": 10
#    },
#    "width": {
#     "type": "wrap_content"
#    }
#   }
#  },
#  "card": {
#   "log_id": "card",
#   "states": [
#    {
#     "div": {
#      "type": "gallery",
#      "items": [
#       {
#        "type": "__main__.CategoriesItem",
#        "icon_url": "https://leonardo.edadeal.io/dyn/re/segments/level1/96/food.png",
#        "text": "Food"
#       },
#       {
#        "type": "__main__.CategoriesItem",
#        "icon_url": "https://leonardo.edadeal.io/dyn/re/segments/level1/96/alcohol.png",
#        "text": "Alcohol"
#       },
#       {
#        "type": "__main__.CategoriesItem",
#        "icon_url": "https://leonardo.edadeal.io/dyn/re/segments/level1/96/household.png",
#        "text": "Household"
#       }
#      ]
#     },
#     "state_id": 0
#    }
#   ]
#  }
# }

Template names

By default, templates are collecting by the metaclass into shared storage when the class is declaring at import time, and have the format {module_name}.{class_name}.

The following example, sure will not occur in the wild, shows a warning if suddenly the names of the classes, and hence the templates, conflict.

import pydivkit as dk


class MyTemplate(dk.DivContainer):
    width = dk.DivWrapContentSize()


class MyTemplate(dk.DivContainer):
    pass

# RuntimeWarning: Template 'test.MyTemplate' already defined in 
# <class 'test.MyTemplate'> and will be replaced to <class 'test.MyTemplate'>

Also, if you do not want to show the structure of your project to the outside, or for some reason you need to make the example above clean, you can rename the template by declaring a special attribute __template_name__

import pydivkit as dk


class MyTemplate(dk.DivContainer):
    width = dk.DivWrapContentSize()

print(MyTemplate.template_name)
# >>> test.MyTemplate

class MyTemplate(dk.DivContainer):
    __template_name__ = "MyTemplate2"

print(MyTemplate.template_name)
# >>> MyTemplate2

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydivkit-28.11.0.tar.gz (67.2 kB view details)

Uploaded Source

Built Distribution

pydivkit-28.11.0-py3-none-any.whl (144.9 kB view details)

Uploaded Python 3

File details

Details for the file pydivkit-28.11.0.tar.gz.

File metadata

  • Download URL: pydivkit-28.11.0.tar.gz
  • Upload date:
  • Size: 67.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.10.8 Linux/5.4.161-26.3

File hashes

Hashes for pydivkit-28.11.0.tar.gz
Algorithm Hash digest
SHA256 2851f8f035a41cd72b6b9585d8adefee1d9e9a759b13f15accc423376ed7f4ee
MD5 3594a0a7a75be5e145f70584c48f4a24
BLAKE2b-256 02536a6a2452c1c6961bc59346f7d7ff3176fb0adb970e505b36b587d1648c17

See more details on using hashes here.

File details

Details for the file pydivkit-28.11.0-py3-none-any.whl.

File metadata

  • Download URL: pydivkit-28.11.0-py3-none-any.whl
  • Upload date:
  • Size: 144.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.10.8 Linux/5.4.161-26.3

File hashes

Hashes for pydivkit-28.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 359e0bb524e3b0b9745f0d268ff3b628323dfadb270a9722ffa72214dd03a084
MD5 2b57b7d2d3acf4857f0d33803b45c082
BLAKE2b-256 70cbb052478ed7c1c47a6b7b7d6ea3edf95d5364237bca98387e2c5e1c139631

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page