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,88 @@
1
+ __all__ = ("QueryFieldList",)
2
+
3
+
4
+ class QueryFieldList:
5
+ """Object that handles combinations of .only() and .exclude() calls"""
6
+
7
+ ONLY = 1
8
+ EXCLUDE = 0
9
+
10
+ def __init__(
11
+ self, fields=None, value=ONLY, always_include=None, _only_called=False
12
+ ):
13
+ """The QueryFieldList builder
14
+
15
+ :param fields: A list of fields used in `.only()` or `.exclude()`
16
+ :param value: How to handle the fields; either `ONLY` or `EXCLUDE`
17
+ :param always_include: Any fields to always_include eg `_cls`
18
+ :param _only_called: Has `.only()` been called? If so its a set of fields
19
+ otherwise it performs a union.
20
+ """
21
+ self.value = value
22
+ self.fields = set(fields or [])
23
+ self.always_include = set(always_include or [])
24
+ self._id = None
25
+ self._only_called = _only_called
26
+ self.slice = {}
27
+
28
+ def __add__(self, f):
29
+ if isinstance(f.value, dict):
30
+ for field in f.fields:
31
+ self.slice[field] = f.value
32
+ if not self.fields:
33
+ self.fields = f.fields
34
+ elif not self.fields:
35
+ self.fields = f.fields
36
+ self.value = f.value
37
+ self.slice = {}
38
+ elif self.value is self.ONLY and f.value is self.ONLY:
39
+ self._clean_slice()
40
+ if self._only_called:
41
+ self.fields = self.fields.union(f.fields)
42
+ else:
43
+ self.fields = f.fields
44
+ elif self.value is self.EXCLUDE and f.value is self.EXCLUDE:
45
+ self.fields = self.fields.union(f.fields)
46
+ self._clean_slice()
47
+ elif self.value is self.ONLY and f.value is self.EXCLUDE:
48
+ self.fields -= f.fields
49
+ self._clean_slice()
50
+ elif self.value is self.EXCLUDE and f.value is self.ONLY:
51
+ self.value = self.ONLY
52
+ self.fields = f.fields - self.fields
53
+ self._clean_slice()
54
+
55
+ if "_id" in f.fields:
56
+ self._id = f.value
57
+
58
+ if self.always_include:
59
+ if self.value is self.ONLY and self.fields:
60
+ if sorted(self.slice.keys()) != sorted(self.fields):
61
+ self.fields = self.fields.union(self.always_include)
62
+ else:
63
+ self.fields -= self.always_include
64
+
65
+ if getattr(f, "_only_called", False):
66
+ self._only_called = True
67
+ return self
68
+
69
+ def __bool__(self):
70
+ return bool(self.fields)
71
+
72
+ def as_dict(self):
73
+ field_list = {field: self.value for field in self.fields}
74
+ if self.slice:
75
+ field_list.update(self.slice)
76
+ if self._id is not None:
77
+ field_list["_id"] = self._id
78
+ return field_list
79
+
80
+ def reset(self):
81
+ self.fields = set()
82
+ self.slice = {}
83
+ self.value = self.ONLY
84
+
85
+ def _clean_slice(self):
86
+ if self.slice:
87
+ for field in set(self.slice.keys()) - self.fields:
88
+ del self.slice[field]
@@ -0,0 +1,58 @@
1
+ from functools import partial
2
+
3
+ from autonomous.db.queryset.queryset import QuerySet
4
+
5
+ __all__ = ("queryset_manager", "QuerySetManager")
6
+
7
+
8
+ class QuerySetManager:
9
+ """
10
+ The default QuerySet Manager.
11
+
12
+ Custom QuerySet Manager functions can extend this class and users can
13
+ add extra queryset functionality. Any custom manager methods must accept a
14
+ :class:`~autonomous.db.Document` class as its first argument, and a
15
+ :class:`~autonomous.db.queryset.QuerySet` as its second argument.
16
+
17
+ The method function should return a :class:`~autonomous.db.queryset.QuerySet`
18
+ , probably the same one that was passed in, but modified in some way.
19
+ """
20
+
21
+ get_queryset = None
22
+ default = QuerySet
23
+
24
+ def __init__(self, queryset_func=None):
25
+ if queryset_func:
26
+ self.get_queryset = queryset_func
27
+
28
+ def __get__(self, instance, owner):
29
+ """Descriptor for instantiating a new QuerySet object when
30
+ Document.objects is accessed.
31
+ """
32
+ if instance is not None:
33
+ # Document object being used rather than a document class
34
+ return self
35
+
36
+ # owner is the document that contains the QuerySetManager
37
+ queryset_class = owner._meta.get("queryset_class", self.default)
38
+ queryset = queryset_class(owner, owner._get_collection())
39
+ if self.get_queryset:
40
+ arg_count = self.get_queryset.__code__.co_argcount
41
+ if arg_count == 1:
42
+ queryset = self.get_queryset(queryset)
43
+ elif arg_count == 2:
44
+ queryset = self.get_queryset(owner, queryset)
45
+ else:
46
+ queryset = partial(self.get_queryset, owner, queryset)
47
+ return queryset
48
+
49
+
50
+ def queryset_manager(func):
51
+ """Decorator that allows you to define custom QuerySet managers on
52
+ :class:`~autonomous.db.Document` classes. The manager must be a function that
53
+ accepts a :class:`~autonomous.db.Document` class as its first argument, and a
54
+ :class:`~autonomous.db.queryset.QuerySet` as its second argument. The method
55
+ function should return a :class:`~autonomous.db.queryset.QuerySet`, probably
56
+ the same one that was passed in, but modified in some way.
57
+ """
58
+ return QuerySetManager(func)
@@ -0,0 +1,189 @@
1
+ from autonomous.db.errors import OperationError
2
+ from autonomous.db.queryset.base import (
3
+ CASCADE,
4
+ DENY,
5
+ DO_NOTHING,
6
+ NULLIFY,
7
+ PULL,
8
+ BaseQuerySet,
9
+ )
10
+
11
+ __all__ = (
12
+ "QuerySet",
13
+ "QuerySetNoCache",
14
+ "DO_NOTHING",
15
+ "NULLIFY",
16
+ "CASCADE",
17
+ "DENY",
18
+ "PULL",
19
+ )
20
+
21
+ # The maximum number of items to display in a QuerySet.__repr__
22
+ REPR_OUTPUT_SIZE = 20
23
+ ITER_CHUNK_SIZE = 100
24
+
25
+
26
+ class QuerySet(BaseQuerySet):
27
+ """The default queryset, that builds queries and handles a set of results
28
+ returned from a query.
29
+
30
+ Wraps a MongoDB cursor, providing :class:`~autonomous.db.Document` objects as
31
+ the results.
32
+ """
33
+
34
+ _has_more = True
35
+ _len = None
36
+ _result_cache = None
37
+
38
+ def __iter__(self):
39
+ """Iteration utilises a results cache which iterates the cursor
40
+ in batches of ``ITER_CHUNK_SIZE``.
41
+
42
+ If ``self._has_more`` the cursor hasn't been exhausted so cache then
43
+ batch. Otherwise iterate the result_cache.
44
+ """
45
+ self._iter = True
46
+
47
+ if self._has_more:
48
+ return self._iter_results()
49
+
50
+ # iterating over the cache.
51
+ return iter(self._result_cache)
52
+
53
+ def __len__(self):
54
+ """Since __len__ is called quite frequently (for example, as part of
55
+ list(qs)), we populate the result cache and cache the length.
56
+ """
57
+ if self._len is not None:
58
+ return self._len
59
+
60
+ # Populate the result cache with *all* of the docs in the cursor
61
+ if self._has_more:
62
+ list(self._iter_results())
63
+
64
+ # Cache the length of the complete result cache and return it
65
+ self._len = len(self._result_cache)
66
+ return self._len
67
+
68
+ def __repr__(self):
69
+ """Provide a string representation of the QuerySet"""
70
+ if self._iter:
71
+ return ".. queryset mid-iteration .."
72
+
73
+ self._populate_cache()
74
+ data = self._result_cache[: REPR_OUTPUT_SIZE + 1]
75
+ if len(data) > REPR_OUTPUT_SIZE:
76
+ data[-1] = "...(remaining elements truncated)..."
77
+ return repr(data)
78
+
79
+ def _iter_results(self):
80
+ """A generator for iterating over the result cache.
81
+
82
+ Also populates the cache if there are more possible results to
83
+ yield. Raises StopIteration when there are no more results.
84
+ """
85
+ if self._result_cache is None:
86
+ self._result_cache = []
87
+
88
+ pos = 0
89
+ while True:
90
+ # For all positions lower than the length of the current result
91
+ # cache, serve the docs straight from the cache w/o hitting the
92
+ # database.
93
+ # XXX it's VERY important to compute the len within the `while`
94
+ # condition because the result cache might expand mid-iteration
95
+ # (e.g. if we call len(qs) inside a loop that iterates over the
96
+ # queryset). Fortunately len(list) is O(1) in Python, so this
97
+ # doesn't cause performance issues.
98
+ while pos < len(self._result_cache):
99
+ yield self._result_cache[pos]
100
+ pos += 1
101
+
102
+ # return if we already established there were no more
103
+ # docs in the db cursor.
104
+ if not self._has_more:
105
+ return
106
+
107
+ # Otherwise, populate more of the cache and repeat.
108
+ if len(self._result_cache) <= pos:
109
+ self._populate_cache()
110
+
111
+ def _populate_cache(self):
112
+ """
113
+ Populates the result cache with ``ITER_CHUNK_SIZE`` more entries
114
+ (until the cursor is exhausted).
115
+ """
116
+ if self._result_cache is None:
117
+ self._result_cache = []
118
+
119
+ # Skip populating the cache if we already established there are no
120
+ # more docs to pull from the database.
121
+ if not self._has_more:
122
+ return
123
+
124
+ # Pull in ITER_CHUNK_SIZE docs from the database and store them in
125
+ # the result cache.
126
+ try:
127
+ for _ in range(ITER_CHUNK_SIZE):
128
+ self._result_cache.append(next(self))
129
+ except StopIteration:
130
+ # Getting this exception means there are no more docs in the
131
+ # db cursor. Set _has_more to False so that we can use that
132
+ # information in other places.
133
+ self._has_more = False
134
+
135
+ def count(self, with_limit_and_skip=False):
136
+ """Count the selected elements in the query.
137
+
138
+ :param with_limit_and_skip (optional): take any :meth:`limit` or
139
+ :meth:`skip` that has been applied to this cursor into account when
140
+ getting the count
141
+ """
142
+ if with_limit_and_skip is False:
143
+ return super().count(with_limit_and_skip)
144
+
145
+ if self._len is None:
146
+ # cache the length
147
+ self._len = super().count(with_limit_and_skip)
148
+
149
+ return self._len
150
+
151
+ def no_cache(self):
152
+ """Convert to a non-caching queryset"""
153
+ if self._result_cache is not None:
154
+ raise OperationError("QuerySet already cached")
155
+
156
+ return self._clone_into(QuerySetNoCache(self._document, self._collection))
157
+
158
+
159
+ class QuerySetNoCache(BaseQuerySet):
160
+ """A non caching QuerySet"""
161
+
162
+ def cache(self):
163
+ """Convert to a caching queryset"""
164
+ return self._clone_into(QuerySet(self._document, self._collection))
165
+
166
+ def __repr__(self):
167
+ """Provides the string representation of the QuerySet"""
168
+ if self._iter:
169
+ return ".. queryset mid-iteration .."
170
+
171
+ data = []
172
+ for _ in range(REPR_OUTPUT_SIZE + 1):
173
+ try:
174
+ data.append(next(self))
175
+ except StopIteration:
176
+ break
177
+
178
+ if len(data) > REPR_OUTPUT_SIZE:
179
+ data[-1] = "...(remaining elements truncated)..."
180
+
181
+ self.rewind()
182
+ return repr(data)
183
+
184
+ def __iter__(self):
185
+ queryset = self
186
+ if queryset._iter:
187
+ queryset = self.clone()
188
+ queryset.rewind()
189
+ return queryset