kadet


Namekadet JSON
Version 0.3.1 PyPI version JSON
download
home_pagehttps://github.com/kapicorp/kadet
SummaryEasily define and reuse complex Python objects that serialize into JSON or YAML.
upload_time2024-03-30 16:52:09
maintainerNone
docs_urlNone
authorRicardo Amaro
requires_python>=3.10
licenseApache-2.0
keywords config kapitan kadet yaml json
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # kadet

Easily define and reuse complex Python objects that serialize into JSON or YAML.

![GitHub Workflow Status](https://img.shields.io/github/workflow/status/kapicorp/kadet/Python%20lint%20and%20tests)

## Example

```python
from kadet import BaseObj
from pprint import pprint

ships = BaseObj()
ships.root.type.container = ["panamax", "suezmax", "post-panamax"]
ships.root.type.carrier = ["conventional", "geared", "gearless"]
ships.root.type.tanker = BaseObj.from_yaml("tankers.yml")

pprint(ships.root)

# output
{'type': {'carrier': ['conventional',
                      'geared',
                      'gearless'],
          'container': ['panamax',
                        'suezmax',
                        'post-panamax'],
          'tanker': ['oil', 'liquified-gas', 'chemical']}}
```

## Installation

Install using `pip install kadet`.

## Overview

### BaseObj

BaseObj implements the basic object that serializes into JSON or YAML.
Setting keys in `self.root` means they will be serialized. Keys can be set as an hierarchy of attributes.

The `self.body()` method is reserved for setting self.root on instantiation.

The example below:

```python
class MyApp(BaseObj):
  def body(self):
    self.root.name = "myapp"
    self.root.inner.foo = "bar"
    self.root.list = [1, 2, 3]

yaml.dump(MyApp().dump())
```

serializes into:

```yaml
---
name: myapp
inner:
  foo: bar
list:
  - 1
  - 2
  - 3
```

The `self.new()` method can be used to define a basic constructor.

`self.need()` checks if a key is set and errors if it isn't (with an optional custom error message).
`self.optional()` sets a key as optional. Use `default` keyword to set default value when not set.

Both `self.new()` and `self.body()` method accept the `istype` keyword to validate value type on runtime.
Supports `typing` types.

`kwargs` that are passed onto a new instance of BaseObj are always accessible via `self.kwargs`

`self.new_with()` is an utility method to call `super().new()` while passing kwargs to the super class.

In this example, MyApp needs `name` and `foo` to be passed as kwargs.

```python
class MyApp(BaseObj):
  def new(self):
    self.need("name")
    self.need("foo", msg="please provide a value for foo")
    self.optional("baz")

  def body(self):
    self.root.name = self.kwargs.name
    self.root.inner.foo = self.kwargs.foo
    self.root.list = [1, 2, 3]

obj = MyApp(name="myapp", foo="bar")
```

### Setting a skeleton

Defining a large body with Python can be quite hard and repetitive to read and write.

The `self.root_file()` method allows importing a YAML/JSON file to set `self.root`.

MyApp's skeleton can be set instead like this:

```yaml
#skel.yml
---
name: myapp
inner:
  foo: bar
list:
  - 1
  - 2
  - 3
```

```python
class MyApp(BaseObj):
  def new(self):
    self.need("name")
    self.need("foo", msg="please provide a value for foo")
    self.root_file("path/to/skel.yml")
```

Extending a MyApp's skeleton is possible just by implementing `self.body()`:

```python
class MyApp(BaseObj):
  def new(self):
    self.need("name")
    self.need("foo", msg="please provide a value for foo")
    self.root_file("path/to/skel.yml")

  def body(self):
    self.set_replicas()
    self.root.metadata.labels = {"app": "mylabel"}

  def set_replicas(self):
    self.root.spec.replicas = 5
```

### Inheritance

Python inheritance will work as expected:

```python

class MyOtherApp(MyApp):
  def new(self):
    super().new()  # MyApp's new()
    self.need("size")

  def body(self):
    super().body()  #  we want to extend MyApp's body
    self.root.size = self.kwargs.size
    del self.root.list  # get rid of "list"

obj = MyOtherApp(name="otherapp1", foo="bar2", size=3)
yaml.dump(obj.dump())
```
serializes to:

```yaml
---
name: otherapp1
inner:
  foo: bar2
replicas: 5
size: 3
```

### BaseModel

BaseModel integrates Kadet semantics with [Pydantic](https://github.com/pydantic/pydantic)'s BaseModel together with powerful data validation and type hinting features.
Just like in BaseObj, keys in `self.root` will be serialized, but kwargs is no longer necessary as BaseModel's parameters are set as attributes in `self`.

The `self.body()` method is reserved for setting self.root on instantiation.

The example below:

```python
class Boat(BaseModel):
  name: str  # Required
  length: int  # Required
  description: str = "I am a boat"  # Default description

  def body(self):
    self.root.name = self.name
    self.root.details.length = self.length
    self.root.details.description = self.description

print(yaml.dump(Boat(name="Boaty", length=600).dump()))

---
details:
  description: I am a boat
  length: 600
name: Boaty
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kapicorp/kadet",
    "name": "kadet",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "config, kapitan, kadet, yaml, json",
    "author": "Ricardo Amaro",
    "author_email": "ramaro@kapicorp.com",
    "download_url": "https://files.pythonhosted.org/packages/96/de/d7f5aa3732c408361ce6e332dd1088dddc97a88e30df0fb0dbcbd47e872e/kadet-0.3.1.tar.gz",
    "platform": null,
    "description": "# kadet\n\nEasily define and reuse complex Python objects that serialize into JSON or YAML.\n\n![GitHub Workflow Status](https://img.shields.io/github/workflow/status/kapicorp/kadet/Python%20lint%20and%20tests)\n\n## Example\n\n```python\nfrom kadet import BaseObj\nfrom pprint import pprint\n\nships = BaseObj()\nships.root.type.container = [\"panamax\", \"suezmax\", \"post-panamax\"]\nships.root.type.carrier = [\"conventional\", \"geared\", \"gearless\"]\nships.root.type.tanker = BaseObj.from_yaml(\"tankers.yml\")\n\npprint(ships.root)\n\n# output\n{'type': {'carrier': ['conventional',\n                      'geared',\n                      'gearless'],\n          'container': ['panamax',\n                        'suezmax',\n                        'post-panamax'],\n          'tanker': ['oil', 'liquified-gas', 'chemical']}}\n```\n\n## Installation\n\nInstall using `pip install kadet`.\n\n## Overview\n\n### BaseObj\n\nBaseObj implements the basic object that serializes into JSON or YAML.\nSetting keys in `self.root` means they will be serialized. Keys can be set as an hierarchy of attributes.\n\nThe `self.body()` method is reserved for setting self.root on instantiation.\n\nThe example below:\n\n```python\nclass MyApp(BaseObj):\n  def body(self):\n    self.root.name = \"myapp\"\n    self.root.inner.foo = \"bar\"\n    self.root.list = [1, 2, 3]\n\nyaml.dump(MyApp().dump())\n```\n\nserializes into:\n\n```yaml\n---\nname: myapp\ninner:\n  foo: bar\nlist:\n  - 1\n  - 2\n  - 3\n```\n\nThe `self.new()` method can be used to define a basic constructor.\n\n`self.need()` checks if a key is set and errors if it isn't (with an optional custom error message).\n`self.optional()` sets a key as optional. Use `default` keyword to set default value when not set.\n\nBoth `self.new()` and `self.body()` method accept the `istype` keyword to validate value type on runtime.\nSupports `typing` types.\n\n`kwargs` that are passed onto a new instance of BaseObj are always accessible via `self.kwargs`\n\n`self.new_with()` is an utility method to call `super().new()` while passing kwargs to the super class.\n\nIn this example, MyApp needs `name` and `foo` to be passed as kwargs.\n\n```python\nclass MyApp(BaseObj):\n  def new(self):\n    self.need(\"name\")\n    self.need(\"foo\", msg=\"please provide a value for foo\")\n    self.optional(\"baz\")\n\n  def body(self):\n    self.root.name = self.kwargs.name\n    self.root.inner.foo = self.kwargs.foo\n    self.root.list = [1, 2, 3]\n\nobj = MyApp(name=\"myapp\", foo=\"bar\")\n```\n\n### Setting a skeleton\n\nDefining a large body with Python can be quite hard and repetitive to read and write.\n\nThe `self.root_file()` method allows importing a YAML/JSON file to set `self.root`.\n\nMyApp's skeleton can be set instead like this:\n\n```yaml\n#skel.yml\n---\nname: myapp\ninner:\n  foo: bar\nlist:\n  - 1\n  - 2\n  - 3\n```\n\n```python\nclass MyApp(BaseObj):\n  def new(self):\n    self.need(\"name\")\n    self.need(\"foo\", msg=\"please provide a value for foo\")\n    self.root_file(\"path/to/skel.yml\")\n```\n\nExtending a MyApp's skeleton is possible just by implementing `self.body()`:\n\n```python\nclass MyApp(BaseObj):\n  def new(self):\n    self.need(\"name\")\n    self.need(\"foo\", msg=\"please provide a value for foo\")\n    self.root_file(\"path/to/skel.yml\")\n\n  def body(self):\n    self.set_replicas()\n    self.root.metadata.labels = {\"app\": \"mylabel\"}\n\n  def set_replicas(self):\n    self.root.spec.replicas = 5\n```\n\n### Inheritance\n\nPython inheritance will work as expected:\n\n```python\n\nclass MyOtherApp(MyApp):\n  def new(self):\n    super().new()  # MyApp's new()\n    self.need(\"size\")\n\n  def body(self):\n    super().body()  #  we want to extend MyApp's body\n    self.root.size = self.kwargs.size\n    del self.root.list  # get rid of \"list\"\n\nobj = MyOtherApp(name=\"otherapp1\", foo=\"bar2\", size=3)\nyaml.dump(obj.dump())\n```\nserializes to:\n\n```yaml\n---\nname: otherapp1\ninner:\n  foo: bar2\nreplicas: 5\nsize: 3\n```\n\n### BaseModel\n\nBaseModel integrates Kadet semantics with [Pydantic](https://github.com/pydantic/pydantic)'s BaseModel together with powerful data validation and type hinting features.\nJust like in BaseObj, keys in `self.root` will be serialized, but kwargs is no longer necessary as BaseModel's parameters are set as attributes in `self`.\n\nThe `self.body()` method is reserved for setting self.root on instantiation.\n\nThe example below:\n\n```python\nclass Boat(BaseModel):\n  name: str  # Required\n  length: int  # Required\n  description: str = \"I am a boat\"  # Default description\n\n  def body(self):\n    self.root.name = self.name\n    self.root.details.length = self.length\n    self.root.details.description = self.description\n\nprint(yaml.dump(Boat(name=\"Boaty\", length=600).dump()))\n\n---\ndetails:\n  description: I am a boat\n  length: 600\nname: Boaty\n```\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Easily define and reuse complex Python objects that serialize into JSON or YAML.",
    "version": "0.3.1",
    "project_urls": {
        "Homepage": "https://github.com/kapicorp/kadet",
        "Repository": "https://github.com/kapicorp/kadet"
    },
    "split_keywords": [
        "config",
        " kapitan",
        " kadet",
        " yaml",
        " json"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2475cf93d7f9312330d8c0cefc95aeadc4f26099f7280de5fdd92bb5582919ec",
                "md5": "3a8a883cf35328910aa3cfbafaa69f2c",
                "sha256": "9b29a316af7d51a57defe859c42d388531f53c87a56ba1816afe152b21d62338"
            },
            "downloads": -1,
            "filename": "kadet-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3a8a883cf35328910aa3cfbafaa69f2c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 8860,
            "upload_time": "2024-03-30T16:52:08",
            "upload_time_iso_8601": "2024-03-30T16:52:08.752352Z",
            "url": "https://files.pythonhosted.org/packages/24/75/cf93d7f9312330d8c0cefc95aeadc4f26099f7280de5fdd92bb5582919ec/kadet-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "96ded7f5aa3732c408361ce6e332dd1088dddc97a88e30df0fb0dbcbd47e872e",
                "md5": "c3a84b7a138ebb1844470bb72df6d9e2",
                "sha256": "bfe727c3e695dcf2b936de810c6aef9cbed9ab907c1f4120a179963835ea3957"
            },
            "downloads": -1,
            "filename": "kadet-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "c3a84b7a138ebb1844470bb72df6d9e2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 8404,
            "upload_time": "2024-03-30T16:52:09",
            "upload_time_iso_8601": "2024-03-30T16:52:09.943112Z",
            "url": "https://files.pythonhosted.org/packages/96/de/d7f5aa3732c408361ce6e332dd1088dddc97a88e30df0fb0dbcbd47e872e/kadet-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-30 16:52:09",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kapicorp",
    "github_project": "kadet",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "kadet"
}
        
Elapsed time: 0.22052s