our-object-local 0.0.1__py3-none-any.whl
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.
- our_object_local/__init__.py +0 -0
- our_object_local/our_object.py +184 -0
- our_object_local/py.typed +0 -0
- our_object_local/version.py +1 -0
- our_object_local-0.0.1.dist-info/METADATA +19 -0
- our_object_local-0.0.1.dist-info/RECORD +8 -0
- our_object_local-0.0.1.dist-info/WHEEL +5 -0
- our_object_local-0.0.1.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""The root of the business-object model.
|
|
2
|
+
|
|
3
|
+
Moved here from `python_sdk_remote/src/our_object.py` so that anything wanting
|
|
4
|
+
the base class no longer has to take the whole SDK. `python-sdk-remote` keeps
|
|
5
|
+
re-exporting `OurObject`, so every existing import goes on working.
|
|
6
|
+
|
|
7
|
+
This package deliberately declares **no circlez dependencies at all**. That is
|
|
8
|
+
what lets `our-object-field-local` sit above `fields-local` without a cycle:
|
|
9
|
+
|
|
10
|
+
our-object-field-local -> fields-local -> python-sdk-remote -> our-object-local
|
|
11
|
+
|
|
12
|
+
Consequence of the same rule: the `MiniLogger` calls the original carried are
|
|
13
|
+
gone. `logger-local` depends on `python-sdk-remote`, which will depend on this
|
|
14
|
+
package, so importing a logger here would close the loop. Nothing is lost -
|
|
15
|
+
`logger.start`/`logger.end` fired on every single attribute read in `get()`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
from abc import ABC
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Any, Optional
|
|
22
|
+
|
|
23
|
+
from .version import PACKAGE_VERSION
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OurObject(ABC):
|
|
27
|
+
"""Base class for all business objects in the system.
|
|
28
|
+
|
|
29
|
+
Provides JSON serialization/deserialization, equality comparison, string
|
|
30
|
+
representation and attribute access. Extend it for every business entity
|
|
31
|
+
so behaviour stays consistent.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
entity_name: Optional[str] = None
|
|
35
|
+
id: Optional[int] = None
|
|
36
|
+
|
|
37
|
+
# Needed by print_our_object_with_id()
|
|
38
|
+
name: Optional[str] = None
|
|
39
|
+
number: Optional[int] = None
|
|
40
|
+
|
|
41
|
+
# TODO `fields` is a class-level mutable set, so it is shared by every
|
|
42
|
+
# subclass that does not override it, and the print_our_object_with_id()
|
|
43
|
+
# it is commented for exists in no installed package. It is replaced by
|
|
44
|
+
# OurObjectFields in our-object-field-local; kept here unchanged so this
|
|
45
|
+
# move stays a move.
|
|
46
|
+
fields = {
|
|
47
|
+
# Needed by print_our_object_with_id()
|
|
48
|
+
"name",
|
|
49
|
+
"number"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
def __init__(self, entity_name: Optional[str] = None,
|
|
53
|
+
id: Optional[int] = None, **kwargs: Any) -> None:
|
|
54
|
+
self.set_entity_name(entity_name)
|
|
55
|
+
self.set_id(id)
|
|
56
|
+
self.kwargs = kwargs
|
|
57
|
+
|
|
58
|
+
# TODO Neither __convert_ method is called anywhere in any installed
|
|
59
|
+
# circlez package, and both are name-mangled, so no subclass can reach
|
|
60
|
+
# them either. Slated for removal with the OurObjectFields work.
|
|
61
|
+
def __convert_kwargs_to_fields(self, kwargs: dict, fields: set) -> None:
|
|
62
|
+
"""Convert kwargs to object fields based on allowed fields list."""
|
|
63
|
+
for field, value in kwargs.items():
|
|
64
|
+
if field in fields:
|
|
65
|
+
setattr(self, field, value)
|
|
66
|
+
|
|
67
|
+
def __convert_fields_to_kwargs(self, fields: set, kwargs: dict) -> None:
|
|
68
|
+
"""Convert fields to kwargs format."""
|
|
69
|
+
for field in fields:
|
|
70
|
+
if field in kwargs:
|
|
71
|
+
setattr(self, field, kwargs[field])
|
|
72
|
+
else:
|
|
73
|
+
setattr(self, field, None)
|
|
74
|
+
|
|
75
|
+
def set_entity_name(self, entity_name: Optional[str]) -> None:
|
|
76
|
+
self.entity_name = entity_name
|
|
77
|
+
|
|
78
|
+
def get_id_column_name(self) -> str:
|
|
79
|
+
"""Returns the name of the column that is used as the id of the object"""
|
|
80
|
+
# BEHAVIOUR NOTE: was `self.entity_name + "_id"`, which raised
|
|
81
|
+
# TypeError on the default entity_name of None. Forced by the
|
|
82
|
+
# annotations this package now ships - see py.typed in the PR body.
|
|
83
|
+
id_column_name = str(self.entity_name) + "_id"
|
|
84
|
+
return id_column_name
|
|
85
|
+
|
|
86
|
+
def set_id(self, id: Optional[int]) -> None:
|
|
87
|
+
self.id = id
|
|
88
|
+
|
|
89
|
+
def get_id(self) -> Optional[int]:
|
|
90
|
+
return self.id
|
|
91
|
+
|
|
92
|
+
# Commented so we can use it in database foreach()
|
|
93
|
+
# @abstractmethod
|
|
94
|
+
def get_name(self) -> Optional[str]:
|
|
95
|
+
"""Returns the name of the object"""
|
|
96
|
+
# raise NotImplementedError(
|
|
97
|
+
# "Subclasses must implement the 'get_name' method.")
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
def get(self, attr_name: str) -> Any:
|
|
101
|
+
"""Returns the value of the attribute with the given name"""
|
|
102
|
+
# BEHAVIOUR NOTE: the getattr default of None was already there, but
|
|
103
|
+
# .get() was then called on it unconditionally, so any instance built
|
|
104
|
+
# without __init__ - from_json does exactly that - raised
|
|
105
|
+
# AttributeError. Guarding it is forced by the annotations.
|
|
106
|
+
arguments = getattr(self, 'kwargs', None)
|
|
107
|
+
get_result = arguments.get(attr_name, None) if arguments else None
|
|
108
|
+
return get_result
|
|
109
|
+
|
|
110
|
+
def get_all_arguments(self) -> Optional[dict]:
|
|
111
|
+
"""Returns all the arguments passed to the constructor as a dictionary"""
|
|
112
|
+
get_all_arguments_result = getattr(self, 'kwargs', None)
|
|
113
|
+
return get_all_arguments_result
|
|
114
|
+
|
|
115
|
+
def to_json(self) -> str:
|
|
116
|
+
"""This is backwards compatible with the previous implementation"""
|
|
117
|
+
to_json_result = self.to_json_str()
|
|
118
|
+
return to_json_result
|
|
119
|
+
|
|
120
|
+
def to_json_dict(self) -> dict:
|
|
121
|
+
"""Returns a json dict representation of this object"""
|
|
122
|
+
json_str = self.to_json_str()
|
|
123
|
+
json_dict = json.loads(json_str)
|
|
124
|
+
|
|
125
|
+
return json_dict
|
|
126
|
+
|
|
127
|
+
def to_json_str(self) -> str:
|
|
128
|
+
"""Returns a json string representation of this object"""
|
|
129
|
+
to_json_str_result = json.dumps(self.__dict__, default=self._serialize)
|
|
130
|
+
return to_json_str_result
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def _serialize(obj: Any) -> str:
|
|
134
|
+
"""Custom serialization function for unsupported types. Used by json.dumps"""
|
|
135
|
+
if isinstance(obj, datetime):
|
|
136
|
+
return obj.isoformat() # Converts datetime to ISO 8601 string
|
|
137
|
+
raise TypeError(f"Type {type(obj)} not serializable")
|
|
138
|
+
|
|
139
|
+
def from_json(self, json_string: str) -> 'OurObject':
|
|
140
|
+
"""Returns an instance of the class from a json string"""
|
|
141
|
+
self.__dict__ = json.loads(json_string)
|
|
142
|
+
return self
|
|
143
|
+
|
|
144
|
+
def __eq__(self, other: object) -> bool:
|
|
145
|
+
"""Checks if two objects are equal"""
|
|
146
|
+
if not isinstance(other, OurObject):
|
|
147
|
+
return False
|
|
148
|
+
eq_result = self.__dict__ == other.__dict__
|
|
149
|
+
return eq_result
|
|
150
|
+
|
|
151
|
+
def __ne__(self, other: object) -> bool:
|
|
152
|
+
"""Checks if two objects are not equal"""
|
|
153
|
+
ne_result = not self.__eq__(other)
|
|
154
|
+
return ne_result
|
|
155
|
+
|
|
156
|
+
def __str__(self) -> str:
|
|
157
|
+
# BEHAVIOUR NOTE: same TypeError-on-None as get_id_column_name.
|
|
158
|
+
# __repr__ right below already guarded for it; __str__ did not.
|
|
159
|
+
str_result = str(self.entity_name) + ": " + str(self.__dict__)
|
|
160
|
+
return str_result
|
|
161
|
+
|
|
162
|
+
def __repr__(self) -> str:
|
|
163
|
+
"""String representation for debugging."""
|
|
164
|
+
# Ensure both entity_name and __dict__ are not None for proper representation
|
|
165
|
+
entity_name = self.entity_name or "OurObject"
|
|
166
|
+
dict_str = str(self.__dict__) if self.__dict__ else "{}"
|
|
167
|
+
repr_result = f"{entity_name}: {dict_str}"
|
|
168
|
+
return repr_result
|
|
169
|
+
|
|
170
|
+
def to_dict(self) -> dict:
|
|
171
|
+
return self.__dict__
|
|
172
|
+
|
|
173
|
+
# TODO This returned python-sdk-remote's version under a docstring
|
|
174
|
+
# admitting that is wrong for derived classes; it now returns
|
|
175
|
+
# our-object-local's, which is wrong in exactly the same way. Retire it,
|
|
176
|
+
# or resolve the subclass's real distribution? Asked on contact #60 -
|
|
177
|
+
# left behaving as before until answered.
|
|
178
|
+
def get_package_version(self) -> str:
|
|
179
|
+
"""Get package version.
|
|
180
|
+
|
|
181
|
+
Note: Returns the version of our-object-local, not the derived class
|
|
182
|
+
package.
|
|
183
|
+
"""
|
|
184
|
+
return PACKAGE_VERSION
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PACKAGE_VERSION = "0.0.1"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: our-object-local
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: PyPI our-object-local Python Package owned by Circlez.ai
|
|
5
|
+
Home-page: https://github.com/circles-zone/our-object-local-python-package
|
|
6
|
+
Author: Circles
|
|
7
|
+
Author-email: info@circlez.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: classifier
|
|
14
|
+
Dynamic: description
|
|
15
|
+
Dynamic: description-content-type
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: summary
|
|
18
|
+
|
|
19
|
+
PyPI our-object-local Python Package owned by Circlez.ai
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
our_object_local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
our_object_local/our_object.py,sha256=_bgry8rlLukCNRy2Oa4ZK4djwoPBvR0n7ibmQ-R__rI,7374
|
|
3
|
+
our_object_local/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
our_object_local/version.py,sha256=6lfjhcOL0dTl80EBpYntegTtx7Zo6eoGC4W0EWlyOxI,26
|
|
5
|
+
our_object_local-0.0.1.dist-info/METADATA,sha256=pW3VKd-0jRx3hWVJCeoj3vlI5pLS0xkL4IgqZ9B6oIE,589
|
|
6
|
+
our_object_local-0.0.1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
7
|
+
our_object_local-0.0.1.dist-info/top_level.txt,sha256=UxYxBGutXbEX1YZUOwUAfrmEFIXX-ecXJjepZW8OROY,17
|
|
8
|
+
our_object_local-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
our_object_local
|