future-framework 2.0.0__tar.gz → 2.1.1__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 (83) hide show
  1. {future_framework-2.0.0 → future_framework-2.1.1}/PKG-INFO +2 -1
  2. {future_framework-2.0.0 → future_framework-2.1.1}/future/application.py +1 -1
  3. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/ElasticsearchDatabase.py +18 -3
  4. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/PostgresDatabase.py +16 -8
  5. {future_framework-2.0.0 → future_framework-2.1.1}/future/response.py +18 -62
  6. {future_framework-2.0.0 → future_framework-2.1.1}/future/seeder.py +62 -2
  7. {future_framework-2.0.0 → future_framework-2.1.1}/pyproject.toml +1 -1
  8. {future_framework-2.0.0 → future_framework-2.1.1}/LICENSE +0 -0
  9. {future_framework-2.0.0 → future_framework-2.1.1}/README.md +0 -0
  10. {future_framework-2.0.0 → future_framework-2.1.1}/future/__init__.py +0 -0
  11. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/Auth0Authentication.py +0 -0
  12. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/AzureADAuthentication.py +0 -0
  13. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/BasicAuthentication.py +0 -0
  14. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/KerberosAuthentication.py +0 -0
  15. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/KeycloakAuthentication.py +0 -0
  16. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/OAuth2Authentication.py +0 -0
  17. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/OpenIdConnectAuthentication.py +0 -0
  18. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/SAMLAuthentication.py +0 -0
  19. {future_framework-2.0.0 → future_framework-2.1.1}/future/authentication/__init__.py +0 -0
  20. {future_framework-2.0.0 → future_framework-2.1.1}/future/cli.py +0 -0
  21. {future_framework-2.0.0 → future_framework-2.1.1}/future/controllers/DebugController.py +0 -0
  22. {future_framework-2.0.0 → future_framework-2.1.1}/future/controllers/GraphQLController.py +0 -0
  23. {future_framework-2.0.0 → future_framework-2.1.1}/future/controllers/OpenAPIController.py +0 -0
  24. {future_framework-2.0.0 → future_framework-2.1.1}/future/controllers/WebSocketController.py +0 -0
  25. {future_framework-2.0.0 → future_framework-2.1.1}/future/controllers/WelcomeController.py +0 -0
  26. {future_framework-2.0.0 → future_framework-2.1.1}/future/controllers/__init__.py +0 -0
  27. {future_framework-2.0.0 → future_framework-2.1.1}/future/database.py +0 -0
  28. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/ClickhouseDatabase.py +0 -0
  29. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/MongoDBDatabase.py +0 -0
  30. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/MySQLDatabase.py +0 -0
  31. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/RedisDatabase.py +0 -0
  32. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/SQLiteDatabase.py +0 -0
  33. {future_framework-2.0.0 → future_framework-2.1.1}/future/databases/__init__.py +0 -0
  34. {future_framework-2.0.0 → future_framework-2.1.1}/future/exceptions.py +0 -0
  35. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/IAuthentication.py +0 -0
  36. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/IController.py +0 -0
  37. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/IDatabase.py +0 -0
  38. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/IMiddleware.py +0 -0
  39. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/IModel.py +0 -0
  40. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/IPlugin.py +0 -0
  41. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/ITask.py +0 -0
  42. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfaces/__init__.py +0 -0
  43. {future_framework-2.0.0 → future_framework-2.1.1}/future/interfacing.py +0 -0
  44. {future_framework-2.0.0 → future_framework-2.1.1}/future/lifespan.py +0 -0
  45. {future_framework-2.0.0 → future_framework-2.1.1}/future/logger.py +0 -0
  46. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/BruteforcePreventionMiddleware.py +0 -0
  47. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/CORSMiddleware.py +0 -0
  48. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/CSRFMiddleware.py +0 -0
  49. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/GZipMiddleware.py +0 -0
  50. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/HTAccessConfuserMiddleware.py +0 -0
  51. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/HeaderConfuserMiddleware.py +0 -0
  52. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/RateLimitMiddleware.py +0 -0
  53. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/ResponseCodeConfuserMiddleware.py +0 -0
  54. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/SQLiConfuserMiddleware.py +0 -0
  55. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/ScopeValidationMiddleware.py +0 -0
  56. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/SessionMiddleware.py +0 -0
  57. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/TestMiddlewareRequest.py +0 -0
  58. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/TestMiddlewareResponse.py +0 -0
  59. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/WebServerConfuserMiddleware.py +0 -0
  60. {future_framework-2.0.0 → future_framework-2.1.1}/future/middleware/__init__.py +0 -0
  61. {future_framework-2.0.0 → future_framework-2.1.1}/future/migrations.py +0 -0
  62. {future_framework-2.0.0 → future_framework-2.1.1}/future/models/PostModel.py +0 -0
  63. {future_framework-2.0.0 → future_framework-2.1.1}/future/models/Query.py +0 -0
  64. {future_framework-2.0.0 → future_framework-2.1.1}/future/models/UserModel.py +0 -0
  65. {future_framework-2.0.0 → future_framework-2.1.1}/future/models/__init__.py +0 -0
  66. {future_framework-2.0.0 → future_framework-2.1.1}/future/openapi.py +0 -0
  67. {future_framework-2.0.0 → future_framework-2.1.1}/future/plugins/ElasticsearchPlugin.py +0 -0
  68. {future_framework-2.0.0 → future_framework-2.1.1}/future/plugins/__init__.py +0 -0
  69. {future_framework-2.0.0 → future_framework-2.1.1}/future/request.py +0 -0
  70. {future_framework-2.0.0 → future_framework-2.1.1}/future/routing.py +0 -0
  71. {future_framework-2.0.0 → future_framework-2.1.1}/future/settings.py +0 -0
  72. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/CheckDNSTask.py +0 -0
  73. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/CheckDiskUsageTask.py +0 -0
  74. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/CheckHttpStatusTask.py +0 -0
  75. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/CheckMemoryUsageTask.py +0 -0
  76. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/CheckSSHBannerTask.py +0 -0
  77. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/CheckSystemUptimeTask.py +0 -0
  78. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/DailyBackupTask.py +0 -0
  79. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/SyncTaskExample.py +0 -0
  80. {future_framework-2.0.0 → future_framework-2.1.1}/future/tasks/__init__.py +0 -0
  81. {future_framework-2.0.0 → future_framework-2.1.1}/future/taskscheduler.py +0 -0
  82. {future_framework-2.0.0 → future_framework-2.1.1}/future/testclient.py +0 -0
  83. {future_framework-2.0.0 → future_framework-2.1.1}/future/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: future-framework
3
- Version: 2.0.0
3
+ Version: 2.1.1
4
4
  Summary: ASGI-based framework for web APIs
5
5
  License: LICENSE
6
6
  License-File: LICENSE
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
13
  Classifier: Programming Language :: Python :: 3.14
14
+ Classifier: Programming Language :: Python :: 3.15
14
15
  Requires-Dist: aiomysql (>=0.2.0,<0.3.0)
15
16
  Requires-Dist: aiosqlite (>=0.21.0,<0.22.0)
16
17
  Requires-Dist: asynch (>=0.2.5,<0.3.0)
@@ -402,7 +402,7 @@ class Future:
402
402
  try:
403
403
  host_domain = request.host.split("/")[0] if "/" in request.host else request.host
404
404
  if not self._validate_domain_access(host_domain):
405
- raise HTTPException("Forbidden", 403)
405
+ raise HTTPException("Not Found", 404)
406
406
 
407
407
  debug = bool(self.config.get("APP_DEBUG")) if self.config else False
408
408
  route_host = host_domain.rsplit(":", 1)[0] if debug and ":" in host_domain else host_domain
@@ -42,7 +42,10 @@ class ElasticsearchDatabase(IDatabase):
42
42
  return None
43
43
  if not result or "_source" not in result:
44
44
  return None
45
- return model.__class__(**result["_source"])
45
+ source = dict(result["_source"] or {})
46
+ if result.get("_id") is not None and not source.get("id"):
47
+ source["id"] = result["_id"]
48
+ return model.__class__(**source)
46
49
 
47
50
  async def all(self, model):
48
51
  if self.client is None:
@@ -51,7 +54,13 @@ class ElasticsearchDatabase(IDatabase):
51
54
  result = await self.client.search(index=model.tableize(), body={"query": {"match_all": {}}, "size": 10000})
52
55
  except Exception:
53
56
  return []
54
- return [model.__class__(**hit["_source"]) for hit in result.get("hits", {}).get("hits", [])]
57
+ rows = []
58
+ for hit in result.get("hits", {}).get("hits", []):
59
+ source = dict(hit.get("_source") or {})
60
+ if hit.get("_id") is not None and not source.get("id"):
61
+ source["id"] = hit["_id"]
62
+ rows.append(model.__class__(**source))
63
+ return rows
55
64
 
56
65
  async def get(self, model, wheres, limit=None, orders=None):
57
66
  if self.client is None:
@@ -85,7 +94,13 @@ class ElasticsearchDatabase(IDatabase):
85
94
  result = await self.client.search(index=model.tableize(), body=body)
86
95
  except Exception:
87
96
  return []
88
- return [model.__class__(**hit["_source"]) for hit in result.get("hits", {}).get("hits", [])]
97
+ rows = []
98
+ for hit in result.get("hits", {}).get("hits", []):
99
+ source = dict(hit.get("_source") or {})
100
+ if hit.get("_id") is not None and not source.get("id"):
101
+ source["id"] = hit["_id"]
102
+ rows.append(model.__class__(**source))
103
+ return rows
89
104
 
90
105
  async def delete(self, model):
91
106
  if self.client is None:
@@ -1,5 +1,6 @@
1
1
  from future.interfaces.IDatabase import IDatabase
2
- from sqlalchemy import text
2
+ from sqlalchemy import BigInteger, String, bindparam, text
3
+ from sqlalchemy.dialects.postgresql import ARRAY
3
4
  from sqlalchemy.ext.asyncio import create_async_engine
4
5
  from urllib.parse import quote_plus
5
6
 
@@ -61,17 +62,21 @@ class PostgresDatabase(IDatabase):
61
62
  table = model.tableize()
62
63
  clauses = []
63
64
  params = {}
65
+ array_binds = {}
64
66
  for index, (column, operator, value) in enumerate(wheres):
65
67
  if operator == "in":
66
68
  values = list(value)
67
69
  if not values:
68
70
  return []
69
- keys = []
70
- for item_index, item in enumerate(values):
71
- key = f"v{index}_{item_index}"
72
- keys.append(f":{key}")
73
- params[key] = item
74
- clauses.append(f'"{column}" IN ({", ".join(keys)})')
71
+ # One array bind avoids Postgres' ~32767 bind-variable limit.
72
+ key = f"v{index}"
73
+ clauses.append(f'"{column}" = ANY(:{key})')
74
+ params[key] = values
75
+ sample = values[0]
76
+ if isinstance(sample, int) and not isinstance(sample, bool):
77
+ array_binds[key] = ARRAY(BigInteger)
78
+ else:
79
+ array_binds[key] = ARRAY(String)
75
80
  continue
76
81
  if operator == "like":
77
82
  key = f"v{index}"
@@ -90,8 +95,11 @@ class PostgresDatabase(IDatabase):
90
95
  sql += " ORDER BY " + ", ".join(f'"{column}" {direction}' for column, direction in orders)
91
96
  if limit is not None:
92
97
  sql += f" LIMIT {int(limit)}"
98
+ stmt = text(sql)
99
+ for key, array_type in array_binds.items():
100
+ stmt = stmt.bindparams(bindparam(key, type_=array_type))
93
101
  async with self.client.connect() as connection:
94
- rows = (await connection.execute(text(sql), params)).mappings().all()
102
+ rows = (await connection.execute(stmt, params)).mappings().all()
95
103
  return [model.__class__(**dict(row)) for row in rows]
96
104
 
97
105
  async def delete(self, model):
@@ -30,7 +30,7 @@ class Response:
30
30
  header_map["content-type"] = content_type
31
31
  # Preserve Set-Cookie headers already appended via set_cookie
32
32
  cookies = [pair for pair in self.headers if pair[0].lower() == b"set-cookie"]
33
- self.headers = [[key.encode(), value.encode()] for key, value in header_map.items()]
33
+ self.headers = [[key.lower().encode(), value.encode()] for key, value in header_map.items()]
34
34
  self.headers.extend(cookies)
35
35
  return self
36
36
 
@@ -54,11 +54,6 @@ class Response:
54
54
  def file(self, body: bytes = b"", status: int = 200, headers: dict[str, str] | None = None, content_type: str = "application/octet-stream") -> "Response":
55
55
  return self._set(body=body, status=status, headers=headers, content_type=content_type)
56
56
 
57
- def stream(self, chunks, status: int = 200, headers: dict[str, str] | None = None, content_type: str = "application/octet-stream") -> "StreamingResponse":
58
- streamed = StreamingResponse(chunks, status=status, headers=headers, content_type=content_type)
59
- streamed.headers.extend([pair for pair in self.headers if pair[0].lower() == b"set-cookie"])
60
- return streamed
61
-
62
57
  def image(self, body: bytes = b"", status: int = 200, headers: dict[str, str] | None = None, content_type: str = "image/png", file_path: str | None = None) -> "Response":
63
58
  if file_path:
64
59
  with open(file_path, "rb") as f:
@@ -149,72 +144,33 @@ class WebSocketResponse:
149
144
  await self.send_text(f"Echo: {text}")
150
145
 
151
146
 
152
- # Temporary wrappers for migration
153
- class PlainTextResponse(Response):
154
- def __init__(self, body: str = "", status: int = 200, headers: dict[str, str] | None = None) -> None:
155
- super().__init__()
156
- self.text(body, status=status, headers=headers)
157
-
158
-
159
- class JSONResponse(Response):
160
- def __init__(self, data: Any = None, status: int = 200, headers: dict[str, str] | None = None) -> None:
161
- super().__init__()
162
- self.json(data, status=status, headers=headers)
163
-
164
-
165
- class EmptyResponse(Response):
166
- def __init__(self, status: int = 204, headers: dict[str, str] | None = None) -> None:
167
- super().__init__()
168
- self.empty(status=status, headers=headers)
169
-
170
-
171
- class HTMLResponse(Response):
172
- def __init__(self, html: str = "", status: int = 200, headers: dict[str, str] | None = None) -> None:
173
- super().__init__()
174
- self.html(html, status=status, headers=headers)
175
-
176
-
177
- class PNGResponse(Response):
178
- def __init__(self, body: bytes = b"", status: int = 200, headers: dict[str, str] | None = None) -> None:
179
- super().__init__()
180
- self.image(body, status=status, headers=headers, content_type="image/png")
181
-
182
-
183
- class ImageResponse(Response):
184
- def __init__(
185
- self, body: bytes = b"", status: int = 200, headers: dict[str, str] | None = None, image_content_type: str = "image/png", file_path: str | None = None
186
- ) -> None:
187
- super().__init__()
188
- self.image(body, status=status, headers=headers, content_type=image_content_type, file_path=file_path)
189
-
190
-
191
- class RedirectResponse(Response):
192
- def __init__(self, url: str = "", status: int = 302, headers: dict[str, str] | None = None) -> None:
193
- super().__init__()
194
- if url:
195
- self.redirect(url, status=status, headers=headers)
196
-
197
-
198
- class FileResponse(Response):
199
- def __init__(self, body: bytes = b"", status: int = 200, headers: dict[str, str] | None = None) -> None:
200
- super().__init__()
201
- self.file(body, status=status, headers=headers)
202
-
203
-
204
147
  class StreamingResponse(Response):
205
148
  def __init__(self, body=(), status: int = 200, headers: dict[str, str] | None = None, content_type: Optional[str] = None) -> None:
206
149
  super().__init__(body=b"", status=status, headers=headers, content_type=content_type or "application/octet-stream")
207
150
  self._chunks = body
208
151
 
209
152
  async def __call__(self, send: Any) -> None:
210
- await send({"type": "http.response.start", "status": self.status, "headers": self.headers})
153
+ await send({"type": "http.response.start", "status": int(self.status), "headers": self.headers})
211
154
  chunks = self._chunks
212
- if isinstance(chunks, (bytes, str)):
155
+ if isinstance(chunks, (bytes, bytearray, memoryview, str)):
213
156
  chunks = [chunks]
214
157
  if hasattr(chunks, "__aiter__"):
215
158
  async for chunk in chunks:
216
- await send({"type": "http.response.body", "body": chunk if isinstance(chunk, bytes) else str(chunk).encode("utf-8"), "more_body": True})
159
+ if isinstance(chunk, (bytes, bytearray, memoryview)):
160
+ body = bytes(chunk)
161
+ elif isinstance(chunk, str):
162
+ body = chunk.encode("utf-8")
163
+ else:
164
+ raise TypeError(f"stream chunk must be bytes or str, got {type(chunk).__name__}")
165
+ await send({"type": "http.response.body", "body": body, "more_body": True})
217
166
  else:
218
167
  for chunk in chunks:
219
- await send({"type": "http.response.body", "body": chunk if isinstance(chunk, bytes) else str(chunk).encode("utf-8"), "more_body": True})
168
+ if isinstance(chunk, (bytes, bytearray, memoryview)):
169
+ body = bytes(chunk)
170
+ elif isinstance(chunk, str):
171
+ body = chunk.encode("utf-8")
172
+ else:
173
+ raise TypeError(f"stream chunk must be bytes or str, got {type(chunk).__name__}")
174
+ await send({"type": "http.response.body", "body": body, "more_body": True})
220
175
  await send({"type": "http.response.body", "body": b"", "more_body": False})
176
+
@@ -65,7 +65,7 @@ class SeedGenerator:
65
65
  return model
66
66
  raise ValueError(f"Model not found: {name}")
67
67
 
68
- def value_expr(self, field, annotation):
68
+ def value_expr(self, field, annotation, model_name=None):
69
69
  origin = get_origin(annotation)
70
70
  if origin is Union or origin is UnionType:
71
71
  args = [arg for arg in get_args(annotation) if arg is not type(None)]
@@ -73,10 +73,30 @@ class SeedGenerator:
73
73
  type_name = getattr(annotation, "__name__", str(annotation))
74
74
  if field == "id":
75
75
  return "fake.uuid4()"
76
+ if field in ("timestamp", "published_at", "generated_at", "joined_at", "trades_synced_at", "last_login_at"):
77
+ return 'fake.date_time_between(start_date="-1y", end_date="now")'
76
78
  if type_name == "datetime":
77
79
  return "fake.date_time_this_year()"
80
+ if field == "historical_trades_offset":
81
+ return "0"
82
+ if field in ("follower_count", "following_count"):
83
+ return "fake.random_int(0, 5000)"
84
+ if field == "average_hold_time":
85
+ return "fake.random_int(1, 365)"
86
+ if field == "rating":
87
+ return "fake.random_int(0, 5)"
88
+ if field == "window_hours":
89
+ return "fake.random_int(1, 168)"
90
+ if field == "unique_traders":
91
+ return "fake.random_int(2, 20)"
78
92
  if type_name == "int":
79
93
  return "fake.random_int(1, 9999)"
94
+ if field == "price":
95
+ return "float(fake.pyfloat(min_value=5, max_value=1500, right_digits=2))"
96
+ if field == "percentage_change":
97
+ return "float(fake.pyfloat(min_value=-25, max_value=25, right_digits=2))"
98
+ if field == "strength":
99
+ return "float(fake.pyfloat(min_value=0, max_value=100, right_digits=2))"
80
100
  if type_name == "float":
81
101
  return "float(fake.pyfloat(min_value=1, max_value=100))"
82
102
  if type_name == "bool":
@@ -85,6 +105,46 @@ class SeedGenerator:
85
105
  return "str(fake.random_int(1000, 9999))"
86
106
  if "email" in field:
87
107
  return "fake.email()"
108
+ if field == "firstname":
109
+ return "fake.first_name()"
110
+ if field == "lastname":
111
+ return "fake.last_name()"
112
+ if field == "instrument_name":
113
+ return "fake.company()"
114
+ if field == "symbol":
115
+ return 'fake.lexify(text="????").upper()'
116
+ if field in ("logo_url", "image_url", "avatar_uri"):
117
+ return "fake.image_url()"
118
+ if field == "url":
119
+ return "fake.url()"
120
+ if field == "currency":
121
+ return 'fake.random_element(elements=("NOK", "SEK", "DKK", "EUR", "USD"))'
122
+ if field == "language":
123
+ return 'fake.random_element(elements=("nb", "sv", "da", "en"))'
124
+ if field == "trade_type" or field == "side":
125
+ return 'fake.random_element(elements=("BUY", "SELL"))'
126
+ if field == "percentage_change_interval":
127
+ return 'fake.random_element(elements=("UNKNOWN", "LESS_THAN_ONE", "ONE_TO_FIVE", "FIVE_TO_TEN", "TEN_TO_TWENTY", "TWENTY_TO_THIRTY", "OVER_ONE_HUNDRED"))'
128
+ if field == "group_type":
129
+ return 'fake.random_element(elements=("COMMON_SHARE", "FND", "ETF", "WARRANT", "OTHER"))'
130
+ if field == "kind":
131
+ return 'fake.random_element(elements=("instruments", "users"))'
132
+ if field == "members":
133
+ return "fake.json()"
134
+ if field == "title":
135
+ return "fake.sentence(nb_words=8)"
136
+ if field in ("summary", "reason"):
137
+ return "fake.sentence()"
138
+ if field == "password_hash":
139
+ return "fake.sha256()"
140
+ if field == "name" and model_name == "NordnetInstrumentModel":
141
+ return 'fake.random_element(elements=("Equinor", "Nordnet Global Indeks", "DNB Teknologi A", "T1 Energy", "Aker BP"))'
142
+ if field == "name" and model_name == "IndexModel":
143
+ return 'fake.random_element(elements=("Nordic Momentum", "Top Shareville Traders", "Consensus Buys", "Long-term Winners"))'
144
+ if field == "country":
145
+ return 'fake.random_element(elements=("NO", "SE", "DK", "FI"))'
146
+ if field == "slug":
147
+ return "fake.slug()"
88
148
  if "name" in field or "username" in field:
89
149
  return "fake.user_name()"
90
150
  if field in ("description", "text", "body", "content") or field.endswith("_original") or field.endswith("_translated"):
@@ -103,7 +163,7 @@ class SeedGenerator:
103
163
  current = non_null[0] if non_null else str
104
164
  if isinstance(current, type) and issubclass(current, IModel):
105
165
  continue
106
- args.append(f" {field}={self.value_expr(field, annotation)},")
166
+ args.append(f" {field}={self.value_expr(field, annotation, name)},")
107
167
  if args:
108
168
  construct = f" await {name}(\n" + "\n".join(args) + f"\n ).save()"
109
169
  else:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "future-framework"
3
- version = "2.0.0"
3
+ version = "2.1.1"
4
4
  description = "ASGI-based framework for web APIs"
5
5
  authors = ["nicolaipre"]
6
6
  license = "LICENSE"