cornflow 1.1.1a1__py3-none-any.whl → 1.1.2__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 (35) hide show
  1. cornflow/app.py +0 -4
  2. cornflow/cli/utils.py +1 -1
  3. cornflow/config.py +2 -10
  4. cornflow/endpoints/__init__.py +0 -14
  5. cornflow/endpoints/execution.py +1 -1
  6. cornflow/endpoints/login.py +6 -26
  7. cornflow/models/__init__.py +0 -2
  8. cornflow/models/execution.py +0 -8
  9. cornflow/models/meta_models.py +12 -23
  10. cornflow/schemas/execution.py +0 -3
  11. cornflow/shared/const.py +0 -21
  12. cornflow/shared/exceptions.py +9 -20
  13. cornflow/tests/const.py +0 -7
  14. cornflow/tests/{custom_live_server.py → custom_liveServer.py} +1 -3
  15. cornflow/tests/custom_test_case.py +3 -2
  16. cornflow/tests/integration/test_commands.py +1 -1
  17. cornflow/tests/integration/test_cornflowclient.py +28 -116
  18. cornflow/tests/unit/test_alarms.py +9 -22
  19. cornflow/tests/unit/test_cli.py +5 -10
  20. cornflow/tests/unit/test_commands.py +2 -6
  21. cornflow/tests/unit/test_executions.py +0 -5
  22. cornflow/tests/unit/test_main_alarms.py +0 -8
  23. cornflow/tests/unit/test_users.py +2 -5
  24. {cornflow-1.1.1a1.dist-info → cornflow-1.1.2.dist-info}/METADATA +7 -7
  25. {cornflow-1.1.1a1.dist-info → cornflow-1.1.2.dist-info}/RECORD +28 -35
  26. cornflow/endpoints/reports.py +0 -283
  27. cornflow/migrations/versions/83164be03c23_.py +0 -40
  28. cornflow/migrations/versions/96f00d0961d1_reports_table.py +0 -50
  29. cornflow/models/reports.py +0 -119
  30. cornflow/schemas/reports.py +0 -48
  31. cornflow/static/v1.json +0 -3854
  32. cornflow/tests/unit/test_reports.py +0 -308
  33. {cornflow-1.1.1a1.dist-info → cornflow-1.1.2.dist-info}/WHEEL +0 -0
  34. {cornflow-1.1.1a1.dist-info → cornflow-1.1.2.dist-info}/entry_points.txt +0 -0
  35. {cornflow-1.1.1a1.dist-info → cornflow-1.1.2.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,8 @@ airflow_config/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
5
5
  airflow_config/plugins/XCom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  airflow_config/plugins/XCom/gce_xcom_backend.py,sha256=vCGvF2jbfZt5bOv-pk5Q_kUR6LomFUojIymimSJmj3o,1795
7
7
  cornflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- cornflow/app.py,sha256=9WV1wrH_6EzaCgBGgpbHu6C8-n0MX_crJI2FxBwR85I,7090
9
- cornflow/config.py,sha256=MqRw-yQM60BVzU7rC9Ui63_f0VfFIuXceq2mw5WlBNs,5106
8
+ cornflow/app.py,sha256=3tj9aMOLFzBGS4QFPD0Zt2A7N0C5lssvy8NZ-G4sU9E,6997
9
+ cornflow/config.py,sha256=CGG2BMn8l1gCB0Okk-8IRrtqiRIUK09fq3xO397ZHig,4738
10
10
  cornflow/gunicorn.py,sha256=uO-Yk7w7nvQSWh12iDxsVvlG-_2BiKIIjm2UiTk4P9E,480
11
11
  cornflow/cli/__init__.py,sha256=5jBmSMpaE1S9rDaQjS8VHJ6x4FfJG8MhKzMzfw7G4Zc,743
12
12
  cornflow/cli/actions.py,sha256=BdTFucT6gZ0QJqo96Zu0C2G9acZ578tLkktKSfTybJ8,414
@@ -18,7 +18,7 @@ cornflow/cli/roles.py,sha256=NFG__qrlyOT0h4L4nwo9FSV4DKjGtMVh3gwiJxwM37w,411
18
18
  cornflow/cli/schemas.py,sha256=sxuJOZf12SBZAXDiAYNPB-n9LSxzSwkB3xyhgS_4K9A,6086
19
19
  cornflow/cli/service.py,sha256=7_va2Gv1qySldWtTHLL0b_Tg6tuYzAVduyeKmoiBgVs,9292
20
20
  cornflow/cli/users.py,sha256=nPnu8rQNLtwmeXLwYtJ_hjlsa_24XOnQLgBJRBP9bJw,2104
21
- cornflow/cli/utils.py,sha256=2BbC0fVuCXQKAH0j-fltSFtaXxOZHFKwGoU2XDMG65Q,708
21
+ cornflow/cli/utils.py,sha256=0tF41gTt6LL9XGOizTQg2GXuOXbqLg6gapCr-HWjJ0Q,733
22
22
  cornflow/cli/views.py,sha256=Xyx2l-Sm7panxQEfR3qksCIUoqF7woMKsYgZALkxUXM,636
23
23
  cornflow/cli/tools/__init__.py,sha256=JtyhYfUfirw78BV1mCsdeY0W25fDPWTmZhNBWdDh0wA,19
24
24
  cornflow/cli/tools/api_generator.py,sha256=7ZEEGBdL9Anbj5gnPm3m_eHQm0ehz7Y7YaD952mGh58,16344
@@ -37,7 +37,7 @@ 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=Haon-F6Zve6eDAQw6TQH6CS4INHYT2CnTerP4cys8SE,7829
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
@@ -45,15 +45,14 @@ cornflow/endpoints/case.py,sha256=80Fpv9p8mwIXzjQFuyq1PnPTz3RaOUk932sCUfw7yGA,18
45
45
  cornflow/endpoints/dag.py,sha256=MRthA2pnZCAFfoPbHCLDW2j1BsQ3WdjRGC17Szl4b28,10390
46
46
  cornflow/endpoints/data_check.py,sha256=ZyYR84IT9snjXxUrQfrlv_RzOec_AYeTsijuHYdLAcA,16496
47
47
  cornflow/endpoints/example_data.py,sha256=1_qAtZfp51N9sU8WCFDZCXOQiOlxCKJjWbXxDOFZ0C8,4372
48
- cornflow/endpoints/execution.py,sha256=cPIqt0MQId5ugl3HC82iOSbLY-vRjK_Obe8U1-1TL1I,27999
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
51
51
  cornflow/endpoints/licenses.py,sha256=82hHWGYvVIiyw9mlwGtMwJMDJ-ShHOi9rvuM6KvfE4U,873
52
- cornflow/endpoints/login.py,sha256=eVZHo7T-YD080ofUckbPNv0Yhtcp4SaumlVsZb2mOxg,8402
52
+ cornflow/endpoints/login.py,sha256=HMPBQm_yEBzPCvBU_UHlOkUYgtWJG5rL9euR8Dzxm0w,7864
53
53
  cornflow/endpoints/main_alarms.py,sha256=GUB-UdnvEFi7n6FGFKO9VtZeZb4Ox3NvBMhB7rdqNyI,2006
54
54
  cornflow/endpoints/meta_resource.py,sha256=eqC6U8IpY65Cbk2WpdphRtE6o5kes2lB4LhezfUB7xI,8471
55
55
  cornflow/endpoints/permission.py,sha256=FpEBIucfUl89UaJ80SC0VR6pFAdqdSsS43SdNkcXWtI,3751
56
- cornflow/endpoints/reports.py,sha256=ESYIvG23muEeaRr-plnnVralfeyg7SS68izbxShY4Vg,10198
57
56
  cornflow/endpoints/roles.py,sha256=54ra4MQ9JmrHDsiGczDAVqHgAT4zwhdTA1dLBOy66v8,6105
58
57
  cornflow/endpoints/schemas.py,sha256=lHyvSpPj0x7zVYDlEeRrz_Qqyp6WNimibs5gK4BHpKI,2933
59
58
  cornflow/endpoints/signup.py,sha256=4Xle2aTd6fiblb2pFcTaBP3ykXSuXsrc7qD0JjpqeZY,3513
@@ -69,8 +68,6 @@ cornflow/migrations/versions/00757b557b02_.py,sha256=PtFD0nIRBHjpDiCrhudxReI6ej6
69
68
  cornflow/migrations/versions/1af47a419bbd_.py,sha256=F6XOkxhojBbOSv3EGiWJvvncSMNAUPy2h5-NV2Gd5ak,1926
70
69
  cornflow/migrations/versions/4aac5e0c6e66_.py,sha256=ecWq38w_1vWpbLqsEkTsPw1tGv88OMt9L8JNZHlu7LI,2200
71
70
  cornflow/migrations/versions/7c3ea5ab5501_.py,sha256=TX9Are_ELRweHeGOo3tV4XAB9cFIVH6LAooCvoNfJxU,1569
72
- cornflow/migrations/versions/83164be03c23_.py,sha256=Ed21NOt_sEdsfdO6MqwkiEjrQu-FQHBwEI1ArA6CGok,1170
73
- cornflow/migrations/versions/96f00d0961d1_reports_table.py,sha256=nWcJ9wPeQTsbrYGdBoMzQb3dmmPCJgKGw5oSlpAfsMM,1464
74
71
  cornflow/migrations/versions/991b98e24225_.py,sha256=oNDQKQw6SfMdAB9HYV9Vb-haz5dJQo9lp3uJR-K9xYk,834
75
72
  cornflow/migrations/versions/a472b5ad50b7_.py,sha256=RpaLV-eTZmOS4BN53F_o0yG6ZGfmfKIJjrn2x2M6THw,1370
76
73
  cornflow/migrations/versions/c2db9409cb5f_.py,sha256=M6udQ0vaIJXEsGpb31ZqAdU_eDwvbHPvWLvNsGQx7yY,1812
@@ -82,19 +79,18 @@ cornflow/migrations/versions/e1a50dae1ac9_.py,sha256=NIRKFg1hvo4F-YqMdsYoX9VwzKl
82
79
  cornflow/migrations/versions/e937a5234ce4_.py,sha256=460JyCKPN6XL5DDcJfC51WKr9V342ovVhuo8F7fwuo0,710
83
80
  cornflow/migrations/versions/ebdd955fcc5e_.py,sha256=MzLbzmiwMWWVkJWJ8EMmmBnCIOzvlwXKGFWxELnOQpE,1848
84
81
  cornflow/migrations/versions/f3bee20314a2_.py,sha256=pgfAeiPvFvPJXhWlFHq6Y7bjYFGvapsfHEFXXX8UJlE,1782
85
- cornflow/models/__init__.py,sha256=pbHTYGk7k-HbQYjB8SpC4KFdM1fp838PbdnaPPxiL6M,534
82
+ cornflow/models/__init__.py,sha256=hvUe_9Xep1gl8hPKcWxCZN9sORH0Opskj_DnNs3bn24,500
86
83
  cornflow/models/action.py,sha256=8MYzQ2qX5bG0zk28OufypzThkR7AU1J1el-5ABoTurg,1200
87
84
  cornflow/models/alarms.py,sha256=R_g3tkWNSJaAG4gSvthgJlyrueY9VDuIZPoVHk5lDvU,1682
88
85
  cornflow/models/base_data_model.py,sha256=mVMHJpEoJeH6Wly_ZIfzLfTPd39nSYpCgmtA_ft2VPs,5577
89
86
  cornflow/models/case.py,sha256=GEs-xeo0bJ5qJETDnIur-2q2IyR3NSj1K0jP3Arz4Xs,9572
90
87
  cornflow/models/dag.py,sha256=DhHpBqJXrLzPoVSyrS_rYI7BotdzITopJDKsql3mQnQ,2930
91
88
  cornflow/models/dag_permissions.py,sha256=QkhPxSLKxH5elIMdf-rnRtV_CEZBQDFFKUOWv15RgwI,1716
92
- cornflow/models/execution.py,sha256=UUrQk0w5ZbaM82ZiLA7vJqKS71ZZcgPMSYR3UrEldmk,6275
89
+ cornflow/models/execution.py,sha256=9sq_GXSAgFgTpDX3kbJGwsHwNQGXH9E_gfNYIfNtDOk,6022
93
90
  cornflow/models/instance.py,sha256=2E9kBKv1a8soaEAvG8X4qXQ4BVC-IWYD5WQcPmZQw00,3979
94
91
  cornflow/models/main_alarms.py,sha256=9S-Ohr2kYFFWB0HomrpSdDIoUr85Eu1rt90Om_Pa8VY,1748
95
- cornflow/models/meta_models.py,sha256=cCYYWfB-Xm5nh-1bJCFeE8i1vrGElhpO-DQucJ_z8hA,12313
92
+ cornflow/models/meta_models.py,sha256=qeliGdpw0_q0GCeZzansF-09Ay5pueaT-QQPVPZ5aj4,12000
96
93
  cornflow/models/permissions.py,sha256=vPHa0A40e18YLzQEzKk9BrqsDQWfguIlsfrSufmW9dY,2804
97
- cornflow/models/reports.py,sha256=hZmwd2whHFQYMI2csMzIXqA3iBWhJzfHDjFkmkYBq4w,4568
98
94
  cornflow/models/role.py,sha256=dEASPw8-aLbRRkoyId2zk7lFTq1twpRPMTkwb0zEOIE,2052
99
95
  cornflow/models/user.py,sha256=podqU5Emhe52ytsUnrBcKShk_jSH_0Em0UXZEAmWgjI,8755
100
96
  cornflow/models/user_role.py,sha256=rr-0S4sV5l6xDQIwd94c3bPepDA50NdStwd3MSzRJbU,4974
@@ -106,7 +102,7 @@ cornflow/schemas/case.py,sha256=OXRsDi_sdB47MQJ59S_1eMjDmLlpUtG7kTFNInV2-cI,2909
106
102
  cornflow/schemas/common.py,sha256=QYuxWcOl4smXFZr_vL07OVgH9H50ZywCrXxycVNr1qA,473
107
103
  cornflow/schemas/dag.py,sha256=0ENA75X9L8YqjJW6ZO1Sb4zE8OxB15_O49_nwA6eAVw,901
108
104
  cornflow/schemas/example_data.py,sha256=hbE8TJakFqOweHXiA3mduNETM6FCX6xLTiQuH3EkSTc,281
109
- cornflow/schemas/execution.py,sha256=tPqRYFs7KB9-t_vffd9zlM6uIzPOoktvg4mfN3dzQy8,4853
105
+ cornflow/schemas/execution.py,sha256=GSRHzikVPlhxMdiKrGnTuGfen8_Lf4wSfheJwvcavTs,4718
110
106
  cornflow/schemas/health.py,sha256=D2NsP9i6nA1hLema-bvegrrdH4JY7pZlYxPcqRJOvao,141
111
107
  cornflow/schemas/instance.py,sha256=qr4km0AlAhoNf9G1Il-pfHphT_vAiiLDpv7A9S3FKAw,1870
112
108
  cornflow/schemas/main_alarms.py,sha256=cC1_Vb1dmo_vdZpZQrA7jH-hRCjVtLRy6Z2JFBlTrlo,604
@@ -114,7 +110,6 @@ cornflow/schemas/model_json.py,sha256=qUsdd1XmxhcsAmb1JB0xAsvucZoAeQhAQD_3wiY-rV
114
110
  cornflow/schemas/patch.py,sha256=nB6vhmscusfC8tSl4Ded0UwQIbGjGF5_Nwx0kxygKWk,260
115
111
  cornflow/schemas/permissions.py,sha256=dgHKXLDyB1-q-Ii7cuHLpovlFPthtEV3mNxRgTe42ac,1270
116
112
  cornflow/schemas/query.py,sha256=lQ6lMy0O6RRQLA-9JtQ95p70yd7vra4cGIbLrYO74GE,984
117
- cornflow/schemas/reports.py,sha256=jqsmTXZwg4ZBEozY54XvAvAPZ7T05D0OM-51WF8hiIg,1255
118
113
  cornflow/schemas/role.py,sha256=lZYoLpA0weuDiFgpk3PWrHYJdljvZ3HEIOS-ISNLcCg,469
119
114
  cornflow/schemas/schemas.py,sha256=vNyOwrchuTT3TMR9Jj07pauSr2sFTM-rfIfiKUycOjo,433
120
115
  cornflow/schemas/solution_log.py,sha256=jSutvj0-2RJIqzn7ANLFanAD4jrSDvtgqf6DF6UZBhs,2255
@@ -124,9 +119,9 @@ cornflow/schemas/user_role.py,sha256=e5y6RgdZZtLqD-h2B3sa5WokI5-pT78tWw85IG34I74
124
119
  cornflow/schemas/view.py,sha256=ctq9Y1TmjrWdyOqgDYeEx7qbbuNLKfSiNOlFTlXmpaw,429
125
120
  cornflow/shared/__init__.py,sha256=1ahcBwWOsSjGI4FEm77JBQjitBdBszOncKcEMjzwGYE,29
126
121
  cornflow/shared/compress.py,sha256=pohQaGs1xbH8CN6URIH6BAHA--pFq7Hmjz8oI3c3B5c,1347
127
- cornflow/shared/const.py,sha256=tEe41Ptw_GTsHpKu9cASn5eNIydXtcES_uDjo-4Fmmw,4005
122
+ cornflow/shared/const.py,sha256=nRZElCjbuJIpjzVlCfZjTN4mAbqDTXIyAbSMlkNL3n8,3440
128
123
  cornflow/shared/email.py,sha256=QNDDMv86LZObkevSCyUbLQeR2UD3zWScPIr82NDzYHQ,3437
129
- cornflow/shared/exceptions.py,sha256=btAKuZelxHAwkwCPJZiYeipj4VfHd2cdsYPwLjd0Zv8,7173
124
+ cornflow/shared/exceptions.py,sha256=BNbC5hzAoC9vDQ3NLM9uLqI14nwCEP1AT3UjeFghnY0,6979
130
125
  cornflow/shared/licenses.py,sha256=Lc71Jw2NxVTFWtoXdQ9wJX_o3BDfYg1xVoehDXvnCkQ,1328
131
126
  cornflow/shared/log_config.py,sha256=FM2ajjp2MB4BlFbUHklnWInT7-LLjtrqQ0mo3k_HRmE,621
132
127
  cornflow/shared/query_tools.py,sha256=6yGLCWjv-I2a_ZU4A0IymyJq67fZPZdRcCGOGQQpSXg,1199
@@ -137,46 +132,44 @@ cornflow/shared/authentication/__init__.py,sha256=cJIChk5X6hbA_16usEvfHr8g4JDFI6
137
132
  cornflow/shared/authentication/auth.py,sha256=aQ8oUq9nC3FMbCivPFr2aWQXqP_cDeP6f7ljDhTm-wM,18664
138
133
  cornflow/shared/authentication/decorators.py,sha256=_QpwOU1kYzpaK85Dl0Btdj5hG8Ps47PFgySp_gqhlgk,1276
139
134
  cornflow/shared/authentication/ldap.py,sha256=QfdC2X_ZMcIJabKC5pYWDGMhS5pIOJJvdZXuuiruq-M,4853
140
- cornflow/static/v1.json,sha256=muwt8Rq63woLy50-wIFKAcq1hTbjnz_tS0jMhhkvfFg,84586
141
135
  cornflow/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- cornflow/tests/const.py,sha256=B7Pc6LIEEogjnxXq-tBXzNRIMf0WktrdJgA4SqaVhXo,2810
143
- cornflow/tests/custom_live_server.py,sha256=BtSPT9FVtqxf2oHL1kbPnkBNJdCi0aAhnHh3TQrfQMU,3149
144
- cornflow/tests/custom_test_case.py,sha256=83WvsjxnLRB8FYpbLpz338GGLFqzZKAXoYUod1jcYNY,25144
136
+ cornflow/tests/const.py,sha256=_5BYFGN42Xg0PXMR8UU5DBL6dYmYn5rgRBgPyptrKso,2499
137
+ cornflow/tests/custom_liveServer.py,sha256=I_0YNrcKIwVmRov3zCQMWwcCWkMe5V246Hpa4gS8AZE,3079
138
+ cornflow/tests/custom_test_case.py,sha256=EeAPnI0F5_0ZAQW0_ku0NdTzYxc8se6fi1FtYNdtLTc,25147
145
139
  cornflow/tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
- cornflow/tests/integration/test_commands.py,sha256=3vLjSK3ji7LYE5ZADJzBHkXRrtxwW_uYVqxcDef749w,696
147
- cornflow/tests/integration/test_cornflowclient.py,sha256=EZ508fLfO0YC06tzw60zXq9Mxr8MrDFRWWWkzLK4xCE,23894
140
+ cornflow/tests/integration/test_commands.py,sha256=FZcoEM-05D4MBMe0L0V-0sxk_L0zMbzQxb9UCd7iBe0,695
141
+ cornflow/tests/integration/test_cornflowclient.py,sha256=ioAQmQKWW6mXVJhdF4LECZcGIOa_N0xPkFaGWGtxOO8,20963
148
142
  cornflow/tests/ldap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
143
  cornflow/tests/ldap/test_ldap_authentication.py,sha256=6Gu1WkF7MQmcV_10IJkpo2qEloZZ9zjpV18ANDD0HRw,4286
150
144
  cornflow/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
145
  cornflow/tests/unit/test_actions.py,sha256=Fg33PyzNTK4B4NjARelMxLQpQl9nE9JppolkkIY9UEo,1755
152
- cornflow/tests/unit/test_alarms.py,sha256=rzh9RBLrGWG6la5acnC1OFJ2wuEWIXbk64fH7oiu8gY,1663
146
+ cornflow/tests/unit/test_alarms.py,sha256=J4Hp2xIZqpFrojx_RvQCSU1ilDk-iC0vm2z8wZNXwIw,1343
153
147
  cornflow/tests/unit/test_apiview.py,sha256=G5DpUPaKVXgbCOaXXTCjBAeGeCtfR8niltp7B0NNB6o,2107
154
148
  cornflow/tests/unit/test_cases.py,sha256=lXLgvHbNGw8qUoCtYUwwXE_O2AWSmSXxLVlxE-hc9Oc,25974
155
- cornflow/tests/unit/test_cli.py,sha256=8x2Bnpp9gfalqxRw0iVXFf3MdPoVz088zwpN01zENLA,12893
156
- cornflow/tests/unit/test_commands.py,sha256=WTPjcbvJ_66lWtVUsYPcYFcChgO1kXnNw4hzCo3PyDc,8897
149
+ cornflow/tests/unit/test_cli.py,sha256=qYcMGAdLIOhTgWV4q0rGu0bv5Bs7JUIsyRd5qt6pcOI,12578
150
+ cornflow/tests/unit/test_commands.py,sha256=QwGHTOxBOwiIYYQg8wcmSR11lKQk0I8Ltr3sbFERufw,8776
157
151
  cornflow/tests/unit/test_dags.py,sha256=5lTJW_fgh7XXE11Zo9yVsQ7wsmbCPxCCRwna2vkPEuA,10350
158
152
  cornflow/tests/unit/test_data_checks.py,sha256=VjB3AAQOHlqnaRT2jI9L2mNLDAcda6llpiZWkW7nnkk,5471
159
153
  cornflow/tests/unit/test_example_data.py,sha256=D-Tgnqw7NZlnBXaDcUU0reNhAca5JlJP2Sdn3KdS4Sw,4127
160
- cornflow/tests/unit/test_executions.py,sha256=a6W20kd6Rk22lCnfA6uAsRr-Hhh37GHUg30G_Fa4z7k,17616
154
+ cornflow/tests/unit/test_executions.py,sha256=_hIaiZri7Blyx4DYhBDHh-0peU1HQh66RSPqQJFveE8,17501
161
155
  cornflow/tests/unit/test_generate_from_schema.py,sha256=L1EdnASbDJ8SjrX1V4WnUKKwV0sRTwVnNYnxSpyeSeQ,15376
162
156
  cornflow/tests/unit/test_health.py,sha256=0E0HXMb63_Z8drbLZdxnJwtTbQyaZS9ZEHut6qsDbh8,1033
163
157
  cornflow/tests/unit/test_instances.py,sha256=RaD9Tue2HODKThBNhciu6krdIvrauDLxOq4Y6a_z8DU,10573
164
158
  cornflow/tests/unit/test_instances_file.py,sha256=zXxSlOM_MMkFvpWNX-iatD40xoIAOGQkinCLf1txb0M,1986
165
159
  cornflow/tests/unit/test_licenses.py,sha256=jgnfE4UMFooGn44HK_KspJXIpmLjUpK_WgsBBeTO5eI,1534
166
160
  cornflow/tests/unit/test_log_in.py,sha256=zwVCNO0sGQhpVcUaJnh8cVv2z-qPEYCdI98y61CNyfE,979
167
- cornflow/tests/unit/test_main_alarms.py,sha256=kWQcsy9tBbUu5ox5cmDGgaXov8bRAY1_ru1K4h7U-4E,2300
161
+ cornflow/tests/unit/test_main_alarms.py,sha256=y--A4Ap2X38TCCRgbimzaZ-QvnTqZY8KHCv7C8kTTwc,2060
168
162
  cornflow/tests/unit/test_permissions.py,sha256=4mLj3GI0Bvhy927eXu_RyAmK8i2XD7raYc6W8lyAO04,8782
169
- cornflow/tests/unit/test_reports.py,sha256=gL_1gQMAi4tMzJtWjC8jOVy9NRjwRo3H6FBbMWn7N0Q,9805
170
163
  cornflow/tests/unit/test_roles.py,sha256=xZ3TohL_sv1ZBPvHv_nnYSsKEhBlrzIchx9soaTb5Ow,16581
171
164
  cornflow/tests/unit/test_schema_from_models.py,sha256=7IfycOGO3U06baX8I-OPJfu-3ZAn5cv8RCdj9wvalMk,4421
172
165
  cornflow/tests/unit/test_schemas.py,sha256=6SpkeYsS3oWntUZEF3GldLqmNa-hpxg-WrKJVTgc-B4,7468
173
166
  cornflow/tests/unit/test_sign_up.py,sha256=-i6VO9z1FwqRHFvaSrpWAzOZx6qa8mHUEmmsjuMXjn8,3481
174
167
  cornflow/tests/unit/test_tables.py,sha256=dY55YgaCkyqwJnqn0LbZHNeXBoL4ZxXWwKkCoTF4WVE,8947
175
168
  cornflow/tests/unit/test_token.py,sha256=OEVPgG8swSMkUbuGJGfGF5Z27utMLICn1eIyma1cM9E,3760
176
- cornflow/tests/unit/test_users.py,sha256=uxKoPqNtpiPh6JADh6kXLTmLSxNMYw44hsA3JTmo1Fw,22454
169
+ cornflow/tests/unit/test_users.py,sha256=WfaMcybPpR7rspXyvzHGgw25p751hMPAV0DOp_caSPM,22430
177
170
  cornflow/tests/unit/tools.py,sha256=ag3sWv2WLi498R1GL5AOUnXqSsszD3UugzLZLC5NqAw,585
178
- cornflow-1.1.1a1.dist-info/METADATA,sha256=ujrEhaExOsV11jZVIhl7t1qmEf9VUfkvfmkk7cYFVZw,9378
179
- cornflow-1.1.1a1.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
180
- cornflow-1.1.1a1.dist-info/entry_points.txt,sha256=r5wKLHpuyVLMUIZ5I29_tpqYf-RuP-3w_8DhFi8_blQ,47
181
- cornflow-1.1.1a1.dist-info/top_level.txt,sha256=Qj9kLFJW1PLb-ZV2s_aCkQ-Wi5W6KC6fFR-LTBrx-rU,24
182
- cornflow-1.1.1a1.dist-info/RECORD,,
171
+ cornflow-1.1.2.dist-info/METADATA,sha256=DX4tFKqUVqnDQxwKGk097ZLgwjRP4BIkovhefRLZi3A,9366
172
+ cornflow-1.1.2.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
173
+ cornflow-1.1.2.dist-info/entry_points.txt,sha256=r5wKLHpuyVLMUIZ5I29_tpqYf-RuP-3w_8DhFi8_blQ,47
174
+ cornflow-1.1.2.dist-info/top_level.txt,sha256=Qj9kLFJW1PLb-ZV2s_aCkQ-Wi5W6KC6fFR-LTBrx-rU,24
175
+ cornflow-1.1.2.dist-info/RECORD,,
@@ -1,283 +0,0 @@
1
- """
2
- External endpoints to manage the reports: create new ones, list all of them, get one in particular
3
- These endpoints have different access url, but manage the same data entities
4
- """
5
- import os
6
-
7
- from flask import current_app, request, send_from_directory
8
- from flask_apispec import marshal_with, use_kwargs, doc
9
- from werkzeug.utils import secure_filename
10
- import uuid
11
-
12
- from cornflow.endpoints.meta_resource import BaseMetaResource
13
- from cornflow.models import ExecutionModel, ReportModel
14
- from cornflow.schemas.reports import (
15
- ReportSchema,
16
- ReportEditRequest,
17
- QueryFiltersReports,
18
- ReportRequest,
19
- )
20
- from cornflow.shared.authentication import Auth, authenticate
21
- from cornflow.shared.const import SERVICE_ROLE
22
- from cornflow.shared.exceptions import (
23
- FileError,
24
- ObjectDoesNotExist,
25
- NoPermission,
26
- )
27
-
28
-
29
- class ReportEndpoint(BaseMetaResource):
30
- """
31
- Endpoint used to create a new report or get all the reports and their information back
32
- """
33
-
34
- ROLES_WITH_ACCESS = [SERVICE_ROLE]
35
-
36
- def __init__(self):
37
- super().__init__()
38
- self.model = ReportModel
39
- self.data_model = ReportModel
40
- self.foreign_data = {"execution_id": ExecutionModel}
41
-
42
- @doc(description="Get all reports", tags=["Reports"])
43
- @authenticate(auth_class=Auth())
44
- @marshal_with(ReportSchema(many=True))
45
- @use_kwargs(QueryFiltersReports, location="query")
46
- def get(self, **kwargs):
47
- """
48
- API method to get all the reports created by the user and its related info
49
- It requires authentication to be passed in the form of a token that has to be linked to
50
- an existing session (login) made by a user
51
-
52
- :return: A dictionary with a message (error if authentication failed or a list with all the reports
53
- created by the authenticated user) and a integer with the HTTP status code
54
- :rtype: Tuple(dict, integer)
55
- """
56
- reports = self.get_list(user=self.get_user(), **kwargs)
57
- current_app.logger.info(f"User {self.get_user()} gets list of reports")
58
- return reports
59
-
60
- @doc(description="Create a report", tags=["Reports"])
61
- @authenticate(auth_class=Auth())
62
- @use_kwargs(ReportRequest, location="form")
63
- @marshal_with(ReportSchema)
64
- def post(self, **kwargs):
65
- """
66
- API method to create a new report linked to an existing execution
67
- It requires authentication to be passed in the form of a token that has to be linked to
68
- an existing session (login) made by a user
69
-
70
- :return: A dictionary with a message (error if authentication failed, error if data is not validated or
71
- the reference_id for the newly created report if successful) and a integer with the HTTP status code
72
- :rtype: Tuple(dict, integer)
73
- """
74
-
75
- execution = ExecutionModel.get_one_object(idx=kwargs["execution_id"])
76
-
77
- if execution is None:
78
- raise ObjectDoesNotExist("The execution does not exist")
79
- if "file" not in request.files:
80
- # we're creating an empty report.
81
- # which is possible
82
- report = ReportModel(get_report_info(kwargs, execution, None))
83
-
84
- report.save()
85
- return report, 201
86
-
87
- file = request.files["file"]
88
- report_name = new_file_name(file)
89
-
90
- report = ReportModel(get_report_info(kwargs, execution, report_name))
91
-
92
- report.save()
93
-
94
- # We try to save the file, if an error is raised then we delete the record on the database
95
- try:
96
- write_file(file, execution.id, report_name)
97
- return report, 201
98
-
99
- except Exception as error:
100
- report.delete()
101
- current_app.logger.error(error)
102
- raise FileError(error=str(error))
103
-
104
-
105
- class ReportDetailsEndpointBase(BaseMetaResource):
106
- """
107
- Endpoint used to get the information of a certain report. But not the data!
108
- """
109
-
110
- def __init__(self):
111
- super().__init__()
112
- self.data_model = ReportModel
113
- self.foreign_data = {"execution_id": ExecutionModel}
114
-
115
-
116
- class ReportDetailsEditEndpoint(ReportDetailsEndpointBase):
117
-
118
- ROLES_WITH_ACCESS = [SERVICE_ROLE]
119
-
120
- @doc(description="Edit a report", tags=["Reports"], inherit=False)
121
- @authenticate(auth_class=Auth())
122
- @use_kwargs(ReportEditRequest, location="form")
123
- def put(self, idx, **data):
124
- """
125
- Edit an existing report
126
-
127
- :param string idx: ID of the report.
128
- :return: A dictionary with a message (error if authentication failed, or the report does not exist or
129
- a message) and an integer with the HTTP status code.
130
- :rtype: Tuple(dict, integer)
131
- """
132
- # TODO: forbid non-service users from running put
133
- current_app.logger.info(f"User {self.get_user()} edits report {idx}")
134
-
135
- report = self.get_detail(idx=idx)
136
-
137
- if "file" not in request.files:
138
- # we're creating an empty report.
139
- # which is possible
140
- report.update(data)
141
- report.save()
142
- return {"message": "Updated correctly"}, 200
143
-
144
- # there's two cases,
145
- # (1) the report already has a file
146
- # (2) the report doesn't yet have a file
147
- file = request.files["file"]
148
- report_name = new_file_name(file)
149
- old_name = report.file_url
150
- # we update the report with the new content, including the new name
151
- report.update(dict(**data, file_url=report_name))
152
-
153
- # We try to save the file, if an error is raised then we delete the record on the database
154
- try:
155
- write_file(file, report.execution_id, report_name)
156
- report.save()
157
-
158
- except Exception as error:
159
- # we do not save the report
160
- current_app.logger.error(error)
161
- raise FileError(error=str(error))
162
-
163
- # if it saves correctly, we delete the old file, if exists
164
- # if unsuccessful, we still return 201 but log the error
165
- if old_name is not None:
166
- try:
167
- os.remove(get_report_path(report))
168
- except OSError as error:
169
- current_app.logger.error(error)
170
- return {"message": "Updated correctly"}, 200
171
-
172
-
173
- class ReportDetailsEndpoint(ReportDetailsEndpointBase):
174
- @doc(description="Get details of a report", tags=["Reports"], inherit=False)
175
- @authenticate(auth_class=Auth())
176
- @marshal_with(ReportSchema)
177
- @BaseMetaResource.get_data_or_404
178
- def get(self, idx):
179
- """
180
- API method to get a report created by the user and its related info.
181
- It requires authentication to be passed in the form of a token that has to be linked to
182
- an existing session (login) made by a user.
183
-
184
- :param str idx: ID of the report.
185
- :return: A dictionary with a message (error if authentication failed, or the report does not exist or
186
- the data of the report) and an integer with the HTTP status code.
187
- :rtype: Tuple(dict, integer)
188
- """
189
- # TODO: are we able to download the name in the database and not as part of the file?
190
- current_app.logger.info(f"User {self.get_user()} gets details of report {idx}")
191
- report = self.get_detail(user=self.get_user(), idx=idx)
192
-
193
- if report is None:
194
- raise ObjectDoesNotExist
195
-
196
- # if there's no file, we do not return it:
197
- if report.file_url is None:
198
- return report, 200
199
-
200
- my_dir = get_report_dir(report.execution_id)
201
- response = send_from_directory(my_dir, report.file_url)
202
- response.headers["File-Description"] = report.description
203
- response.headers["File-Name"] = report.file_url
204
- return response
205
-
206
- @doc(description="Delete a report", tags=["Reports"], inherit=False)
207
- @authenticate(auth_class=Auth())
208
- def delete(self, idx):
209
- """
210
- API method to delete a report created by the user and its related info.
211
- It requires authentication to be passed in the form of a token that has to be linked to
212
- an existing session (login) made by a user.
213
-
214
- :param string idx: ID of the report.
215
- :return: A dictionary with a message (error if authentication failed, or the report does not exist or
216
- a message) and an integer with the HTTP status code.
217
- :rtype: Tuple(dict, integer)
218
- """
219
-
220
- # get report objet
221
- report = self.get_detail(user_id=self.get_user_id(), idx=idx)
222
-
223
- if report is None:
224
- raise ObjectDoesNotExist
225
-
226
- # delete file
227
- os.remove(get_report_path(report))
228
-
229
- return self.delete_detail(user_id=self.get_user_id(), idx=idx)
230
-
231
-
232
- def get_report_dir(execution_id):
233
- return f"{current_app.config['UPLOAD_FOLDER']}/{execution_id}"
234
-
235
-
236
- def get_report_path(report):
237
- try:
238
- return f"{get_report_dir(report['execution_id'])}/{report['file_url']}"
239
- except:
240
- return f"{get_report_dir(report.execution_id)}/{report.file_url}"
241
-
242
-
243
- def new_file_name(file):
244
-
245
- filename = secure_filename(file.filename)
246
- filename_extension = filename.split(".")[-1]
247
-
248
- if filename_extension not in current_app.config["ALLOWED_EXTENSIONS"]:
249
- return {
250
- "message": f"Invalid file extension. "
251
- f"Valid extensions are: {current_app.config['ALLOWED_EXTENSIONS']}"
252
- }, 400
253
-
254
- report_name = f"{uuid.uuid4().hex}.{filename_extension}"
255
-
256
- return report_name
257
-
258
-
259
- def write_file(file, execution_id, file_name):
260
- my_directory = get_report_dir(execution_id)
261
-
262
- # we create a directory for the execution
263
- if not os.path.exists(my_directory):
264
- current_app.logger.info(f"Creating directory {my_directory}")
265
- os.mkdir(my_directory)
266
-
267
- save_path = os.path.normpath(os.path.join(my_directory, file_name))
268
-
269
- if "static" not in save_path or ".." in save_path:
270
- raise NoPermission("Invalid file name")
271
- file.save(save_path)
272
-
273
-
274
- def get_report_info(data, execution, file_url=None):
275
- return {
276
- "name": data["name"],
277
- "file_url": file_url,
278
- "execution_id": execution.id,
279
- "user_id": execution.user_id,
280
- "description": data.get("description", ""),
281
- "state": data.get("state"),
282
- "state_message": data.get("state_message"),
283
- }
@@ -1,40 +0,0 @@
1
- """empty message
2
-
3
- Revision ID: 83164be03c23
4
- Revises: 96f00d0961d1
5
- Create Date: 2024-07-23 13:18:47.748324
6
-
7
- """
8
- from alembic import op
9
- import sqlalchemy as sa
10
-
11
-
12
- # revision identifiers, used by Alembic.
13
- revision = '83164be03c23'
14
- down_revision = '96f00d0961d1'
15
- branch_labels = None
16
- depends_on = None
17
-
18
-
19
- def upgrade():
20
- # ### commands auto generated by Alembic - please adjust! ###
21
- with op.batch_alter_table('reports', schema=None) as batch_op:
22
- batch_op.add_column(sa.Column('state', sa.SmallInteger(), nullable=True))
23
- batch_op.add_column(sa.Column('state_message', sa.TEXT(), nullable=True))
24
- batch_op.alter_column('file_url',
25
- existing_type=sa.VARCHAR(length=256),
26
- nullable=True)
27
-
28
- # ### end Alembic commands ###
29
-
30
-
31
- def downgrade():
32
- # ### commands auto generated by Alembic - please adjust! ###
33
- with op.batch_alter_table('reports', schema=None) as batch_op:
34
- batch_op.alter_column('file_url',
35
- existing_type=sa.VARCHAR(length=256),
36
- nullable=False)
37
- batch_op.drop_column('state_message')
38
- batch_op.drop_column('state')
39
-
40
- # ### end Alembic commands ###
@@ -1,50 +0,0 @@
1
- """
2
- Adds reports table to database
3
-
4
- Revision ID: 96f00d0961d1
5
- Revises: 991b98e24225
6
- Create Date: 2024-06-12 18:47:06.366487
7
-
8
- """
9
-
10
- from alembic import op
11
- import sqlalchemy as sa
12
-
13
-
14
- # revision identifiers, used by Alembic.
15
- revision = "96f00d0961d1"
16
- down_revision = "991b98e24225"
17
- branch_labels = None
18
- depends_on = None
19
-
20
-
21
- def upgrade():
22
- # ### commands auto generated by Alembic - please adjust! ###
23
- op.create_table(
24
- "reports",
25
- sa.Column("created_at", sa.DateTime(), nullable=False),
26
- sa.Column("updated_at", sa.DateTime(), nullable=False),
27
- sa.Column("deleted_at", sa.DateTime(), nullable=True),
28
- sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
29
- sa.Column("execution_id", sa.String(length=256), nullable=False),
30
- sa.Column("name", sa.String(length=256), nullable=False),
31
- sa.Column("description", sa.TEXT(), nullable=True),
32
- sa.Column("file_url", sa.String(length=256), nullable=False),
33
- sa.Column("user_id", sa.Integer(), nullable=False),
34
- sa.ForeignKeyConstraint(
35
- ["execution_id"],
36
- ["executions.id"],
37
- ),
38
- sa.ForeignKeyConstraint(
39
- ["user_id"],
40
- ["users.id"],
41
- ),
42
- sa.PrimaryKeyConstraint("id"),
43
- )
44
- # ### end Alembic commands ###
45
-
46
-
47
- def downgrade():
48
- # ### commands auto generated by Alembic - please adjust! ###
49
- op.drop_table("reports")
50
- # ### end Alembic commands ###
@@ -1,119 +0,0 @@
1
- """
2
- Model for the reports
3
- """
4
-
5
- # Import from libraries
6
- from sqlalchemy.dialects.postgresql import TEXT
7
- from sqlalchemy.ext.declarative import declared_attr
8
-
9
- # Imports from internal modules
10
- from cornflow.models.base_data_model import TraceAttributesModel
11
- from cornflow.shared import db
12
- from cornflow.shared.const import REPORT_STATE, REPORT_STATE_MSG
13
-
14
-
15
- class ReportModel(TraceAttributesModel):
16
- """
17
- Model class for the Reports.
18
- It inherits from :class:`TraceAttributesModel<cornflow.models.base_data_model.TraceAttributesModel>` to have the trace fields and user field.
19
-
20
- - **id**: int, the report id, primary key for the reports.
21
- - **execution_id**: str, the foreign key for the execution (:class:`ExecutionModel`). It links the report to its
22
- parent execution.
23
- - **file_url**: str, the link with the actual report. It should be a valid url to a cloud storage bucket or a file.
24
- - **name**: str, the name of the report given by the user.
25
- - **description**: str, the description of the report given by the user. It is optional.
26
- - **user_id**: int, the foreign key for the user (:class:`UserModel`). It links the report to its owner.
27
- - **created_at**: datetime, the datetime when the report was created (in UTC).
28
- This datetime is generated automatically, the user does not need to provide it.
29
- - **updated_at**: datetime, the datetime when the report was last updated (in UTC).
30
- This datetime is generated automatically, the user does not need to provide it.
31
- - **deleted_at**: datetime, the datetime when the report was deleted (in UTC). Even though it is deleted,
32
- actually, it is not deleted from the database, in order to have a command that cleans up deleted data
33
- after a certain time of its deletion.
34
- This datetime is generated automatically, the user does not need to provide it.
35
-
36
- """
37
-
38
- # Table name in the database
39
- __tablename__ = "reports"
40
-
41
- # Model fields
42
- id = db.Column(db.Integer, primary_key=True, autoincrement=True)
43
- execution_id = db.Column(
44
- db.String(256), db.ForeignKey("executions.id"), nullable=False
45
- )
46
- name = db.Column(db.String(256), nullable=False)
47
- description = db.Column(TEXT, nullable=True)
48
- file_url = db.Column(db.String(256), nullable=True)
49
- state = db.Column(db.SmallInteger, default=REPORT_STATE.CORRECT)
50
- state_message = db.Column(TEXT, default=REPORT_STATE_MSG[REPORT_STATE.CORRECT])
51
-
52
- @declared_attr
53
- def user_id(self):
54
- """
55
- The foreign key for the user (:class:`UserModel<cornflow.models.UserModel>`).
56
- """
57
- return db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
58
-
59
- @declared_attr
60
- def user(self):
61
- return db.relationship("UserModel")
62
-
63
- def __init__(self, data: dict):
64
- super().__init__()
65
- self.user_id = data.get("user_id")
66
- self.execution_id = data.get("execution_id")
67
- self.name = data.get("name")
68
- self.description = data.get("description")
69
- self.file_url = data.get("file_url")
70
- self.state = data.get("state")
71
- if self.state is None:
72
- if self.file_url is None:
73
- self.state = REPORT_STATE.UNKNOWN
74
- else:
75
- self.state = REPORT_STATE.CORRECT
76
- self.state_message = data.get("state_message")
77
- if self.state_message is None:
78
- self.state_message = REPORT_STATE_MSG.get(self.state)
79
-
80
- def update(self, data):
81
- """
82
- Method used to update a report from the database
83
-
84
- :param dict data: the data of the object
85
- :return: None
86
- :rtype: None
87
- """
88
- # we try to keep the state_message synced, by default
89
- if "state" in data and "state_message" not in data:
90
- data["state_message"] = REPORT_STATE_MSG[data["state"]]
91
- super().update(data)
92
-
93
- def update_link(self, file_url: str):
94
- """
95
- Method to update the report link
96
-
97
- :param str file_url: new URL for the report
98
- :return: nothing
99
- """
100
- self.file_url = file_url
101
- super().update({})
102
-
103
- def __repr__(self):
104
- """
105
- Method to represent the class :class:`ReportModel`
106
-
107
- :return: The representation of the :class:`ReportModel`
108
- :rtype: str
109
- """
110
- return f"<Report {self.id}>"
111
-
112
- def __str__(self):
113
- """
114
- Method to print a string representation of the :class:`ReportModel`
115
-
116
- :return: The string for the :class:`ReportModel`
117
- :rtype: str
118
- """
119
- return self.__repr__()