jsonobjectify 0.0.0__tar.gz → 0.1.0__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,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: jsonobjectify
3
+ Version: 0.1.0
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
+ Requires-Python: >=3.12
10
+ Project-URL: Homepage, https://github.com/sandeepsuryaprasad/jsonobjectify
11
+ Project-URL: Repository, https://github.com/sandeepsuryaprasad/jsonobjectify
12
+ Project-URL: Issues, https://github.com/sandeepsuryaprasad/jsonobjectify/issues
13
+ Description-Content-Type: text/markdown
14
+
15
+ # jsonobjectify
16
+
17
+ [![CI](https://github.com/sandeepsuryaprasad/jsonobjectify/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sandeepsuryaprasad/jsonobjectify/actions/workflows/ci-test.yml) [![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)
18
+
19
+ A lightweight Python library for converting JSON data into Python objects,
20
+ simplifying access to nested structures through dot notation. Instead of writing chained
21
+ dictionary lookups, you can navigate nested JSON structures using a clean, readable,
22
+ object-oriented interface.
23
+
24
+ ## Installation
25
+
26
+ ```console
27
+ pip install jsonobjectify
28
+ ```
29
+
30
+ ## Usage
31
+ Consider the following JSON data representing an employee and their department:
32
+
33
+ ```python
34
+ response = """{
35
+ "id": 1,
36
+ "name": "John Doe",
37
+ "email": "john.doe@example.com",
38
+ "website": "www.example.dev",
39
+ "address": {
40
+ "city": "Austin",
41
+ "state": "TX",
42
+ "country": "United States",
43
+ "geo_location": {"lat": "30.2672", "lng": "-97.7431"}
44
+ },
45
+ "skills": [
46
+ {"name": "Python", "level": "Advanced"},
47
+ {"name": "C", "level": "Advanced"},
48
+ {"name": "C++", "level": "Intermediate"}
49
+ ]
50
+ }"""
51
+ ```
52
+ ### Create `JsonPath` object from JSON string.
53
+ Here, response is a string containing valid JSON. The `from_string` class method parses
54
+ the JSON data and creates a `JsonPath` object that allows you to access properties using
55
+ dot notation.
56
+ ```console
57
+ >>> employee = JsonPath.from_string(response)
58
+ ```
59
+ You can now access and traverse nested JSON objects using **dot notation**.
60
+ For JSON arrays, use the standard Python indexing syntax.
61
+ ```console
62
+ >>> employee.name
63
+ 'John Doe'
64
+ >>> employee.address.city
65
+ 'Austin'
66
+ >>> employee.address.geo_location.lng
67
+ '-97.7431'
68
+ >>> employee.skills[0].name
69
+ 'Python'
70
+ >>> employee.skills[1].level
71
+ 'Advanced'
72
+ >>>
73
+ ```
74
+ You can also iterate over JSON arrays using a standard Python for loop and access each
75
+ element's properties using dot notation.
76
+ ```console
77
+ >>> for skill in employee.skills:
78
+ ... print(f"{skill.name}, {skill.level}")
79
+ ...
80
+ Python, Advanced
81
+ C, Advanced
82
+ C++, Intermediate
83
+ >>>
84
+ ```
85
+ ### Root response is an array of JSON objects
86
+ A JSON response can contain an array of objects at the root level. You can use
87
+ `JsonPath.from_string` to parse the response and access each object's properties using
88
+ dot notation.
89
+ ```python
90
+ response = """[
91
+ {
92
+ "name": "Olivia Bennett",
93
+ "email": "olivia.bennett@example.com",
94
+ "website": "www.example.dev"
95
+ },
96
+ {
97
+ "name": "Ethan Parker",
98
+ "email": "ethan.parker@example.com",
99
+ "website": "www.example.io"
100
+ },
101
+ {
102
+ "name": "Sophia Turner",
103
+ "email": "sophia.turner@example.com",
104
+ "website": "www.example.edu"
105
+ }
106
+ ]"""
107
+ ```
108
+ ```console
109
+ >>> employees = JsonPath.from_string(response)
110
+ >>> employees[0]
111
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7d50>
112
+ >>> employees[1]
113
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7b50>
114
+ >>> employees[2]
115
+ <jsonobjectify.jsonobject.JsonObject object at 0x101aa2120>
116
+ >>> employees[0].name
117
+ 'Olivia Bennett'
118
+ >>> employees[0].email
119
+ 'olivia.bennett@example.com'
120
+ >>> employees[0].website
121
+ 'www.example.dev'
122
+ >>>
123
+ ```
124
+ You can also iterate over JSON arrays using a standard Python for loop and access each
125
+ element's properties using dot notation.
126
+ ```console
127
+ >>> for employee in employees:
128
+ ... print(f"{employee.name}, {employee.email}, {employee.website}")
129
+ ...
130
+ Olivia Bennett, olivia.bennett@example.com, www.example.dev
131
+ Ethan Parker, ethan.parker@example.com, www.example.io
132
+ Sophia Turner, sophia.turner@example.com, www.example.edu
133
+ >>>
134
+ ```
135
+
136
+ ### Create a `JsonPath` object from a JSON file
137
+ You can also create a JsonPath object directly from a JSON file using the `from_file`
138
+ class method. This allows you to work with JSON data stored in a file without having to
139
+ read and parse its contents manually.
140
+
141
+ For example, consider an `employee.json` file containing the employee data shown in the
142
+ previous example.
143
+
144
+ ```console
145
+ >>> employee = JsonPath.from_file("employee.json")
146
+ ```
147
+ Once the object is created, you can access nested properties and iterate over JSON arrays
148
+ in the same way
149
+
150
+ ```console
151
+ >>> employee.name
152
+ 'Michael Anderson'
153
+ >>> employee.address.city
154
+ 'Austin'
155
+ >>> for skill in employee.skills:
156
+ ... print(f"{skill.name}, {skill.level}")
157
+ ...
158
+ Python, Advanced
159
+ C, Advanced
160
+ C++, Intermediate
161
+ ```
162
+
163
+ ### Working with Scalar Values
164
+ If the **root JSON** value is a scalar, such as a string, number, boolean or null, you can
165
+ access the underlying value using the `value` property.
166
+
167
+ ```console
168
+ >>> data = JsonPath.from_string("26")
169
+ >>> data.value
170
+ 26
171
+ >>> data = JsonPath.from_string("true")
172
+ >>> data.value
173
+ True
174
+ >>> data = JsonPath.from_string("null")
175
+ >>> data.value
176
+ >>>
177
+ >>> json = JsonPath.from_string('"hello world"')
178
+ >>> json.value
179
+ 'hello world'
180
+ ```
181
+ ### Accessing JSON Properties with Normalized Keys
182
+ JSON property names may contain hyphens, spaces, or periods, which cannot be used directly
183
+ in Python attribute names. jsonobjectify normalizes these characters to underscores,
184
+ allowing you to access such properties using dot notation.
185
+
186
+ ```python
187
+ response = """{
188
+ "first-name": "Olivia",
189
+ "job title": "Software Engineer",
190
+ "contact.email": "olivia@example.com"
191
+ }"""
192
+ ```
193
+ ```console
194
+ >>> employee = JsonPath.from_string(response)
195
+ ```
196
+ You can access these properties using normalized attribute names,
197
+
198
+ ```console
199
+ >>> employee.first_name
200
+ 'Olivia'
201
+ >>> employee.job_title
202
+ 'Software Engineer'
203
+ >>> employee.contact_email
204
+ 'olivia@example.com'
205
+ ```
206
+ **The original JSON property names are preserved when converting the object back to
207
+ a dictionary or JSON string.**
208
+
209
+ ### Converting Objects Back to JSON
210
+
211
+ `jsonobjectify` is intended to support conversion back to standard Python dictionaries and
212
+ JSON strings, making it convenient to work with transformed data.
213
+
214
+ ```python
215
+ # Convert the object to a Python dictionary
216
+ data = employee.to_dict()
217
+
218
+ # Serialize the object to a JSON string
219
+ json_data = employee.to_json()
220
+ ```
221
+
222
+ ### Requirements
223
+ * Python 3.12 or later
224
+
225
+ ### Contributing
226
+ Contributions, bug reports, and feature suggestions are welcome. Please open an issue to
227
+ discuss a proposed change before submitting a pull request.
228
+
229
+ ### License
230
+
231
+ This package is distributed under the terms of [MIT](https://github.com/sandeepsuryaprasad/jsonobjectify/blob/main/LICENSE) license
@@ -0,0 +1,217 @@
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-test.yml) [![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)
4
+
5
+ A lightweight Python library for converting JSON data into Python objects,
6
+ simplifying access to nested structures through dot notation. Instead of writing chained
7
+ dictionary lookups, you can navigate nested JSON structures using a clean, readable,
8
+ object-oriented interface.
9
+
10
+ ## Installation
11
+
12
+ ```console
13
+ pip install jsonobjectify
14
+ ```
15
+
16
+ ## Usage
17
+ Consider the following JSON data representing an employee and their department:
18
+
19
+ ```python
20
+ response = """{
21
+ "id": 1,
22
+ "name": "John Doe",
23
+ "email": "john.doe@example.com",
24
+ "website": "www.example.dev",
25
+ "address": {
26
+ "city": "Austin",
27
+ "state": "TX",
28
+ "country": "United States",
29
+ "geo_location": {"lat": "30.2672", "lng": "-97.7431"}
30
+ },
31
+ "skills": [
32
+ {"name": "Python", "level": "Advanced"},
33
+ {"name": "C", "level": "Advanced"},
34
+ {"name": "C++", "level": "Intermediate"}
35
+ ]
36
+ }"""
37
+ ```
38
+ ### Create `JsonPath` object from JSON string.
39
+ Here, response is a string containing valid JSON. The `from_string` class method parses
40
+ the JSON data and creates a `JsonPath` object that allows you to access properties using
41
+ dot notation.
42
+ ```console
43
+ >>> employee = JsonPath.from_string(response)
44
+ ```
45
+ You can now access and traverse nested JSON objects using **dot notation**.
46
+ For JSON arrays, use the standard Python indexing syntax.
47
+ ```console
48
+ >>> employee.name
49
+ 'John Doe'
50
+ >>> employee.address.city
51
+ 'Austin'
52
+ >>> employee.address.geo_location.lng
53
+ '-97.7431'
54
+ >>> employee.skills[0].name
55
+ 'Python'
56
+ >>> employee.skills[1].level
57
+ 'Advanced'
58
+ >>>
59
+ ```
60
+ You can also iterate over JSON arrays using a standard Python for loop and access each
61
+ element's properties using dot notation.
62
+ ```console
63
+ >>> for skill in employee.skills:
64
+ ... print(f"{skill.name}, {skill.level}")
65
+ ...
66
+ Python, Advanced
67
+ C, Advanced
68
+ C++, Intermediate
69
+ >>>
70
+ ```
71
+ ### Root response is an array of JSON objects
72
+ A JSON response can contain an array of objects at the root level. You can use
73
+ `JsonPath.from_string` to parse the response and access each object's properties using
74
+ dot notation.
75
+ ```python
76
+ response = """[
77
+ {
78
+ "name": "Olivia Bennett",
79
+ "email": "olivia.bennett@example.com",
80
+ "website": "www.example.dev"
81
+ },
82
+ {
83
+ "name": "Ethan Parker",
84
+ "email": "ethan.parker@example.com",
85
+ "website": "www.example.io"
86
+ },
87
+ {
88
+ "name": "Sophia Turner",
89
+ "email": "sophia.turner@example.com",
90
+ "website": "www.example.edu"
91
+ }
92
+ ]"""
93
+ ```
94
+ ```console
95
+ >>> employees = JsonPath.from_string(response)
96
+ >>> employees[0]
97
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7d50>
98
+ >>> employees[1]
99
+ <jsonobjectify.jsonobject.JsonObject object at 0x101bb7b50>
100
+ >>> employees[2]
101
+ <jsonobjectify.jsonobject.JsonObject object at 0x101aa2120>
102
+ >>> employees[0].name
103
+ 'Olivia Bennett'
104
+ >>> employees[0].email
105
+ 'olivia.bennett@example.com'
106
+ >>> employees[0].website
107
+ 'www.example.dev'
108
+ >>>
109
+ ```
110
+ You can also iterate over JSON arrays using a standard Python for loop and access each
111
+ element's properties using dot notation.
112
+ ```console
113
+ >>> for employee in employees:
114
+ ... print(f"{employee.name}, {employee.email}, {employee.website}")
115
+ ...
116
+ Olivia Bennett, olivia.bennett@example.com, www.example.dev
117
+ Ethan Parker, ethan.parker@example.com, www.example.io
118
+ Sophia Turner, sophia.turner@example.com, www.example.edu
119
+ >>>
120
+ ```
121
+
122
+ ### Create a `JsonPath` object from a JSON file
123
+ You can also create a JsonPath object directly from a JSON file using the `from_file`
124
+ class method. This allows you to work with JSON data stored in a file without having to
125
+ read and parse its contents manually.
126
+
127
+ For example, consider an `employee.json` file containing the employee data shown in the
128
+ previous example.
129
+
130
+ ```console
131
+ >>> employee = JsonPath.from_file("employee.json")
132
+ ```
133
+ Once the object is created, you can access nested properties and iterate over JSON arrays
134
+ in the same way
135
+
136
+ ```console
137
+ >>> employee.name
138
+ 'Michael Anderson'
139
+ >>> employee.address.city
140
+ 'Austin'
141
+ >>> for skill in employee.skills:
142
+ ... print(f"{skill.name}, {skill.level}")
143
+ ...
144
+ Python, Advanced
145
+ C, Advanced
146
+ C++, Intermediate
147
+ ```
148
+
149
+ ### Working with Scalar Values
150
+ If the **root JSON** value is a scalar, such as a string, number, boolean or null, you can
151
+ access the underlying value using the `value` property.
152
+
153
+ ```console
154
+ >>> data = JsonPath.from_string("26")
155
+ >>> data.value
156
+ 26
157
+ >>> data = JsonPath.from_string("true")
158
+ >>> data.value
159
+ True
160
+ >>> data = JsonPath.from_string("null")
161
+ >>> data.value
162
+ >>>
163
+ >>> json = JsonPath.from_string('"hello world"')
164
+ >>> json.value
165
+ 'hello world'
166
+ ```
167
+ ### Accessing JSON Properties with Normalized Keys
168
+ JSON property names may contain hyphens, spaces, or periods, which cannot be used directly
169
+ in Python attribute names. jsonobjectify normalizes these characters to underscores,
170
+ allowing you to access such properties using dot notation.
171
+
172
+ ```python
173
+ response = """{
174
+ "first-name": "Olivia",
175
+ "job title": "Software Engineer",
176
+ "contact.email": "olivia@example.com"
177
+ }"""
178
+ ```
179
+ ```console
180
+ >>> employee = JsonPath.from_string(response)
181
+ ```
182
+ You can access these properties using normalized attribute names,
183
+
184
+ ```console
185
+ >>> employee.first_name
186
+ 'Olivia'
187
+ >>> employee.job_title
188
+ 'Software Engineer'
189
+ >>> employee.contact_email
190
+ 'olivia@example.com'
191
+ ```
192
+ **The original JSON property names are preserved when converting the object back to
193
+ a dictionary or JSON string.**
194
+
195
+ ### Converting Objects Back to JSON
196
+
197
+ `jsonobjectify` is intended to support conversion back to standard Python dictionaries and
198
+ JSON strings, making it convenient to work with transformed data.
199
+
200
+ ```python
201
+ # Convert the object to a Python dictionary
202
+ data = employee.to_dict()
203
+
204
+ # Serialize the object to a JSON string
205
+ json_data = employee.to_json()
206
+ ```
207
+
208
+ ### Requirements
209
+ * Python 3.12 or later
210
+
211
+ ### Contributing
212
+ Contributions, bug reports, and feature suggestions are welcome. Please open an issue to
213
+ discuss a proposed change before submitting a pull request.
214
+
215
+ ### License
216
+
217
+ This package is distributed under the terms of [MIT](https://github.com/sandeepsuryaprasad/jsonobjectify/blob/main/LICENSE) license
@@ -1,9 +1,20 @@
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.0"
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
+ ]
7
18
  dependencies = []
8
19
 
9
20
  [[project.authors]]
@@ -18,14 +29,11 @@ Issues = "https://github.com/sandeepsuryaprasad/jsonobjectify/issues"
18
29
  module-root = "src"
19
30
  module-name = "jsonobjectify"
20
31
  classifiers = [
21
- "Development Status :: 4 - Beta",
22
- "Intended Audience :: Developers",
32
+ "Development Status :: 3 - Alpha",
23
33
  "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
34
  "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Programming Language :: Python :: 3.14",
29
37
  ]
30
38
 
31
39
  [tool.ruff]
@@ -94,12 +102,8 @@ ignore = [
94
102
  convention = "google"
95
103
 
96
104
  [tool.pytest.ini_options]
97
- testpaths = ["./tests"]
105
+ testpaths = ["tests"]
98
106
 
99
107
  [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"
108
+ test = ["pytest>=8.0.0"]
109
+ lint = ["ruff>=0.14.0"]
@@ -1,27 +1,31 @@
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.0"
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
  ]
17
+ dependencies = []
11
18
 
12
19
  [tool.uv.build-backend]
13
20
  module-root = "src"
14
21
  module-name = "jsonobjectify"
15
22
 
16
23
  classifiers = [
17
- "Development Status :: 4 - Beta",
18
- "Intended Audience :: Developers",
24
+ "Development Status :: 3 - Alpha",
19
25
  "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
26
  "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
25
29
  ]
26
30
 
27
31
  [project.urls]
@@ -30,8 +34,8 @@ Repository = "https://github.com/sandeepsuryaprasad/jsonobjectify"
30
34
  Issues = "https://github.com/sandeepsuryaprasad/jsonobjectify/issues"
31
35
 
32
36
  [dependency-groups]
33
- test = ["pytest==8.2.2"]
34
- lint = ["ruff==0.11.12"]
37
+ test = ["pytest>=8.0.0"]
38
+ lint = ["ruff>=0.14.0"]
35
39
 
36
40
  [tool.ruff]
37
41
  line-length = 119
@@ -100,8 +104,4 @@ ignore = [
100
104
  convention = "google"
101
105
 
102
106
  [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"
107
+ 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.