objtyping Object converter with type definition

origin

Python is not strongly typed, and developers are not in the habit of typing data. While this is flexible, it is not convenient when dealing with complex business logic — the lack of type checking can make it difficult to find errors and code prompts when coding in the IDE. So this gadget was developed to solve it.

Basic usage

  • First define the business class and define the type of each field through the class variable.
from typing import List


class Person:
    name: str
    age: int


class Company:
    name: str
    revenue: float
    employees: List[Person]
Copy the code

Class variables are chosen because they are the most concise and intuitive. By contrast, if an instance variable is initialized in an __init__ method, there is no way to get type_hint; If you’re using an @property annotation or a getter, setter method, it’s a little bit more complicated. None of them are as simple and elegant as defining class variables directly. But there is a downside to using class variables: they are used as metadata here, so if you really need to define class-level shared variables, you can’t tell them apart. This problem can be solved later by developing custom annotations.

  • The next step is to convert the dict-list nested data conforming to the class definition structure into an instance object of the class:
from objtyping import objtyping

company1 = objtyping.from_dict_list({
    'name': 'Apple'.'revenue': 18.5.'employees': [{
        'name': 'Tom'.'age': 20
    }, {
        'name': 'Jerry'.'age': 31
    }]
}, Company)

Copy the code

Company1 is a complete Company object. You can use company1.name, company1.employees[0]. Name to access its properties.

  • It is also possible to revert the business object back to the dict-list nested form
from objtyping import objtyping

dict_list = objtyping.to_dict_list(company1)
Copy the code

The dict_list object is a bunch of dict and list nested primitives

Usage scenarios

Initialize an object

Python doesn’t have as convenient a way to initialize an object as JS, but with this tool you can write:

from typing import List

from objtyping import objtyping


class Person:
    name: str
    age: int


class Company:
    name: str
    revenue: float
    employees: List[Person]

    def __str__(self) :  # In fact, it is generally possible to use this simple
        return "'{}' has {} employees: {}".format(self.name, len(self.employees), ' and '.join(map(lambda emp: emp.name, self.employees)))


if __name__ == '__main__':
    company1 = objtyping.from_dict_list({
        'name': 'Apple'.'revenue': 18.5.'employees': [{
            'name': 'Tom'.'age': 20
        }, {
            'name': 'Jerry'.'age': 31
        }]
    }, Company)

    print(company1)

Copy the code

Output result:

'Apple' has 2 employees: Tom and Jerry
Copy the code

Serialize/deserialize

Python’s common serialization requirements include JSON and YAML data formats, both of which have relatively complete processing libraries. But again, without emphasizing types, they deal with objects in the original dict-list format. This tool is perfect for further transformation.

json

The sample

import json
import sys
from typing import List

from objtyping import objtyping


class X:
    x: int
    y: str


class A:
    q: str
    a: str
    b: int
    c: List[X]


if __name__ == '__main__':
    print("\r\n-----json-------")
    json_obj = json.loads('{"q":9, "a":"Mark", "b":3, "c":[{"x":15, "y":"male"},{"x":9, "y":"female", "z":13}]}')
    typed_obj = objtyping.from_dict_list(json_obj, A)
    d_l_obj = objtyping.to_dict_list(typed_obj)
    print(json.dumps(d_l_obj))

    sys.exit()

Copy the code

The output

-----json-------
{"q": "9", "a": "Mark", "b": 3, "c": [{"x": 15, "y": "male"}, {"x": 9, "y": "female", "z": 13}]}
Copy the code

Note here: The property “q” was originally a number in the JSON structure, but since the class variable was defined as a string, it is typed as a string when converted to a business object — the objtyping tool attempts to cast between the underlying types as defined by the class.

yaml

The sample

import sys
from ruamel.yaml import YAML
from typing import List
from objtyping import objtyping


class X:
    x: int
    y: str


class A:
    q: str
    a: str
    b: int
    c: List[X]


if __name__ == '__main__':
    print("\r\n-----yaml-------")
    yaml = YAML()
    yaml_obj = yaml.load(''' q: 9 a: Mark b: 3 c: - x: 15 y: male - x: 9 y: female z: 13 ''')
    typed_obj = objtyping.from_dict_list(yaml_obj, A)
    d_l_obj = objtyping.to_dict_list(typed_obj)
    yaml.dump(d_l_obj, sys.stdout)

    sys.exit()

Copy the code

The output

-----yaml-------
q: '9'
a: Mark
b: 3
c:
- x: 15
  y: male
- x: 9
  y: female
  z: 13
Copy the code

Here the property “q” is also strongly typed.


Project Address:Github.com/songofhawk/…