cornflow 1.1.0a1__py3-none-any.whl → 1.1.0a2__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.
@@ -4,8 +4,8 @@ All references to endpoints should be imported from here
4
4
  The login resource gets created on app startup as it depends on configuration
5
5
  """
6
6
  from .action import ActionListEndpoint
7
+ from .alarms import AlarmsEndpoint
7
8
  from .apiview import ApiViewListEndpoint
8
-
9
9
  from .case import (
10
10
  CaseEndpoint,
11
11
  CaseFromInstanceExecutionEndpoint,
@@ -15,7 +15,6 @@ from .case import (
15
15
  CaseToInstance,
16
16
  CaseCompare,
17
17
  )
18
-
19
18
  from .dag import (
20
19
  DAGDetailEndpoint,
21
20
  DAGEndpointManual,
@@ -24,7 +23,12 @@ from .dag import (
24
23
  DeployedDAGEndpoint,
25
24
  DeployedDagDetailEndpoint,
26
25
  )
27
-
26
+ from .data_check import (
27
+ DataCheckExecutionEndpoint,
28
+ DataCheckInstanceEndpoint,
29
+ DataCheckCaseEndpoint,
30
+ )
31
+ from .example_data import ExampleDataListEndpoint, ExampleDataDetailEndpoint
28
32
  from .execution import (
29
33
  ExecutionEndpoint,
30
34
  ExecutionDetailsEndpoint,
@@ -33,36 +37,22 @@ from .execution import (
33
37
  ExecutionLogEndpoint,
34
38
  ExecutionRelaunchEndpoint,
35
39
  )
36
-
37
40
  from .health import HealthEndpoint
38
-
39
41
  from .instance import (
40
42
  InstanceEndpoint,
41
43
  InstanceDetailsEndpoint,
42
44
  InstanceFileEndpoint,
43
45
  InstanceDataEndpoint,
44
46
  )
45
-
46
- from .data_check import (
47
- DataCheckExecutionEndpoint,
48
- DataCheckInstanceEndpoint,
49
- DataCheckCaseEndpoint,
50
- )
51
47
  from .licenses import LicensesEndpoint
48
+ from .main_alarms import MainAlarmsEndpoint
52
49
  from .permission import PermissionsViewRoleEndpoint, PermissionsViewRoleDetailEndpoint
53
-
54
50
  from .roles import RolesListEndpoint, RoleDetailEndpoint
55
-
56
51
  from .schemas import SchemaDetailsEndpoint, SchemaEndpoint
52
+ from .tables import TablesEndpoint, TablesDetailsEndpoint
57
53
  from .token import TokenEndpoint
58
- from .example_data import ExampleDataDetailsEndpoint
59
54
  from .user import UserEndpoint, UserDetailsEndpoint, ToggleUserAdmin, RecoverPassword
60
55
  from .user_role import UserRoleListEndpoint, UserRoleDetailEndpoint
61
- from .alarms import AlarmsEndpoint
62
- from .main_alarms import MainAlarmsEndpoint
63
-
64
- from .tables import TablesEndpoint, TablesDetailsEndpoint
65
-
66
56
 
67
57
  resources = [
68
58
  dict(resource=InstanceEndpoint, urls="/instance/", endpoint="instance"),
@@ -157,10 +147,15 @@ resources = [
157
147
  endpoint="schema-details",
158
148
  ),
159
149
  dict(
160
- resource=ExampleDataDetailsEndpoint,
150
+ resource=ExampleDataListEndpoint,
161
151
  urls="/example/<string:dag_name>/",
162
152
  endpoint="example-data",
163
153
  ),
154
+ dict(
155
+ resource=ExampleDataDetailEndpoint,
156
+ urls="/example/<string:dag_name>/<string:example_name>/",
157
+ endpoint="example-data-detail",
158
+ ),
164
159
  dict(resource=HealthEndpoint, urls="/health/", endpoint="health"),
165
160
  dict(
166
161
  resource=CaseFromInstanceExecutionEndpoint,
@@ -1,36 +1,78 @@
1
1
  """
2
2
  Endpoints to get the example data from a DAG
3
3
  """
4
+ import json
4
5
 
5
- # Import from libraries
6
6
  from cornflow_client.airflow.api import Airflow
7
7
  from flask import current_app, request
8
8
  from flask_apispec import marshal_with, doc
9
- import json
10
9
 
11
- # Import from internal modules
12
10
  from cornflow.endpoints.meta_resource import BaseMetaResource
13
11
  from cornflow.models import PermissionsDAG
14
- from cornflow.schemas.example_data import ExampleData
12
+ from cornflow.schemas.example_data import ExampleListData, ExampleDetailData
15
13
  from cornflow.shared.authentication import Auth, authenticate
16
14
  from cornflow.shared.const import VIEWER_ROLE, PLANNER_ROLE, ADMIN_ROLE
17
- from cornflow.shared.exceptions import AirflowError, NoPermission
15
+ from cornflow.shared.exceptions import AirflowError, NoPermission, ObjectDoesNotExist
18
16
 
19
17
 
20
- class ExampleDataDetailsEndpoint(BaseMetaResource):
18
+ class ExampleDataListEndpoint(BaseMetaResource):
21
19
  """
22
20
  Endpoint used to obtain schemas for one app
23
21
  """
24
22
 
25
23
  ROLES_WITH_ACCESS = [VIEWER_ROLE, PLANNER_ROLE, ADMIN_ROLE]
26
24
 
27
- @doc(description="Get example data from DAG", tags=["DAG"])
25
+ @doc(description="Get lsit of example data from DAG", tags=["DAG"])
28
26
  @authenticate(auth_class=Auth())
29
- @marshal_with(ExampleData)
27
+ @marshal_with(ExampleListData(many=True))
30
28
  def get(self, dag_name):
31
29
  """
32
30
  API method to get example data for a given dag
33
31
 
32
+ :return: A dictionary with the names and descriptions of available data examples
33
+ and an integer with the HTTP status code
34
+ :rtype: Tuple(dict, integer)
35
+ """
36
+ user = Auth().get_user_from_header(request.headers)
37
+ permission = PermissionsDAG.check_if_has_permissions(
38
+ user_id=user.id, dag_id=dag_name
39
+ )
40
+
41
+ if permission:
42
+ af_client = Airflow.from_config(current_app.config)
43
+ if not af_client.is_alive():
44
+ current_app.logger.error(
45
+ "Airflow not accessible when getting data {}".format(dag_name)
46
+ )
47
+ raise AirflowError(error="Airflow is not accessible")
48
+
49
+ # try airflow and see if dag_name exists
50
+ af_client.get_dag_info(dag_name)
51
+
52
+ current_app.logger.info("User gets example data from {}".format(dag_name))
53
+
54
+ variable_name = f"z_{dag_name}_examples"
55
+ response = af_client.get_one_variable(variable_name)
56
+
57
+ return json.loads(response["value"])
58
+ else:
59
+ err = "User does not have permission to access this dag."
60
+ raise NoPermission(
61
+ error=err,
62
+ status_code=403,
63
+ log_txt=f"Error while user {user} tries to get example data for dag {dag_name}. "
64
+ + err,
65
+ )
66
+
67
+
68
+ class ExampleDataDetailEndpoint(BaseMetaResource):
69
+ @doc(description="Get example data from DAG", tags=["DAG"])
70
+ @authenticate(auth_class=Auth())
71
+ @marshal_with(ExampleDetailData)
72
+ def get(self, dag_name, example_name):
73
+ """
74
+ API method to get one example data for a given dag
75
+
34
76
  :return: A dictionary with a message and a integer with the HTTP status code
35
77
  :rtype: Tuple(dict, integer)
36
78
  """
@@ -54,15 +96,24 @@ class ExampleDataDetailsEndpoint(BaseMetaResource):
54
96
 
55
97
  variable_name = f"z_{dag_name}_examples"
56
98
  response = af_client.get_one_variable(variable_name)
57
- result = dict()
58
- result["examples"] = json.loads(response["value"])
59
- result["name"] = response["key"]
60
99
 
61
- return result
100
+ example = None
101
+ for item in json.loads(response["value"]):
102
+ if item["name"] == example_name:
103
+ example = item
104
+ break
105
+
106
+ if example is None:
107
+ raise ObjectDoesNotExist(
108
+ error="The example does not exist", status_code=404
109
+ )
110
+
111
+ return example
62
112
  else:
63
113
  err = "User does not have permission to access this dag."
64
114
  raise NoPermission(
65
115
  error=err,
66
116
  status_code=403,
67
- log_txt=f"Error while user {user} tries to get example data for dag {dag_name}. " + err
117
+ log_txt=f"Error while user {user} tries to get example data for dag {dag_name}. "
118
+ + err,
68
119
  )
@@ -1,6 +1,11 @@
1
1
  from marshmallow import fields, Schema
2
2
 
3
3
 
4
- class ExampleData(Schema):
4
+ class ExampleListData(Schema):
5
5
  name = fields.Str(required=True)
6
- examples = fields.Raw(required=True)
6
+ description = fields.Str(required=False)
7
+
8
+
9
+ class ExampleDetailData(ExampleListData):
10
+ instance = fields.Raw(required=True)
11
+ solution = fields.Raw(required=False)
@@ -131,7 +131,7 @@ class CLITests(TestCase):
131
131
  result = runner.invoke(cli, ["views", "init", "-v"])
132
132
  self.assertEqual(result.exit_code, 0)
133
133
  views = ViewModel.get_all_objects().all()
134
- self.assertEqual(len(views), 48)
134
+ self.assertEqual(len(views), 49)
135
135
 
136
136
  def test_permissions_entrypoint(self):
137
137
  runner = CliRunner()
@@ -155,8 +155,8 @@ class CLITests(TestCase):
155
155
  permissions = PermissionViewRoleModel.get_all_objects().all()
156
156
  self.assertEqual(len(actions), 5)
157
157
  self.assertEqual(len(roles), 4)
158
- self.assertEqual(len(views), 48)
159
- self.assertEqual(len(permissions), 530)
158
+ self.assertEqual(len(views), 49)
159
+ self.assertEqual(len(permissions), 546)
160
160
 
161
161
  def test_permissions_base_command(self):
162
162
  runner = CliRunner()
@@ -171,8 +171,8 @@ class CLITests(TestCase):
171
171
  permissions = PermissionViewRoleModel.get_all_objects().all()
172
172
  self.assertEqual(len(actions), 5)
173
173
  self.assertEqual(len(roles), 4)
174
- self.assertEqual(len(views), 48)
175
- self.assertEqual(len(permissions), 530)
174
+ self.assertEqual(len(views), 49)
175
+ self.assertEqual(len(permissions), 546)
176
176
 
177
177
  def test_service_entrypoint(self):
178
178
  runner = CliRunner()
@@ -1,15 +1,9 @@
1
- """
2
-
3
- """
4
-
5
- # General imports
6
1
  import json
7
2
 
8
- # Partial imports
9
- from unittest.mock import patch
10
3
 
4
+ from unittest.mock import patch
11
5
 
12
- # Imports from internal modules
6
+ from cornflow.models import PermissionsDAG
13
7
  from cornflow.tests.const import EXAMPLE_URL, INSTANCE_PATH
14
8
  from cornflow.tests.custom_test_case import CustomTestCase
15
9
 
@@ -23,7 +17,18 @@ class TestExampleDataEndpoint(CustomTestCase):
23
17
  temp = json.load(f)
24
18
  return temp
25
19
 
26
- self.example = load_file(INSTANCE_PATH)
20
+ self.example = [
21
+ {
22
+ "name": "test_example_1",
23
+ "description": "some_description",
24
+ "instance": load_file(INSTANCE_PATH),
25
+ },
26
+ {
27
+ "name": "test_example_2",
28
+ "description": "some_description",
29
+ "instance": load_file(INSTANCE_PATH),
30
+ },
31
+ ]
27
32
  self.url = EXAMPLE_URL
28
33
  self.schema_name = "solve_model_dag"
29
34
 
@@ -38,17 +43,82 @@ class TestExampleDataEndpoint(CustomTestCase):
38
43
  af_client.get_all_schemas.return_value = [{"name": self.schema_name}]
39
44
  return af_client
40
45
 
46
+ def patch_af_client_not_alive(self, Airflow_mock):
47
+ af_client = Airflow_mock.return_value
48
+ af_client.is_alive.return_value = False
49
+ af_client.is_alive.return_value = False
50
+ return af_client
51
+
52
+ @patch("cornflow.endpoints.example_data.Airflow.from_config")
53
+ def test_get_list_of_examples(self, airflow_init):
54
+ af_client = self.patch_af_client(airflow_init)
55
+ examples = self.get_one_row(
56
+ f"{self.url}/{self.schema_name}/",
57
+ {},
58
+ expected_status=200,
59
+ check_payload=False,
60
+ )
61
+
62
+ for pos, item in enumerate(examples):
63
+ self.assertIn("name", item)
64
+ self.assertEqual(self.example[pos]["name"], item["name"])
65
+ self.assertIn("description", item)
66
+ self.assertEqual(self.example[pos]["description"], item["description"])
67
+
41
68
  @patch("cornflow.endpoints.example_data.Airflow.from_config")
42
- def test_get_example(self, airflow_init):
69
+ def test_get_one_example(self, airflow_init):
70
+ def load_file(_file):
71
+ with open(_file) as f:
72
+ temp = json.load(f)
73
+ return temp
74
+
43
75
  af_client = self.patch_af_client(airflow_init)
44
76
  keys_to_check = ["name", "examples"]
45
77
  example = self.get_one_row(
46
- self.url + "{}/".format(self.schema_name),
78
+ f"{self.url}/{self.schema_name}/test_example_1/",
47
79
  {},
48
80
  expected_status=200,
49
81
  check_payload=False,
50
82
  keys_to_check=keys_to_check,
51
83
  )
52
- self.assertIn("examples", example)
84
+
53
85
  self.assertIn("name", example)
54
- self.assertEqual(example["examples"], self.example)
86
+ self.assertEqual("test_example_1", example["name"])
87
+ self.assertIn("description", example)
88
+ self.assertIn("instance", example)
89
+ self.assertEqual(load_file(INSTANCE_PATH), example["instance"])
90
+
91
+ @patch("cornflow.endpoints.example_data.Airflow.from_config")
92
+ def test_airflow_not_available(self, airflow_init):
93
+ af_client = self.patch_af_client_not_alive(airflow_init)
94
+ self.get_one_row(
95
+ f"{self.url}/{self.schema_name}/test_example_1/",
96
+ {},
97
+ expected_status=400,
98
+ check_payload=False,
99
+ )
100
+
101
+ self.get_one_row(
102
+ f"{self.url}/{self.schema_name}/",
103
+ {},
104
+ expected_status=400,
105
+ check_payload=False,
106
+ )
107
+
108
+ def test_if_no_permission(self):
109
+ with patch.object(
110
+ PermissionsDAG, "check_if_has_permissions", return_value=False
111
+ ) as mock_permission:
112
+ self.get_one_row(
113
+ f"{self.url}/{self.schema_name}/",
114
+ {},
115
+ expected_status=403,
116
+ check_payload=False,
117
+ )
118
+
119
+ self.get_one_row(
120
+ f"{self.url}/{self.schema_name}/test_example_1/",
121
+ {},
122
+ expected_status=403,
123
+ check_payload=False,
124
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cornflow
3
- Version: 1.1.0a1
3
+ Version: 1.1.0a2
4
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
@@ -15,7 +15,7 @@ Requires-Python: >=3.8
15
15
  Requires-Dist: alembic ==1.9.2
16
16
  Requires-Dist: apispec <=6.2.0
17
17
  Requires-Dist: click <=8.1.3
18
- Requires-Dist: cornflow-client ==1.1.0a1
18
+ Requires-Dist: cornflow-client ==1.1.0a2
19
19
  Requires-Dist: cryptography <=42.0.5
20
20
  Requires-Dist: disposable-email-domains >=0.0.86
21
21
  Requires-Dist: Flask ==2.3.2
@@ -37,14 +37,14 @@ cornflow/commands/roles.py,sha256=Oux-UkswkQ74zqaMEJYIEsZpQZGBcGaSahVzx9feAHU,15
37
37
  cornflow/commands/schemas.py,sha256=QjLXLw5So3f8ZqTg5_uvXxwpo4vE0dMT4_gFMKZHGvQ,1828
38
38
  cornflow/commands/users.py,sha256=MEfqMm2ujso0NQgdUm-crOet-G0M43GNqVCx2Ls-2HY,2591
39
39
  cornflow/commands/views.py,sha256=K2Ld1-l1ZKn9m6e2W1LCxmN44QokwR-8u8rIrviiEf8,2276
40
- cornflow/endpoints/__init__.py,sha256=EGUIDL5EGsDQtm1YQ4aKkmRG1roW_3Ki87MeZr79Lx0,7168
40
+ cornflow/endpoints/__init__.py,sha256=RI-cNRxYFCuYELPdM0kDDgJhopMMX88HJe-ArTTilNM,7346
41
41
  cornflow/endpoints/action.py,sha256=ksHK3F919cjkONLcFV2tUIbG-eZw5XbYkqVjYx9iq5I,1359
42
42
  cornflow/endpoints/alarms.py,sha256=3FN7mosBFP_DcJQxfg1h5_phy755FYESXyQ62XpvFbs,1956
43
43
  cornflow/endpoints/apiview.py,sha256=cpxZFkWy6yrRHiAq2tseyVAK1r8uvjnFuOgJjGT0rKI,1370
44
44
  cornflow/endpoints/case.py,sha256=80Fpv9p8mwIXzjQFuyq1PnPTz3RaOUk932sCUfw7yGA,18670
45
45
  cornflow/endpoints/dag.py,sha256=MRthA2pnZCAFfoPbHCLDW2j1BsQ3WdjRGC17Szl4b28,10390
46
46
  cornflow/endpoints/data_check.py,sha256=ZyYR84IT9snjXxUrQfrlv_RzOec_AYeTsijuHYdLAcA,16496
47
- cornflow/endpoints/example_data.py,sha256=fzolSYl1sYCSCR4Ctr7QD9JM3NdxCjBiiQLVxCPCbJg,2441
47
+ cornflow/endpoints/example_data.py,sha256=1_qAtZfp51N9sU8WCFDZCXOQiOlxCKJjWbXxDOFZ0C8,4372
48
48
  cornflow/endpoints/execution.py,sha256=5SWwgbxBUj_gDU6Yb7Z-iKNakr9vr3g5qU82Bw9y5wQ,27998
49
49
  cornflow/endpoints/health.py,sha256=TWmWjKdQOoDzpqwcfksuaAGOLIb2idxzPQcGMWrdkCY,1610
50
50
  cornflow/endpoints/instance.py,sha256=WAnloocXFxSW4vunBJo3CIHx4NzC_0GPJh5bj3ETd9U,11615
@@ -101,7 +101,7 @@ cornflow/schemas/alarms.py,sha256=Y-VQ93jbDLtEv49qkNDHwrhwkG7OzEQ0nceqJCqeScQ,54
101
101
  cornflow/schemas/case.py,sha256=OXRsDi_sdB47MQJ59S_1eMjDmLlpUtG7kTFNInV2-cI,2909
102
102
  cornflow/schemas/common.py,sha256=QYuxWcOl4smXFZr_vL07OVgH9H50ZywCrXxycVNr1qA,473
103
103
  cornflow/schemas/dag.py,sha256=0ENA75X9L8YqjJW6ZO1Sb4zE8OxB15_O49_nwA6eAVw,901
104
- cornflow/schemas/example_data.py,sha256=7BeaujSgj10RHK6Z__4wRZ273-QmVjVOs6uEvYw7PnE,146
104
+ cornflow/schemas/example_data.py,sha256=hbE8TJakFqOweHXiA3mduNETM6FCX6xLTiQuH3EkSTc,281
105
105
  cornflow/schemas/execution.py,sha256=GSRHzikVPlhxMdiKrGnTuGfen8_Lf4wSfheJwvcavTs,4718
106
106
  cornflow/schemas/health.py,sha256=D2NsP9i6nA1hLema-bvegrrdH4JY7pZlYxPcqRJOvao,141
107
107
  cornflow/schemas/instance.py,sha256=qr4km0AlAhoNf9G1Il-pfHphT_vAiiLDpv7A9S3FKAw,1870
@@ -146,11 +146,11 @@ cornflow/tests/unit/test_actions.py,sha256=Fg33PyzNTK4B4NjARelMxLQpQl9nE9Jppolkk
146
146
  cornflow/tests/unit/test_alarms.py,sha256=J4Hp2xIZqpFrojx_RvQCSU1ilDk-iC0vm2z8wZNXwIw,1343
147
147
  cornflow/tests/unit/test_apiview.py,sha256=G5DpUPaKVXgbCOaXXTCjBAeGeCtfR8niltp7B0NNB6o,2107
148
148
  cornflow/tests/unit/test_cases.py,sha256=lXLgvHbNGw8qUoCtYUwwXE_O2AWSmSXxLVlxE-hc9Oc,25974
149
- cornflow/tests/unit/test_cli.py,sha256=IK7nhPpVy2dSXGRSies_Lh9DImNaL2SFCXb-gxKUmDI,12578
149
+ cornflow/tests/unit/test_cli.py,sha256=qYcMGAdLIOhTgWV4q0rGu0bv5Bs7JUIsyRd5qt6pcOI,12578
150
150
  cornflow/tests/unit/test_commands.py,sha256=QwGHTOxBOwiIYYQg8wcmSR11lKQk0I8Ltr3sbFERufw,8776
151
151
  cornflow/tests/unit/test_dags.py,sha256=5lTJW_fgh7XXE11Zo9yVsQ7wsmbCPxCCRwna2vkPEuA,10350
152
152
  cornflow/tests/unit/test_data_checks.py,sha256=VjB3AAQOHlqnaRT2jI9L2mNLDAcda6llpiZWkW7nnkk,5471
153
- cornflow/tests/unit/test_example_data.py,sha256=TR6b7ekpc6pLOpDnlKl3fHe-FD7gXw5M1JGVj-Dlfvk,1605
153
+ cornflow/tests/unit/test_example_data.py,sha256=D-Tgnqw7NZlnBXaDcUU0reNhAca5JlJP2Sdn3KdS4Sw,4127
154
154
  cornflow/tests/unit/test_executions.py,sha256=_hIaiZri7Blyx4DYhBDHh-0peU1HQh66RSPqQJFveE8,17501
155
155
  cornflow/tests/unit/test_generate_from_schema.py,sha256=L1EdnASbDJ8SjrX1V4WnUKKwV0sRTwVnNYnxSpyeSeQ,15376
156
156
  cornflow/tests/unit/test_health.py,sha256=0E0HXMb63_Z8drbLZdxnJwtTbQyaZS9ZEHut6qsDbh8,1033
@@ -168,8 +168,8 @@ cornflow/tests/unit/test_tables.py,sha256=dY55YgaCkyqwJnqn0LbZHNeXBoL4ZxXWwKkCoT
168
168
  cornflow/tests/unit/test_token.py,sha256=OEVPgG8swSMkUbuGJGfGF5Z27utMLICn1eIyma1cM9E,3760
169
169
  cornflow/tests/unit/test_users.py,sha256=WfaMcybPpR7rspXyvzHGgw25p751hMPAV0DOp_caSPM,22430
170
170
  cornflow/tests/unit/tools.py,sha256=ag3sWv2WLi498R1GL5AOUnXqSsszD3UugzLZLC5NqAw,585
171
- cornflow-1.1.0a1.dist-info/METADATA,sha256=TFEqw1OCDTa8w9adMHT5zMsibVdTOrokQgEYHG6wRkc,9402
172
- cornflow-1.1.0a1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
173
- cornflow-1.1.0a1.dist-info/entry_points.txt,sha256=r5wKLHpuyVLMUIZ5I29_tpqYf-RuP-3w_8DhFi8_blQ,47
174
- cornflow-1.1.0a1.dist-info/top_level.txt,sha256=Qj9kLFJW1PLb-ZV2s_aCkQ-Wi5W6KC6fFR-LTBrx-rU,24
175
- cornflow-1.1.0a1.dist-info/RECORD,,
171
+ cornflow-1.1.0a2.dist-info/METADATA,sha256=Q3l-3geC8Y0gRpUe4cqdRz8NTtZ53IZ8eo6s_wdqyNc,9402
172
+ cornflow-1.1.0a2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
173
+ cornflow-1.1.0a2.dist-info/entry_points.txt,sha256=r5wKLHpuyVLMUIZ5I29_tpqYf-RuP-3w_8DhFi8_blQ,47
174
+ cornflow-1.1.0a2.dist-info/top_level.txt,sha256=Qj9kLFJW1PLb-ZV2s_aCkQ-Wi5W6KC6fFR-LTBrx-rU,24
175
+ cornflow-1.1.0a2.dist-info/RECORD,,