jsonobjectify 0.0.0__tar.gz → 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sandeep Suryaprasad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: jsonobjectify
3
+ Version: 0.1.1
4
+ Summary: A lightweight Python library for converting JSON data into Python objects, simplifying access to nested structures through intuitive dot notation.
5
+ Keywords: json-parsing,Attribute lookup,automated-json-parsing
6
+ Author: Sandeep Suryaprasad
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Python: >=3.12
15
+ Project-URL: Homepage, https://github.com/sandeepsuryaprasad/jsonobjectify
16
+ Project-URL: Repository, https://github.com/sandeepsuryaprasad/jsonobjectify
17
+ Project-URL: Issues, https://github.com/sandeepsuryaprasad/jsonobjectify/issues
18
+ Description-Content-Type: text/markdown
19
+
20
+ # jsonobjectify
21
+
22
+ [![CI](https://github.com/sandeepsuryaprasad/jsonobjectify/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sandeepsuryaprasad/jsonobjectify/actions/workflows/ci.yml)
23
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
24
+ [![PyPI version](https://img.shields.io/pypi/v/jsonobjectify)](https://pypi.org/project/jsonobjectify/)
25
+ [![Python versions](https://img.shields.io/pypi/pyversions/jsonobjectify)](https://pypi.org/project/jsonobjectify/)
26
+
27
+ A lightweight Python library for converting JSON data into Python objects,
28
+ simplifying access to nested structures through dot notation. Instead of writing chained
29
+ dictionary lookups, you can navigate nested JSON structures using a clean, readable,
30
+ object-oriented interface.
31
+
32
+ ## Installation
33
+
34
+ ```console
35
+ pip install jsonobjectify
36
+ ```
37
+
38
+ ## Usage
39
+ Consider the following JSON data representing an employee and their department:
40
+
41
+ ```python
42
+ response = """{
43
+ "id": 1,
44
+ "name": "John Doe",
45
+ "email": "john.doe@example.com",
46
+ "website": "www.example.dev",
47
+ "address": {
48
+ "city": "Austin",
49
+ "state": "TX",
50
+ "country": "United States",
51
+ "geo_location": {"lat": "30.2672", "lng": "-97.7431"}
52
+ },
53
+ "skills": [
54
+ {"name": "Python", "level": "Advanced"},
55
+ {"name": "C", "level": "Advanced"},
56
+ {"name": "C++", "level": "Intermediate"}
57
+ ]
58
+ }"""
59
+ ```
60
+ ### Create `JsonPath` object from JSON string.
61
+ Here, response is a string containing valid JSON. The `from_string` class method parses
62
+ the JSON data and creates a `JsonPath` object that allows you to access properties using
63
+ dot notation.
64
+ ```console
65
+ >>> employee = JsonPath.from_string(response)
66
+ ```
67
+ You can now access and traverse nested JSON objects using **dot notation**.
68
+ For JSON arrays, use the standard Python indexing syntax.
69
+ ```console
70
+ >>> employee.name
71
+ 'John Doe'
72
+ >>> employee.address.city
73
+ 'Austin'
74
+ >>> employee.address.geo_location.lng
75
+ '-97.7431'
76
+ >>> employee.skills[0].name
77
+ 'Python'
78
+ >>> employee.skills[1].level
79
+ 'Advanced'
80
+ >>>
81
+ ```
82
+ You can also iterate over JSON arrays using a standard Python for loop and access each
83
+ element's properties using dot notation.
84
+ ```console
85
+ >>> for skill in employee.skills:
86
+ ... print(f"{skill.name}, {skill.level}")
87
+ ...
88
+ Python, Advanced
89
+ C, Advanced
90
+ C++, Intermediate
91
+ >>>
92
+ ```
93
+ ### Root response is an array of JSON objects
94
+ A JSON response can contain an array of objects at the root level. You can use
95
+ `JsonPath.from_string` to parse the response and access each object's properties using
96
+ dot notation.
97
+ ```python
98
+ response = """[
99
+ {
100
+ "name": "Olivia Bennett",
101
+ "email": "olivia.bennett@example.com",
102
+ "website": "www.example.dev"
103
+ },
104
+ {
105
+ "name": "Ethan Parker",
106
+ "email": "ethan.parker@example.com",
107
+ "website": "www.example.io"
108
+ },
109
+ {
110
+ "name": "Sophia Turner",
111
+ "email": "sophia.turner@example.com",
112
+ "website": "www.example.edu"
113
+ }
114
+ ]"""
115
+ ```
116
+ ```console
117
+ >>> employees = JsonPath.from_string(response)
118
+ >>> employees[0]
119
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7d50>
120
+ >>> employees[1]
121
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7b50>
122
+ >>> employees[2]
123
+ <jsonobjectify.jsonobject.JsonObject object at 0x101aa2120>
124
+ >>> employees[0].name
125
+ 'Olivia Bennett'
126
+ >>> employees[0].email
127
+ 'olivia.bennett@example.com'
128
+ >>> employees[0].website
129
+ 'www.example.dev'
130
+ >>>
131
+ ```
132
+ You can also iterate over JSON arrays using a standard Python for loop and access each
133
+ element's properties using dot notation.
134
+ ```console
135
+ >>> for employee in employees:
136
+ ... print(f"{employee.name}, {employee.email}, {employee.website}")
137
+ ...
138
+ Olivia Bennett, olivia.bennett@example.com, www.example.dev
139
+ Ethan Parker, ethan.parker@example.com, www.example.io
140
+ Sophia Turner, sophia.turner@example.com, www.example.edu
141
+ >>>
142
+ ```
143
+
144
+ ### Create a `JsonPath` object from a JSON file
145
+ You can also create a JsonPath object directly from a JSON file using the `from_file`
146
+ class method. This allows you to work with JSON data stored in a file without having to
147
+ read and parse its contents manually.
148
+
149
+ For example, consider an `employee.json` file containing the employee data shown in the
150
+ previous example.
151
+
152
+ ```console
153
+ >>> employee = JsonPath.from_file("employee.json")
154
+ ```
155
+ Once the object is created, you can access nested properties and iterate over JSON arrays
156
+ in the same way
157
+
158
+ ```console
159
+ >>> employee.name
160
+ 'Michael Anderson'
161
+ >>> employee.address.city
162
+ 'Austin'
163
+ >>> for skill in employee.skills:
164
+ ... print(f"{skill.name}, {skill.level}")
165
+ ...
166
+ Python, Advanced
167
+ C, Advanced
168
+ C++, Intermediate
169
+ ```
170
+
171
+ ### Working with Scalar Values
172
+ If the **root JSON** value is a scalar, such as a string, number, boolean or null, you can
173
+ access the underlying value using the `value` property.
174
+
175
+ ```console
176
+ >>> data = JsonPath.from_string("26")
177
+ >>> data.value
178
+ 26
179
+ >>> data = JsonPath.from_string("true")
180
+ >>> data.value
181
+ True
182
+ >>> data = JsonPath.from_string("null")
183
+ >>> data.value
184
+ >>>
185
+ >>> json = JsonPath.from_string('"hello world"')
186
+ >>> json.value
187
+ 'hello world'
188
+ ```
189
+ ### Accessing JSON Properties with Normalized Keys
190
+ JSON property names may contain hyphens, spaces, or periods, which cannot be used directly
191
+ in Python attribute names. jsonobjectify normalizes these characters to underscores,
192
+ allowing you to access such properties using dot notation.
193
+
194
+ ```python
195
+ response = """{
196
+ "first-name": "Olivia",
197
+ "job title": "Software Engineer",
198
+ "contact.email": "olivia@example.com"
199
+ }"""
200
+ ```
201
+ ```console
202
+ >>> employee = JsonPath.from_string(response)
203
+ ```
204
+ You can access these properties using normalized attribute names,
205
+
206
+ ```console
207
+ >>> employee.first_name
208
+ 'Olivia'
209
+ >>> employee.job_title
210
+ 'Software Engineer'
211
+ >>> employee.contact_email
212
+ 'olivia@example.com'
213
+ ```
214
+ **The original JSON property names are preserved when converting the object back to
215
+ a dictionary or JSON string.**
216
+
217
+ ### Converting Objects Back to JSON
218
+
219
+ `jsonobjectify` is intended to support conversion back to standard Python dictionaries and
220
+ JSON strings, making it convenient to work with transformed data.
221
+
222
+ ```python
223
+ # Convert the object to a Python dictionary
224
+ data = employee.to_dict()
225
+
226
+ # Serialize the object to a JSON string
227
+ json_data = employee.to_json()
228
+ ```
229
+
230
+ ### Requirements
231
+ * Python 3.12 or later
232
+
233
+ ### Contributing
234
+ Contributions, bug reports, and feature suggestions are welcome. Please open an issue to
235
+ discuss a proposed change before submitting a pull request.
236
+
237
+ ### License
238
+
239
+ This package is distributed under the terms of [MIT](https://github.com/sandeepsuryaprasad/jsonobjectify/blob/main/LICENSE) license
@@ -0,0 +1,220 @@
1
+ # jsonobjectify
2
+
3
+ [![CI](https://github.com/sandeepsuryaprasad/jsonobjectify/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sandeepsuryaprasad/jsonobjectify/actions/workflows/ci.yml)
4
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
5
+ [![PyPI version](https://img.shields.io/pypi/v/jsonobjectify)](https://pypi.org/project/jsonobjectify/)
6
+ [![Python versions](https://img.shields.io/pypi/pyversions/jsonobjectify)](https://pypi.org/project/jsonobjectify/)
7
+
8
+ A lightweight Python library for converting JSON data into Python objects,
9
+ simplifying access to nested structures through dot notation. Instead of writing chained
10
+ dictionary lookups, you can navigate nested JSON structures using a clean, readable,
11
+ object-oriented interface.
12
+
13
+ ## Installation
14
+
15
+ ```console
16
+ pip install jsonobjectify
17
+ ```
18
+
19
+ ## Usage
20
+ Consider the following JSON data representing an employee and their department:
21
+
22
+ ```python
23
+ response = """{
24
+ "id": 1,
25
+ "name": "John Doe",
26
+ "email": "john.doe@example.com",
27
+ "website": "www.example.dev",
28
+ "address": {
29
+ "city": "Austin",
30
+ "state": "TX",
31
+ "country": "United States",
32
+ "geo_location": {"lat": "30.2672", "lng": "-97.7431"}
33
+ },
34
+ "skills": [
35
+ {"name": "Python", "level": "Advanced"},
36
+ {"name": "C", "level": "Advanced"},
37
+ {"name": "C++", "level": "Intermediate"}
38
+ ]
39
+ }"""
40
+ ```
41
+ ### Create `JsonPath` object from JSON string.
42
+ Here, response is a string containing valid JSON. The `from_string` class method parses
43
+ the JSON data and creates a `JsonPath` object that allows you to access properties using
44
+ dot notation.
45
+ ```console
46
+ >>> employee = JsonPath.from_string(response)
47
+ ```
48
+ You can now access and traverse nested JSON objects using **dot notation**.
49
+ For JSON arrays, use the standard Python indexing syntax.
50
+ ```console
51
+ >>> employee.name
52
+ 'John Doe'
53
+ >>> employee.address.city
54
+ 'Austin'
55
+ >>> employee.address.geo_location.lng
56
+ '-97.7431'
57
+ >>> employee.skills[0].name
58
+ 'Python'
59
+ >>> employee.skills[1].level
60
+ 'Advanced'
61
+ >>>
62
+ ```
63
+ You can also iterate over JSON arrays using a standard Python for loop and access each
64
+ element's properties using dot notation.
65
+ ```console
66
+ >>> for skill in employee.skills:
67
+ ... print(f"{skill.name}, {skill.level}")
68
+ ...
69
+ Python, Advanced
70
+ C, Advanced
71
+ C++, Intermediate
72
+ >>>
73
+ ```
74
+ ### Root response is an array of JSON objects
75
+ A JSON response can contain an array of objects at the root level. You can use
76
+ `JsonPath.from_string` to parse the response and access each object's properties using
77
+ dot notation.
78
+ ```python
79
+ response = """[
80
+ {
81
+ "name": "Olivia Bennett",
82
+ "email": "olivia.bennett@example.com",
83
+ "website": "www.example.dev"
84
+ },
85
+ {
86
+ "name": "Ethan Parker",
87
+ "email": "ethan.parker@example.com",
88
+ "website": "www.example.io"
89
+ },
90
+ {
91
+ "name": "Sophia Turner",
92
+ "email": "sophia.turner@example.com",
93
+ "website": "www.example.edu"
94
+ }
95
+ ]"""
96
+ ```
97
+ ```console
98
+ >>> employees = JsonPath.from_string(response)
99
+ >>> employees[0]
100
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7d50>
101
+ >>> employees[1]
102
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7b50>
103
+ >>> employees[2]
104
+ <jsonobjectify.jsonobject.JsonObject object at 0x101aa2120>
105
+ >>> employees[0].name
106
+ 'Olivia Bennett'
107
+ >>> employees[0].email
108
+ 'olivia.bennett@example.com'
109
+ >>> employees[0].website
110
+ 'www.example.dev'
111
+ >>>
112
+ ```
113
+ You can also iterate over JSON arrays using a standard Python for loop and access each
114
+ element's properties using dot notation.
115
+ ```console
116
+ >>> for employee in employees:
117
+ ... print(f"{employee.name}, {employee.email}, {employee.website}")
118
+ ...
119
+ Olivia Bennett, olivia.bennett@example.com, www.example.dev
120
+ Ethan Parker, ethan.parker@example.com, www.example.io
121
+ Sophia Turner, sophia.turner@example.com, www.example.edu
122
+ >>>
123
+ ```
124
+
125
+ ### Create a `JsonPath` object from a JSON file
126
+ You can also create a JsonPath object directly from a JSON file using the `from_file`
127
+ class method. This allows you to work with JSON data stored in a file without having to
128
+ read and parse its contents manually.
129
+
130
+ For example, consider an `employee.json` file containing the employee data shown in the
131
+ previous example.
132
+
133
+ ```console
134
+ >>> employee = JsonPath.from_file("employee.json")
135
+ ```
136
+ Once the object is created, you can access nested properties and iterate over JSON arrays
137
+ in the same way
138
+
139
+ ```console
140
+ >>> employee.name
141
+ 'Michael Anderson'
142
+ >>> employee.address.city
143
+ 'Austin'
144
+ >>> for skill in employee.skills:
145
+ ... print(f"{skill.name}, {skill.level}")
146
+ ...
147
+ Python, Advanced
148
+ C, Advanced
149
+ C++, Intermediate
150
+ ```
151
+
152
+ ### Working with Scalar Values
153
+ If the **root JSON** value is a scalar, such as a string, number, boolean or null, you can
154
+ access the underlying value using the `value` property.
155
+
156
+ ```console
157
+ >>> data = JsonPath.from_string("26")
158
+ >>> data.value
159
+ 26
160
+ >>> data = JsonPath.from_string("true")
161
+ >>> data.value
162
+ True
163
+ >>> data = JsonPath.from_string("null")
164
+ >>> data.value
165
+ >>>
166
+ >>> json = JsonPath.from_string('"hello world"')
167
+ >>> json.value
168
+ 'hello world'
169
+ ```
170
+ ### Accessing JSON Properties with Normalized Keys
171
+ JSON property names may contain hyphens, spaces, or periods, which cannot be used directly
172
+ in Python attribute names. jsonobjectify normalizes these characters to underscores,
173
+ allowing you to access such properties using dot notation.
174
+
175
+ ```python
176
+ response = """{
177
+ "first-name": "Olivia",
178
+ "job title": "Software Engineer",
179
+ "contact.email": "olivia@example.com"
180
+ }"""
181
+ ```
182
+ ```console
183
+ >>> employee = JsonPath.from_string(response)
184
+ ```
185
+ You can access these properties using normalized attribute names,
186
+
187
+ ```console
188
+ >>> employee.first_name
189
+ 'Olivia'
190
+ >>> employee.job_title
191
+ 'Software Engineer'
192
+ >>> employee.contact_email
193
+ 'olivia@example.com'
194
+ ```
195
+ **The original JSON property names are preserved when converting the object back to
196
+ a dictionary or JSON string.**
197
+
198
+ ### Converting Objects Back to JSON
199
+
200
+ `jsonobjectify` is intended to support conversion back to standard Python dictionaries and
201
+ JSON strings, making it convenient to work with transformed data.
202
+
203
+ ```python
204
+ # Convert the object to a Python dictionary
205
+ data = employee.to_dict()
206
+
207
+ # Serialize the object to a JSON string
208
+ json_data = employee.to_json()
209
+ ```
210
+
211
+ ### Requirements
212
+ * Python 3.12 or later
213
+
214
+ ### Contributing
215
+ Contributions, bug reports, and feature suggestions are welcome. Please open an issue to
216
+ discuss a proposed change before submitting a pull request.
217
+
218
+ ### License
219
+
220
+ This package is distributed under the terms of [MIT](https://github.com/sandeepsuryaprasad/jsonobjectify/blob/main/LICENSE) license
@@ -1,9 +1,27 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.9.13,<0.12.0"]
3
+ build-backend = "uv_build"
4
+
1
5
  [project]
2
6
  name = "jsonobjectify"
3
- version = "0.0.0"
7
+ version = "0.1.1"
4
8
  description = "A lightweight Python library for converting JSON data into Python objects, simplifying access to nested structures through intuitive dot notation."
5
9
  readme = "README.md"
6
- requires-python = ">=3.9"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ keywords = [
14
+ "json-parsing",
15
+ "Attribute lookup",
16
+ "automated-json-parsing",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Topic :: Software Development :: Libraries :: Python Modules",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ ]
7
25
  dependencies = []
8
26
 
9
27
  [[project.authors]]
@@ -14,19 +32,13 @@ Homepage = "https://github.com/sandeepsuryaprasad/jsonobjectify"
14
32
  Repository = "https://github.com/sandeepsuryaprasad/jsonobjectify"
15
33
  Issues = "https://github.com/sandeepsuryaprasad/jsonobjectify/issues"
16
34
 
35
+ [dependency-groups]
36
+ test = ["pytest>=8.0.0"]
37
+ lint = ["ruff>=0.14.0"]
38
+
17
39
  [tool.uv.build-backend]
18
40
  module-root = "src"
19
41
  module-name = "jsonobjectify"
20
- classifiers = [
21
- "Development Status :: 4 - Beta",
22
- "Intended Audience :: Developers",
23
- "Topic :: Software Development :: Libraries :: Python Modules",
24
- "Programming Language :: Python :: 3",
25
- "Programming Language :: Python :: 3.9",
26
- "Programming Language :: Python :: 3.10",
27
- "Programming Language :: Python :: 3.11",
28
- "Programming Language :: Python :: 3.12",
29
- ]
30
42
 
31
43
  [tool.ruff]
32
44
  line-length = 119
@@ -94,12 +106,4 @@ ignore = [
94
106
  convention = "google"
95
107
 
96
108
  [tool.pytest.ini_options]
97
- testpaths = ["./tests"]
98
-
99
- [dependency-groups]
100
- test = ["pytest==8.2.2"]
101
- lint = ["ruff==0.11.12"]
102
-
103
- [build-system]
104
- requires = ["uv_build>=0.9.13,<0.12.0"]
105
- build-backend = "uv_build"
109
+ testpaths = ["tests"]
@@ -1,28 +1,27 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.9.13,<0.12.0"]
3
+ build-backend = "uv_build"
4
+
1
5
  [project]
2
6
  name = "jsonobjectify"
3
- version = "0.0.0"
7
+ version = "0.1.1"
4
8
  description = "A lightweight Python library for converting JSON data into Python objects, simplifying access to nested structures through intuitive dot notation."
5
9
  readme = "README.md"
6
- requires-python = ">=3.9"
7
- dependencies = []
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ keywords =["json-parsing", "Attribute lookup", "automated-json-parsing"]
8
14
  authors = [
9
15
  {name= "Sandeep Suryaprasad"}
10
16
  ]
11
-
12
- [tool.uv.build-backend]
13
- module-root = "src"
14
- module-name = "jsonobjectify"
15
-
16
17
  classifiers = [
17
- "Development Status :: 4 - Beta",
18
- "Intended Audience :: Developers",
18
+ "Development Status :: 3 - Alpha",
19
19
  "Topic :: Software Development :: Libraries :: Python Modules",
20
- "Programming Language :: Python :: 3",
21
- "Programming Language :: Python :: 3.9",
22
- "Programming Language :: Python :: 3.10",
23
- "Programming Language :: Python :: 3.11",
24
20
  "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
25
23
  ]
24
+ dependencies = []
26
25
 
27
26
  [project.urls]
28
27
  Homepage = "https://github.com/sandeepsuryaprasad/jsonobjectify"
@@ -30,8 +29,12 @@ Repository = "https://github.com/sandeepsuryaprasad/jsonobjectify"
30
29
  Issues = "https://github.com/sandeepsuryaprasad/jsonobjectify/issues"
31
30
 
32
31
  [dependency-groups]
33
- test = ["pytest==8.2.2"]
34
- lint = ["ruff==0.11.12"]
32
+ test = ["pytest>=8.0.0"]
33
+ lint = ["ruff>=0.14.0"]
34
+
35
+ [tool.uv.build-backend]
36
+ module-root = "src"
37
+ module-name = "jsonobjectify"
35
38
 
36
39
  [tool.ruff]
37
40
  line-length = 119
@@ -100,8 +103,4 @@ ignore = [
100
103
  convention = "google"
101
104
 
102
105
  [tool.pytest.ini_options]
103
- testpaths = ["./tests"]
104
-
105
- [build-system]
106
- requires = ["uv_build>=0.9.13,<0.12.0"]
107
- build-backend = "uv_build"
106
+ testpaths = ["tests"]
@@ -1,17 +1,23 @@
1
1
  from json import dumps
2
+ from re import sub
2
3
 
3
4
 
4
5
  class JsonObject:
5
6
  """Represent a JSON object as a Python object."""
7
+
6
8
  def __init__(self, info):
7
9
  self._info = info
8
10
 
9
- def __getattr__(self, name):
11
+ def _normalize_key(self, key: str) -> str:
12
+ """Normalize a JSON key for Python attribute access."""
13
+ return sub(r"[-\s\.]+", "_", key)
14
+
15
+ def __getattr__(self, name: str):
10
16
  """Return a value from the underlying JSON data using dot notation."""
11
- try:
12
- return self._info[name]
13
- except KeyError:
14
- raise AttributeError(f"{type(self).__name__} has no attribute {name!r}") from None
17
+ for key, value in self._info.items():
18
+ if self._normalize_key(key) == name:
19
+ return value
20
+ raise AttributeError(f"{type(self).__name__} has no attribute {name!r}") from None
15
21
 
16
22
  def __setattr__(self, name, value):
17
23
  """Set an attribute (_info) or update the underlying JSON data."""
@@ -1,6 +1,7 @@
1
1
  from json import load, loads
2
2
  from pathlib import Path
3
- from .json_object import JsonObject
3
+
4
+ from .jsonobject import JsonObject
4
5
 
5
6
 
6
7
  class JsonPath:
@@ -9,7 +10,14 @@ class JsonPath:
9
10
  self._root_json_object = None
10
11
 
11
12
  def __getattr__(self, name):
12
- """Delegate attribute access to the json object."""
13
+ """Delegate attribute access to the root JSON object.
14
+
15
+ Raises:
16
+ AttributeError: If the requested attribute is 'value' or does not
17
+ exist on the root JSON object.
18
+ """
19
+ if name == "value":
20
+ raise AttributeError("'value' attribute is available only for scalar values")
13
21
  return getattr(self._root_json_object, name)
14
22
 
15
23
  def __getitem__(self, index):
@@ -23,17 +31,34 @@ class JsonPath:
23
31
  return len(self._root_json_object)
24
32
 
25
33
  def __setattr__(self, name, value):
34
+ """Set an attribute on the root JSON object.
35
+
36
+ Delegates attribute assignment to the root JSON object, except for
37
+ `_root_json_object`, which is assigned directly.
38
+ """
26
39
  if name == "_root_json_object":
27
40
  super().__setattr__(name, value)
28
41
  else:
29
42
  setattr(self._root_json_object, name, value)
30
43
 
31
44
  def __str__(self):
45
+ """Return the string representation of the root JSON value.
46
+
47
+ Serializes a root `JsonObject` as a JSON string. For scalar values,
48
+ returns their standard Python string representation without JSON
49
+ quoting or formatting.
50
+ """
32
51
  if isinstance(self._root_json_object, JsonObject):
33
52
  return self._root_json_object.to_json()
34
53
  return f"{self._root_json_object}"
35
54
 
36
55
  def __repr__(self):
56
+ """Return an unambiguous string representation of the instance.
57
+
58
+ Includes the class name and root JSON value. Converts a `JsonObject`
59
+ to a Python dictionary; scalar values use their standard Python
60
+ representation.
61
+ """
37
62
  if isinstance(self._root_json_object, JsonObject):
38
63
  return f"{type(self).__name__}({self._root_json_object.to_dict()})"
39
64
  return f"{type(self).__name__}({self._root_json_object})"
@@ -42,14 +67,6 @@ class JsonPath:
42
67
  """Wrap a dictionary in a JsonObject."""
43
68
  return JsonObject(data)
44
69
 
45
- def _is_valid_json_key(self, key):
46
- """Check whether a JSON key can be used as a Python attribute."""
47
- if key.isidentifier():
48
- return True
49
- else:
50
- print(f"Skipping invalid JSON key {key!r}")
51
- return False
52
-
53
70
  def _process_list(self, data: list):
54
71
  """Recursively process items in a list."""
55
72
  return [self._process_object(item) for item in data]
@@ -59,7 +76,6 @@ class JsonPath:
59
76
  _data = {
60
77
  key: self._process_object(value)
61
78
  for key, value in data.items()
62
- if self._is_valid_json_key(key)
63
79
  }
64
80
  return self._wrap_dict(_data)
65
81
 
@@ -75,14 +91,30 @@ class JsonPath:
75
91
  """Build the root object from the deserialized JSON."""
76
92
  return self._process_object(py_object)
77
93
 
94
+ @property
95
+ def value(self):
96
+ """Return the root value if the JSON response is a scalar.
97
+
98
+ Raises:
99
+ AttributeError: If the root JSON response is an object or array.
100
+ """
101
+ if isinstance(self._root_json_object, (JsonObject, list)):
102
+ raise AttributeError("'value' attribute is available only for scalar values")
103
+ return self._root_json_object
104
+
78
105
  @classmethod
79
106
  def _from_py_object(cls, py_object):
107
+ """Create a `JsonPath` instance from a Python object.
108
+
109
+ Builds the root JSON structure from the supplied Python object and
110
+ returns the initialized instance.
111
+ """
80
112
  obj = cls()
81
113
  obj._root_json_object = obj._build_root_object(py_object)
82
114
  return obj
83
115
 
84
116
  @classmethod
85
- def from_json_string(cls, json_string):
117
+ def from_string(cls, json_string):
86
118
  """Create a JsonPath instance from a JSON string."""
87
119
  if not isinstance(json_string, str):
88
120
  raise TypeError("json_string must be a string")
@@ -91,7 +123,7 @@ class JsonPath:
91
123
  return cls._from_py_object(loads(json_string))
92
124
 
93
125
  @classmethod
94
- def from_json_file(cls, filename: str):
126
+ def from_file(cls, filename: str):
95
127
  """Create a JsonPath instance from a JSON file."""
96
128
  path = Path(filename)
97
129
  if not path.is_file():
@@ -1,115 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: jsonobjectify
3
- Version: 0.0.0
4
- Summary: A lightweight Python library for converting JSON data into Python objects, simplifying access to nested structures through intuitive dot notation.
5
- Author: Sandeep Suryaprasad
6
- Requires-Python: >=3.9
7
- Project-URL: Homepage, https://github.com/sandeepsuryaprasad/jsonobjectify
8
- Project-URL: Repository, https://github.com/sandeepsuryaprasad/jsonobjectify
9
- Project-URL: Issues, https://github.com/sandeepsuryaprasad/jsonobjectify/issues
10
- Description-Content-Type: text/markdown
11
-
12
- # jsonobjectify
13
-
14
- A lightweight Python library for converting JSON data into Python objects,
15
- simplifying access to nested structures through intuitive dot notation.
16
-
17
- ## Overview
18
- Working with complex JSON data often involves repetitive dictionary lookups, especially
19
- when accessing deeply nested structures. `jsonobjectify` simplifies this process by
20
- converting JSON data into Python objects, allowing you to access JSON properties using
21
- familiar attribute notation.
22
-
23
- Instead of writing chained dictionary lookups, you can navigate nested JSON structures
24
- using a clean, readable, object-oriented interface.
25
-
26
- ## Features
27
-
28
- * **Dot-notation access:** Access JSON properties using Python attributes.
29
- * **Nested object support:** Navigate deeply nested JSON structures naturally.
30
- * **List support:** Work with collections of JSON objects.
31
- * **Dictionary conversion:** Convert mapped objects back into standard Python dictionaries.
32
- * **JSON serialization:** Serialize objects back into JSON.
33
- * **Simple API:** Keep your code readable when working with complex JSON responses.
34
-
35
- ## Installation
36
-
37
- ```bash
38
- pip install jsonobjectify
39
- ```
40
-
41
- ## Usage
42
-
43
- Consider the following JSON data representing an employee and their department:
44
-
45
- ```python
46
- response = """{
47
- "id": 1,
48
- "name": "Michael Anderson",
49
- "email": "michael.anderson@example.com",
50
- "website": "www.example.dev",
51
- "address": {
52
- "city": "Austin",
53
- "state": "TX",
54
- "country": "United States",
55
- "geo_location": {"lat": "30.2672", "lng": "-97.7431"}
56
- },
57
- "skills": [
58
- {"name": "Python", "level": "Advanced"},
59
- {"name": "C", "level": "Advanced"},
60
- {"name": "C++", "level": "Intermediate"}
61
- ]
62
- }"""
63
- ```
64
-
65
- With `jsonobjectify`, you can access the data through object attributes rather than
66
- repeated dictionary lookups.
67
-
68
- ```python
69
- from jsonobjectify import JsonPath
70
-
71
- employee = JsonPath.from_json_string(response)
72
-
73
- print(employee.name)
74
- print(employee.address.city)
75
- print(employee.skills[0].name)
76
- print(employee.skills[1].level)
77
- ```
78
-
79
- **Output**
80
-
81
- ```text
82
- 'Michael Anderson'
83
- 'Austin'
84
- 'Python'
85
- 'Advanced'
86
- ```
87
-
88
- The example above illustrates the intended API. Adjust the import and construction methods
89
- to match the implementation in your repository.
90
-
91
- ## Converting Objects Back to JSON
92
-
93
- `jsonobjectify` is intended to support conversion back to standard Python dictionaries and
94
- JSON strings, making it convenient to work with transformed data.
95
-
96
- ```python
97
- # Convert the object to a Python dictionary
98
- data = employee.to_dict()
99
-
100
- # Serialize the object to a JSON string
101
- json_data = employee.to_json()
102
- ```
103
-
104
- ## Requirements
105
-
106
- * Python 3.9 or later
107
-
108
- ## Contributing
109
-
110
- Contributions, bug reports, and feature suggestions are welcome. Please open an issue to
111
- discuss a proposed change before submitting a pull request.
112
-
113
- ## License
114
-
115
- This project is licensed under the MIT License. See the `LICENSE` file for details.
@@ -1,104 +0,0 @@
1
- # jsonobjectify
2
-
3
- A lightweight Python library for converting JSON data into Python objects,
4
- simplifying access to nested structures through intuitive dot notation.
5
-
6
- ## Overview
7
- Working with complex JSON data often involves repetitive dictionary lookups, especially
8
- when accessing deeply nested structures. `jsonobjectify` simplifies this process by
9
- converting JSON data into Python objects, allowing you to access JSON properties using
10
- familiar attribute notation.
11
-
12
- Instead of writing chained dictionary lookups, you can navigate nested JSON structures
13
- using a clean, readable, object-oriented interface.
14
-
15
- ## Features
16
-
17
- * **Dot-notation access:** Access JSON properties using Python attributes.
18
- * **Nested object support:** Navigate deeply nested JSON structures naturally.
19
- * **List support:** Work with collections of JSON objects.
20
- * **Dictionary conversion:** Convert mapped objects back into standard Python dictionaries.
21
- * **JSON serialization:** Serialize objects back into JSON.
22
- * **Simple API:** Keep your code readable when working with complex JSON responses.
23
-
24
- ## Installation
25
-
26
- ```bash
27
- pip install jsonobjectify
28
- ```
29
-
30
- ## Usage
31
-
32
- Consider the following JSON data representing an employee and their department:
33
-
34
- ```python
35
- response = """{
36
- "id": 1,
37
- "name": "Michael Anderson",
38
- "email": "michael.anderson@example.com",
39
- "website": "www.example.dev",
40
- "address": {
41
- "city": "Austin",
42
- "state": "TX",
43
- "country": "United States",
44
- "geo_location": {"lat": "30.2672", "lng": "-97.7431"}
45
- },
46
- "skills": [
47
- {"name": "Python", "level": "Advanced"},
48
- {"name": "C", "level": "Advanced"},
49
- {"name": "C++", "level": "Intermediate"}
50
- ]
51
- }"""
52
- ```
53
-
54
- With `jsonobjectify`, you can access the data through object attributes rather than
55
- repeated dictionary lookups.
56
-
57
- ```python
58
- from jsonobjectify import JsonPath
59
-
60
- employee = JsonPath.from_json_string(response)
61
-
62
- print(employee.name)
63
- print(employee.address.city)
64
- print(employee.skills[0].name)
65
- print(employee.skills[1].level)
66
- ```
67
-
68
- **Output**
69
-
70
- ```text
71
- 'Michael Anderson'
72
- 'Austin'
73
- 'Python'
74
- 'Advanced'
75
- ```
76
-
77
- The example above illustrates the intended API. Adjust the import and construction methods
78
- to match the implementation in your repository.
79
-
80
- ## Converting Objects Back to JSON
81
-
82
- `jsonobjectify` is intended to support conversion back to standard Python dictionaries and
83
- JSON strings, making it convenient to work with transformed data.
84
-
85
- ```python
86
- # Convert the object to a Python dictionary
87
- data = employee.to_dict()
88
-
89
- # Serialize the object to a JSON string
90
- json_data = employee.to_json()
91
- ```
92
-
93
- ## Requirements
94
-
95
- * Python 3.9 or later
96
-
97
- ## Contributing
98
-
99
- Contributions, bug reports, and feature suggestions are welcome. Please open an issue to
100
- discuss a proposed change before submitting a pull request.
101
-
102
- ## License
103
-
104
- This project is licensed under the MIT License. See the `LICENSE` file for details.