Name | objdict-bf JSON |
Version |
0.1.24
JSON |
| download |
home_page | https://github.com/B4PT0R/objdict |
Summary | A custom wrapper object around dict that allows attribute-style access to dictionary items and support for serialization of nested data. |
upload_time | 2024-01-14 11:25:49 |
maintainer | |
docs_url | None |
author | Baptiste Ferrand |
requires_python | >=3.6 |
license | |
keywords |
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# objdict-bf
`objdict-bf` is a Python module that provides a wrapper class to conveniently manipulate dictionaries or dict-based nested structures using attribute-like syntax. It is intended mostly to ease manipulation of serialized data, web requests and responses, configuration files, dynamic prototyping...
## Features
- Attribute-style access to dictionary items (e.g., `obj.key` instead of `obj['key']`).
- Synchronization with the original dictionary if passed at instantiation.
- Utility methods for recursive conversion of nested structures to and from `objdict` and `dict`.
- Serialization and deserialization methods for both strings and files with json, toml, yaml and jsonpickle backend support.
- Advanced default value attribution features for missing keys.
- optional object-like behavior, by auto-passing the objdict instance as 'self' to callable attributes having 'self' in their signature.
## Installation
```bash
pip install objdict-bf
```
## Signature of the constructor
```python
objdict(*args,_use_default=False,_default=None,_file=None,_backend=None,_auto_self=False,**kwargs)
```
Parameters:
- `*args`: either dicts, objdicts or iterables on key:value pairs. If the first arg is a dict, it will serve as the internal _data_dict of the objdict instance.
- `_use_default`: boolean, determines if a default value is attributed to missing keys
- `_default`: can be any value or callable. If it is callable with adequate signature, this callable will be used to handle default values generation.
- `_file`: reference to a file path for dumping (extension must match the backend used)
- `_backend`: either 'json', 'toml','yaml' or 'jsonpickle'. Determines the backend used for serialization/deserialization when dumping/loading (None defaults to 'json').
- `_auto_self`: boolean. Determines if the instance is auto-passed a 'self' to its callable attributes having 'self' in their signature (mocked object behavior).
- `**kwargs`: key value pairs passed as kwargs to update the objdict
## Usage
```python
from objdict_bf import objdict
# Create an objdict with some initial data
data = objdict(
name='John',
age=30,
location='New York'
)
#Or synchronize with an existing dict
d={'name': 'John', 'age': 30, 'location': 'New York'}
data = objdict(d)
#Access data using attribute-style access
print(data.name) # Output: John
print(data.age) # Output: 30
#Modify data
data.age = 31
#Create a new key:value pair
data.job='developer'
#Changes are reflected on the original dict
print(d['age']) #Ouput: 31
print(d['job']) #Ouput: 'developer'
#Chaining attributes is supported for nested structures involving lists
d={
'profile':{
'name':'John',
'hobbies':[
{'type':'sport','title':'tennis'},
{'type':'music','title':'guitar playing'}
]
}
}
data = objdict(d)
print(data) #Output: the repr of the above dict
print(data.profile.hobbies[1].title) #Output: guitar playing
#Conversion of dict items to their objdict version is automatic upon access.
#The created objdicts will inherit the parent objdict settings, namely: _backend,_use_default, _default, _auto_self).
#The objdict being essentially a wrapper interface on the initial dict,
#this conversion is reflected in the initial dict content as well
print(isinstance(data.profile.hobbies[1],objdict)) #Output: True
print(isinstance(d['profile']['hobbies'][1],objdict)) #Output: True
#to_dict returns the underlying dict, converting recursively all objdicts found in the nested structure back to dicts
print(d is data.to_dict()) #Ouptut: True
print(isinstance(d['profile']['hobbies'][1], dict)) #Output: True
#-----------------------------Serialization-------------------------------
# Serialize to JSON string
json_string = data.dumps()
print(json_string)
#or use another backend for serialization
toml_string=data.dumps(_backend='toml')
print(toml_string)
#dump to a file
data.dump("my_json_file.json")
#or
data.dump("my_toml_file.toml",_backend='toml')
#make some more changes
data.email="dummy.email@gmail.com"
#the reference to the file and backend preference from the last dump is kept in the objdict instance so you don't have to pass them again
data.dump()
# Deserialize from a string (new instance keeping reference to the chosen backend)
data = objdict.loads(json_string)
#or
data = objdict.loads(toml_string,_backend='toml')
# Deserialize from a file (new instance keeping reference to the chosen file and backend)
data = objdict.load("my_json_file.json")
#or
data = objdict.load("my_toml_file.toml",_backend='toml')
#Mismatching file extension and backend will throw an exception
#any class method creating a new instance can be passed parameters accepted in the objdict constructor to control the properties of the created instance:
data = objdict.loads(string,_backend='json',_use_default=True,_default=None,_auto_self=False)
data = objdict.load(file,_backend='toml',_use_default=False,_auto_self=True)
#update data
data.email="dummy.email@gmail.com"
data.user="dummy_username"
#dump changes to the file using the previously chosen backend
data.dump()
#-------------------Working with default value generators-------------------
#Default value (None) when accessing a missing key
obj=objdict(_use_default=True)
#Will set the value to None and won't raise a KeyError
print(obj.a) #Output: None
#Or, choose a default value
obj=objdict(_use_default=True,_default=3)
#Missing key will be initialized to 3 and returned
print(obj.a) #Output: 3
#Or pass a default value generator depending on the key (must have 'key' in its signature)
default_gen=lambda key: f"Missing key: {key}"
obj=objdict(_use_default=True,_default=default_gen)
print(obj.a) #Output: "Missing key: a"
print(obj.b) #Output: "Missing key: b"
#Or pass a default value generator whose output depends on the current state/content of the objdict
#Must have 'self' in its signature
#Will use 'self' as the keyword refering to the current objdict instance
def default_gen(self):
if 'a' in self:
return self.a.value
else:
return objdict(value=5)
obj=objdict(_use_default=True,_default=default_gen)
print(obj.a) #Output: {'value':5}
print(obj.b) #Output: 5
#Accepted signature of default value generators are () ; (self,); (key,) ; (self,key)
#This allows implementing context-aware and key-dependant logic for default value attribution.
#Any other signature will be considered invalid and will fall back to assign the callable itself as the default value for all keys.
#Example: Using a default value generator to automatically create new child objdict instances inheriting the parent's settings when accessing missing keys
def child_instance(self):
return objdict(_use_default=True,_default=child_instance,_backend=self._backend,_auto_self=self._auto_self)
obj=objdict(_use_default=True,_default=child_instance,_backend='toml',_auto_self=True)
obj.a.b.c=3
print(obj) #Output: {'a':{'b':{'c':3}}}
#child elements inherit the chosen parent properties
print(obj.a.b._backend) #Output: 'toml'
print(obj.a.b._auto_self) #Output: True
#The child_instance generator hard-coded above is already implemented as the objdict.child_instance static method which you may pass as _default parameter
obj=objdict(_use_default=True,_default=objdict.child_instance)
obj.a.b.c=3
print(obj) #Output: {'a':{'b':{'c':3}}}
#--------------------------------Mock objects-------------------------------
#Using the objdict as a mocked object with context aware methods thanks to the _auto_self parameter which automatically passes the objdict instance as 'self' to callable attributes having 'self' as first parameter in their signature.
obj=objdict(_auto_self=True)
obj.a=2
#create a function with 'self' as first parameter (any other name won't receive the instance)
def add_to_a(self,b):
self.a+=b
#attach the function as attribute
obj.add_to_a=add_to_a
obj.add_to_a(3)
print(obj.a) #output 5
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": "https://github.com/B4PT0R/objdict",
"name": "objdict-bf",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "",
"author": "Baptiste Ferrand",
"author_email": "bferrand.maths@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/9e/46/6b4582171b00f79a8c40346cc8a23a782afad51b759814796590b3ad850a/objdict_bf-0.1.24.tar.gz",
"platform": null,
"description": "# objdict-bf\n\n`objdict-bf` is a Python module that provides a wrapper class to conveniently manipulate dictionaries or dict-based nested structures using attribute-like syntax. It is intended mostly to ease manipulation of serialized data, web requests and responses, configuration files, dynamic prototyping...\n\n## Features\n\n- Attribute-style access to dictionary items (e.g., `obj.key` instead of `obj['key']`).\n- Synchronization with the original dictionary if passed at instantiation.\n- Utility methods for recursive conversion of nested structures to and from `objdict` and `dict`.\n- Serialization and deserialization methods for both strings and files with json, toml, yaml and jsonpickle backend support.\n- Advanced default value attribution features for missing keys. \n- optional object-like behavior, by auto-passing the objdict instance as 'self' to callable attributes having 'self' in their signature.\n\n## Installation\n\n```bash\npip install objdict-bf\n```\n\n## Signature of the constructor\n\n```python\nobjdict(*args,_use_default=False,_default=None,_file=None,_backend=None,_auto_self=False,**kwargs)\n```\n\nParameters:\n- `*args`: either dicts, objdicts or iterables on key:value pairs. If the first arg is a dict, it will serve as the internal _data_dict of the objdict instance.\n- `_use_default`: boolean, determines if a default value is attributed to missing keys\n- `_default`: can be any value or callable. If it is callable with adequate signature, this callable will be used to handle default values generation.\n- `_file`: reference to a file path for dumping (extension must match the backend used)\n- `_backend`: either 'json', 'toml','yaml' or 'jsonpickle'. Determines the backend used for serialization/deserialization when dumping/loading (None defaults to 'json').\n- `_auto_self`: boolean. Determines if the instance is auto-passed a 'self' to its callable attributes having 'self' in their signature (mocked object behavior).\n- `**kwargs`: key value pairs passed as kwargs to update the objdict\n\n\n## Usage\n\n```python\nfrom objdict_bf import objdict\n\n# Create an objdict with some initial data\ndata = objdict(\n name='John',\n age=30,\n location='New York'\n)\n\n#Or synchronize with an existing dict\nd={'name': 'John', 'age': 30, 'location': 'New York'}\ndata = objdict(d)\n\n#Access data using attribute-style access\nprint(data.name) # Output: John\nprint(data.age) # Output: 30\n\n#Modify data\ndata.age = 31\n\n#Create a new key:value pair\ndata.job='developer'\n\n#Changes are reflected on the original dict\nprint(d['age']) #Ouput: 31\nprint(d['job']) #Ouput: 'developer'\n\n#Chaining attributes is supported for nested structures involving lists\nd={\n 'profile':{\n 'name':'John',\n 'hobbies':[\n {'type':'sport','title':'tennis'},\n {'type':'music','title':'guitar playing'}\n ]\n }\n}\ndata = objdict(d)\n\nprint(data) #Output: the repr of the above dict\nprint(data.profile.hobbies[1].title) #Output: guitar playing\n\n#Conversion of dict items to their objdict version is automatic upon access. \n#The created objdicts will inherit the parent objdict settings, namely: _backend,_use_default, _default, _auto_self).\n#The objdict being essentially a wrapper interface on the initial dict, \n#this conversion is reflected in the initial dict content as well\n\nprint(isinstance(data.profile.hobbies[1],objdict)) #Output: True\nprint(isinstance(d['profile']['hobbies'][1],objdict)) #Output: True\n\n#to_dict returns the underlying dict, converting recursively all objdicts found in the nested structure back to dicts\nprint(d is data.to_dict()) #Ouptut: True\nprint(isinstance(d['profile']['hobbies'][1], dict)) #Output: True \n\n#-----------------------------Serialization-------------------------------\n\n# Serialize to JSON string\njson_string = data.dumps()\nprint(json_string)\n#or use another backend for serialization \ntoml_string=data.dumps(_backend='toml')\nprint(toml_string)\n\n#dump to a file\ndata.dump(\"my_json_file.json\")\n#or\ndata.dump(\"my_toml_file.toml\",_backend='toml')\n\n#make some more changes\ndata.email=\"dummy.email@gmail.com\"\n\n#the reference to the file and backend preference from the last dump is kept in the objdict instance so you don't have to pass them again\ndata.dump()\n\n# Deserialize from a string (new instance keeping reference to the chosen backend)\ndata = objdict.loads(json_string)\n#or\ndata = objdict.loads(toml_string,_backend='toml')\n\n\n# Deserialize from a file (new instance keeping reference to the chosen file and backend)\ndata = objdict.load(\"my_json_file.json\")\n#or\ndata = objdict.load(\"my_toml_file.toml\",_backend='toml')\n\n#Mismatching file extension and backend will throw an exception \n\n#any class method creating a new instance can be passed parameters accepted in the objdict constructor to control the properties of the created instance:\ndata = objdict.loads(string,_backend='json',_use_default=True,_default=None,_auto_self=False)\ndata = objdict.load(file,_backend='toml',_use_default=False,_auto_self=True)\n\n#update data\ndata.email=\"dummy.email@gmail.com\"\ndata.user=\"dummy_username\"\n\n#dump changes to the file using the previously chosen backend \ndata.dump()\n\n#-------------------Working with default value generators-------------------\n\n\n#Default value (None) when accessing a missing key\nobj=objdict(_use_default=True)\n\n#Will set the value to None and won't raise a KeyError\nprint(obj.a) #Output: None\n\n#Or, choose a default value\nobj=objdict(_use_default=True,_default=3)\n#Missing key will be initialized to 3 and returned\nprint(obj.a) #Output: 3\n\n#Or pass a default value generator depending on the key (must have 'key' in its signature)\ndefault_gen=lambda key: f\"Missing key: {key}\" \nobj=objdict(_use_default=True,_default=default_gen)\nprint(obj.a) #Output: \"Missing key: a\"\nprint(obj.b) #Output: \"Missing key: b\"\n\n#Or pass a default value generator whose output depends on the current state/content of the objdict\n#Must have 'self' in its signature\n#Will use 'self' as the keyword refering to the current objdict instance\ndef default_gen(self):\n if 'a' in self:\n return self.a.value\n else:\n return objdict(value=5)\n \nobj=objdict(_use_default=True,_default=default_gen)\nprint(obj.a) #Output: {'value':5}\nprint(obj.b) #Output: 5\n\n#Accepted signature of default value generators are () ; (self,); (key,) ; (self,key)\n#This allows implementing context-aware and key-dependant logic for default value attribution. \n#Any other signature will be considered invalid and will fall back to assign the callable itself as the default value for all keys.\n\n#Example: Using a default value generator to automatically create new child objdict instances inheriting the parent's settings when accessing missing keys\ndef child_instance(self):\n return objdict(_use_default=True,_default=child_instance,_backend=self._backend,_auto_self=self._auto_self)\n\nobj=objdict(_use_default=True,_default=child_instance,_backend='toml',_auto_self=True)\nobj.a.b.c=3\nprint(obj) #Output: {'a':{'b':{'c':3}}}\n#child elements inherit the chosen parent properties\nprint(obj.a.b._backend) #Output: 'toml'\nprint(obj.a.b._auto_self) #Output: True\n\n#The child_instance generator hard-coded above is already implemented as the objdict.child_instance static method which you may pass as _default parameter\nobj=objdict(_use_default=True,_default=objdict.child_instance)\nobj.a.b.c=3\nprint(obj) #Output: {'a':{'b':{'c':3}}}\n\n#--------------------------------Mock objects-------------------------------\n\n#Using the objdict as a mocked object with context aware methods thanks to the _auto_self parameter which automatically passes the objdict instance as 'self' to callable attributes having 'self' as first parameter in their signature.\n\nobj=objdict(_auto_self=True)\nobj.a=2\n\n#create a function with 'self' as first parameter (any other name won't receive the instance)\ndef add_to_a(self,b):\n self.a+=b\n\n#attach the function as attribute\nobj.add_to_a=add_to_a\nobj.add_to_a(3)\nprint(obj.a) #output 5\n\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": "",
"summary": "A custom wrapper object around dict that allows attribute-style access to dictionary items and support for serialization of nested data.",
"version": "0.1.24",
"project_urls": {
"Homepage": "https://github.com/B4PT0R/objdict"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5a87a4f262ca9b3045c3e92fd44117192bfc6ef7a876faaa23dd0f82b21172a1",
"md5": "9484c01ec88866fb92eb283bb1778a7a",
"sha256": "62baae1fe236cdec2f624588813322d97c2b48b6add5e13fdba2e83ed3662ca5"
},
"downloads": -1,
"filename": "objdict_bf-0.1.24-py3-none-any.whl",
"has_sig": false,
"md5_digest": "9484c01ec88866fb92eb283bb1778a7a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 10032,
"upload_time": "2024-01-14T11:25:47",
"upload_time_iso_8601": "2024-01-14T11:25:47.217882Z",
"url": "https://files.pythonhosted.org/packages/5a/87/a4f262ca9b3045c3e92fd44117192bfc6ef7a876faaa23dd0f82b21172a1/objdict_bf-0.1.24-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "9e466b4582171b00f79a8c40346cc8a23a782afad51b759814796590b3ad850a",
"md5": "0529be31fce42df98e2e361210f284f8",
"sha256": "bd5c76495bb18fc6d36ee5c089ca4c17309356f64c01df3d9a61c336a24f69fe"
},
"downloads": -1,
"filename": "objdict_bf-0.1.24.tar.gz",
"has_sig": false,
"md5_digest": "0529be31fce42df98e2e361210f284f8",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 11959,
"upload_time": "2024-01-14T11:25:49",
"upload_time_iso_8601": "2024-01-14T11:25:49.060213Z",
"url": "https://files.pythonhosted.org/packages/9e/46/6b4582171b00f79a8c40346cc8a23a782afad51b759814796590b3ad850a/objdict_bf-0.1.24.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-01-14 11:25:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "B4PT0R",
"github_project": "objdict",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "objdict-bf"
}