recce-nightly 1.20.0.20250918__py3-none-any.whl → 1.20.0.20250922__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 (30) hide show
  1. recce/VERSION +1 -1
  2. recce/adapter/dbt_adapter/__init__.py +1 -1
  3. recce/artifact.py +16 -16
  4. recce/cli.py +280 -28
  5. recce/config.py +2 -2
  6. recce/connect_to_cloud.py +1 -1
  7. recce/data/404.html +1 -1
  8. recce/data/_next/static/chunks/app/{page-8b1eb61c94f06c1b.js → page-9f7291a41c6274cd.js} +1 -1
  9. recce/data/index.html +1 -1
  10. recce/data/index.txt +2 -2
  11. recce/event/__init__.py +6 -6
  12. recce/github.py +1 -1
  13. recce/pull_request.py +1 -1
  14. recce/run.py +2 -2
  15. recce/server.py +3 -3
  16. recce/state/cloud.py +54 -54
  17. recce/state/state_loader.py +4 -4
  18. recce/util/io.py +2 -2
  19. recce/util/recce_cloud.py +57 -20
  20. recce/yaml/__init__.py +2 -2
  21. {recce_nightly-1.20.0.20250918.dist-info → recce_nightly-1.20.0.20250922.dist-info}/METADATA +1 -1
  22. {recce_nightly-1.20.0.20250918.dist-info → recce_nightly-1.20.0.20250922.dist-info}/RECORD +30 -29
  23. tests/test_cli.py +27 -0
  24. tests/test_cloud_listing_cli.py +324 -0
  25. /recce/data/_next/static/{ZUbzMSlc3CArT7vsmEueJ → 15wXG4tmVWP4KygQN515-}/_buildManifest.js +0 -0
  26. /recce/data/_next/static/{ZUbzMSlc3CArT7vsmEueJ → 15wXG4tmVWP4KygQN515-}/_ssgManifest.js +0 -0
  27. {recce_nightly-1.20.0.20250918.dist-info → recce_nightly-1.20.0.20250922.dist-info}/WHEEL +0 -0
  28. {recce_nightly-1.20.0.20250918.dist-info → recce_nightly-1.20.0.20250922.dist-info}/entry_points.txt +0 -0
  29. {recce_nightly-1.20.0.20250918.dist-info → recce_nightly-1.20.0.20250922.dist-info}/licenses/LICENSE +0 -0
  30. {recce_nightly-1.20.0.20250918.dist-info → recce_nightly-1.20.0.20250922.dist-info}/top_level.txt +0 -0
recce/VERSION CHANGED
@@ -1 +1 @@
1
- 1.20.0.20250918
1
+ 1.20.0.20250922
@@ -1591,7 +1591,7 @@ class DbtAdapter(BaseAdapter):
1591
1591
  if not os.path.isfile(path):
1592
1592
  return None
1593
1593
 
1594
- with open(path, "r") as f:
1594
+ with open(path, "r", encoding="utf-8") as f:
1595
1595
  json_content = f.read()
1596
1596
  return json.loads(json_content)
1597
1597
 
recce/artifact.py CHANGED
@@ -40,7 +40,7 @@ def verify_artifacts_path(target_path: str) -> bool:
40
40
 
41
41
 
42
42
  def parse_dbt_version(file_path: str) -> str:
43
- with open(file_path, "r") as f:
43
+ with open(file_path, "r", encoding="utf-8") as f:
44
44
  data = json.load(f)
45
45
 
46
46
  dbt_version = data.get("metadata", {}).get("dbt_version", None)
@@ -80,8 +80,8 @@ def archive_artifacts(target_path: str) -> (str, str):
80
80
  return artifacts_tar_gz_path, dbt_version
81
81
 
82
82
 
83
- def upload_artifacts_to_snapshot(target_path: str, snapshot_id: str, token: str, debug: bool = False):
84
- """Upload dbt artifacts to a specific snapshot ID in Recce Cloud."""
83
+ def upload_artifacts_to_session(target_path: str, session_id: str, token: str, debug: bool = False):
84
+ """Upload dbt artifacts to a specific session ID in Recce Cloud."""
85
85
  console = Console()
86
86
  if verify_artifacts_path(target_path) is False:
87
87
  console.print(f"[[red]Error[/red]] Invalid target path: {target_path}")
@@ -92,7 +92,7 @@ def upload_artifacts_to_snapshot(target_path: str, snapshot_id: str, token: str,
92
92
  catalog_path = os.path.join(target_path, "catalog.json")
93
93
 
94
94
  # get the adapter type from the manifest file
95
- with open(manifest_path, "r") as f:
95
+ with open(manifest_path, "r", encoding="utf-8") as f:
96
96
  manifest_data = json.load(f)
97
97
  adapter_type = manifest_data.get("metadata", {}).get("adapter_type")
98
98
  if adapter_type is None:
@@ -100,29 +100,29 @@ def upload_artifacts_to_snapshot(target_path: str, snapshot_id: str, token: str,
100
100
 
101
101
  recce_cloud = RecceCloud(token)
102
102
 
103
- snapshot = recce_cloud.get_snapshot(snapshot_id)
103
+ session = recce_cloud.get_session(session_id)
104
104
 
105
- org_id = snapshot.get("org_id")
105
+ org_id = session.get("org_id")
106
106
  if org_id is None:
107
- raise Exception(f"Snapshot ID {snapshot_id} does not belong to any organization.")
107
+ raise Exception(f"Session ID {session_id} does not belong to any organization.")
108
108
 
109
- project_id = snapshot.get("project_id")
109
+ project_id = session.get("project_id")
110
110
  if project_id is None:
111
- raise Exception(f"Snapshot ID {snapshot_id} does not belong to any project.")
111
+ raise Exception(f"Session ID {session_id} does not belong to any project.")
112
112
 
113
- # Get the presigned URL for uploading the artifacts using snapshot ID
114
- console.print(f'Uploading artifacts for snapshot ID "{snapshot_id}"')
115
- presigned_urls = recce_cloud.get_upload_urls_by_snapshot_id(org_id, project_id, snapshot_id)
113
+ # Get the presigned URL for uploading the artifacts using session ID
114
+ console.print(f'Uploading artifacts for session ID "{session_id}"')
115
+ presigned_urls = recce_cloud.get_upload_urls_by_session_id(org_id, project_id, session_id)
116
116
  if debug:
117
117
  console.rule("Debug information", style="blue")
118
118
  console.print(f"Org ID: {org_id}")
119
119
  console.print(f"Project ID: {project_id}")
120
- console.print(f"Snapshot ID: {snapshot_id}")
120
+ console.print(f"Session ID: {session_id}")
121
121
  console.print(f"Manifest path: {presigned_urls['manifest_url']}")
122
122
  console.print(f"Catalog path: {presigned_urls['catalog_url']}")
123
123
  console.print(f"Adapter type: {adapter_type}")
124
124
 
125
- # Upload the compressed artifacts (no password needed for snapshot uploads)
125
+ # Upload the compressed artifacts (no password needed for session uploads)
126
126
  console.print(f'Uploading manifest from path "{manifest_path}"')
127
127
  response = requests.put(presigned_urls["manifest_url"], data=open(manifest_path, "rb").read())
128
128
  if response.status_code != 200 and response.status_code != 204:
@@ -132,8 +132,8 @@ def upload_artifacts_to_snapshot(target_path: str, snapshot_id: str, token: str,
132
132
  if response.status_code != 200 and response.status_code != 204:
133
133
  raise Exception(response.text)
134
134
 
135
- # Update the snapshot metadata
136
- recce_cloud.update_snapshot(org_id, project_id, snapshot_id, adapter_type)
135
+ # Update the session metadata
136
+ recce_cloud.update_session(org_id, project_id, session_id, adapter_type)
137
137
 
138
138
  return 0
139
139
 
recce/cli.py CHANGED
@@ -10,7 +10,7 @@ from click import Abort
10
10
  from recce import event
11
11
  from recce.artifact import (
12
12
  download_dbt_artifacts,
13
- upload_artifacts_to_snapshot,
13
+ upload_artifacts_to_session,
14
14
  upload_dbt_artifacts,
15
15
  )
16
16
  from recce.config import RECCE_CONFIG_FILE, RECCE_ERROR_LOG_FILE, RecceConfig
@@ -143,6 +143,12 @@ recce_cloud_options = [
143
143
  ),
144
144
  ]
145
145
 
146
+ recce_cloud_auth_options = [
147
+ click.option(
148
+ "--api-token", help="The personal token generated by Recce Cloud.", type=click.STRING, envvar="RECCE_API_TOKEN"
149
+ )
150
+ ]
151
+
146
152
  recce_dbt_artifact_dir_options = [
147
153
  click.option(
148
154
  "--target-path",
@@ -173,10 +179,10 @@ recce_hidden_options = [
173
179
  hidden=True,
174
180
  ),
175
181
  click.option(
176
- "--snapshot-id",
177
- help="The snapshot ID triggers this instance.",
182
+ "--session-id",
183
+ help="The session ID triggers this instance.",
178
184
  type=click.STRING,
179
- envvar="RECCE_SNAPSHOT_ID",
185
+ envvar=["RECCE_SESSION_ID", "RECCE_SNAPSHOT_ID"], # Backward compatibility with RECCE_SNAPSHOT_ID
180
186
  hidden=True,
181
187
  ),
182
188
  ]
@@ -460,7 +466,7 @@ def server(host, port, lifetime, state_file=None, **kwargs):
460
466
  }
461
467
 
462
468
  share_url = kwargs.get("share_url")
463
- snapshot_id = kwargs.get("snapshot_id")
469
+ session_id = kwargs.get("session_id")
464
470
  if share_url:
465
471
  share_id = share_url.split("/")[-1]
466
472
  if not share_id:
@@ -476,12 +482,12 @@ def server(host, port, lifetime, state_file=None, **kwargs):
476
482
  "api_token": api_token,
477
483
  "share_id": share_id,
478
484
  }
479
- elif snapshot_id:
485
+ elif session_id:
480
486
  is_review = kwargs["review"] = True
481
487
  cloud_options = {
482
488
  "host": kwargs.get("state_file_host"),
483
489
  "api_token": api_token,
484
- "snapshot_id": snapshot_id,
490
+ "session_id": session_id,
485
491
  }
486
492
  else:
487
493
  cloud_options = {
@@ -1177,6 +1183,227 @@ def download_base_artifacts(**kwargs):
1177
1183
  return _download_artifacts(branch, cloud_token, console, kwargs, password, target_path)
1178
1184
 
1179
1185
 
1186
+ @cloud.command(cls=TrackCommand, name="list-organizations")
1187
+ @click.option("--api-token", help="The Recce Cloud API token.", type=click.STRING, envvar="RECCE_CLOUD_API_TOKEN")
1188
+ @add_options(recce_options)
1189
+ def list_organizations(**kwargs):
1190
+ """
1191
+ List organizations from Recce Cloud
1192
+
1193
+ Lists all organizations that the authenticated user has access to.
1194
+ """
1195
+ from rich.console import Console
1196
+ from rich.table import Table
1197
+
1198
+ console = Console()
1199
+ handle_debug_flag(**kwargs)
1200
+
1201
+ try:
1202
+ api_token = prepare_api_token(**kwargs)
1203
+ except RecceConfigException:
1204
+ show_invalid_api_token_message()
1205
+ exit(1)
1206
+
1207
+ try:
1208
+ from recce.util.recce_cloud import RecceCloud
1209
+
1210
+ cloud = RecceCloud(api_token)
1211
+ organizations = cloud.list_organizations()
1212
+
1213
+ if not organizations:
1214
+ console.print("No organizations found.")
1215
+ return
1216
+
1217
+ table = Table(title="Organizations")
1218
+ table.add_column("ID", style="cyan")
1219
+ table.add_column("Name", style="green")
1220
+ table.add_column("Display Name", style="yellow")
1221
+
1222
+ for org in organizations:
1223
+ table.add_row(str(org.get("id", "")), org.get("name", ""), org.get("display_name", ""))
1224
+
1225
+ console.print(table)
1226
+
1227
+ except RecceCloudException as e:
1228
+ console.print(f"[[red]Error[/red]] {e}")
1229
+ exit(1)
1230
+ except Exception as e:
1231
+ console.print(f"[[red]Error[/red]] {e}")
1232
+ exit(1)
1233
+
1234
+
1235
+ @cloud.command(cls=TrackCommand, name="list-projects")
1236
+ @click.option(
1237
+ "--organization",
1238
+ "-o",
1239
+ help="Organization ID (can also be set via RECCE_ORGANIZATION_ID environment variable)",
1240
+ type=click.STRING,
1241
+ envvar="RECCE_ORGANIZATION_ID",
1242
+ )
1243
+ @click.option("--api-token", help="The Recce Cloud API token.", type=click.STRING, envvar="RECCE_CLOUD_API_TOKEN")
1244
+ @add_options(recce_options)
1245
+ def list_projects(**kwargs):
1246
+ """
1247
+ List projects from Recce Cloud
1248
+
1249
+ Lists all projects in the specified organization that the authenticated user has access to.
1250
+
1251
+ Examples:
1252
+
1253
+ # Using environment variable
1254
+ export RECCE_ORGANIZATION_ID=8
1255
+ recce cloud list-projects
1256
+
1257
+ # Using command line argument
1258
+ recce cloud list-projects --organization 8
1259
+
1260
+ # Override environment variable
1261
+ export RECCE_ORGANIZATION_ID=8
1262
+ recce cloud list-projects --organization 10
1263
+ """
1264
+ from rich.console import Console
1265
+ from rich.table import Table
1266
+
1267
+ console = Console()
1268
+ handle_debug_flag(**kwargs)
1269
+
1270
+ try:
1271
+ api_token = prepare_api_token(**kwargs)
1272
+ except RecceConfigException:
1273
+ show_invalid_api_token_message()
1274
+ exit(1)
1275
+
1276
+ organization = kwargs.get("organization")
1277
+ if not organization:
1278
+ console.print("[[red]Error[/red]] Organization ID is required. Please provide it via:")
1279
+ console.print(" --organization <id> or set RECCE_ORGANIZATION_ID environment variable")
1280
+ exit(1)
1281
+
1282
+ try:
1283
+ from recce.util.recce_cloud import RecceCloud
1284
+
1285
+ cloud = RecceCloud(api_token)
1286
+ projects = cloud.list_projects(organization)
1287
+
1288
+ if not projects:
1289
+ console.print(f"No projects found in organization {organization}.")
1290
+ return
1291
+
1292
+ table = Table(title=f"Projects in Organization {organization}")
1293
+ table.add_column("ID", style="cyan")
1294
+ table.add_column("Name", style="green")
1295
+ table.add_column("Display Name", style="yellow")
1296
+
1297
+ for project in projects:
1298
+ table.add_row(str(project.get("id", "")), project.get("name", ""), project.get("display_name", ""))
1299
+
1300
+ console.print(table)
1301
+
1302
+ except RecceCloudException as e:
1303
+ console.print(f"[[red]Error[/red]] {e}")
1304
+ exit(1)
1305
+ except Exception as e:
1306
+ console.print(f"[[red]Error[/red]] {e}")
1307
+ exit(1)
1308
+
1309
+
1310
+ @cloud.command(cls=TrackCommand, name="list-sessions")
1311
+ @click.option(
1312
+ "--organization",
1313
+ "-o",
1314
+ help="Organization ID (can also be set via RECCE_ORGANIZATION_ID environment variable)",
1315
+ type=click.STRING,
1316
+ envvar="RECCE_ORGANIZATION_ID",
1317
+ )
1318
+ @click.option(
1319
+ "--project",
1320
+ "-p",
1321
+ help="Project ID (can also be set via RECCE_PROJECT_ID environment variable)",
1322
+ type=click.STRING,
1323
+ envvar="RECCE_PROJECT_ID",
1324
+ )
1325
+ @click.option("--api-token", help="The Recce Cloud API token.", type=click.STRING, envvar="RECCE_CLOUD_API_TOKEN")
1326
+ @add_options(recce_options)
1327
+ def list_sessions(**kwargs):
1328
+ """
1329
+ List sessions from Recce Cloud
1330
+
1331
+ Lists all sessions in the specified project that the authenticated user has access to.
1332
+
1333
+ Examples:
1334
+
1335
+ # Using environment variables
1336
+ export RECCE_ORGANIZATION_ID=8
1337
+ export RECCE_PROJECT_ID=7
1338
+ recce cloud list-sessions
1339
+
1340
+ # Using command line arguments
1341
+ recce cloud list-sessions --organization 8 --project 7
1342
+
1343
+ # Mixed usage (env + CLI override)
1344
+ export RECCE_ORGANIZATION_ID=8
1345
+ recce cloud list-sessions --project 7
1346
+
1347
+ # Override environment variables
1348
+ export RECCE_ORGANIZATION_ID=8
1349
+ export RECCE_PROJECT_ID=7
1350
+ recce cloud list-sessions --organization 10 --project 9
1351
+ """
1352
+ from rich.console import Console
1353
+ from rich.table import Table
1354
+
1355
+ console = Console()
1356
+ handle_debug_flag(**kwargs)
1357
+
1358
+ try:
1359
+ api_token = prepare_api_token(**kwargs)
1360
+ except RecceConfigException:
1361
+ show_invalid_api_token_message()
1362
+ exit(1)
1363
+
1364
+ organization = kwargs.get("organization")
1365
+ project = kwargs.get("project")
1366
+
1367
+ # Validate required parameters
1368
+ if not organization:
1369
+ console.print("[[red]Error[/red]] Organization ID is required. Please provide it via:")
1370
+ console.print(" --organization <id> or set RECCE_ORGANIZATION_ID environment variable")
1371
+ exit(1)
1372
+
1373
+ if not project:
1374
+ console.print("[[red]Error[/red]] Project ID is required. Please provide it via:")
1375
+ console.print(" --project <id> or set RECCE_PROJECT_ID environment variable")
1376
+ exit(1)
1377
+
1378
+ try:
1379
+ from recce.util.recce_cloud import RecceCloud
1380
+
1381
+ cloud = RecceCloud(api_token)
1382
+ sessions = cloud.list_sessions(organization, project)
1383
+
1384
+ if not sessions:
1385
+ console.print(f"No sessions found in project {project}.")
1386
+ return
1387
+
1388
+ table = Table(title=f"Sessions in Project {project}")
1389
+ table.add_column("ID", style="cyan")
1390
+ table.add_column("Name", style="green")
1391
+ table.add_column("Is Base", style="yellow")
1392
+
1393
+ for session in sessions:
1394
+ is_base = "✓" if session.get("is_base", False) else ""
1395
+ table.add_row(session.get("id", ""), session.get("name", ""), is_base)
1396
+
1397
+ console.print(table)
1398
+
1399
+ except RecceCloudException as e:
1400
+ console.print(f"[[red]Error[/red]] {e}")
1401
+ exit(1)
1402
+ except Exception as e:
1403
+ console.print(f"[[red]Error[/red]] {e}")
1404
+ exit(1)
1405
+
1406
+
1180
1407
  @cli.group("github", short_help="GitHub related commands", hidden=True)
1181
1408
  def github(**kwargs):
1182
1409
  pass
@@ -1264,41 +1491,51 @@ def share(state_file, **kwargs):
1264
1491
  exit(1)
1265
1492
 
1266
1493
 
1267
- @cli.command(cls=TrackCommand, hidden=True)
1268
- @click.option(
1494
+ snapshot_id_option = click.option(
1269
1495
  "--snapshot-id",
1270
1496
  help="The snapshot ID to upload artifacts to cloud.",
1271
1497
  type=click.STRING,
1272
- envvar="RECCE_SNAPSHOT_ID",
1498
+ envvar=["RECCE_SNAPSHOT_ID", "RECCE_SESSION_ID"],
1273
1499
  required=True,
1274
1500
  )
1275
- @click.option(
1501
+
1502
+ session_id_option = click.option(
1503
+ "--session-id",
1504
+ help="The session ID to upload artifacts to cloud.",
1505
+ type=click.STRING,
1506
+ envvar=["RECCE_SESSION_ID", "RECCE_SNAPSHOT_ID"],
1507
+ required=True,
1508
+ )
1509
+
1510
+ target_path_option = click.option(
1276
1511
  "--target-path",
1277
1512
  help="dbt artifacts directory for your artifacts.",
1278
1513
  type=click.STRING,
1279
1514
  default="target",
1280
1515
  show_default=True,
1281
1516
  )
1282
- @click.option(
1283
- "--api-token", help="The personal token generated by Recce Cloud.", type=click.STRING, envvar="RECCE_API_TOKEN"
1284
- )
1517
+
1518
+
1519
+ @cli.command(cls=TrackCommand, hidden=True)
1520
+ @add_options([session_id_option, target_path_option])
1521
+ @add_options(recce_cloud_auth_options)
1285
1522
  @add_options(recce_options)
1286
- def snapshot(**kwargs):
1523
+ def upload_session(**kwargs):
1287
1524
  """
1288
- Upload target/manifest.json and target/catalog.json to the specific snapshot ID
1525
+ Upload target/manifest.json and target/catalog.json to the specific session ID
1289
1526
 
1290
- Upload the dbt artifacts (manifest.json, catalog.json) to Recce Cloud for the given snapshot ID.
1291
- This allows you to associate artifacts with a specific snapshot for later use.
1527
+ Upload the dbt artifacts (manifest.json, catalog.json) to Recce Cloud for the given session ID.
1528
+ This allows you to associate artifacts with a specific session for later use.
1292
1529
 
1293
1530
  Examples:\n
1294
1531
 
1295
1532
  \b
1296
- # Upload artifacts to a snapshot ID
1297
- recce snapshot --snapshot-id <snapshot-id>
1533
+ # Upload artifacts to a session ID
1534
+ recce upload-session --session-id <session-id>
1298
1535
 
1299
1536
  \b
1300
- # Upload artifacts from custom target path to a snapshot ID
1301
- recce snapshot --snapshot-id <snapshot-id> --target-path my-target
1537
+ # Upload artifacts from custom target path to a session ID
1538
+ recce upload-session --session-id <session-id> --target-path my-target
1302
1539
  """
1303
1540
  from rich.console import Console
1304
1541
 
@@ -1314,25 +1551,40 @@ def snapshot(**kwargs):
1314
1551
  show_invalid_api_token_message()
1315
1552
  exit(1)
1316
1553
 
1317
- snapshot_id = kwargs.get("snapshot_id")
1554
+ session_id = kwargs.get("session_id")
1318
1555
  target_path = kwargs.get("target_path")
1319
1556
 
1320
1557
  try:
1321
- rc = upload_artifacts_to_snapshot(
1322
- target_path, snapshot_id=snapshot_id, token=api_token, debug=kwargs.get("debug", False)
1558
+ rc = upload_artifacts_to_session(
1559
+ target_path, session_id=session_id, token=api_token, debug=kwargs.get("debug", False)
1323
1560
  )
1324
1561
  console.rule("Uploaded Successfully")
1325
1562
  console.print(
1326
- f'Uploaded dbt artifacts to Recce Cloud for snapshot ID "{snapshot_id}" from "{os.path.abspath(target_path)}"'
1563
+ f'Uploaded dbt artifacts to Recce Cloud for session ID "{session_id}" from "{os.path.abspath(target_path)}"'
1327
1564
  )
1328
1565
  except Exception as e:
1329
- console.rule("Failed to Snapshot", style="red")
1330
- console.print(f"[[red]Error[/red]] Failed to upload the dbt artifacts to the snapshot {snapshot_id}.")
1566
+ console.rule("Failed to Upload Session", style="red")
1567
+ console.print(f"[[red]Error[/red]] Failed to upload the dbt artifacts to the session {session_id}.")
1331
1568
  console.print(f"Reason: {e}")
1332
1569
  rc = 1
1333
1570
  return rc
1334
1571
 
1335
1572
 
1573
+ # Backward compatibility for `recce snapshot` command
1574
+ @cli.command(
1575
+ cls=TrackCommand,
1576
+ hidden=True,
1577
+ deprecated=True,
1578
+ help="Upload target/manifest.json and target/catalog.json to the specific snapshot ID",
1579
+ )
1580
+ @add_options([snapshot_id_option, target_path_option])
1581
+ @add_options(recce_cloud_auth_options)
1582
+ @add_options(recce_options)
1583
+ def snapshot(**kwargs):
1584
+ kwargs["session_id"] = kwargs.get("snapshot_id")
1585
+ return upload_session(**kwargs)
1586
+
1587
+
1336
1588
  @cli.command(hidden=True, cls=TrackCommand)
1337
1589
  @click.argument("state_file", required=True)
1338
1590
  @click.option("--host", default="localhost", show_default=True, help="The host to bind to.")
recce/config.py CHANGED
@@ -21,7 +21,7 @@ class RecceConfig(metaclass=SingletonMeta):
21
21
 
22
22
  def load(self):
23
23
  try:
24
- with open(self.config_file, "r") as f:
24
+ with open(self.config_file, "r", encoding="utf-8") as f:
25
25
  config = yaml.safe_load(f)
26
26
  self.config = config if config else {}
27
27
  self._verify_preset_checks()
@@ -117,7 +117,7 @@ class RecceConfig(metaclass=SingletonMeta):
117
117
  self.config[key] = value
118
118
 
119
119
  def save(self):
120
- with open(RECCE_CONFIG_FILE, "w") as f:
120
+ with open(RECCE_CONFIG_FILE, "w", encoding="utf-8") as f:
121
121
  yaml.dump(self.config, f)
122
122
 
123
123
  def __str__(self):
recce/connect_to_cloud.py CHANGED
@@ -58,7 +58,7 @@ def make_callback_handler(private_key: RSAPrivateKey):
58
58
  class OneTimeHTTPRequestHandler(BaseHTTPRequestHandler):
59
59
  def do_GET(self):
60
60
  try:
61
- with open(os.path.join(static_folder_path, "auth_callback.html"), "r") as f:
61
+ with open(os.path.join(static_folder_path, "auth_callback.html"), "r", encoding="utf-8") as f:
62
62
  callback_html_content = f.read()
63
63
 
64
64
  # Parse query parameters