recce-nightly 1.2.0.20250506__py3-none-any.whl → 1.4.0.20250514__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.

Potentially problematic release.


This version of recce-nightly might be problematic. Click here for more details.

Files changed (93) hide show
  1. recce/VERSION +1 -1
  2. recce/__init__.py +22 -22
  3. recce/adapter/base.py +11 -14
  4. recce/adapter/dbt_adapter/__init__.py +355 -316
  5. recce/adapter/dbt_adapter/dbt_version.py +3 -0
  6. recce/adapter/sqlmesh_adapter.py +24 -35
  7. recce/apis/check_api.py +39 -28
  8. recce/apis/check_func.py +33 -27
  9. recce/apis/run_api.py +25 -19
  10. recce/apis/run_func.py +29 -23
  11. recce/artifact.py +44 -49
  12. recce/cli.py +484 -285
  13. recce/config.py +42 -33
  14. recce/core.py +52 -44
  15. recce/data/404.html +1 -1
  16. recce/data/_next/static/chunks/{368-7587b306577df275.js → 778-aef312bffb4c0312.js} +15 -15
  17. recce/data/_next/static/chunks/8d700b6a.ed11a130057c7a47.js +1 -0
  18. recce/data/_next/static/chunks/app/layout-c713a2829d3279e4.js +1 -0
  19. recce/data/_next/static/chunks/app/page-7086764277331fcb.js +1 -0
  20. recce/data/_next/static/chunks/{cd9f8d63-cf0d5a7b0f7a92e8.js → cd9f8d63-e020f408095ed77c.js} +3 -3
  21. recce/data/_next/static/chunks/webpack-b787cb1a4f2293de.js +1 -0
  22. recce/data/_next/static/css/88b8abc134cfd59a.css +3 -0
  23. recce/data/index.html +2 -2
  24. recce/data/index.txt +2 -2
  25. recce/diff.py +6 -12
  26. recce/event/__init__.py +74 -72
  27. recce/event/collector.py +27 -20
  28. recce/event/track.py +39 -27
  29. recce/exceptions.py +1 -1
  30. recce/git.py +7 -7
  31. recce/github.py +57 -53
  32. recce/models/__init__.py +1 -1
  33. recce/models/check.py +6 -7
  34. recce/models/run.py +1 -0
  35. recce/models/types.py +27 -27
  36. recce/pull_request.py +26 -24
  37. recce/run.py +148 -111
  38. recce/server.py +105 -88
  39. recce/state.py +209 -177
  40. recce/summary.py +168 -143
  41. recce/tasks/__init__.py +3 -3
  42. recce/tasks/core.py +11 -13
  43. recce/tasks/dataframe.py +19 -17
  44. recce/tasks/histogram.py +69 -34
  45. recce/tasks/lineage.py +2 -2
  46. recce/tasks/profile.py +152 -86
  47. recce/tasks/query.py +139 -87
  48. recce/tasks/rowcount.py +33 -30
  49. recce/tasks/schema.py +14 -14
  50. recce/tasks/top_k.py +35 -35
  51. recce/tasks/valuediff.py +216 -152
  52. recce/util/breaking.py +77 -84
  53. recce/util/cll.py +55 -51
  54. recce/util/io.py +19 -17
  55. recce/util/logger.py +1 -1
  56. recce/util/recce_cloud.py +70 -72
  57. recce/util/singleton.py +4 -4
  58. recce/yaml/__init__.py +7 -10
  59. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.4.0.20250514.dist-info}/METADATA +5 -2
  60. recce_nightly-1.4.0.20250514.dist-info/RECORD +143 -0
  61. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.4.0.20250514.dist-info}/WHEEL +1 -1
  62. tests/adapter/dbt_adapter/conftest.py +1 -0
  63. tests/adapter/dbt_adapter/dbt_test_helper.py +28 -18
  64. tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -15
  65. tests/adapter/dbt_adapter/test_dbt_cll.py +39 -32
  66. tests/adapter/dbt_adapter/test_selector.py +22 -21
  67. tests/tasks/test_histogram.py +58 -66
  68. tests/tasks/test_lineage.py +36 -23
  69. tests/tasks/test_preset_checks.py +45 -31
  70. tests/tasks/test_profile.py +340 -15
  71. tests/tasks/test_query.py +40 -40
  72. tests/tasks/test_row_count.py +65 -46
  73. tests/tasks/test_schema.py +65 -42
  74. tests/tasks/test_top_k.py +22 -18
  75. tests/tasks/test_valuediff.py +43 -32
  76. tests/test_cli.py +71 -58
  77. tests/test_config.py +7 -9
  78. tests/test_core.py +5 -3
  79. tests/test_dbt.py +7 -7
  80. tests/test_pull_request.py +1 -1
  81. tests/test_server.py +19 -13
  82. tests/test_state.py +40 -27
  83. tests/test_summary.py +18 -14
  84. recce/data/_next/static/chunks/8d700b6a-f0b1f6b9e0d97ce2.js +0 -1
  85. recce/data/_next/static/chunks/app/layout-9102e22cb73f74d6.js +0 -1
  86. recce/data/_next/static/chunks/app/page-cee661090afbd6aa.js +0 -1
  87. recce/data/_next/static/chunks/webpack-567d72f0bc0820d5.js +0 -1
  88. recce_nightly-1.2.0.20250506.dist-info/RECORD +0 -142
  89. /recce/data/_next/static/{Kcbs3GEIyH2LxgLYat0es → E_HPXsXdrqHg2YEHmU3mK}/_buildManifest.js +0 -0
  90. /recce/data/_next/static/{Kcbs3GEIyH2LxgLYat0es → E_HPXsXdrqHg2YEHmU3mK}/_ssgManifest.js +0 -0
  91. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.4.0.20250514.dist-info}/entry_points.txt +0 -0
  92. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.4.0.20250514.dist-info}/licenses/LICENSE +0 -0
  93. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.4.0.20250514.dist-info}/top_level.txt +0 -0
@@ -17,21 +17,21 @@ def test_row_count(dbt_test_helper):
17
17
  2,Bob,25
18
18
  """
19
19
 
20
- dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr, unique_id='model.customers')
21
- task = RowCountDiffTask(dict(node_names=['customers']))
20
+ dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr, unique_id="model.customers")
21
+ task = RowCountDiffTask(dict(node_names=["customers"]))
22
22
  run_result = task.execute()
23
- assert run_result['customers']['base'] == 2
24
- assert run_result['customers']['curr'] == 3
23
+ assert run_result["customers"]["base"] == 2
24
+ assert run_result["customers"]["curr"] == 3
25
25
 
26
- task = RowCountDiffTask(dict(node_names=['customers_']))
26
+ task = RowCountDiffTask(dict(node_names=["customers_"]))
27
27
  run_result = task.execute()
28
- assert run_result['customers_']['base'] is None
29
- assert run_result['customers_']['curr'] is None
28
+ assert run_result["customers_"]["base"] is None
29
+ assert run_result["customers_"]["curr"] is None
30
30
 
31
- task = RowCountDiffTask(dict(node_ids=['model.customers']))
31
+ task = RowCountDiffTask(dict(node_ids=["model.customers"]))
32
32
  run_result = task.execute()
33
- assert run_result['customers']['base'] == 2
34
- assert run_result['customers']['curr'] == 3
33
+ assert run_result["customers"]["base"] == 2
34
+ assert run_result["customers"]["curr"] == 3
35
35
 
36
36
 
37
37
  def test_row_count_with_selector(dbt_test_helper):
@@ -49,13 +49,14 @@ def test_row_count_with_selector(dbt_test_helper):
49
49
  """
50
50
 
51
51
  dbt_test_helper.create_model("model_1", csv_data_1, csv_data_2, depends_on=[])
52
- dbt_test_helper.create_model("model_2", csv_data_1, csv_data_1, depends_on=['model_1'],
53
- package_name='other_package')
54
- task = RowCountDiffTask(dict(select='model_1'))
52
+ dbt_test_helper.create_model(
53
+ "model_2", csv_data_1, csv_data_1, depends_on=["model_1"], package_name="other_package"
54
+ )
55
+ task = RowCountDiffTask(dict(select="model_1"))
55
56
  run_result = task.execute()
56
57
  assert len(run_result) == 1
57
58
 
58
- task = RowCountDiffTask(dict(select='model_1+'))
59
+ task = RowCountDiffTask(dict(select="model_1+"))
59
60
  run_result = task.execute()
60
61
  assert len(run_result) == 2
61
62
 
@@ -66,51 +67,69 @@ def test_validator():
66
67
  validator = RowCountDiffCheckValidator()
67
68
 
68
69
  def validate(params: dict):
69
- validator.validate({
70
- 'name': 'test',
71
- 'type': 'row_count_diff',
72
- 'params': params,
73
- })
70
+ validator.validate(
71
+ {
72
+ "name": "test",
73
+ "type": "row_count_diff",
74
+ "params": params,
75
+ }
76
+ )
74
77
 
75
78
  # Select all modesl
76
79
  validate({})
77
80
 
78
81
  # Select by node name
79
- validate({
80
- 'node_names': ['abc'],
81
- })
82
+ validate(
83
+ {
84
+ "node_names": ["abc"],
85
+ }
86
+ )
82
87
  with pytest.raises(ValueError):
83
- validate({
84
- 'node_names': 'abc',
85
- })
88
+ validate(
89
+ {
90
+ "node_names": "abc",
91
+ }
92
+ )
86
93
 
87
94
  # Select by node id
88
- validate({
89
- 'node_ids': ['model.abc'],
90
- })
95
+ validate(
96
+ {
97
+ "node_ids": ["model.abc"],
98
+ }
99
+ )
91
100
 
92
101
  # Select by selector
93
- validate({
94
- 'select': 'customers',
95
- 'exclude': 'customers',
96
- 'packages': ['jaffle_shop'],
97
- 'view_mode': 'all',
98
- })
102
+ validate(
103
+ {
104
+ "select": "customers",
105
+ "exclude": "customers",
106
+ "packages": ["jaffle_shop"],
107
+ "view_mode": "all",
108
+ }
109
+ )
99
110
 
100
111
  # packages should be an array
101
112
  with pytest.raises(ValueError):
102
- validate({
103
- 'packages': 'jaffle_shop',
104
- })
113
+ validate(
114
+ {
115
+ "packages": "jaffle_shop",
116
+ }
117
+ )
105
118
 
106
119
  # view_mode should be 'all' or 'changed_models'
107
- validate({
108
- 'view_mode': None,
109
- })
110
- validate({
111
- 'view_mode': 'all',
112
- })
120
+ validate(
121
+ {
122
+ "view_mode": None,
123
+ }
124
+ )
125
+ validate(
126
+ {
127
+ "view_mode": "all",
128
+ }
129
+ )
113
130
  with pytest.raises(ValueError):
114
- validate({
115
- 'view_mode': 'abc',
116
- })
131
+ validate(
132
+ {
133
+ "view_mode": "abc",
134
+ }
135
+ )
@@ -4,58 +4,75 @@ from unittest.mock import MagicMock
4
4
 
5
5
  import pytest
6
6
 
7
- from recce.adapter.dbt_adapter import load_manifest, load_catalog, DbtAdapter
7
+ from recce.adapter.dbt_adapter import DbtAdapter, load_catalog, load_manifest
8
8
  from recce.core import RecceContext, set_default_context
9
9
  from recce.run import schema_diff_should_be_approved
10
10
 
11
11
 
12
12
  def test_validator():
13
13
  from recce.tasks.schema import SchemaDiffCheckValidator
14
+
14
15
  validator = SchemaDiffCheckValidator()
15
16
 
16
17
  def validate(params: dict):
17
- validator.validate({
18
- 'name': 'test',
19
- 'type': 'schema_diff',
20
- 'params': params,
21
- })
18
+ validator.validate(
19
+ {
20
+ "name": "test",
21
+ "type": "schema_diff",
22
+ "params": params,
23
+ }
24
+ )
22
25
 
23
26
  # Select all models
24
27
  validate({})
25
28
 
26
29
  # Select by node name
27
- validate({
28
- 'node_id': 'abc',
29
- })
30
- validate({
31
- 'node_id': ['abc'],
32
- })
30
+ validate(
31
+ {
32
+ "node_id": "abc",
33
+ }
34
+ )
35
+ validate(
36
+ {
37
+ "node_id": ["abc"],
38
+ }
39
+ )
33
40
 
34
41
  # Select by selector
35
- validate({
36
- 'select': 'customers',
37
- 'exclude': 'customers',
38
- 'packages': ['jaffle_shop'],
39
- 'view_mode': 'all',
40
- })
42
+ validate(
43
+ {
44
+ "select": "customers",
45
+ "exclude": "customers",
46
+ "packages": ["jaffle_shop"],
47
+ "view_mode": "all",
48
+ }
49
+ )
41
50
 
42
51
  # packages should be an array
43
52
  with pytest.raises(ValueError):
44
- validate({
45
- 'packages': 'jaffle_shop',
46
- })
53
+ validate(
54
+ {
55
+ "packages": "jaffle_shop",
56
+ }
57
+ )
47
58
 
48
59
  # view_mode should be 'all' or 'changed_models'
49
- validate({
50
- 'view_mode': None,
51
- })
52
- validate({
53
- 'view_mode': 'all',
54
- })
60
+ validate(
61
+ {
62
+ "view_mode": None,
63
+ }
64
+ )
65
+ validate(
66
+ {
67
+ "view_mode": "all",
68
+ }
69
+ )
55
70
  with pytest.raises(ValueError):
56
- validate({
57
- 'view_mode': 'abc',
58
- })
71
+ validate(
72
+ {
73
+ "view_mode": "abc",
74
+ }
75
+ )
59
76
 
60
77
 
61
78
  test_root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -65,8 +82,8 @@ class TestSchemaDiffAutoApprove(TestCase):
65
82
 
66
83
  def setUp(self):
67
84
  self.default_context = MagicMock(spec=RecceContext)
68
- manifest = load_manifest(path=os.path.join(test_root_path, 'manifest.json'))
69
- catalog = load_catalog(path=os.path.join(test_root_path, 'catalog.json'))
85
+ manifest = load_manifest(path=os.path.join(test_root_path, "manifest.json"))
86
+ catalog = load_catalog(path=os.path.join(test_root_path, "catalog.json"))
70
87
  dbt_adapter = DbtAdapter(curr_manifest=manifest, curr_catalog=catalog)
71
88
  self.default_context.adapter = dbt_adapter
72
89
 
@@ -80,20 +97,26 @@ class TestSchemaDiffAutoApprove(TestCase):
80
97
 
81
98
  def test_schema_diff_should_be_approved(self):
82
99
  # Node_id is string
83
- is_approved = schema_diff_should_be_approved({
84
- 'node_id': 'model.jaffle_shop.customers',
85
- })
100
+ is_approved = schema_diff_should_be_approved(
101
+ {
102
+ "node_id": "model.jaffle_shop.customers",
103
+ }
104
+ )
86
105
  assert is_approved is True
87
106
 
88
107
  # Node_id is list
89
- is_approved = schema_diff_should_be_approved({
90
- 'node_id': ['model.jaffle_shop.customers'],
91
- })
108
+ is_approved = schema_diff_should_be_approved(
109
+ {
110
+ "node_id": ["model.jaffle_shop.customers"],
111
+ }
112
+ )
92
113
  assert is_approved is True
93
114
 
94
115
  # Select all models
95
- self.default_context.adapter.select_nodes.return_value = ['model.jaffle_shop.customers']
96
- is_approved = schema_diff_should_be_approved({
97
- 'select': 'customers',
98
- })
116
+ self.default_context.adapter.select_nodes.return_value = ["model.jaffle_shop.customers"]
117
+ is_approved = schema_diff_should_be_approved(
118
+ {
119
+ "select": "customers",
120
+ }
121
+ )
99
122
  assert is_approved is True
tests/tasks/test_top_k.py CHANGED
@@ -38,10 +38,10 @@ def test_top_k(dbt_test_helper):
38
38
  # 'valids': 4,
39
39
  # 'total': 4
40
40
  # }
41
- assert run_result['current']['values'][0] == 'Bob'
42
- assert run_result['current']['counts'][0] == 2
43
- assert run_result['current']['valids'] == 4
44
- assert run_result['current']['total'] == 4
41
+ assert run_result["current"]["values"][0] == "Bob"
42
+ assert run_result["current"]["counts"][0] == 2
43
+ assert run_result["current"]["valids"] == 4
44
+ assert run_result["current"]["total"] == 4
45
45
 
46
46
  # {
47
47
  # 'values': ['Bob', 'Alice', 'Charlie'],
@@ -49,25 +49,29 @@ def test_top_k(dbt_test_helper):
49
49
  # 'valids': 3,
50
50
  # 'total': 4
51
51
  # }
52
- assert run_result['base']['counts'][0] == 1
53
- assert run_result['base']['valids'] == 3
54
- assert run_result['base']['total'] == 4
52
+ assert run_result["base"]["counts"][0] == 1
53
+ assert run_result["base"]["valids"] == 3
54
+ assert run_result["base"]["total"] == 4
55
55
 
56
56
 
57
57
  def test_validator():
58
58
  def validate(params: dict = {}, view_options: dict = {}):
59
- TopKDiffCheckValidator().validate({
60
- 'name': 'test',
61
- 'type': 'top_k_diff',
62
- 'params': params,
63
- 'view_options': view_options,
64
- })
59
+ TopKDiffCheckValidator().validate(
60
+ {
61
+ "name": "test",
62
+ "type": "top_k_diff",
63
+ "params": params,
64
+ "view_options": view_options,
65
+ }
66
+ )
65
67
 
66
- validate({
67
- "model": "customers",
68
- "column_name": "name",
69
- "k": 50,
70
- })
68
+ validate(
69
+ {
70
+ "model": "customers",
71
+ "column_name": "name",
72
+ "k": 50,
73
+ }
74
+ )
71
75
 
72
76
  with pytest.raises(ValueError):
73
77
  validate({})
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
 
3
- from recce.tasks import ValueDiffTask, ValueDiffDetailTask
3
+ from recce.tasks import ValueDiffDetailTask, ValueDiffTask
4
4
 
5
5
 
6
6
  def test_value_diff(dbt_test_helper):
@@ -19,13 +19,13 @@ def test_value_diff(dbt_test_helper):
19
19
  """
20
20
 
21
21
  dbt_test_helper.create_model("customers", csv_data_base, csv_data_curr)
22
- params = dict(model='customers', primary_key=['customer_id'])
22
+ params = dict(model="customers", primary_key=["customer_id"])
23
23
  task = ValueDiffTask(params)
24
24
  run_result = task.execute()
25
25
  assert len(run_result.data.columns) == 3
26
26
  assert len(run_result.data.data) == 3
27
27
 
28
- params = dict(model='customers', primary_key=['customer_id'])
28
+ params = dict(model="customers", primary_key=["customer_id"])
29
29
  task = ValueDiffDetailTask(params)
30
30
  run_result = task.execute()
31
31
  assert len(run_result.columns) == 5
@@ -36,39 +36,50 @@ def test_validator():
36
36
  from recce.tasks.valuediff import ValueDiffCheckValidator
37
37
 
38
38
  def validate(params: dict = {}, view_options: dict = {}):
39
- ValueDiffCheckValidator().validate({
40
- 'name': 'test',
41
- 'type': 'value_diff',
42
- 'params': params,
43
- 'view_options': view_options,
44
- })
39
+ ValueDiffCheckValidator().validate(
40
+ {
41
+ "name": "test",
42
+ "type": "value_diff",
43
+ "params": params,
44
+ "view_options": view_options,
45
+ }
46
+ )
45
47
 
46
- validate({
47
- 'model': 'customers',
48
- 'primary_key': 'customer_id',
49
- })
50
- validate({
51
- 'model': 'customers',
52
- 'primary_key': ['customer_id'],
53
- })
54
- validate({
55
- 'model': 'customers',
56
- 'primary_key': ['customer_id'],
57
- 'columns': ['name', 'age'],
58
- })
48
+ validate(
49
+ {
50
+ "model": "customers",
51
+ "primary_key": "customer_id",
52
+ }
53
+ )
54
+ validate(
55
+ {
56
+ "model": "customers",
57
+ "primary_key": ["customer_id"],
58
+ }
59
+ )
60
+ validate(
61
+ {
62
+ "model": "customers",
63
+ "primary_key": ["customer_id"],
64
+ "columns": ["name", "age"],
65
+ }
66
+ )
59
67
 
60
68
  with pytest.raises(ValueError):
61
- validate({
62
- })
69
+ validate({})
63
70
 
64
71
  with pytest.raises(ValueError):
65
- validate({
66
- 'model': 'customers',
67
- })
72
+ validate(
73
+ {
74
+ "model": "customers",
75
+ }
76
+ )
68
77
 
69
78
  with pytest.raises(ValueError):
70
- validate({
71
- 'model': 'customers',
72
- 'primary_key': ['customer_id'],
73
- 'columns': 'name',
74
- })
79
+ validate(
80
+ {
81
+ "model": "customers",
82
+ "primary_key": ["customer_id"],
83
+ "columns": "name",
84
+ }
85
+ )
tests/test_cli.py CHANGED
@@ -1,20 +1,22 @@
1
1
  from unittest import TestCase
2
- from unittest.mock import patch, MagicMock
2
+ from unittest.mock import MagicMock, patch
3
3
 
4
4
  from click.testing import CliRunner
5
5
 
6
- from recce.cli import server as cli_command_server, run as cli_command_run
6
+ from recce.cli import run as cli_command_run
7
+ from recce.cli import server as cli_command_server
7
8
  from recce.core import RecceContext
8
9
  from recce.state import RecceStateLoader
9
10
 
10
11
 
11
12
  def test_cmd_version():
12
- from recce.cli import version
13
13
  from recce import __version__
14
+ from recce.cli import version
15
+
14
16
  runner = CliRunner()
15
17
  result = runner.invoke(version, [])
16
18
  assert result.exit_code == 0
17
- assert result.output.replace('\n', '') == __version__
19
+ assert result.output.replace("\n", "") == __version__
18
20
 
19
21
 
20
22
  class TestCommandServer(TestCase):
@@ -22,90 +24,101 @@ class TestCommandServer(TestCase):
22
24
  self.runner = CliRunner()
23
25
  pass
24
26
 
25
- @patch.object(RecceContext, 'verify_required_artifacts')
26
- @patch('recce.cli.uvicorn.run')
27
+ @patch.object(RecceContext, "verify_required_artifacts")
28
+ @patch("recce.cli.uvicorn.run")
27
29
  def test_cmd_server(self, mock_run, mock_verify_required_artifacts):
28
30
  from recce.server import app
31
+
29
32
  mock_verify_required_artifacts.return_value = True, None
30
- self.runner.invoke(cli_command_server, ['--host', 'unittest', '--port', 5566])
31
- mock_run.assert_called_once_with(app, host='unittest', port=5566, lifespan='on')
33
+ self.runner.invoke(cli_command_server, ["--host", "unittest", "--port", 5566])
34
+ mock_run.assert_called_once_with(app, host="unittest", port=5566, lifespan="on")
32
35
 
33
- @patch('recce.cli.uvicorn.run')
36
+ @patch("recce.cli.uvicorn.run")
34
37
  def test_cmd_server_with_cloud_without_password(self, mock_run):
35
38
  # Should fail if no password is provided
36
- result = self.runner.invoke(cli_command_server, ['--cloud'])
39
+ result = self.runner.invoke(cli_command_server, ["--cloud"])
37
40
  assert result.exit_code == 1
38
41
 
39
- @patch('recce.cli.uvicorn.run')
42
+ @patch("recce.cli.uvicorn.run")
40
43
  def test_cmd_server_with_cloud_without_token(self, mock_run):
41
44
  # Should fail if no token is provided
42
- result = self.runner.invoke(cli_command_server, ['--cloud', '--password', 'unittest'])
45
+ result = self.runner.invoke(cli_command_server, ["--cloud", "--password", "unittest"])
43
46
  assert result.exit_code == 1
44
47
 
45
- @patch.object(RecceContext, 'verify_required_artifacts')
46
- @patch('recce.util.recce_cloud.get_recce_cloud_onboarding_state')
47
- @patch('recce.cli.uvicorn.run')
48
- @patch('recce.cli.RecceStateLoader')
49
- def test_cmd_server_with_cloud(self, mock_state_loader_class, mock_run, mock_get_recce_cloud_onboarding_state,
50
- mock_verify_required_artifacts):
48
+ @patch.object(RecceContext, "verify_required_artifacts")
49
+ @patch("recce.util.recce_cloud.get_recce_cloud_onboarding_state")
50
+ @patch("recce.cli.uvicorn.run")
51
+ @patch("recce.cli.RecceStateLoader")
52
+ def test_cmd_server_with_cloud(
53
+ self, mock_state_loader_class, mock_run, mock_get_recce_cloud_onboarding_state, mock_verify_required_artifacts
54
+ ):
51
55
  mock_state_loader = MagicMock(spec=RecceStateLoader)
52
56
  mock_state_loader.verify.return_value = True
53
57
  mock_state_loader.review_mode = True
54
- mock_get_recce_cloud_onboarding_state.return_value = 'completed'
58
+ mock_get_recce_cloud_onboarding_state.return_value = "completed"
55
59
  mock_verify_required_artifacts.return_value = True, None
56
60
 
57
61
  mock_state_loader_class.return_value = mock_state_loader
58
- self.runner.invoke(cli_command_server, ['--cloud', '--password', 'unittest', '--cloud-token', 'unittest'])
62
+ self.runner.invoke(cli_command_server, ["--cloud", "--password", "unittest", "--cloud-token", "unittest"])
59
63
  mock_state_loader_class.assert_called_once()
60
64
  mock_run.assert_called_once()
61
65
 
62
- @patch.object(RecceContext, 'verify_required_artifacts')
63
- @patch('os.path.isdir', side_effect=lambda path: True if path == 'existed_folder' else False)
64
- @patch('recce.cli.uvicorn.run')
65
- @patch('recce.server.AppState')
66
- def test_cmd_server_with_single_env(self,
67
- mock_app_state, mock_run, mock_isdir, mock_verify_required_artifacts):
66
+ @patch.object(RecceContext, "verify_required_artifacts")
67
+ @patch("os.path.isdir", side_effect=lambda path: True if path == "existed_folder" else False)
68
+ @patch("recce.cli.uvicorn.run")
69
+ @patch("recce.server.AppState")
70
+ def test_cmd_server_with_single_env(self, mock_app_state, mock_run, mock_isdir, mock_verify_required_artifacts):
68
71
  mock_verify_required_artifacts.return_value = True, None
69
- self.runner.invoke(cli_command_server,
70
- [
71
- '--target-path', 'existed_folder',
72
- '--target-base-path', 'non_existed_folder',
73
- ])
72
+ self.runner.invoke(
73
+ cli_command_server,
74
+ [
75
+ "--target-path",
76
+ "existed_folder",
77
+ "--target-base-path",
78
+ "non_existed_folder",
79
+ ],
80
+ )
74
81
  mock_run.assert_called_once()
75
82
 
76
83
  # Onboarding mode should be set to True
77
84
  app_state_call_args = mock_app_state.call_args
78
- app_state_flag = app_state_call_args.kwargs['flag']
79
- assert 'single_env_onboarding' in app_state_flag
80
- assert app_state_flag['single_env_onboarding'] is True
81
- assert 'show_relaunch_hint' in app_state_flag
82
- assert app_state_flag['show_relaunch_hint'] is True
85
+ app_state_flag = app_state_call_args.kwargs["flag"]
86
+ assert "single_env_onboarding" in app_state_flag
87
+ assert app_state_flag["single_env_onboarding"] is True
88
+ assert "show_relaunch_hint" in app_state_flag
89
+ assert app_state_flag["show_relaunch_hint"] is True
83
90
 
84
91
  # The target_base_path should be set to the same as target_path
85
92
  verify_required_artifacts_args = mock_verify_required_artifacts.call_args
86
- assert verify_required_artifacts_args.kwargs['target_path'] == verify_required_artifacts_args.kwargs[
87
- 'target_base_path']
88
-
89
- @patch.object(RecceContext, 'verify_required_artifacts')
90
- @patch('os.path.isdir', side_effect=lambda path: True if path == 'existed_folder' else False)
91
- @patch('recce.cli.uvicorn.run')
92
- @patch('recce.server.AppState')
93
- def test_cmd_server_with_single_env_but_review_mode_enabled(self,
94
- mock_app_state, mock_run, mock_isdir,
95
- mock_verify_required_artifacts):
93
+ assert (
94
+ verify_required_artifacts_args.kwargs["target_path"]
95
+ == verify_required_artifacts_args.kwargs["target_base_path"]
96
+ )
97
+
98
+ @patch.object(RecceContext, "verify_required_artifacts")
99
+ @patch("os.path.isdir", side_effect=lambda path: True if path == "existed_folder" else False)
100
+ @patch("recce.cli.uvicorn.run")
101
+ @patch("recce.server.AppState")
102
+ def test_cmd_server_with_single_env_but_review_mode_enabled(
103
+ self, mock_app_state, mock_run, mock_isdir, mock_verify_required_artifacts
104
+ ):
96
105
  mock_verify_required_artifacts.return_value = True, None
97
- self.runner.invoke(cli_command_server,
98
- [
99
- 'existed_state_file',
100
- '--review',
101
- '--target-path', 'existed_folder',
102
- '--target-base-path', 'non_existed_folder',
103
- ])
106
+ self.runner.invoke(
107
+ cli_command_server,
108
+ [
109
+ "existed_state_file",
110
+ "--review",
111
+ "--target-path",
112
+ "existed_folder",
113
+ "--target-base-path",
114
+ "non_existed_folder",
115
+ ],
116
+ )
104
117
  mock_run.assert_called_once()
105
118
  app_state_call_args = mock_app_state.call_args
106
- app_state_flag = app_state_call_args.kwargs['flag']
107
- assert 'single_env_onboarding' in app_state_flag
108
- assert app_state_flag['single_env_onboarding'] is False
119
+ app_state_flag = app_state_call_args.kwargs["flag"]
120
+ assert "single_env_onboarding" in app_state_flag
121
+ assert app_state_flag["single_env_onboarding"] is False
109
122
 
110
123
 
111
124
  class TestCommandRun(TestCase):
@@ -113,8 +126,8 @@ class TestCommandRun(TestCase):
113
126
  self.runner = CliRunner()
114
127
  pass
115
128
 
116
- @patch.object(RecceContext, 'verify_required_artifacts')
117
- @patch('recce.cli.cli_run')
129
+ @patch.object(RecceContext, "verify_required_artifacts")
130
+ @patch("recce.cli.cli_run")
118
131
  def test_cmd_run(self, mock_cli_run, mock_verify_required_artifacts):
119
132
  mock_verify_required_artifacts.return_value = True, None
120
133