autonomous-app 0.2.25__py3-none-any.whl → 0.3.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.
Files changed (59) hide show
  1. autonomous/__init__.py +5 -2
  2. autonomous/ai/audioagent.py +32 -0
  3. autonomous/ai/imageagent.py +31 -0
  4. autonomous/ai/jsonagent.py +40 -0
  5. autonomous/ai/models/__init__.py +0 -0
  6. autonomous/ai/models/openai.py +308 -0
  7. autonomous/ai/oaiagent.py +20 -194
  8. autonomous/ai/textagent.py +35 -0
  9. autonomous/auth/autoauth.py +11 -11
  10. autonomous/auth/user.py +24 -11
  11. autonomous/db/__init__.py +41 -0
  12. autonomous/db/base/__init__.py +33 -0
  13. autonomous/db/base/common.py +62 -0
  14. autonomous/db/base/datastructures.py +476 -0
  15. autonomous/db/base/document.py +1230 -0
  16. autonomous/db/base/fields.py +767 -0
  17. autonomous/db/base/metaclasses.py +468 -0
  18. autonomous/db/base/utils.py +22 -0
  19. autonomous/db/common.py +79 -0
  20. autonomous/db/connection.py +472 -0
  21. autonomous/db/context_managers.py +313 -0
  22. autonomous/db/dereference.py +291 -0
  23. autonomous/db/document.py +1141 -0
  24. autonomous/db/errors.py +165 -0
  25. autonomous/db/fields.py +2732 -0
  26. autonomous/db/mongodb_support.py +24 -0
  27. autonomous/db/pymongo_support.py +80 -0
  28. autonomous/db/queryset/__init__.py +28 -0
  29. autonomous/db/queryset/base.py +2033 -0
  30. autonomous/db/queryset/field_list.py +88 -0
  31. autonomous/db/queryset/manager.py +58 -0
  32. autonomous/db/queryset/queryset.py +189 -0
  33. autonomous/db/queryset/transform.py +527 -0
  34. autonomous/db/queryset/visitor.py +189 -0
  35. autonomous/db/signals.py +59 -0
  36. autonomous/logger.py +3 -0
  37. autonomous/model/autoattr.py +120 -0
  38. autonomous/model/automodel.py +121 -308
  39. autonomous/storage/imagestorage.py +9 -54
  40. autonomous/tasks/autotask.py +0 -25
  41. {autonomous_app-0.2.25.dist-info → autonomous_app-0.3.1.dist-info}/METADATA +7 -8
  42. autonomous_app-0.3.1.dist-info/RECORD +60 -0
  43. {autonomous_app-0.2.25.dist-info → autonomous_app-0.3.1.dist-info}/WHEEL +1 -1
  44. autonomous/db/autodb.py +0 -86
  45. autonomous/db/table.py +0 -156
  46. autonomous/errors/__init__.py +0 -1
  47. autonomous/errors/danglingreferenceerror.py +0 -8
  48. autonomous/model/autoattribute.py +0 -20
  49. autonomous/model/orm.py +0 -86
  50. autonomous/model/serializer.py +0 -110
  51. autonomous_app-0.2.25.dist-info/RECORD +0 -36
  52. /autonomous/{storage → apis}/version_control/GHCallbacks.py +0 -0
  53. /autonomous/{storage → apis}/version_control/GHOrganization.py +0 -0
  54. /autonomous/{storage → apis}/version_control/GHRepo.py +0 -0
  55. /autonomous/{storage → apis}/version_control/GHVersionControl.py +0 -0
  56. /autonomous/{storage → apis}/version_control/__init__.py +0 -0
  57. /autonomous/{storage → utils}/markdown.py +0 -0
  58. {autonomous_app-0.2.25.dist-info → autonomous_app-0.3.1.dist-info}/LICENSE +0 -0
  59. {autonomous_app-0.2.25.dist-info → autonomous_app-0.3.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,189 @@
1
+ import copy
2
+ import warnings
3
+
4
+ from autonomous.db.errors import InvalidQueryError
5
+ from autonomous.db.queryset import transform
6
+
7
+ __all__ = ("Q", "QNode")
8
+
9
+
10
+ def warn_empty_is_deprecated():
11
+ msg = "'empty' property is deprecated in favour of using 'not bool(filter)'"
12
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
13
+
14
+
15
+ class QNodeVisitor:
16
+ """Base visitor class for visiting Q-object nodes in a query tree."""
17
+
18
+ def visit_combination(self, combination):
19
+ """Called by QCombination objects."""
20
+ return combination
21
+
22
+ def visit_query(self, query):
23
+ """Called by (New)Q objects."""
24
+ return query
25
+
26
+
27
+ class DuplicateQueryConditionsError(InvalidQueryError):
28
+ pass
29
+
30
+
31
+ class SimplificationVisitor(QNodeVisitor):
32
+ """Simplifies query trees by combining unnecessary 'and' connection nodes
33
+ into a single Q-object.
34
+ """
35
+
36
+ def visit_combination(self, combination):
37
+ if combination.operation == combination.AND:
38
+ # The simplification only applies to 'simple' queries
39
+ if all(isinstance(node, Q) for node in combination.children):
40
+ queries = [n.query for n in combination.children]
41
+ try:
42
+ return Q(**self._query_conjunction(queries))
43
+ except DuplicateQueryConditionsError:
44
+ # Cannot be simplified
45
+ pass
46
+ return combination
47
+
48
+ def _query_conjunction(self, queries):
49
+ """Merges query dicts - effectively &ing them together."""
50
+ query_ops = set()
51
+ combined_query = {}
52
+ for query in queries:
53
+ ops = set(query.keys())
54
+ # Make sure that the same operation isn't applied more than once
55
+ # to a single field
56
+ intersection = ops.intersection(query_ops)
57
+ if intersection:
58
+ raise DuplicateQueryConditionsError()
59
+
60
+ query_ops.update(ops)
61
+ combined_query.update(copy.deepcopy(query))
62
+ return combined_query
63
+
64
+
65
+ class QueryCompilerVisitor(QNodeVisitor):
66
+ """Compiles the nodes in a query tree to a PyMongo-compatible query
67
+ dictionary.
68
+ """
69
+
70
+ def __init__(self, document):
71
+ self.document = document
72
+
73
+ def visit_combination(self, combination):
74
+ operator = "$and"
75
+ if combination.operation == combination.OR:
76
+ operator = "$or"
77
+ return {operator: combination.children}
78
+
79
+ def visit_query(self, query):
80
+ return transform.query(self.document, **query.query)
81
+
82
+
83
+ class QNode:
84
+ """Base class for nodes in query trees."""
85
+
86
+ AND = 0
87
+ OR = 1
88
+
89
+ def to_query(self, document):
90
+ query = self.accept(SimplificationVisitor())
91
+ query = query.accept(QueryCompilerVisitor(document))
92
+ return query
93
+
94
+ def accept(self, visitor):
95
+ raise NotImplementedError
96
+
97
+ def _combine(self, other, operation):
98
+ """Combine this node with another node into a QCombination
99
+ object.
100
+ """
101
+ # If the other Q() is empty, ignore it and just use `self`.
102
+ if not bool(other):
103
+ return self
104
+
105
+ # Or if this Q is empty, ignore it and just use `other`.
106
+ if not bool(self):
107
+ return other
108
+
109
+ return QCombination(operation, [self, other])
110
+
111
+ @property
112
+ def empty(self):
113
+ warn_empty_is_deprecated()
114
+ return False
115
+
116
+ def __or__(self, other):
117
+ return self._combine(other, self.OR)
118
+
119
+ def __and__(self, other):
120
+ return self._combine(other, self.AND)
121
+
122
+
123
+ class QCombination(QNode):
124
+ """Represents the combination of several conditions by a given
125
+ logical operator.
126
+ """
127
+
128
+ def __init__(self, operation, children):
129
+ self.operation = operation
130
+ self.children = []
131
+ for node in children:
132
+ # If the child is a combination of the same type, we can merge its
133
+ # children directly into this combinations children
134
+ if isinstance(node, QCombination) and node.operation == operation:
135
+ self.children += node.children
136
+ else:
137
+ self.children.append(node)
138
+
139
+ def __repr__(self):
140
+ op = " & " if self.operation is self.AND else " | "
141
+ return "(%s)" % op.join([repr(node) for node in self.children])
142
+
143
+ def __bool__(self):
144
+ return bool(self.children)
145
+
146
+ def accept(self, visitor):
147
+ for i in range(len(self.children)):
148
+ if isinstance(self.children[i], QNode):
149
+ self.children[i] = self.children[i].accept(visitor)
150
+
151
+ return visitor.visit_combination(self)
152
+
153
+ @property
154
+ def empty(self):
155
+ warn_empty_is_deprecated()
156
+ return not bool(self.children)
157
+
158
+ def __eq__(self, other):
159
+ return (
160
+ self.__class__ == other.__class__
161
+ and self.operation == other.operation
162
+ and self.children == other.children
163
+ )
164
+
165
+
166
+ class Q(QNode):
167
+ """A simple query object, used in a query tree to build up more complex
168
+ query structures.
169
+ """
170
+
171
+ def __init__(self, **query):
172
+ self.query = query
173
+
174
+ def __repr__(self):
175
+ return "Q(**%s)" % repr(self.query)
176
+
177
+ def __bool__(self):
178
+ return bool(self.query)
179
+
180
+ def __eq__(self, other):
181
+ return self.__class__ == other.__class__ and self.query == other.query
182
+
183
+ def accept(self, visitor):
184
+ return visitor.visit_query(self)
185
+
186
+ @property
187
+ def empty(self):
188
+ warn_empty_is_deprecated()
189
+ return not bool(self.query)
@@ -0,0 +1,59 @@
1
+ __all__ = (
2
+ "pre_init",
3
+ "post_init",
4
+ "pre_save",
5
+ "pre_save_post_validation",
6
+ "post_save",
7
+ "pre_delete",
8
+ "post_delete",
9
+ )
10
+
11
+ signals_available = False
12
+ try:
13
+ from blinker import Namespace
14
+
15
+ signals_available = True
16
+ except ImportError:
17
+
18
+ class Namespace:
19
+ def signal(self, name, doc=None):
20
+ return _FakeSignal(name, doc)
21
+
22
+ class _FakeSignal:
23
+ """If blinker is unavailable, create a fake class with the same
24
+ interface that allows sending of signals but will fail with an
25
+ error on anything else. Instead of doing anything on send, it
26
+ will just ignore the arguments and do nothing instead.
27
+ """
28
+
29
+ def __init__(self, name, doc=None):
30
+ self.name = name
31
+ self.__doc__ = doc
32
+
33
+ def _fail(self, *args, **kwargs):
34
+ raise RuntimeError(
35
+ "signalling support is unavailable "
36
+ "because the blinker library is "
37
+ "not installed."
38
+ )
39
+
40
+ send = lambda *a, **kw: None # noqa
41
+ connect = disconnect = has_receivers_for = receivers_for = (
42
+ temporarily_connected_to
43
+ ) = _fail
44
+ del _fail
45
+
46
+
47
+ # the namespace for code signals. If you are not autonomous.db code, do
48
+ # not put signals in here. Create your own namespace instead.
49
+ _signals = Namespace()
50
+
51
+ pre_init = _signals.signal("pre_init")
52
+ post_init = _signals.signal("post_init")
53
+ pre_save = _signals.signal("pre_save")
54
+ pre_save_post_validation = _signals.signal("pre_save_post_validation")
55
+ post_save = _signals.signal("post_save")
56
+ pre_delete = _signals.signal("pre_delete")
57
+ post_delete = _signals.signal("post_delete")
58
+ pre_bulk_insert = _signals.signal("pre_bulk_insert")
59
+ post_bulk_insert = _signals.signal("post_bulk_insert")
autonomous/logger.py CHANGED
@@ -43,6 +43,7 @@ class Logger:
43
43
 
44
44
  def __call__(self, *args, **kwargs):
45
45
  if self.enabled:
46
+ is_printed = kwargs.pop("_print", False)
46
47
  caller = inspect.stack()[1]
47
48
  fn = caller.filename.split("/")[-1]
48
49
  msg = f"\n\n{'='*20}\t{fn}:{caller.function}()::{caller.lineno}\t{'='*20}\n"
@@ -57,6 +58,8 @@ class Logger:
57
58
  current.write(f"{msg}\n")
58
59
  with open(self.logarchive, "a") as archive:
59
60
  archive.write(f"{msg}\n")
61
+ if is_printed:
62
+ print(msg)
60
63
 
61
64
 
62
65
  log = Logger()
@@ -0,0 +1,120 @@
1
+ from autonomous import log
2
+ from autonomous.db.fields import (
3
+ BooleanField,
4
+ DateTimeField,
5
+ DictField,
6
+ DoesNotExist,
7
+ EmailField,
8
+ EnumField,
9
+ FileField,
10
+ FloatField,
11
+ GenericLazyReferenceField,
12
+ GenericReferenceField,
13
+ ImageField,
14
+ IntField,
15
+ ListField,
16
+ StringField,
17
+ )
18
+
19
+
20
+ class StringAttr(StringField):
21
+ pass
22
+
23
+
24
+ class IntAttr(IntField):
25
+ pass
26
+
27
+
28
+ class FloatAttr(FloatField):
29
+ pass
30
+
31
+
32
+ class BoolAttr(BooleanField):
33
+ pass
34
+
35
+
36
+ class DateTimeAttr(DateTimeField):
37
+ pass
38
+
39
+
40
+ class EmailAttr(EmailField):
41
+ pass
42
+
43
+
44
+ class FileAttr(FileField):
45
+ pass
46
+
47
+
48
+ class ImageAttr(ImageField):
49
+ pass
50
+
51
+
52
+ class ReferenceAttr(GenericReferenceField):
53
+ def __get__(self, instance, owner):
54
+ try:
55
+ result = super().__get__(instance, owner)
56
+ except DoesNotExist as e:
57
+ log(f"ReferenceAttr Error: {e}")
58
+ return None
59
+ return result
60
+
61
+
62
+ # class ReferenceAttr(GenericLazyReferenceField):
63
+ # def __get__(self, instance, owner):
64
+ # try:
65
+ # result = super().__get__(instance, owner)
66
+ # except DoesNotExist as e:
67
+ # log(f"ReferenceAttr Error: {e}")
68
+ # return None
69
+ # return result.fetch() if result and result.pk else result
70
+
71
+ # except DoesNotExist:
72
+ # If the document doesn't exist, return None
73
+ # return None
74
+
75
+ # def validate(self, value):
76
+ # if value is not None and not self.required:
77
+ # super().validate(value)
78
+
79
+
80
+ class ListAttr(ListField):
81
+ # pass
82
+ def __get__(self, instance, owner):
83
+ # log(instance, owner)
84
+ results = super().__get__(instance, owner) or []
85
+ # print(self.name, self.field, owner, results)
86
+ if isinstance(self.field, ReferenceAttr):
87
+ i = 0
88
+ while i < len(results):
89
+ try:
90
+ if not results[i]:
91
+ log(f"Removing Object: {results[i]}")
92
+ results.pop(i)
93
+ else:
94
+ i += 1
95
+ except DoesNotExist:
96
+ results.pop(i)
97
+ log(f"Object Not Found: {results[i]}")
98
+ # log(results)
99
+ return results
100
+
101
+
102
+ class DictAttr(DictField):
103
+ def __get__(self, instance, owner):
104
+ # log(instance, owner)
105
+ results = super().__get__(instance, owner) or {}
106
+ log(self.name, self.field, owner, results)
107
+ for key, lazy_obj in results.items():
108
+ try:
109
+ if hasattr(lazy_obj, "fetch"):
110
+ lazy_obj = (
111
+ lazy_obj.fetch() if lazy_obj and lazy_obj.pk else lazy_obj
112
+ )
113
+ except DoesNotExist:
114
+ log(f"Object Not Found: {lazy_obj}")
115
+ results[key] = lazy_obj
116
+ return results
117
+
118
+
119
+ class EnumAttr(EnumField):
120
+ pass