cornflow 2.0.0a12__py3-none-any.whl → 2.0.0a14__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 (48) hide show
  1. cornflow/app.py +3 -1
  2. cornflow/cli/__init__.py +4 -0
  3. cornflow/cli/actions.py +4 -0
  4. cornflow/cli/config.py +4 -0
  5. cornflow/cli/migrations.py +13 -8
  6. cornflow/cli/permissions.py +4 -0
  7. cornflow/cli/roles.py +4 -0
  8. cornflow/cli/schemas.py +5 -0
  9. cornflow/cli/service.py +260 -147
  10. cornflow/cli/tools/api_generator.py +13 -10
  11. cornflow/cli/tools/endpoint_tools.py +191 -196
  12. cornflow/cli/tools/models_tools.py +87 -60
  13. cornflow/cli/tools/schema_generator.py +161 -67
  14. cornflow/cli/tools/schemas_tools.py +4 -5
  15. cornflow/cli/users.py +8 -0
  16. cornflow/cli/views.py +4 -0
  17. cornflow/commands/dag.py +3 -2
  18. cornflow/commands/schemas.py +6 -4
  19. cornflow/commands/users.py +12 -17
  20. cornflow/config.py +3 -2
  21. cornflow/endpoints/dag.py +27 -25
  22. cornflow/endpoints/data_check.py +102 -164
  23. cornflow/endpoints/example_data.py +9 -3
  24. cornflow/endpoints/execution.py +27 -23
  25. cornflow/endpoints/health.py +4 -5
  26. cornflow/endpoints/instance.py +39 -12
  27. cornflow/endpoints/meta_resource.py +4 -5
  28. cornflow/schemas/execution.py +1 -0
  29. cornflow/shared/airflow.py +157 -0
  30. cornflow/shared/authentication/auth.py +73 -42
  31. cornflow/shared/const.py +9 -0
  32. cornflow/shared/databricks.py +10 -10
  33. cornflow/shared/exceptions.py +3 -1
  34. cornflow/shared/utils_tables.py +36 -8
  35. cornflow/shared/validators.py +1 -1
  36. cornflow/tests/const.py +1 -0
  37. cornflow/tests/custom_test_case.py +4 -4
  38. cornflow/tests/unit/test_alarms.py +1 -2
  39. cornflow/tests/unit/test_cases.py +4 -7
  40. cornflow/tests/unit/test_executions.py +105 -43
  41. cornflow/tests/unit/test_log_in.py +46 -9
  42. cornflow/tests/unit/test_tables.py +3 -3
  43. cornflow/tests/unit/tools.py +31 -13
  44. {cornflow-2.0.0a12.dist-info → cornflow-2.0.0a14.dist-info}/METADATA +2 -2
  45. {cornflow-2.0.0a12.dist-info → cornflow-2.0.0a14.dist-info}/RECORD +48 -47
  46. {cornflow-2.0.0a12.dist-info → cornflow-2.0.0a14.dist-info}/WHEEL +1 -1
  47. {cornflow-2.0.0a12.dist-info → cornflow-2.0.0a14.dist-info}/entry_points.txt +0 -0
  48. {cornflow-2.0.0a12.dist-info → cornflow-2.0.0a14.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  """
2
2
  This file has the class that creates the new API
3
3
  """
4
+
4
5
  import json
5
6
  import os
6
7
  import re
@@ -10,6 +11,8 @@ from .models_tools import ModelGenerator, model_shared_imports
10
11
  from .schemas_tools import SchemaGenerator, schemas_imports
11
12
  from .tools import generate_class_def
12
13
 
14
+ INIT_FILE = "__init__.py"
15
+
13
16
 
14
17
  class APIGenerator:
15
18
  """
@@ -52,7 +55,7 @@ class APIGenerator:
52
55
  self.endpoint_path = os.path.join(self.output_path, "endpoints")
53
56
  self.schema_path = os.path.join(self.output_path, "schemas")
54
57
  self.init_resources = []
55
- self.init_file = os.path.join(self.endpoint_path, "__init__.py")
58
+ self.init_file = os.path.join(self.endpoint_path, INIT_FILE)
56
59
 
57
60
  def import_schema(self) -> dict:
58
61
  """
@@ -77,23 +80,23 @@ class APIGenerator:
77
80
  if not os.path.isdir(self.model_path):
78
81
  os.mkdir(self.model_path)
79
82
 
80
- init_path = os.path.join(self.model_path, "__init__.py")
83
+ init_path = os.path.join(self.model_path, INIT_FILE)
81
84
  with open(init_path, "w") as file:
82
- file.write(f'"""\nThis file exposes the models\n"""\n')
85
+ file.write("\nThis file exposes the models\n\n")
83
86
 
84
87
  if not os.path.isdir(self.endpoint_path):
85
88
  os.mkdir(self.endpoint_path)
86
89
 
87
- init_path = os.path.join(self.endpoint_path, "__init__.py")
90
+ init_path = os.path.join(self.endpoint_path, INIT_FILE)
88
91
  with open(init_path, "w") as file:
89
- file.write(f'"""\nThis file exposes the endpoints\n"""\n')
92
+ file.write("\nThis file exposes the endpoints\n\n")
90
93
 
91
94
  if not os.path.isdir(self.schema_path):
92
95
  os.mkdir(self.schema_path)
93
96
 
94
- init_path = os.path.join(self.schema_path, "__init__.py")
97
+ init_path = os.path.join(self.schema_path, INIT_FILE)
95
98
  with open(init_path, "w") as file:
96
- file.write(f'"""\nThis file exposes the schemas\n"""\n')
99
+ file.write("\nThis file exposes the schemas\n\n")
97
100
 
98
101
  def main(self):
99
102
  """
@@ -151,7 +154,7 @@ class APIGenerator:
151
154
  fd.write(mg.generate_model_repr_str())
152
155
  fd.write("\n")
153
156
 
154
- init_file = os.path.join(self.model_path, "__init__.py")
157
+ init_file = os.path.join(self.model_path, INIT_FILE)
155
158
 
156
159
  with open(init_file, "a") as file:
157
160
  file.write(f"from .{self.prefix}{table_name} import {class_name}\n")
@@ -207,7 +210,7 @@ class APIGenerator:
207
210
  fd.write(generate_class_def(class_name_one, parents_class))
208
211
  fd.write(sg.generate_schema())
209
212
 
210
- init_file = os.path.join(self.schema_path, "__init__.py")
213
+ init_file = os.path.join(self.schema_path, INIT_FILE)
211
214
  with open(init_file, "a") as file:
212
215
  file.write(
213
216
  f"from .{self.prefix}{table_name} import {class_name_one}, "
@@ -432,7 +435,7 @@ class APIGenerator:
432
435
  :return: str: the type in format "<type:idx>"
433
436
  """
434
437
  schema_table = self.schema["properties"][table_name]["items"]["properties"]
435
- id_type=None
438
+ id_type = None
436
439
  if "id" in schema_table.keys():
437
440
  id_type = schema_table["id"]["type"]
438
441
  if id_type == "string" or isinstance(id_type, list):
@@ -2,7 +2,15 @@
2
2
  SP8 = 8 * " "
3
3
  SP12 = 12 * " "
4
4
 
5
+ DOC_DECORATOR = "@doc"
6
+ AUTH_DECORATOR = "@authenticate(auth_class=Auth())"
7
+ COMMENT_AUTH_1 = "It requires authentication to be passed in the form of a token that has to be linked to\n"
8
+ COMMENT_AUTH_2 = "an existing session (login) made by a user.\n"
9
+ PARAM_IDX_DOCSTRING = ":param idx: ID of the row\n"
10
+ RETURN_DOCSTRING_1 = ":rtype: Tuple(dict, integer)\n"
5
11
 
12
+
13
+ # TODO: refactor these methods to make them more modular
6
14
  class EndpointGenerator:
7
15
  def __init__(self, table_name, app_name, model_name, schemas_names):
8
16
  self.table_name = table_name
@@ -12,7 +20,7 @@ class EndpointGenerator:
12
20
  self.descriptions = {
13
21
  "base": "Endpoint used to manage the table",
14
22
  "bulk": "Endpoint used to perform bulk operations on the table",
15
- "detail": "Endpoint used to perform detail operations on the table"
23
+ "detail": "Endpoint used to perform detail operations on the table",
16
24
  }
17
25
 
18
26
  def generate_endpoints_imports(self, roles):
@@ -41,8 +49,10 @@ class EndpointGenerator:
41
49
  :param ep_type: type of endpoint (base, bulk or detail)
42
50
  :return:
43
51
  """
44
- name_types = dict(base="list", bulk ="bulk", detail ="detail")
45
- return [v[0] for v in [m.split("_") for m in methods] if v[1] == name_types[ep_type]]
52
+ name_types = dict(base="list", bulk="bulk", detail="detail")
53
+ return [
54
+ v[0] for v in [m.split("_") for m in methods] if v[1] == name_types[ep_type]
55
+ ]
46
56
 
47
57
  def generate_endpoint_description(self, methods, ep_type="base"):
48
58
  """
@@ -55,7 +65,7 @@ class EndpointGenerator:
55
65
  """
56
66
  type_methods = self.get_type_methods(methods, ep_type)
57
67
  description = self.descriptions[ep_type]
58
- app_name = f' of app {self.app_name}' if self.app_name is not None else ""
68
+ app_name = f" of app {self.app_name}" if self.app_name is not None else ""
59
69
  res = ' """\n'
60
70
  res += f" {description} {self.table_name}{app_name}.\n\n"
61
71
  res += f" Available methods: [{', '.join(type_methods)}]\n"
@@ -66,223 +76,208 @@ class EndpointGenerator:
66
76
  res = " def __init__(self):\n"
67
77
  res += SP8 + "super().__init__()\n"
68
78
  res += SP8 + f"self.data_model = {self.model_name}\n"
69
- res += SP8 + f"self.unique = ['id']\n"
79
+ res += SP8 + "self.unique = ['id']\n"
70
80
  return res
71
81
 
72
- def generate_endpoint_get_all(self):
73
- schema_name = self.schemas_names["one"]
74
- res = " @doc(\n"
75
- res += SP8 + 'description="Get list of all the elements in the table",\n'
76
- res += SP8 + f'tags=["{self.app_name}"],\n'
77
- res += " )\n"
78
- res += " @authenticate(auth_class=Auth())\n"
79
- res += f" @marshal_with({schema_name}(many=True))\n"
80
- res += " def get(self, **kwargs):\n"
81
- res += SP8 + '"""\n'
82
- res += SP8 + "API method to get all the rows of the table.\n"
83
- res += (
84
- SP8
85
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
82
+ def _generate_docstring(self, summary, param_idx=False, return_desc=""):
83
+ """Generates the common docstring structure for endpoint methods."""
84
+ lines = [
85
+ SP8 + '"""\n',
86
+ SP8 + summary + "\n",
87
+ f"{SP8}{COMMENT_AUTH_1}",
88
+ f"{SP8}{COMMENT_AUTH_2}",
89
+ ]
90
+ if param_idx:
91
+ lines.append(f"{SP8}{PARAM_IDX_DOCSTRING}")
92
+ if return_desc:
93
+ lines.append(SP8 + return_desc + "\n")
94
+ lines.append(f"{SP8}{RETURN_DOCSTRING_1}")
95
+ lines.append(SP8 + '"""\n')
96
+ return "".join(lines)
97
+
98
+ def _generate_method(
99
+ self,
100
+ http_method: str,
101
+ method_name: str,
102
+ is_detail: bool,
103
+ doc_description: str,
104
+ docstring_summary: str,
105
+ docstring_return_desc: str,
106
+ base_method_call: str,
107
+ marshal_schema: str = None,
108
+ kwargs_schema: str = None,
109
+ marshal_many: bool = False,
110
+ ):
111
+ """Generates the complete string for an endpoint method."""
112
+ lines = []
113
+
114
+ # @doc decorator
115
+ lines.append(f" {DOC_DECORATOR}(")
116
+ lines.append(f' description="{doc_description}",')
117
+ lines.append(
118
+ f' tags=["{self.app_name}"],'
119
+ ) # Add comma if needed for future args
120
+ lines.append(" )")
121
+
122
+ # @authenticate decorator
123
+ lines.append(f" {AUTH_DECORATOR}")
124
+
125
+ # @marshal_with decorator
126
+ if marshal_schema:
127
+ many_str = "(many=True)" if marshal_many else ""
128
+ lines.append(f" @marshal_with({marshal_schema}{many_str})")
129
+
130
+ # @use_kwargs decorator
131
+ if kwargs_schema:
132
+ lines.append(f' @use_kwargs({kwargs_schema}, location="json")')
133
+
134
+ # Method signature
135
+ params = "idx" if is_detail else "**kwargs"
136
+ if http_method in ["put", "patch"] and is_detail:
137
+ params = "idx, **data"
138
+ elif http_method == "post" and not is_detail:
139
+ params = "**kwargs" # Keep as kwargs for bulk post
140
+
141
+ lines.append(f" def {method_name}(self, {params}):")
142
+
143
+ # Docstring
144
+ docstring = self._generate_docstring(
145
+ summary=docstring_summary,
146
+ param_idx=is_detail,
147
+ return_desc=docstring_return_desc,
86
148
  )
87
- res += SP8 + "an existing session (login) made by a user.\n\n"
88
- res += (
89
- SP8
90
- + ":return: A list of objects with the data, and an integer with the HTTP status code.\n"
149
+ lines.append(docstring.strip("\n")) # Remove leading/trailing newlines if any
150
+
151
+ # Base method call
152
+ lines.append(f"{SP8}return {base_method_call}")
153
+
154
+ return "\n".join(lines) + "\n" # Ensure trailing newline
155
+
156
+ def generate_endpoint_get_all(self):
157
+ return self._generate_method(
158
+ http_method="get",
159
+ method_name="get",
160
+ is_detail=False,
161
+ doc_description="Get list of all the elements in the table",
162
+ marshal_schema=self.schemas_names["one"],
163
+ marshal_many=True,
164
+ docstring_summary="API method to get all the rows of the table.",
165
+ docstring_return_desc=":return: A list of objects with the data, and an integer with the HTTP status code.",
166
+ base_method_call="self.get_list(**kwargs)",
91
167
  )
92
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
93
- res += SP8 + '"""\n'
94
- res += SP8 + "return self.get_list(**kwargs)\n"
95
- return res
96
168
 
97
169
  def generate_endpoint_get_one(self):
98
- schema_name = self.schemas_names["one"]
99
- res = " @doc(\n"
100
- res += SP8 + 'description="Get one element of the table",\n'
101
- res += SP8 + f'tags=["{self.app_name}"],\n'
102
- res += " )\n"
103
- res += " @authenticate(auth_class=Auth())\n"
104
- res += f" @marshal_with({schema_name})\n"
105
- res += " def get(self, idx):\n"
106
- res += SP8 + '"""\n'
107
- res += SP8 + "API method to get a row of the table.\n"
108
- res += (
109
- SP8
110
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
170
+ return self._generate_method(
171
+ http_method="get",
172
+ method_name="get",
173
+ is_detail=True,
174
+ doc_description="Get one element of the table",
175
+ marshal_schema=self.schemas_names["one"],
176
+ docstring_summary="API method to get a row of the table.",
177
+ docstring_return_desc=":return: A dictionary with the response data and an integer with the HTTP status code.",
178
+ base_method_call="self.get_detail(idx=idx)",
111
179
  )
112
- res += SP8 + "an existing session (login) made by a user.\n\n"
113
- res += SP8 + ":param idx: ID of the row\n"
114
- res += (
115
- SP8
116
- + ":return: A dictionary with the response data and an integer with the HTTP status code.\n"
117
- )
118
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
119
- res += SP8 + '"""\n'
120
- res += SP8 + "return self.get_detail(idx=idx)\n"
121
- return res
122
180
 
123
181
  def generate_endpoint_post(self):
124
- schema_marshal = self.schemas_names["one"]
125
- schema_kwargs = self.schemas_names["postRequest"]
126
- res = " @doc(\n"
127
- res += SP8 + 'description="Add a new row to the table",\n'
128
- res += SP8 + f'tags=["{self.app_name}"],\n'
129
- res += " )\n"
130
- res += " @authenticate(auth_class=Auth())\n"
131
- res += f" @marshal_with({schema_marshal})\n"
132
- res += f' @use_kwargs({schema_kwargs}, location="json")\n'
133
- res += " def post(self, **kwargs):\n"
134
- res += SP8 + '"""\n'
135
- res += SP8 + "API method to add a row to the table.\n"
136
- res += (
137
- SP8
138
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
182
+ return self._generate_method(
183
+ http_method="post",
184
+ method_name="post",
185
+ is_detail=False,
186
+ doc_description="Add a new row to the table",
187
+ marshal_schema=self.schemas_names["one"],
188
+ kwargs_schema=self.schemas_names["postRequest"],
189
+ docstring_summary="API method to add a row to the table.",
190
+ docstring_return_desc=":return: An object with the data for the created row,\\n"
191
+ + SP8
192
+ + "and an integer with the HTTP status code.",
193
+ base_method_call="self.post_list(data=kwargs)",
139
194
  )
140
- res += SP8 + "an existing session (login) made by a user.\n\n"
141
- res += SP8 + ":return: An object with the data for the created row,\n"
142
- res += SP8 + "and an integer with the HTTP status code.\n"
143
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
144
- res += SP8 + '"""\n'
145
- res += SP8 + "return self.post_list(data=kwargs)\n"
146
- return res
147
195
 
148
196
  def generate_endpoint_delete_one(self):
149
- res = " @doc(\n"
150
- res += SP8 + 'description="Delete one row of the table",\n'
151
- res += SP8 + f'tags=["{self.app_name}"], \n'
152
- res += " )\n"
153
- res += " @authenticate(auth_class=Auth())\n"
154
- res += " def delete(self, idx):\n"
155
- res += SP8 + '"""\n'
156
- res += SP8 + "API method to delete a row of the table.\n"
157
- res += (
158
- SP8
159
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
160
- )
161
- res += SP8 + "an existing session (login) made by a user.\n\n"
162
- res += SP8 + ":param idx: ID of the row\n"
163
- res += (
164
- SP8
165
- + ":return: A dictionary with a message (error if authentication failed, "
166
- + "or the execution does not exist or\n"
197
+ return self._generate_method(
198
+ http_method="delete",
199
+ method_name="delete",
200
+ is_detail=True,
201
+ doc_description="Delete one row of the table",
202
+ docstring_summary="API method to delete a row of the table.",
203
+ docstring_return_desc=":return: A dictionary with a message (error if authentication failed, or the execution does not exist or\\n"
204
+ + SP8
205
+ + "a message) and an integer with the HTTP status code.",
206
+ base_method_call="self.delete_detail(idx=idx)",
167
207
  )
168
- res += SP8 + "a message) and an integer with the HTTP status code.\n"
169
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
170
- res += SP8 + '"""\n'
171
- res += SP8 + "return self.delete_detail(idx=idx)\n"
172
- return res
173
208
 
174
209
  def generate_endpoint_put(self):
175
- schema_name = self.schemas_names["editRequest"]
176
- res = " @doc(\n"
177
- res += SP8 + 'description="Edit one row of the table",\n'
178
- res += SP8 + f'tags=["{self.app_name}"], \n'
179
- res += " )\n"
180
- res += " @authenticate(auth_class=Auth())\n"
181
- res += f' @use_kwargs({schema_name}, location="json")\n'
182
- res += " def put(self, idx, **data):\n"
183
- res += SP8 + '"""\n'
184
- res += SP8 + "API method to edit a row of the table.\n"
185
- res += (
186
- SP8
187
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
210
+ return self._generate_method(
211
+ http_method="put",
212
+ method_name="put",
213
+ is_detail=True,
214
+ doc_description="Edit one row of the table",
215
+ kwargs_schema=self.schemas_names["editRequest"],
216
+ docstring_summary="API method to edit a row of the table.",
217
+ docstring_return_desc=":return: A dictionary with a message (error if authentication failed, or the execution does not exist or\\n"
218
+ + SP8
219
+ + "a message) and an integer with the HTTP status code.",
220
+ base_method_call="self.put_detail(data=data, idx=idx)",
188
221
  )
189
- res += SP8 + "an existing session (login) made by a user.\n\n"
190
- res += SP8 + ":param idx: ID of the row\n"
191
- res += (
192
- SP8
193
- + ":return: A dictionary with a message (error if authentication failed, "
194
- + "or the execution does not exist or\n"
195
- )
196
- res += SP8 + "a message) and an integer with the HTTP status code.\n"
197
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
198
- res += SP8 + '"""\n'
199
- res += SP8 + "return self.put_detail(data=data, idx=idx)\n"
200
- return res
201
222
 
202
223
  def generate_endpoint_patch(self):
203
- schema_name = self.schemas_names["editRequest"]
204
- res = " @doc(\n"
205
- res += SP8 + 'description="Patch one row of the table",\n'
206
- res += SP8 + f'tags=["{self.app_name}"], \n'
207
- res += " )\n"
208
- res += " @authenticate(auth_class=Auth())\n"
209
- res += f' @use_kwargs({schema_name}, location="json")\n'
210
- res += " def patch(self, idx, **data):\n"
211
- res += SP8 + '"""\n'
212
- res += SP8 + "API method to patch a row of the table.\n"
213
- res += (
214
- SP8
215
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
216
- )
217
- res += SP8 + "an existing session (login) made by a user.\n\n"
218
- res += SP8 + ":param idx: ID of the row\n"
219
- res += (
220
- SP8
221
- + ":return: A dictionary with a message (error if authentication failed, "
222
- + "or the execution does not exist or\n"
224
+ return self._generate_method(
225
+ http_method="patch",
226
+ method_name="patch",
227
+ is_detail=True,
228
+ doc_description="Patch one row of the table",
229
+ kwargs_schema=self.schemas_names["editRequest"],
230
+ docstring_summary="API method to patch a row of the table.",
231
+ docstring_return_desc=":return: A dictionary with a message (error if authentication failed, or the execution does not exist or\\n"
232
+ + SP8
233
+ + "a message) and an integer with the HTTP status code.",
234
+ base_method_call="self.patch_detail(data=data, idx=idx)",
223
235
  )
224
- res += SP8 + "a message) and an integer with the HTTP status code.\n"
225
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
226
- res += SP8 + '"""\n'
227
- res += SP8 + "return self.patch_detail(data=data, idx=idx)\n"
228
- return res
229
236
 
230
237
  def generate_endpoint_post_bulk(self):
231
- schema_marshal = self.schemas_names["one"]
232
- schema_kwargs = self.schemas_names["postBulkRequest"]
233
- res = " @doc(\n"
234
- res += SP8 + 'description="Add several new rows to the table",\n'
235
- res += SP8 + f'tags=["{self.app_name}"],\n'
236
- res += " )\n"
237
- res += " @authenticate(auth_class=Auth())\n"
238
- res += f" @marshal_with({schema_marshal}(many=True))\n"
239
- res += f' @use_kwargs({schema_kwargs}, location="json")\n'
240
- res += " def post(self, **kwargs):\n"
241
- res += SP8 + '"""\n'
242
- res += SP8 + "API method to add several new rows to the table.\n"
243
- res += (
244
- SP8
245
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
238
+ return self._generate_method(
239
+ http_method="post",
240
+ method_name="post",
241
+ is_detail=False,
242
+ doc_description="Add several new rows to the table",
243
+ marshal_schema=self.schemas_names["one"],
244
+ marshal_many=True,
245
+ kwargs_schema=self.schemas_names["postBulkRequest"],
246
+ docstring_summary="API method to add several new rows to the table.",
247
+ docstring_return_desc=":return: An object with the data for the created row,\\n"
248
+ + SP8
249
+ + "and an integer with the HTTP status code.",
250
+ base_method_call="self.post_bulk(data=kwargs)",
246
251
  )
247
- res += SP8 + "an existing session (login) made by a user.\n\n"
248
- res += SP8 + ":return: An object with the data for the created row,\n"
249
- res += SP8 + "and an integer with the HTTP status code.\n"
250
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
251
- res += SP8 + '"""\n'
252
- res += SP8 + "return self.post_bulk(data=kwargs)\n"
253
- return res
254
252
 
255
253
  def generate_endpoint_put_bulk(self):
256
- schema_marshal = self.schemas_names["one"]
257
- schema_kwargs = self.schemas_names["putBulkRequest"]
258
- res = " @doc(\n"
259
- res += SP8 + 'description="Updates several rows of the table or adds them if they do not exist",\n'
260
- res += SP8 + f'tags=["{self.app_name}"],\n'
261
- res += " )\n"
262
- res += " @authenticate(auth_class=Auth())\n"
263
- res += f" @marshal_with({schema_marshal}(many=True))\n"
264
- res += f' @use_kwargs({schema_kwargs}, location="json")\n'
265
- res += " def put(self, **kwargs):\n"
266
- res += SP8 + '"""\n'
267
- res += SP8 + "API method to add several new rows to the table.\n"
268
- res += (
269
- SP8
270
- + "It requires authentication to be passed in the form of a token that has to be linked to\n"
254
+ return self._generate_method(
255
+ http_method="put",
256
+ method_name="put",
257
+ is_detail=False,
258
+ doc_description="Updates several rows of the table or adds them if they do not exist",
259
+ marshal_schema=self.schemas_names["one"],
260
+ marshal_many=True,
261
+ kwargs_schema=self.schemas_names["putBulkRequest"],
262
+ docstring_summary="API method to add or update several rows to the table.",
263
+ docstring_return_desc=":return: An object with the data for the created/updated rows,\\n"
264
+ + SP8
265
+ + "and an integer with the HTTP status code.",
266
+ base_method_call="self.post_bulk_update(data=kwargs)",
271
267
  )
272
- res += SP8 + "an existing session (login) made by a user.\n\n"
273
- res += SP8 + ":return: An object with the data for the created row,\n"
274
- res += SP8 + "and an integer with the HTTP status code.\n"
275
- res += SP8 + ":rtype: Tuple(dict, integer)\n"
276
- res += SP8 + '"""\n'
277
- res += SP8 + "return self.post_bulk_update(data=kwargs)\n"
278
- return res
279
268
 
280
269
  def generate_endpoint(self, method):
281
- ep_map = dict(get_list=self.generate_endpoint_get_all, post_list=self.generate_endpoint_post, get_detail=self.generate_endpoint_get_one,
282
- put_detail=self.generate_endpoint_put,
283
- patch_detail=self.generate_endpoint_patch,
284
- delete_detail= self.generate_endpoint_delete_one,
285
- post_bulk=self.generate_endpoint_post_bulk,
286
- put_bulk=self.generate_endpoint_put_bulk
270
+ ep_map = dict(
271
+ get_list=self.generate_endpoint_get_all,
272
+ post_list=self.generate_endpoint_post,
273
+ get_detail=self.generate_endpoint_get_one,
274
+ put_detail=self.generate_endpoint_put,
275
+ patch_detail=self.generate_endpoint_patch,
276
+ delete_detail=self.generate_endpoint_delete_one,
277
+ post_bulk=self.generate_endpoint_post_bulk,
278
+ put_bulk=self.generate_endpoint_put_bulk,
287
279
  )
288
- return ep_map[method]()
280
+ generator_func = ep_map.get(method)
281
+ if generator_func is None:
282
+ raise ValueError(f"Unsupported endpoint generation method: {method}")
283
+ return generator_func()