cornflow 2.0.0a11__py3-none-any.whl → 2.0.0a13__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 (52) hide show
  1. airflow_config/airflow_local_settings.py +1 -1
  2. cornflow/app.py +8 -3
  3. cornflow/cli/migrations.py +23 -3
  4. cornflow/cli/service.py +18 -18
  5. cornflow/cli/utils.py +16 -1
  6. cornflow/commands/dag.py +1 -1
  7. cornflow/config.py +13 -8
  8. cornflow/endpoints/__init__.py +8 -2
  9. cornflow/endpoints/alarms.py +66 -2
  10. cornflow/endpoints/data_check.py +53 -26
  11. cornflow/endpoints/execution.py +387 -132
  12. cornflow/endpoints/login.py +81 -63
  13. cornflow/endpoints/meta_resource.py +11 -3
  14. cornflow/migrations/versions/999b98e24225.py +34 -0
  15. cornflow/models/base_data_model.py +4 -32
  16. cornflow/models/execution.py +2 -3
  17. cornflow/models/meta_models.py +28 -22
  18. cornflow/models/user.py +7 -10
  19. cornflow/schemas/alarms.py +8 -0
  20. cornflow/schemas/execution.py +2 -1
  21. cornflow/schemas/query.py +2 -1
  22. cornflow/schemas/user.py +5 -20
  23. cornflow/shared/authentication/auth.py +201 -264
  24. cornflow/shared/const.py +3 -14
  25. cornflow/shared/databricks.py +5 -1
  26. cornflow/tests/const.py +2 -0
  27. cornflow/tests/custom_test_case.py +77 -26
  28. cornflow/tests/unit/test_actions.py +2 -2
  29. cornflow/tests/unit/test_alarms.py +55 -1
  30. cornflow/tests/unit/test_apiview.py +108 -3
  31. cornflow/tests/unit/test_cases.py +20 -29
  32. cornflow/tests/unit/test_cli.py +6 -5
  33. cornflow/tests/unit/test_commands.py +3 -3
  34. cornflow/tests/unit/test_dags.py +5 -6
  35. cornflow/tests/unit/test_executions.py +491 -118
  36. cornflow/tests/unit/test_instances.py +14 -2
  37. cornflow/tests/unit/test_instances_file.py +1 -1
  38. cornflow/tests/unit/test_licenses.py +1 -1
  39. cornflow/tests/unit/test_log_in.py +230 -207
  40. cornflow/tests/unit/test_permissions.py +8 -8
  41. cornflow/tests/unit/test_roles.py +48 -10
  42. cornflow/tests/unit/test_schemas.py +1 -1
  43. cornflow/tests/unit/test_tables.py +7 -7
  44. cornflow/tests/unit/test_token.py +19 -5
  45. cornflow/tests/unit/test_users.py +22 -6
  46. cornflow/tests/unit/tools.py +75 -10
  47. {cornflow-2.0.0a11.dist-info → cornflow-2.0.0a13.dist-info}/METADATA +16 -15
  48. {cornflow-2.0.0a11.dist-info → cornflow-2.0.0a13.dist-info}/RECORD +51 -51
  49. {cornflow-2.0.0a11.dist-info → cornflow-2.0.0a13.dist-info}/WHEEL +1 -1
  50. cornflow/endpoints/execution_databricks.py +0 -808
  51. {cornflow-2.0.0a11.dist-info → cornflow-2.0.0a13.dist-info}/entry_points.txt +0 -0
  52. {cornflow-2.0.0a11.dist-info → cornflow-2.0.0a13.dist-info}/top_level.txt +0 -0
@@ -43,7 +43,7 @@ class TestPermissionsViewRoleEndpoint(CustomTestCase):
43
43
  follow_redirects=True,
44
44
  headers={
45
45
  "Content-Type": "application/json",
46
- "Authorization": "Bearer " + self.token,
46
+ "Authorization": f"Bearer {self.token}",
47
47
  },
48
48
  )
49
49
 
@@ -58,7 +58,7 @@ class TestPermissionsViewRoleEndpoint(CustomTestCase):
58
58
  follow_redirects=True,
59
59
  headers={
60
60
  "Content-Type": "application/json",
61
- "Authorization": "Bearer " + self.token,
61
+ "Authorization": f"Bearer {self.token}",
62
62
  },
63
63
  )
64
64
 
@@ -103,7 +103,7 @@ class TestPermissionViewRolesDetailEndpoint(CustomTestCase):
103
103
  data=json.dumps(self.payload),
104
104
  headers={
105
105
  "Content-Type": "application/json",
106
- "Authorization": "Bearer " + self.token,
106
+ "Authorization": f"Bearer {self.token}",
107
107
  },
108
108
  ).json["id"]
109
109
  view_id = 2
@@ -127,7 +127,7 @@ class TestPermissionViewRolesDetailEndpoint(CustomTestCase):
127
127
  data=json.dumps(self.payload),
128
128
  headers={
129
129
  "Content-Type": "application/json",
130
- "Authorization": "Bearer " + self.token,
130
+ "Authorization": f"Bearer {self.token}",
131
131
  },
132
132
  ).json["id"]
133
133
  for role in ROLES_MAP:
@@ -151,7 +151,7 @@ class TestPermissionViewRolesDetailEndpoint(CustomTestCase):
151
151
  data=json.dumps(self.payload),
152
152
  headers={
153
153
  "Content-Type": "application/json",
154
- "Authorization": "Bearer " + self.token,
154
+ "Authorization": f"Bearer {self.token}",
155
155
  },
156
156
  ).json["id"]
157
157
 
@@ -160,7 +160,7 @@ class TestPermissionViewRolesDetailEndpoint(CustomTestCase):
160
160
  follow_redirects=True,
161
161
  headers={
162
162
  "Content-Type": "application/json",
163
- "Authorization": "Bearer " + self.token,
163
+ "Authorization": f"Bearer {self.token}",
164
164
  },
165
165
  )
166
166
  self.assertEqual(200, response.status_code)
@@ -174,7 +174,7 @@ class TestPermissionViewRolesDetailEndpoint(CustomTestCase):
174
174
  data=json.dumps(self.payload),
175
175
  headers={
176
176
  "Content-Type": "application/json",
177
- "Authorization": "Bearer " + self.token,
177
+ "Authorization": f"Bearer {self.token}",
178
178
  },
179
179
  ).json["id"]
180
180
 
@@ -186,7 +186,7 @@ class TestPermissionViewRolesDetailEndpoint(CustomTestCase):
186
186
  follow_redirects=True,
187
187
  headers={
188
188
  "Content-Type": "application/json",
189
- "Authorization": "Bearer " + self.token,
189
+ "Authorization": f"Bearer {self.token}",
190
190
  },
191
191
  )
192
192
  self.assertEqual(403, response.status_code)
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Unit test for the role endpoints
3
3
  """
4
+
4
5
  import json
5
6
  import logging as log
6
7
  from cornflow.models import PermissionViewRoleModel, RoleModel
@@ -47,7 +48,7 @@ class TestRolesListEndpoint(CustomTestCase):
47
48
  follow_redirects=True,
48
49
  headers={
49
50
  "Content-Type": "application/json",
50
- "Authorization": "Bearer " + self.token,
51
+ "Authorization": f"Bearer {self.token}",
51
52
  },
52
53
  )
53
54
  self.assertEqual(200, response.status_code)
@@ -63,7 +64,7 @@ class TestRolesListEndpoint(CustomTestCase):
63
64
  follow_redirects=True,
64
65
  headers={
65
66
  "Content-Type": "application/json",
66
- "Authorization": "Bearer " + self.token,
67
+ "Authorization": f"Bearer {self.token}",
67
68
  },
68
69
  )
69
70
 
@@ -75,7 +76,7 @@ class TestRolesListEndpoint(CustomTestCase):
75
76
  follow_redirects=True,
76
77
  headers={
77
78
  "Content-Type": "application/json",
78
- "Authorization": "Bearer " + self.token,
79
+ "Authorization": f"Bearer {self.token}",
79
80
  },
80
81
  )
81
82
 
@@ -91,7 +92,7 @@ class TestRolesListEndpoint(CustomTestCase):
91
92
  follow_redirects=True,
92
93
  headers={
93
94
  "Content-Type": "application/json",
94
- "Authorization": "Bearer " + self.token,
95
+ "Authorization": f"Bearer {self.token}",
95
96
  },
96
97
  )
97
98
  self.assertEqual(403, response.status_code)
@@ -157,7 +158,7 @@ class TestRolesDetailEndpoint(CustomTestCase):
157
158
  follow_redirects=True,
158
159
  headers={
159
160
  "Content-Type": "application/json",
160
- "Authorization": "Bearer " + self.token,
161
+ "Authorization": f"Bearer {self.token}",
161
162
  },
162
163
  )
163
164
 
@@ -191,7 +192,7 @@ class TestRolesDetailEndpoint(CustomTestCase):
191
192
  follow_redirects=True,
192
193
  headers={
193
194
  "Content-Type": "application/json",
194
- "Authorization": "Bearer " + self.token,
195
+ "Authorization": f"Bearer {self.token}",
195
196
  },
196
197
  )
197
198
 
@@ -203,7 +204,7 @@ class TestRolesDetailEndpoint(CustomTestCase):
203
204
  follow_redirects=True,
204
205
  headers={
205
206
  "Content-Type": "application/json",
206
- "Authorization": "Bearer " + self.token,
207
+ "Authorization": f"Bearer {self.token}",
207
208
  },
208
209
  )
209
210
 
@@ -246,7 +247,7 @@ class TestUserRolesListEndpoint(CustomTestCase):
246
247
  follow_redirects=True,
247
248
  headers={
248
249
  "Content-Type": "application/json",
249
- "Authorization": "Bearer " + self.token,
250
+ "Authorization": f"Bearer {self.token}",
250
251
  },
251
252
  )
252
253
  self.assertEqual(200, response.status_code)
@@ -261,7 +262,7 @@ class TestUserRolesListEndpoint(CustomTestCase):
261
262
  follow_redirects=True,
262
263
  headers={
263
264
  "Content-Type": "application/json",
264
- "Authorization": "Bearer " + self.token,
265
+ "Authorization": f"Bearer {self.token}",
265
266
  },
266
267
  )
267
268
  self.assertEqual(403, response.status_code)
@@ -431,7 +432,7 @@ class TestRolesModelMethods(CustomTestCase):
431
432
  self.payload = {"name": "test_role"}
432
433
 
433
434
  def test_user_role_delete_cascade(self):
434
- payload = {"user_id": self.user}
435
+ payload = {"user_id": self.user.id}
435
436
  self.token = self.create_user_with_role(ADMIN_ROLE)
436
437
  self.cascade_delete(
437
438
  self.url,
@@ -472,3 +473,40 @@ class TestRolesModelMethods(CustomTestCase):
472
473
  self.token = self.create_user_with_role(ADMIN_ROLE)
473
474
  idx = self.create_new_row(self.url, self.model, self.payload)
474
475
  self.str_method(idx, "<Role test_role>")
476
+
477
+ def test_get_all_objects(self):
478
+ """
479
+ Tests the get_all_objects method
480
+ """
481
+ # We expect 4 roles to be present (from ROLES_MAP constant)
482
+ instances = RoleModel.get_all_objects().all()
483
+ self.assertEqual(len(instances), 4)
484
+
485
+ # Check that all the roles from ROLES_MAP are present
486
+ role_names = [role.name for role in instances]
487
+ expected_names = list(ROLES_MAP.values())
488
+ self.assertCountEqual(role_names, expected_names)
489
+
490
+ # Test offset parameter - should get all except the first role
491
+ instances = RoleModel.get_all_objects(offset=1).all()
492
+ self.assertEqual(len(instances), 3)
493
+
494
+ # Get the names of all roles except the first one
495
+ remaining_roles = [role.name for role in instances]
496
+ # The first role is skipped due to offset=1
497
+ first_role = RoleModel.get_all_objects().first().name
498
+ self.assertNotIn(first_role, remaining_roles)
499
+
500
+ # Test offset and limit parameters
501
+ instances = RoleModel.get_all_objects(offset=1, limit=1).all()
502
+ self.assertEqual(len(instances), 1)
503
+
504
+ # Verify that we get the second role when using offset=1 and limit=1
505
+ second_role = RoleModel.get_all_objects().all()[1]
506
+ self.assertEqual(instances[0].id, second_role.id)
507
+ self.assertEqual(instances[0].name, second_role.name)
508
+
509
+ # Test filtering by name
510
+ instances = RoleModel.get_all_objects(limit=1, name="admin").all()
511
+ self.assertEqual(len(instances), 1)
512
+ self.assertEqual(instances[0].name, "admin")
@@ -189,7 +189,7 @@ class TestNewSchemaEndpointOpen(CustomTestCase):
189
189
 
190
190
  def test_get_all_schemas(self):
191
191
  schemas = self.get_one_row(self.url, {}, 200, False, keys_to_check=["name"])
192
- dags = [{"name": dag} for dag in ["solve_model_dag", "gc", "timer"]]
192
+ dags = [{"name": dag} for dag in ["solve_model_dag", "gc", "timer", "979073949072767"]]
193
193
 
194
194
  self.assertEqual(dags, schemas)
195
195
 
@@ -81,7 +81,7 @@ class TestTablesListEndpoint(TestCase):
81
81
  follow_redirects=True,
82
82
  headers={
83
83
  "Content-Type": "application/json",
84
- "Authorization": "Bearer " + self.token,
84
+ "Authorization": f"Bearer {self.token}",
85
85
  },
86
86
  )
87
87
  self.assertEqual(response.status_code, 200)
@@ -111,7 +111,7 @@ class TestTablesListEndpoint(TestCase):
111
111
  follow_redirects=True,
112
112
  headers={
113
113
  "Content-Type": "application/json",
114
- "Authorization": "Bearer " + self.token,
114
+ "Authorization": f"Bearer {self.token}",
115
115
  },
116
116
  query_string=dict(limit=3),
117
117
  )
@@ -187,7 +187,7 @@ class TestTablesDetailEndpoint(TestCase):
187
187
  follow_redirects=True,
188
188
  headers={
189
189
  "Content-Type": "application/json",
190
- "Authorization": "Bearer " + self.token,
190
+ "Authorization": f"Bearer {self.token}",
191
191
  },
192
192
  )
193
193
 
@@ -204,7 +204,7 @@ class TestTablesDetailEndpoint(TestCase):
204
204
  follow_redirects=True,
205
205
  headers={
206
206
  "Content-Type": "application/json",
207
- "Authorization": "Bearer " + self.token,
207
+ "Authorization": f"Bearer {self.token}",
208
208
  },
209
209
  )
210
210
  self.assertEqual(response.status_code, 400)
@@ -216,7 +216,7 @@ class TestTablesDetailEndpoint(TestCase):
216
216
  follow_redirects=True,
217
217
  headers={
218
218
  "Content-Type": "application/json",
219
- "Authorization": "Bearer " + self.token,
219
+ "Authorization": f"Bearer {self.token}",
220
220
  },
221
221
  )
222
222
  self.assertEqual(response.status_code, 404)
@@ -270,7 +270,7 @@ class TestTablesEndpointAdmin(TestCase):
270
270
  follow_redirects=True,
271
271
  headers={
272
272
  "Content-Type": "application/json",
273
- "Authorization": "Bearer " + self.token,
273
+ "Authorization": f"Bearer {self.token}",
274
274
  },
275
275
  )
276
276
  self.assertEqual(response.status_code, 403)
@@ -284,7 +284,7 @@ class TestTablesEndpointAdmin(TestCase):
284
284
  follow_redirects=True,
285
285
  headers={
286
286
  "Content-Type": "application/json",
287
- "Authorization": "Bearer " + self.token,
287
+ "Authorization": f"Bearer {self.token}",
288
288
  },
289
289
  )
290
290
 
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Unit test for the token endpoint
3
3
  """
4
+
4
5
  import json
5
6
 
6
7
  from flask import current_app
@@ -87,15 +88,28 @@ class TestUnexpiringToken(CustomTestCase):
87
88
  def test_token_unexpiring(self):
88
89
  auth = BIAuth()
89
90
 
91
+ # Generate token dynamically
90
92
  token = auth.generate_token(1)
91
93
 
94
+ # Verify that the token decodes correctly
92
95
  response = auth.decode_token(token)
93
- self.assertEqual(response, {"user_id": 1})
94
-
95
- token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDM1OTI1OTIsInN1YiI6MX0.Plvmi02FMfZOTn6bxArELEmDeyuP-2X794c5VtAFgCg"
96
96
 
97
- response = auth.decode_token(token)
98
- self.assertEqual(response, {"user_id": 1})
97
+ self.assertIn("iat", response)
98
+ self.assertIn("iss", response)
99
+ self.assertIn("sub", response)
100
+ self.assertEqual("testname", response["sub"])
101
+ # Don't use hardcoded token, generate another dynamic one
102
+ user = UserModel.get_one_user(1)
103
+ self.assertIsNotNone(user)
104
+
105
+ # Verify that another generated token also works
106
+ token2 = auth.generate_token(1)
107
+ response2 = auth.decode_token(token2)
108
+
109
+ self.assertIn("iat", response2)
110
+ self.assertIn("iss", response2)
111
+ self.assertIn("sub", response2)
112
+ self.assertEqual("testname", response2["sub"])
99
113
 
100
114
  def test_user_not_valid(self):
101
115
  auth = BIAuth()
@@ -1,8 +1,22 @@
1
+ """
2
+ Unit tests for the user endpoints.
3
+
4
+ This module contains tests for the user-related functionalities, including:
5
+ - User authentication and authorization
6
+ - User role management
7
+ - Password handling and rotation
8
+ - User profile operations
9
+
10
+ All tests follow a consistent pattern of setting up test data,
11
+ executing operations, and verifying results against expected outcomes.
12
+ """
13
+
1
14
  import json
15
+ from datetime import datetime, timedelta, timezone
2
16
 
3
17
  from flask import current_app
4
18
  from flask_testing import TestCase
5
- from datetime import datetime, timedelta
19
+
6
20
  from cornflow.app import create_app
7
21
  from cornflow.commands.access import access_init_command
8
22
  from cornflow.commands.dag import register_deployed_dags_command_test
@@ -15,9 +29,8 @@ from cornflow.models import (
15
29
  UserModel,
16
30
  UserRoleModel,
17
31
  )
18
-
19
- from cornflow.shared.const import ADMIN_ROLE, PLANNER_ROLE, SERVICE_ROLE, VIEWER_ROLE
20
32
  from cornflow.shared import db
33
+ from cornflow.shared.const import ADMIN_ROLE, SERVICE_ROLE, PLANNER_ROLE, VIEWER_ROLE
21
34
  from cornflow.tests.const import (
22
35
  CASE_PATH,
23
36
  CASE_URL,
@@ -363,15 +376,18 @@ class TestUserEndpoint(TestCase):
363
376
 
364
377
  def test_change_password_rotation(self):
365
378
  current_app.config["PWD_ROTATION_TIME"] = 1 # in days
366
- payload = {"pwd_last_change": (datetime.utcnow() - timedelta(days=2)).strftime("%Y-%m-%dT%H:%M:%SZ")}
367
- self.modify_info(self.planner, self.planner, payload)
379
+ payload = {"pwd_last_change": (datetime.now(timezone.utc) - timedelta(days=2))}
380
+
381
+ planner = UserModel.get_one_user(self.planner["id"])
382
+ planner.update(payload)
383
+
368
384
  response = self.log_in(self.planner)
369
385
  self.assertEqual(True, response.json["change_password"])
370
386
 
371
387
  payload = {"password": "Newtestpassword1!"}
372
388
  self.modify_info(self.planner, self.planner, payload)
373
389
  self.planner.update(payload)
374
- print(self.planner)
390
+
375
391
  response = self.log_in(self.planner)
376
392
  self.assertEqual(False, response.json["change_password"])
377
393
 
@@ -1,13 +1,78 @@
1
- from unittest.mock import Mock
1
+ from unittest.mock import Mock, patch
2
+ from flask import Flask
3
+ import json
4
+ import os
5
+
6
+ from cornflow.shared.const import DATABRICKS_TERMINATE_STATE, DATABRICKS_FINISH_TO_STATE_MAP
7
+
8
+
9
+ def create_test_app():
10
+ app = Flask(__name__)
11
+ app.config["CORNFLOW_BACKEND"] = 2
12
+ return app
2
13
 
3
14
 
4
15
  def patch_af_client(af_client_class):
5
- af_client_mock = Mock()
6
- responses_mock = Mock()
7
- responses_mock.json.return_value = {"is_paused": False, "dag_run_id": "12345", "state": "success"}
8
- af_client_mock.is_alive.return_value = True
9
- af_client_mock.get_orch_info.return_value = responses_mock
10
- af_client_mock.run_workflow.return_value = responses_mock
11
- af_client_mock.get_run_status.return_value = responses_mock
12
- af_client_mock.set_dag_run_to_fail.return_value = None
13
- af_client_class.from_config.return_value = af_client_mock
16
+ with patch(
17
+ "cornflow.endpoints.execution.current_app.config"
18
+ ) as mock_config:
19
+ mock_config.__getitem__.side_effect = lambda key: (
20
+ 1 if key == "CORNFLOW_BACKEND" else {}
21
+ )
22
+ af_client_mock = Mock()
23
+ responses_mock = Mock()
24
+ responses_mock.json.return_value = {
25
+ "is_paused": False,
26
+ "dag_run_id": "12345",
27
+ "state": "success",
28
+ }
29
+ af_client_mock.is_alive.return_value = True
30
+ af_client_mock.get_orch_info.return_value = responses_mock
31
+ af_client_mock.run_workflow.return_value = responses_mock
32
+ af_client_mock.get_run_status.return_value = responses_mock
33
+ af_client_mock.set_dag_run_to_fail.return_value = None
34
+ af_client_class.from_config.return_value = af_client_mock
35
+
36
+
37
+ def patch_db_client(db_client_class):
38
+ mock_config = {"CORNFLOW_BACKEND": 2}
39
+
40
+ with patch(
41
+ "cornflow.endpoints.execution.current_app.config", mock_config
42
+ ):
43
+ db_client_mock = Mock()
44
+ responses_mock = Mock()
45
+ responses_mock.json.return_value = {
46
+ "status": {"state": "SUCCESS", "termination_details": {"code": "SUCCESS"}}
47
+ }
48
+ response_run_workflow = Mock()
49
+ response_run_workflow.json.return_value = {
50
+ "run_id": 350148078719367,
51
+ "number_in_job": 350148078719367,
52
+ }
53
+ response_get_orch_info = Mock()
54
+ current_dir = os.path.dirname(os.path.abspath(__file__))
55
+ test_data_dir = os.path.join(os.path.dirname(current_dir), "data")
56
+ with open(
57
+ os.path.join(test_data_dir, "patch_databricks_get_orch_info.json")
58
+ ) as f:
59
+ response_get_orch_info.json.return_value = json.load(f)
60
+ response_get_run_status = Mock()
61
+ with open(
62
+ os.path.join(test_data_dir, "patch_databricks_get_run_status.json")
63
+ ) as f:
64
+ response_get_run_status.json.return_value = json.load(f)
65
+ state = response_get_run_status.json.return_value["status"]["state"]
66
+ if state == DATABRICKS_TERMINATE_STATE:
67
+ if (
68
+ response_get_run_status.json.return_value["status"]["termination_details"]["code"]
69
+ in DATABRICKS_FINISH_TO_STATE_MAP.keys()
70
+ ):
71
+ response_get_run_status = response_get_run_status.json.return_value["status"]["termination_details"]["code"]
72
+ else:
73
+ response_get_run_status = "OTHER_FINISH_ERROR"
74
+ db_client_mock.is_alive.return_value = True
75
+ db_client_mock.get_orch_info.return_value = response_get_orch_info
76
+ db_client_mock.run_workflow.return_value = response_run_workflow
77
+ db_client_mock.get_run_status.return_value = response_get_run_status
78
+ db_client_class.from_config.return_value = db_client_mock
@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: cornflow
3
- Version: 2.0.0a11
4
- Summary: Cornflow is an open source multi-solver optimization server with a REST API built using flask.
3
+ Version: 2.0.0a13
4
+ Summary: cornflow is an open source multi-solver optimization server with a REST API built using flask.
5
5
  Home-page: https://github.com/baobabsoluciones/cornflow
6
6
  Author: baobab soluciones
7
7
  Author-email: cornflow@baobabsoluciones.es
@@ -12,9 +12,10 @@ Classifier: Development Status :: 5 - Production/Stable
12
12
  Requires-Python: >=3.9
13
13
  Requires-Dist: alembic==1.9.2
14
14
  Requires-Dist: apispec<=6.3.0
15
+ Requires-Dist: cachetools==5.3.3
15
16
  Requires-Dist: click<=8.1.7
16
- Requires-Dist: cornflow-client==2.0.0a10
17
- Requires-Dist: cryptography<=42.0.5
17
+ Requires-Dist: cornflow-client==2.0.0a13
18
+ Requires-Dist: cryptography<=44.0.1
18
19
  Requires-Dist: databricks-sdk==0.29.0
19
20
  Requires-Dist: disposable-email-domains>=0.0.86
20
21
  Requires-Dist: Flask==2.3.2
@@ -29,7 +30,7 @@ Requires-Dist: Flask-SQLAlchemy==2.5.1
29
30
  Requires-Dist: gevent==23.9.1
30
31
  Requires-Dist: greenlet<=2.0.2; python_version < "3.11"
31
32
  Requires-Dist: greenlet==3.0.3; python_version >= "3.11"
32
- Requires-Dist: gunicorn<=22.0.0
33
+ Requires-Dist: gunicorn<=23.0.0
33
34
  Requires-Dist: jsonpatch<=1.33
34
35
  Requires-Dist: ldap3<=2.9.1
35
36
  Requires-Dist: marshmallow<=3.20.2
@@ -50,7 +51,7 @@ Dynamic: requires-dist
50
51
  Dynamic: requires-python
51
52
  Dynamic: summary
52
53
 
53
- Cornflow
54
+ cornflow
54
55
  =========
55
56
 
56
57
  .. image:: https://github.com/baobabsoluciones/cornflow/workflows/build/badge.svg?style=svg
@@ -70,13 +71,13 @@ Cornflow
70
71
 
71
72
  .. image:: https://img.shields.io/badge/License-Apache2.0-blue
72
73
 
73
- Cornflow is an open source multi-solver optimization server with a REST API built using `flask <https://flask.palletsprojects.com>`_, `airflow <https://airflow.apache.org/>`_ and `pulp <https://coin-or.github.io/pulp/>`_.
74
+ cornflow is an open source multi-solver optimization server with a REST API built using `flask <https://flask.palletsprojects.com>`_, `airflow <https://airflow.apache.org/>`_ and `pulp <https://coin-or.github.io/pulp/>`_.
74
75
 
75
- While most deployment servers are based on the solving technique (MIP, CP, NLP, etc.), Cornflow focuses on the optimization problems themselves. However, it does not impose any constraint on the type of problem and solution method to use.
76
+ While most deployment servers are based on the solving technique (MIP, CP, NLP, etc.), cornflow focuses on the optimization problems themselves. However, it does not impose any constraint on the type of problem and solution method to use.
76
77
 
77
- With Cornflow you can deploy a Traveling Salesman Problem solver next to a Knapsack solver or a Nurse Rostering Problem solver. As long as you describe the input and output data, you can upload any solution method for any problem and then use it with any data you want.
78
+ With cornflow you can deploy a Traveling Salesman Problem solver next to a Knapsack solver or a Nurse Rostering Problem solver. As long as you describe the input and output data, you can upload any solution method for any problem and then use it with any data you want.
78
79
 
79
- Cornflow helps you formalize your problem by proposing development guidelines. It also provides a range of functionalities around your deployed solution method, namely:
80
+ cornflow helps you formalize your problem by proposing development guidelines. It also provides a range of functionalities around your deployed solution method, namely:
80
81
 
81
82
  * storage of users, instances, solutions and solution logs.
82
83
  * deployment and maintenance of models, solvers and algorithms.
@@ -92,9 +93,9 @@ Cornflow helps you formalize your problem by proposing development guidelines. I
92
93
  Installation instructions
93
94
  -------------------------------
94
95
 
95
- Cornflow is tested with Ubuntu 20.04, python >= 3.8 and git.
96
+ cornflow is tested with Ubuntu 20.04, python >= 3.8 and git.
96
97
 
97
- Download the Cornflow project and install requirements::
98
+ Download the cornflow project and install requirements::
98
99
 
99
100
  python3 -m venv venv
100
101
  venv/bin/pip3 install cornflow
@@ -110,7 +111,7 @@ initialize the sqlite database::
110
111
  flask create_admin_user -u cornflow -e cornflow_admin@admin.com -p cornflow_admin_password
111
112
 
112
113
 
113
- activate the virtual environment and run Cornflow::
114
+ activate the virtual environment and run cornflow::
114
115
 
115
116
  source venv/bin/activate
116
117
  export FLASK_APP=cornflow.app
@@ -121,7 +122,7 @@ activate the virtual environment and run Cornflow::
121
122
  export AIRFLOW_PWD=airflow_pwd
122
123
  flask run
123
124
 
124
- **Cornflow needs a running installation of Airflow to operate and more configuration**. Check `the installation docs <https://baobabsoluciones.github.io/cornflow/main/install.html>`_ for more details on installing airflow, configuring the application and initializing the database.
125
+ **cornflow needs a running installation of Airflow to operate and more configuration**. Check `the installation docs <https://baobabsoluciones.github.io/cornflow/main/install.html>`_ for more details on installing airflow, configuring the application and initializing the database.
125
126
 
126
127
  Using cornflow to solve a PuLP model
127
128
  ---------------------------------------