Skip to main content

load yaml/json to python object or pack it back

Project description

Module yaml_json_config

This is a module to facilitate reading a config file or text string in json or yaml to a python object, vice versa.

Not only flat key value style is supported, nested objects and list of objects can be supported.

Demo of Usage

Let's say there is a sample config file in yaml format to represent a company

address: "#368 GuangZhou District, GZ, GD"
telephone: "+86206666666666"
boss:
  name: alpha
  id: 001
  age: 40
  linkman:
    name: omega
members:
  - name: alpha
    id: 001 
    age: 40
  - name: beta 
    id: 002 
    age: 33
  - name: sigma
    id: 003 
    age: 38

There are 4 shallow attributes, 'address', 'telephone' are simple strings, 'members' is a list of common nested structure, 'boss' is a nested structure with a nested structure 'linkman'.

Shallow Load to Object

from yaml_json_config_paco.GenericItem import GenericItem

class Company0(GenericItem):
    """shallow load demo"""
    pass

if __name__=='__main__':
    company0 = Company0.from_file("sample.yml") 
    print(f"company0.address:  {company0.address}")
    print(f"company0.telephone:  {company0.telephone}")
    print(f"company0.boss:  {company0.boss}")
    print(f"company0.members:  {company0.members}")
    print(f"company0.dump_to_dict(): {company0.dump_to_dict()}")
    print(f"company0.jsonify():\n{company0.jsonify()}")
    print(f"company0.yamlize():\n{company0.yamlize()}")

run above code, you will get below, the 4 shallow attribute can be access directly by attribute name as object attributes, the nested structures are kept as OrderedDict and list of OrderedDict, the nested structure is just kept as OrderedDict in side OrderedDict

company0.address:  #368 GuangZhou District, GZ, GD
company0.telephone:  +86206666666666
company0.boss:  OrderedDict([('name', 'alpha'), ('id', 1), ('age', 40), ('linkman', OrderedDict([('name', 'omega')]))])
company0.members:  [OrderedDict([('name', 'alpha'), ('id', 1), ('age', 40)]), OrderedDict([('name', 'beta'), ('id', 2), ('age', 33)]), OrderedDict([('name', 'sigma'), ('id', 3), ('age', 38)])]
company0.dump_to_dict(): OrderedDict([('address', '#368 GuangZhou District, GZ, GD'), ('telephone', '+86206666666666'), ('boss', OrderedDict([('name', 'alpha'), ('id', 1), ('age', 40), ('linkman', OrderedDict([('name', 'omega')]))])), ('members', [OrderedDict([('name', 'alpha'), ('id', 1), ('age', 40)]), OrderedDict([('name', 'beta'), ('id', 2), ('age', 33)]), OrderedDict([('name', 'sigma'), ('id', 3), ('age', 38)])])])

# This is the way to dump to json
company0.jsonify(): 
{
  "address": "#368 GuangZhou District, GZ, GD",
  "telephone": "+86206666666666",
  "boss": {
    "name": "alpha",
    "id": 1,
    "age": 40,
    "linkman": {
      "name": "omega"
    }
  },
  "members": [
    {
      "name": "alpha",
      "id": 1,
      "age": 40
    },
    {
      "name": "beta",
      "id": 2,
      "age": 33
    },
    {
      "name": "sigma",
      "id": 3,
      "age": 38
    }
  ]
}

# this is the way to dump to yaml
company0.yamlize(): 
address: '#368 GuangZhou District, GZ, GD'
telephone: '+86206666666666'
boss:
  name: alpha
  id: 1
  age: 40
  linkman:
    name: omega
members:
- name: alpha
  id: 1
  age: 40
- name: beta
  id: 2
  age: 33
- name: sigma
  id: 3
  age: 38

Deep Load to Object

from yaml_json_config_paco.GenericItem import GenericItem

class Person(GenericItem):
    pass


class Company(GenericItem):
    def __nested__(self):
        # return a tuple for GenericItem to build nested objects
        return (('boss', Person),  # tell GenericItem to load boss as Person Class object
                ('members', Person, list),  # tell GenericItem to load members as list of Person Class objects
                )

if __name__=='__main__':
    company = Company.from_file("sample.yml") 
    print(f"company.address:  {company.address}")
    print(f"company.boss:  {company.boss}")
    print(f"company.boss.name:  {company.boss.name}")
    print(f"company.boss.linkman:  {company.boss.linkman}")
    print(f"company.members:  {company.members}")
    print(f"company.members[1]: {company.members[1]}")
    print(f"company.members[1].name: {company.members[1].name}")
    print(f"company.jsonify():\n{company.jsonify()}")
    print(f"company.yamlize():\n{company.yamlize()}")

run above will get below. The 'attr_to_convert_to_list' and 'attr_to_convert' will be called by GenericItem so that it will get information how to deal with some nested attributes. The nested can be recursive.

company.address:  #368 GuangZhou District, GZ, GD
company.boss:  {
  "name": "alpha",
  "id": 1,
  "age": 40,
  "linkman": {
    "name": "omega"
  }
}
# this time, boss' name can be access by attribute name
company.boss.name:  alpha
# linkman is not specified with a python class, so it is kept as a OrderDict
company.boss.linkman:  OrderedDict([('name', 'omega')])
# members is a list of Person, so it can be access by index to the Person object, and access by Person attributes
company.members:  [{
  "name": "alpha",
  "id": 1,
  "age": 40
}, {
  "name": "beta",
  "id": 2,
  "age": 33
}, {
  "name": "sigma",
  "id": 3,
  "age": 38
}]
company.members[1]: {
  "name": "beta",
  "id": 2,
  "age": 33
}
company.members[1].name: beta

company.jsonify():
{
  "address": "#368 GuangZhou District, GZ, GD",
  "telephone": "+86206666666666",
  "boss": {
    "name": "alpha",
    "id": 1,
    "age": 40,
    "linkman": {
      "name": "omega"
    }
  },
  "members": [
    {
      "name": "alpha",
      "id": 1,
      "age": 40
    },
    {
      "name": "beta",
      "id": 2,
      "age": 33
    },
    {
      "name": "sigma",
      "id": 3,
      "age": 38
    }
  ]
}

company.yamlize():
address: '#368 GuangZhou District, GZ, GD'
telephone: '+86206666666666'
boss:
  name: alpha
  id: 1
  age: 40
  linkman:
    name: omega
members:
- name: alpha
  id: 1
  age: 40
- name: beta
  id: 2
  age: 33
- name: sigma
  id: 3
  age: 38

Default Value and Optiontal Attribute

from yaml_json_config_paco.GenericItem import GenericItem

class Person(GenericItem):
    def __init__(self):
        self.name = None   # set None as mandatory attribute
        self.id = "na"     # set value as default value
        self.age = "na"    # set value as default value
        self.linkman = ""  # set to "" as optional, as this attribute 'linkman' is mentioned in self.__nested__ method,
                           # and some of Person object do not have linkman, this line is needed.

    def __nested__(self):
        return (('linkman', Person),)  # tell GenericItem to load 'linkman' attribute as a Person object

class Company(GenericItem):
    def __nested__(self):
        return (('boss', Person),  # tell GenericItem to load 'boss' as Person Class object
                ('members', Person, list))  # tell GenericItem to load 'members' as list of Person Class objects

if __name__=='__main__':
    company = Company.from_file("sample.yml") 
    print(f"company.address:  {company.address}")
    print(f"company.boss:  {company.boss}")
    print(f"company.boss.name:  {company.boss.name}")
    print(f"company.boss.linkman.name:  {company.boss.linkman.name}")
    print(f"company.members:  {company.members}")
    print(f"company.members[1]: {company.members[1]}")
    print(f"company.members[1].name: {company.members[1].name}")
    print(f"company.members[1].linkman: {company.members[1].linkman}")

run above to get below,

company.address:  #368 GuangZhou District, GZ, GD
company.boss:  {
  "name": "alpha",
  "id": 1,
  "age": 40,
  "linkman": {
    "name": "omega",
    "id": "na",            # with default value as the config file not set
    "age": "na"            # with default value
  }
}
company.boss.name:  alpha
company.boss.linkman.name:  omega
company.members:  [{    # the optional linkman is not present here
  "name": "alpha",
  "id": 1,
  "age": 40
}, {
  "name": "beta",
  "id": 2,
  "age": 33
}, {
  "name": "sigma",
  "id": 3,
  "age": 38
}]
company.members[1]: {
  "name": "beta",
  "id": 2,
  "age": 33
}
company.members[1].name: beta
company.members[1].linkman: 
# pack to yaml
company.yamlize():  
address: '#368 GuangZhou District, GZ, GD'
telephone: '+86206666666666'
boss:
  name: alpha
  id: 1
  age: 40
  linkman:
    name: omega
    id: na
    age: na
members:
- name: alpha
  id: 1
  age: 40
- name: beta
  id: 2
  age: 33
- name: sigma
  id: 3
  age: 38

Dump and Load, Json or Yaml

A GenericItem classmethod 'from_file' is provided to load from file. A GenericItem method 'dump_to_file' is provide to dump to file. The format is automatically recognized by the suffix of the filename you feed, 'json', 'yml', 'yaml' are supported.

Example:

company.dump_to_file("sample.json")
with open("sample.json", "r", encoding="utf-8") as f:
   print(f"read sample.json file:\n{f.read()}\n")

company2 = Company.from_file("sample.json")
print(f"company2.yamlize():\n{company2.yamlize()}")

Run above to get below

read sample.json file:
{
  "address": "#368 GuangZhou District, GZ, GD",
  "telephone": "+86206666666666",
  "boss": {
    "name": "alpha",
    "id": 1,
    "age": 40,
    "linkman": {
      "name": "omega"
    }
  },
  "members": [
    {
      "name": "alpha",
      "id": 1,
      "age": 40
    },
    {
      "name": "beta",
      "id": 2,
      "age": 33
    },
    {
      "name": "sigma",
      "id": 3,
      "age": 38
    }
  ]
}

company2.yamlize():
address: '#368 GuangZhou District, GZ, GD'
telephone: '+86206666666666'
boss:
  name: alpha
  id: 1
  age: 40
  linkman:
    name: omega
members:
- name: alpha
  id: 1
  age: 40
- name: beta
  id: 2
  age: 33
- name: sigma
  id: 3
  age: 38

Project details


Download files

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

Source Distribution

yaml_json_config_paco-0.1.0.tar.gz (9.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yaml_json_config_paco-0.1.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file yaml_json_config_paco-0.1.0.tar.gz.

File metadata

  • Download URL: yaml_json_config_paco-0.1.0.tar.gz
  • Upload date:
  • Size: 9.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.6

File hashes

Hashes for yaml_json_config_paco-0.1.0.tar.gz
Algorithm Hash digest
SHA256 93800b468ac8c6257226fe3fe982bb0515eb0b4fa5a21db0b27b224865a98196
MD5 7cb67f6b000b22671ee9815783e91d16
BLAKE2b-256 87254c4abfe04593d319d7044056cd4956d08f8a7f35bcbfad8ea646f17f8588

See more details on using hashes here.

File details

Details for the file yaml_json_config_paco-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for yaml_json_config_paco-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5f28acdbb687e078c4d055d73bf7fc8b0aeeba19a6583948f40811ac0e1f61b9
MD5 cb758c51bf46515deee090041f1a2920
BLAKE2b-256 18bb7bb5da35d6460899d1e033c300346a3bef26a6149e64c4720a9014956e7b

See more details on using hashes here.

Supported by

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