autonomous-app 0.3.0__tar.gz → 0.3.2__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.
Files changed (69) hide show
  1. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/PKG-INFO +2 -2
  2. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/requirements.txt +1 -1
  3. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/__init__.py +1 -1
  4. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/audioagent.py +1 -1
  5. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/imageagent.py +1 -1
  6. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/jsonagent.py +1 -1
  7. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/models/openai.py +81 -53
  8. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/oaiagent.py +1 -14
  9. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/textagent.py +1 -1
  10. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/auth/autoauth.py +10 -10
  11. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/auth/user.py +17 -2
  12. autonomous_app-0.3.2/src/autonomous/db/__init__.py +42 -0
  13. autonomous_app-0.3.2/src/autonomous/db/base/__init__.py +33 -0
  14. autonomous_app-0.3.2/src/autonomous/db/base/common.py +62 -0
  15. autonomous_app-0.3.2/src/autonomous/db/base/datastructures.py +476 -0
  16. autonomous_app-0.3.2/src/autonomous/db/base/document.py +1230 -0
  17. autonomous_app-0.3.2/src/autonomous/db/base/fields.py +767 -0
  18. autonomous_app-0.3.2/src/autonomous/db/base/metaclasses.py +468 -0
  19. autonomous_app-0.3.2/src/autonomous/db/base/utils.py +22 -0
  20. autonomous_app-0.3.2/src/autonomous/db/common.py +79 -0
  21. autonomous_app-0.3.2/src/autonomous/db/connection.py +472 -0
  22. autonomous_app-0.3.2/src/autonomous/db/context_managers.py +313 -0
  23. autonomous_app-0.3.2/src/autonomous/db/dereference.py +291 -0
  24. autonomous_app-0.3.2/src/autonomous/db/document.py +1141 -0
  25. autonomous_app-0.3.2/src/autonomous/db/errors.py +165 -0
  26. autonomous_app-0.3.2/src/autonomous/db/fields.py +2732 -0
  27. autonomous_app-0.3.2/src/autonomous/db/mongodb_support.py +24 -0
  28. autonomous_app-0.3.2/src/autonomous/db/pymongo_support.py +80 -0
  29. autonomous_app-0.3.2/src/autonomous/db/queryset/__init__.py +28 -0
  30. autonomous_app-0.3.2/src/autonomous/db/queryset/base.py +2033 -0
  31. autonomous_app-0.3.2/src/autonomous/db/queryset/field_list.py +88 -0
  32. autonomous_app-0.3.2/src/autonomous/db/queryset/manager.py +58 -0
  33. autonomous_app-0.3.2/src/autonomous/db/queryset/queryset.py +189 -0
  34. autonomous_app-0.3.2/src/autonomous/db/queryset/transform.py +527 -0
  35. autonomous_app-0.3.2/src/autonomous/db/queryset/visitor.py +189 -0
  36. autonomous_app-0.3.2/src/autonomous/db/signals.py +59 -0
  37. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/logger.py +3 -0
  38. autonomous_app-0.3.2/src/autonomous/model/autoattr.py +120 -0
  39. autonomous_app-0.3.2/src/autonomous/model/automodel.py +220 -0
  40. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/storage/imagestorage.py +49 -8
  41. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous_app.egg-info/PKG-INFO +2 -2
  42. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous_app.egg-info/SOURCES.txt +25 -0
  43. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous_app.egg-info/requires.txt +1 -1
  44. autonomous_app-0.3.0/src/autonomous/model/autoattr.py +0 -105
  45. autonomous_app-0.3.0/src/autonomous/model/automodel.py +0 -159
  46. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/LICENSE +0 -0
  47. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/README.md +0 -0
  48. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/pyproject.toml +0 -0
  49. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/setup.cfg +0 -0
  50. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/setup.py +0 -0
  51. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/__init__.py +0 -0
  52. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/ai/models/__init__.py +0 -0
  53. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/apis/version_control/GHCallbacks.py +0 -0
  54. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/apis/version_control/GHOrganization.py +0 -0
  55. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/apis/version_control/GHRepo.py +0 -0
  56. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/apis/version_control/GHVersionControl.py +0 -0
  57. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/apis/version_control/__init__.py +0 -0
  58. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/auth/__init__.py +0 -0
  59. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/auth/github.py +0 -0
  60. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/auth/google.py +0 -0
  61. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/cli.py +0 -0
  62. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/model/__init__.py +0 -0
  63. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/storage/__init__.py +0 -0
  64. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/storage/localstorage.py +0 -0
  65. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/tasks/__init__.py +0 -0
  66. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/tasks/autotask.py +0 -0
  67. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous/utils/markdown.py +0 -0
  68. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous_app.egg-info/dependency_links.txt +0 -0
  69. {autonomous_app-0.3.0 → autonomous_app-0.3.2}/src/autonomous_app.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autonomous-app
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Containerized application framework built on Flask with additional libraries and tools for rapid development of web applications.
5
5
  Author-email: Steven A Moore <samoore@binghamton.edu>
6
6
  License: MIT License
@@ -34,9 +34,9 @@ License-File: LICENSE
34
34
  Requires-Dist: Flask
35
35
  Requires-Dist: setuptools
36
36
  Requires-Dist: python-dotenv
37
+ Requires-Dist: blinker
37
38
  Requires-Dist: PyGithub
38
39
  Requires-Dist: pygit2
39
- Requires-Dist: mongoengine
40
40
  Requires-Dist: pillow
41
41
  Requires-Dist: redis
42
42
  Requires-Dist: jsmin
@@ -12,12 +12,12 @@ Flask
12
12
 
13
13
  setuptools
14
14
  python-dotenv
15
+ blinker
15
16
 
16
17
  ##### Storage #####
17
18
 
18
19
  PyGithub
19
20
  pygit2
20
- mongoengine
21
21
  pillow
22
22
  redis
23
23
 
@@ -1,4 +1,4 @@
1
- __version__ = "0.3.00"
1
+ __version__ = "0.3.2"
2
2
 
3
3
  from dotenv import load_dotenv
4
4
 
@@ -6,7 +6,7 @@ from .models.openai import OpenAIModel
6
6
 
7
7
 
8
8
  class AudioAgent(AutoModel):
9
- client = ReferenceAttr()
9
+ client = ReferenceAttr(choices=[OpenAIModel])
10
10
  name = StringAttr(default="audioagent")
11
11
  instructions = StringAttr(
12
12
  default="You are highly skilled AI trained to assist with generating audio files."
@@ -5,7 +5,7 @@ from .models.openai import OpenAIModel
5
5
 
6
6
 
7
7
  class ImageAgent(AutoModel):
8
- client = ReferenceAttr()
8
+ client = ReferenceAttr(choices=[OpenAIModel])
9
9
  name = StringAttr(default="imageagent")
10
10
  instructions = StringAttr(
11
11
  default="You are highly skilled AI trained to assist with generating images."
@@ -7,7 +7,7 @@ from .models.openai import OpenAIModel
7
7
 
8
8
 
9
9
  class JSONAgent(AutoModel):
10
- client = ReferenceAttr()
10
+ client = ReferenceAttr(choices=[OpenAIModel])
11
11
  name = StringAttr(default="jsonagent")
12
12
  instructions = StringAttr(
13
13
  default="You are highly skilled AI trained to assist with generating JSON formatted data."
@@ -4,6 +4,7 @@ import random
4
4
  import time
5
5
  from base64 import b64decode
6
6
 
7
+ import openai
7
8
  from openai import NotFoundError as openai_NotFoundError
8
9
  from openai import OpenAI
9
10
 
@@ -14,9 +15,9 @@ from autonomous.model.automodel import AutoModel
14
15
 
15
16
  class OpenAIModel(AutoModel):
16
17
  _client = None
17
- text_model = StringAttr(default="gpt-4o")
18
- image_model = StringAttr(default="dall-e-3")
19
- json_model = StringAttr(default="gpt-4o")
18
+ _text_model = "gpt-4o-mini"
19
+ _image_model = "dall-e-3"
20
+ _json_model = "gpt-4o"
20
21
  agent_id = StringAttr()
21
22
  messages = ListAttr(StringAttr(default=[]))
22
23
  tools = DictAttr()
@@ -59,23 +60,25 @@ class OpenAIModel(AutoModel):
59
60
  instructions=self.instructions,
60
61
  description=self.description,
61
62
  name=self.name,
62
- model=self.json_model,
63
+ model=self._json_model,
63
64
  )
64
65
  self.agent_id = agent.id
65
66
  log(f"==== Creating Agent with ID: {self.agent_id} ====")
66
67
  self.save()
67
68
  return self.agent_id
68
69
 
69
- def clear_files(self, file_id=None):
70
+ def clear_files(self, file_id=None, all=False):
70
71
  if not file_id:
71
72
  store_files = self.client.files.list().data
72
- for sf in store_files:
73
- self.client.files.delete(file_id=sf.id)
73
+
74
74
  for vs in self.client.beta.vector_stores.list().data:
75
75
  try:
76
76
  self.client.beta.vector_stores.delete(vs.id)
77
77
  except openai_NotFoundError:
78
78
  log(f"==== Vector Store {vs.id} not found ====")
79
+ if all:
80
+ for sf in store_files:
81
+ self.client.files.delete(file_id=sf.id)
79
82
  else:
80
83
  self.client.files.delete(file_id=file_id)
81
84
  self.tools.pop("file_search", None)
@@ -112,17 +115,18 @@ class OpenAIModel(AutoModel):
112
115
 
113
116
  def _add_function(self, user_function):
114
117
  user_function["strict"] = True
115
- user_function["parameters"]["required"] = list(
116
- user_function["parameters"]["properties"].keys()
117
- )
118
118
  user_function["parameters"]["additionalProperties"] = False
119
+ if not user_function["parameters"].get("required"):
120
+ user_function["parameters"]["required"] = list(
121
+ user_function["parameters"]["properties"].keys()
122
+ )
119
123
 
120
124
  self.tools["function"] = {"type": "function", "function": user_function}
121
125
  self.client.beta.assistants.update(
122
126
  self._get_agent_id(), tools=list(self.tools.values())
123
127
  )
124
128
  return """
125
- IMPORTANT: Always use the function 'response' tool to respond to the user with the only the requested JSON schema. DO NOT add any text to the response outside of the JSON schema.
129
+ IMPORTANT: Always use the function 'response' tool to respond to the user with only the requested JSON schema. DO NOT add any text to the response outside of the JSON schema.
126
130
 
127
131
  """
128
132
 
@@ -141,34 +145,64 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with t
141
145
  return message_list
142
146
 
143
147
  def generate_json(self, messages, function, additional_instructions=""):
144
- _instructions_addition = self._add_function(function)
145
- _instructions_addition += additional_instructions
148
+ # _instructions_addition = self._add_function(function)
149
+ function["strict"] = True
150
+ function["parameters"]["additionalProperties"] = False
151
+ function["parameters"]["required"] = list(
152
+ function["parameters"]["properties"].keys()
153
+ )
146
154
 
147
155
  formatted_messages = self._format_messages(messages)
148
156
  thread = self.client.beta.threads.create(messages=formatted_messages)
149
-
150
- run = self.client.beta.threads.runs.create(
151
- thread_id=thread.id,
152
- assistant_id=self._get_agent_id(),
153
- additional_instructions=_instructions_addition,
154
- parallel_tool_calls=False,
155
- )
156
-
157
- while run.status in ["queued", "in_progress"]:
158
- run = self.client.beta.threads.runs.retrieve(
159
- thread_id=thread.id,
160
- run_id=run.id,
161
- )
162
- time.sleep(0.5)
163
- log(f"==== Job Status: {run.status} ====")
164
- print(f"==== Job Status: {run.status} ====")
165
-
157
+ # log(function, _print=True)
158
+ running_job = True
159
+ while running_job:
160
+ try:
161
+ run = self.client.beta.threads.runs.create_and_poll(
162
+ thread_id=thread.id,
163
+ assistant_id=self._get_agent_id(),
164
+ additional_instructions=additional_instructions,
165
+ parallel_tool_calls=False,
166
+ tools=[
167
+ {"type": "file_search"},
168
+ {"type": "function", "function": function},
169
+ ],
170
+ tool_choice={
171
+ "type": "function",
172
+ "function": {"name": function["name"]},
173
+ },
174
+ )
175
+ log(f"==== Job Status: {run.status} ====", _print=True)
176
+ if run.status in [
177
+ "failed",
178
+ "expired",
179
+ "canceled",
180
+ "completed",
181
+ "incomplete",
182
+ "requires_action",
183
+ ]:
184
+ running_job = False
185
+
186
+ except openai.error.BadRequestError as e:
187
+ # Handle specific bad request errors
188
+ error_message = e.json_body.get("error", {}).get("message", "")
189
+ if "already has an active run" in error_message:
190
+ log("Previous run is still active. Waiting...", _print=True)
191
+ time.sleep(2) # wait before retrying or checking run status
192
+ else:
193
+ raise e
194
+
195
+ # while run.status in ["queued", "in_progress"]:
196
+ # run = self.client.beta.threads.runs.retrieve(
197
+ # thread_id=thread.id,
198
+ # run_id=run.id,
199
+ # )
200
+ # time.sleep(0.5)
166
201
  if run.status in ["failed", "expired", "canceled"]:
167
- log(f"==== Error: {run.last_error} ====")
168
- print(f"==== Error: {run.last_error} ====")
202
+ log(f"==== !!! ERROR !!!: {run.last_error} ====", _print=True)
169
203
  return None
170
- print("=================== RUN COMPLETED ===================")
171
- print(run.status)
204
+ log("=================== RUN COMPLETED ===================", _print=True)
205
+ log(run.status, _print=True)
172
206
  if run.status == "completed":
173
207
  response = self.client.beta.threads.messages.list(thread_id=thread.id)
174
208
  results = response.data[0].content[0].text.value
@@ -177,21 +211,18 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with t
177
211
  0
178
212
  ].function.arguments
179
213
  else:
180
- log(f"====Status: {run.status} Error: {run.last_error} ====")
181
- print(f"====Status: {run.status} Error: {run.last_error} ====")
214
+ log(f"====Status: {run.status} Error: {run.last_error} ====", _print=True)
182
215
  return None
183
216
 
184
217
  results = results[results.find("{") : results.rfind("}") + 1]
185
218
  try:
186
219
  results = json.loads(results, strict=False)
187
220
  except Exception:
188
- print(f"==== Invalid JSON:\n{results}")
189
- log(f"==== Invalid JSON:\n{results}")
221
+ print(f"==== Invalid JSON:\n{results}", _print=True)
190
222
  return {}
191
223
  else:
192
- log(f"==== Results: {results} ====")
193
- print(results)
194
- print("=================== END REPORT ===================")
224
+ log(f"==== Results: {results}", _print=True)
225
+ log("=================== END REPORT ===================", _print=True)
195
226
  return results
196
227
 
197
228
  def generate_text(self, messages, additional_instructions=""):
@@ -211,25 +242,22 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with t
211
242
  run_id=run.id,
212
243
  )
213
244
  time.sleep(0.5)
214
- log(f"==== Job Status: {run.status} ====")
215
- print(f"==== Job Status: {run.status} ====")
245
+ log(f"==== Job Status: {run.status} ====", _print=True)
216
246
 
217
247
  if run.status in ["failed", "expired", "canceled"]:
218
- log(f"==== Error: {run.last_error} ====")
219
- print(f"==== Error: {run.last_error} ====")
248
+ log(f"==== Error: {run.last_error} ====", _print=True)
220
249
  return None
221
- print("=================== RUN COMPLETED ===================")
222
- print(run.status)
250
+ log("=================== RUN COMPLETED ===================", _print=True)
251
+ log(run.status, _print=True)
223
252
  if run.status == "completed":
224
253
  response = self.client.beta.threads.messages.list(thread_id=thread.id)
225
254
  results = response.data[0].content[0].text.value
226
255
  else:
227
- log(f"====Status: {run.status} Error: {run.last_error} ====")
228
- print(f"====Status: {run.status} Error: {run.last_error} ====")
256
+ log(f"====Status: {run.status} Error: {run.last_error} ====", _print=True)
229
257
  return None
230
258
 
231
- print(results)
232
- print("=================== END REPORT ===================")
259
+ log(results, _print=True)
260
+ log("=================== END REPORT ===================", _print=True)
233
261
  return results
234
262
 
235
263
  def generate_audio(self, prompt, file_path, **kwargs):
@@ -248,7 +276,7 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with t
248
276
  image = None
249
277
  try:
250
278
  response = self.client.images.generate(
251
- model=self.image_model,
279
+ model=self._image_model,
252
280
  prompt=prompt,
253
281
  response_format="b64_json",
254
282
  **kwargs,
@@ -269,7 +297,7 @@ IMPORTANT: Always use the function 'response' tool to respond to the user with t
269
297
  {"role": "user", "content": text},
270
298
  ]
271
299
  response = self.client.chat.completions.create(
272
- model="gpt-4o-mini", messages=message
300
+ model=self._text_model, messages=message
273
301
  )
274
302
  try:
275
303
  result = response.choices[0].message.content
@@ -1,13 +1,3 @@
1
- import io
2
- import json
3
- import os
4
- import random
5
- import time
6
- from base64 import b64decode
7
-
8
- from openai import OpenAI
9
- from pydantic import model_validator
10
-
11
1
  from autonomous import log
12
2
  from autonomous.model.autoattr import ReferenceAttr
13
3
  from autonomous.model.automodel import AutoModel
@@ -16,7 +6,7 @@ from .models.openai import OpenAIModel
16
6
 
17
7
 
18
8
  class OAIAgent(AutoModel):
19
- client_model = ReferenceAttr()
9
+ client_model = ReferenceAttr(choices=[OpenAIModel])
20
10
  _ai_model = OpenAIModel
21
11
 
22
12
  @property
@@ -26,9 +16,6 @@ class OAIAgent(AutoModel):
26
16
  self.save()
27
17
  return self.client_model
28
18
 
29
- def __init__(self, **kwargs):
30
- self._client = OpenAI(api_key=os.environ.get("OPENAI_KEY"))
31
-
32
19
  def clear_files(self, file_id=None):
33
20
  return self.client.clear_files(file_id)
34
21
 
@@ -6,7 +6,7 @@ from .models.openai import OpenAIModel
6
6
 
7
7
 
8
8
  class TextAgent(AutoModel):
9
- client = ReferenceAttr()
9
+ client = ReferenceAttr(choices=[OpenAIModel])
10
10
  name = StringAttr(default="textagent")
11
11
  instructions = StringAttr(
12
12
  default="You are highly skilled AI trained to assist with generating text according to the given requirements."
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import uuid
2
3
  from datetime import datetime
3
4
  from functools import wraps
@@ -7,11 +8,11 @@ from authlib.integrations.requests_client import OAuth2Auth, OAuth2Session
7
8
  from flask import redirect, session, url_for
8
9
 
9
10
  from autonomous import log
10
- from autonomous.auth.user import AutoUser
11
+ from autonomous.auth.user import User
11
12
 
12
13
 
13
14
  class AutoAuth:
14
- user_class: type[AutoUser] = AutoUser
15
+ user_class: type[User] = User
15
16
 
16
17
  def __init__(
17
18
  self,
@@ -46,13 +47,12 @@ class AutoAuth:
46
47
  """
47
48
  Returns the current user.
48
49
  """
49
- user = cls.user_class.get_guest()
50
- if session.get("user") and session["user"]["state"] == "authenticated":
51
- try:
52
- user = cls.user_class.get(session["user"].get("pk"))
53
- user.pk
54
- except Exception as e:
55
- log(e, session["user"])
50
+
51
+ user = (
52
+ cls.user_class.from_json(session["user"]) if session.get("user") else None
53
+ )
54
+ if not user or user.state != "authenticated":
55
+ user = cls.user_class.get_guest()
56
56
  return user
57
57
 
58
58
  def authenticate(self):
@@ -106,7 +106,7 @@ class AutoAuth:
106
106
  user.last_login = datetime.now()
107
107
  # log(user)
108
108
  user.save()
109
- session["user"] = user.serialize()
109
+ session["user"] = user.to_json()
110
110
  # log(guest, user.is_guest)
111
111
  if not guest and user.is_guest:
112
112
  return redirect(url_for("auth.login"))
@@ -14,6 +14,11 @@ class AutoUser(AutoModel):
14
14
  This class represents a user who can authenticate using OpenID.
15
15
  """
16
16
 
17
+ meta = {
18
+ "abstract": True,
19
+ "allow_inheritance": True,
20
+ "strict": False,
21
+ }
17
22
  name = StringAttr(default="Anonymous")
18
23
  email = StringAttr(required=True)
19
24
  last_login = DateTimeAttr(default=datetime.now)
@@ -34,9 +39,10 @@ class AutoUser(AutoModel):
34
39
  email = user_info["email"].strip()
35
40
  name = user_info["name"].strip()
36
41
  user = cls.find(email=email)
42
+ log(email, user)
37
43
  if not user:
38
44
  log(f"Creating new user for {email}")
39
- user = cls(name=name, email=email)
45
+ # user = cls(name=name, email=email)
40
46
 
41
47
  # parse user_info into a user object
42
48
  user.name = name
@@ -51,7 +57,7 @@ class AutoUser(AutoModel):
51
57
  """
52
58
  Returns a guest user.
53
59
  """
54
- guest = cls.find(name="_GuestOfAutonomous_", state="guest")
60
+ guest = cls.find(name="_GuestOfAutonomous_")
55
61
  if not guest:
56
62
  guest = cls(
57
63
  name="_GuestOfAutonomous_",
@@ -82,3 +88,12 @@ class AutoUser(AutoModel):
82
88
  Returns True if the user is a guest, False otherwise.
83
89
  """
84
90
  return self.is_authenticated and self.role == "admin"
91
+
92
+
93
+ class User(AutoUser):
94
+ """
95
+ This class represents a user who can authenticate using OpenID.
96
+ """
97
+
98
+ def __repr__(self):
99
+ return f"<User {self.pk} {self.email}>"
@@ -0,0 +1,42 @@
1
+ # Import submodules so that we can expose their __all__
2
+ # Import everything from each submodule so that it can be accessed via
3
+ # autonomous.db, e.g. instead of `from autonomous.db.connection import connect`,
4
+ # users can simply use `from autonomous.db import connect`, or even
5
+ # `from autonomous.db import *` and then `connect('testdb')`.
6
+ from autonomous.db import (
7
+ connection,
8
+ document,
9
+ errors,
10
+ fields,
11
+ queryset,
12
+ signals,
13
+ )
14
+ from autonomous.db.connection import * # noqa: F401
15
+ from autonomous.db.document import * # noqa: F401
16
+ from autonomous.db.errors import * # noqa: F401
17
+ from autonomous.db.fields import * # noqa: F401
18
+ from autonomous.db.queryset import * # noqa: F401
19
+ from autonomous.db.signals import * # noqa: F401
20
+
21
+ __all__ = (
22
+ list(document.__all__)
23
+ + list(fields.__all__)
24
+ + list(connection.__all__)
25
+ + list(queryset.__all__)
26
+ + list(signals.__all__)
27
+ + list(errors.__all__)
28
+ )
29
+
30
+
31
+ VERSION = (0, 29, 0)
32
+
33
+
34
+ def get_version():
35
+ """Return the VERSION as a string.
36
+
37
+ For example, if `VERSION == (0, 10, 7)`, return '0.10.7'.
38
+ """
39
+ return ".".join(map(str, VERSION))
40
+
41
+
42
+ __version__ = get_version()
@@ -0,0 +1,33 @@
1
+ # Base module is split into several files for convenience. Files inside of
2
+ # this module should import from a specific submodule (e.g.
3
+ # `from autonomous.db.base.document import BaseDocument`), but all of the
4
+ # other modules should import directly from the top-level module (e.g.
5
+ # `from autonomous.db.base import BaseDocument`). This approach is cleaner and
6
+ # also helps with cyclical import errors.
7
+ from autonomous.db.base.common import *
8
+ from autonomous.db.base.datastructures import *
9
+ from autonomous.db.base.document import *
10
+ from autonomous.db.base.fields import *
11
+ from autonomous.db.base.metaclasses import *
12
+
13
+ __all__ = (
14
+ # common
15
+ "UPDATE_OPERATORS",
16
+ "_document_registry",
17
+ "get_document",
18
+ # datastructures
19
+ "BaseDict",
20
+ "BaseList",
21
+ "EmbeddedDocumentList",
22
+ "LazyReference",
23
+ # document
24
+ "BaseDocument",
25
+ # fields
26
+ "BaseField",
27
+ "ComplexBaseField",
28
+ "ObjectIdField",
29
+ "GeoJsonBaseField",
30
+ # metaclasses
31
+ "DocumentMetaclass",
32
+ "TopLevelDocumentMetaclass",
33
+ )
@@ -0,0 +1,62 @@
1
+ from autonomous.db.errors import NotRegistered
2
+
3
+ __all__ = ("UPDATE_OPERATORS", "get_document", "_document_registry")
4
+
5
+
6
+ UPDATE_OPERATORS = {
7
+ "set",
8
+ "unset",
9
+ "inc",
10
+ "dec",
11
+ "mul",
12
+ "pop",
13
+ "push",
14
+ "push_all",
15
+ "pull",
16
+ "pull_all",
17
+ "add_to_set",
18
+ "set_on_insert",
19
+ "min",
20
+ "max",
21
+ "rename",
22
+ }
23
+
24
+
25
+ _document_registry = {}
26
+
27
+
28
+ def get_document(name):
29
+ """Get a registered Document class by name."""
30
+ doc = _document_registry.get(name, None)
31
+ if not doc:
32
+ # Possible old style name
33
+ single_end = name.split(".")[-1]
34
+ compound_end = ".%s" % single_end
35
+ possible_match = [
36
+ k for k in _document_registry if k.endswith(compound_end) or k == single_end
37
+ ]
38
+ if len(possible_match) == 1:
39
+ doc = _document_registry.get(possible_match.pop(), None)
40
+ if not doc:
41
+ raise NotRegistered(
42
+ """
43
+ `%s` has not been registered in the document registry.
44
+ Importing the document class automatically registers it, has it
45
+ been imported?
46
+ """.strip()
47
+ % name
48
+ )
49
+ return doc
50
+
51
+
52
+ def _get_documents_by_db(connection_alias, default_connection_alias):
53
+ """Get all registered Documents class attached to a given database"""
54
+
55
+ def get_doc_alias(doc_cls):
56
+ return doc_cls._meta.get("db_alias", default_connection_alias)
57
+
58
+ return [
59
+ doc_cls
60
+ for doc_cls in _document_registry.values()
61
+ if get_doc_alias(doc_cls) == connection_alias
62
+ ]