qalita 2.2.9__py3-none-any.whl → 2.3.1__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.
qalita/__main__.py CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  import os
5
5
  import click
6
-
6
+
7
7
  from qalita.internal.utils import logger, get_version
8
8
  from qalita.internal.config import Config
9
9
 
@@ -37,8 +37,8 @@ pass_config = click.make_pass_decorator(Config, ensure=True)
37
37
  @click.pass_context
38
38
  def cli(ctx, ui=False, port=7070, host="localhost"):
39
39
  """
40
- ------------------ Qalita Platform Command Line Interface ------------------\n\r
41
- Hello and thanks for using Qalita Platform to monitor and ensure the quality of your data. \n\r
40
+ ------------------ QALITA Platform Command Line Interface ------------------\n\r
41
+ Hello and thanks for using QALITA Platform to monitor and ensure the quality of your data. \n\r
42
42
  ----------------------------------------------------------------------------\n\r
43
43
  Please, Help us improve our service by reporting any bug by filing a bug report, Thanks ! \n\r
44
44
  mail : contact@qalita.io \n\r
qalita/commands/agent.py CHANGED
@@ -56,7 +56,7 @@ ROUTINE_LAST_SCHEDULED_UTC = {}
56
56
  )
57
57
  @pass_config
58
58
  def agent(config, name, mode, token, url):
59
- """Manage Qalita Platform Agents"""
59
+ """Manage QALITA Platform Agents"""
60
60
 
61
61
  all_check_pass = True
62
62
 
@@ -200,7 +200,7 @@ def send_alive(config, config_file, mode="", status="online"):
200
200
 
201
201
  @pass_config
202
202
  def authenticate(config, user_id):
203
- """Authenticate the agent to the Qalita Platform"""
203
+ """Authenticate the agent to the QALITA Platform"""
204
204
  try:
205
205
  r = send_request.__wrapped__(
206
206
  config,
@@ -345,7 +345,7 @@ def authenticate(config, user_id):
345
345
  @pass_config
346
346
  def login(config):
347
347
  """
348
- Register the agent to the Qalita Platform
348
+ Register the agent to the QALITA Platform
349
349
  """
350
350
  if config.verbose:
351
351
  logger.info("Verbose mode enabled")
@@ -356,8 +356,8 @@ def login(config):
356
356
  r = send_request(request=f"{config.url}/api/v1/version", mode="get")
357
357
  if r.status_code == 200:
358
358
  if r.json()["version"] != get_version():
359
- logger.info(f"Qalita Platform Version : {r.json()['version']}")
360
- logger.info(f"Qalita CLI Version : {get_version()}")
359
+ logger.info(f"QALITA Platform Version : {r.json()['version']}")
360
+ logger.info(f"QALITA CLI Version : {get_version()}")
361
361
  logger.info(
362
362
  "Make sure you are using compatible versions for the platform and the cli,\n\t> check compatibility matrix on the documentation <"
363
363
  )
@@ -465,6 +465,9 @@ def run(
465
465
  # check routines before checking jobs
466
466
  check_routines(config, agent_start_datetime)
467
467
 
468
+ # try to claim one pending unassigned job compatible with this agent
469
+ claim_unassigned_jobs(config)
470
+
468
471
  check_job = send_api_request(
469
472
  request=f'/api/v1/agents/{agent_conf["context"]["remote"]["id"]}/jobs/next',
470
473
  mode="get",
@@ -874,7 +877,7 @@ def post_run(
874
877
  ## LOGS
875
878
  # Initialize logs_id to None
876
879
  logs_id = None
877
- logger.info(f"Uploading logs to Qalita Platform...")
880
+ logger.info(f"Uploading logs to QALITA Platform...")
878
881
  logger.info(f"run_path: {run_path}")
879
882
  if os.path.exists(run_path + "/logs.txt"):
880
883
  api_url = agent_conf["context"]["local"]["url"]
@@ -912,12 +915,12 @@ def post_run(
912
915
  else:
913
916
  logger.info(f"No logs.txt file found")
914
917
 
915
- logger.info(f"Uploading results to Qalita Platform...")
918
+ logger.info(f"Uploading results to QALITA Platform...")
916
919
 
917
920
  #########################################################
918
921
  ## Recommendations
919
922
  if os.path.exists(run_path + "/recommendations.json"):
920
- logger.info(f"\tUploading recommendations to Qalita Platform...")
923
+ logger.info(f"\tUploading recommendations to QALITA Platform...")
921
924
 
922
925
  api_url = agent_conf["context"]["local"]["url"]
923
926
  registry_id = agent_conf["registries"][0]["id"]
@@ -949,7 +952,7 @@ def post_run(
949
952
  #########################################################
950
953
  ## Schemas
951
954
  if os.path.exists(run_path + "/schemas.json"):
952
- logger.info(f"\tUploading schemas to Qalita Platform...")
955
+ logger.info(f"\tUploading schemas to QALITA Platform...")
953
956
 
954
957
  api_url = agent_conf["context"]["local"]["url"]
955
958
  registry_id = agent_conf["registries"][0]["id"]
@@ -981,7 +984,7 @@ def post_run(
981
984
  #########################################################
982
985
  ## Metrics
983
986
  if os.path.exists(run_path + "/metrics.json"):
984
- logger.info(f"\tUploading Metrics to Qalita Platform...")
987
+ logger.info(f"\tUploading Metrics to QALITA Platform...")
985
988
 
986
989
  api_url = agent_conf["context"]["local"]["url"]
987
990
  registry_id = agent_conf["registries"][0]["id"]
@@ -1066,7 +1069,6 @@ def create_scheduled_job(routine, agent_conf):
1066
1069
  request=f"/api/v2/jobs/create",
1067
1070
  mode="post",
1068
1071
  data={
1069
- "agent_id": agent_conf["context"]["remote"]["id"],
1070
1072
  "source_id": routine["source"]["id"],
1071
1073
  "target_id": routine["target"]["id"] if routine.get("target") else None,
1072
1074
  "pack_id": routine["pack"]["id"],
@@ -1238,3 +1240,89 @@ def check_routines(config, agent_start_datetime):
1238
1240
  ROUTINE_LAST_SCHEDULED_UTC[routine.get("id")] = datetime.now(timezone.utc)
1239
1241
  else:
1240
1242
  logger.warning("Can't fetch routines or jobs from the platform")
1243
+
1244
+
1245
+ def claim_unassigned_jobs(config):
1246
+ """Claim one pending unassigned job that this agent can execute.
1247
+
1248
+ Strategy:
1249
+ - Fetch all jobs (v2)
1250
+ - Select first job with status == pending and no agent assigned
1251
+ - Check local capability: source (and target if provided) must exist locally
1252
+ - PUT to assign agent_id to this agent; on success, run job
1253
+ - On contention (another agent already claimed), ignore and return
1254
+ """
1255
+ try:
1256
+ source_conf = config.load_source_config(verbose=False)
1257
+ agent_conf = config.load_agent_config()
1258
+ local_source_ids = [s["id"] for s in source_conf["sources"] if "id" in s]
1259
+
1260
+ r = send_api_request(
1261
+ request=f"/api/v2/jobs",
1262
+ mode="get",
1263
+ )
1264
+ if r.status_code not in [200, 204]:
1265
+ return
1266
+ jobs = r.json()
1267
+ if not isinstance(jobs, list):
1268
+ return
1269
+
1270
+ def extract_id(maybe_obj, fallback_key):
1271
+ if isinstance(maybe_obj, dict):
1272
+ return maybe_obj.get("id")
1273
+ return maybe_obj if isinstance(maybe_obj, int) else None
1274
+
1275
+ for job in jobs:
1276
+ try:
1277
+ if job.get("status") != "pending":
1278
+ continue
1279
+ # unassigned: support either agent_id field or nested agent object
1280
+ is_unassigned = (
1281
+ (job.get("agent_id") is None or job.get("agent_id") == 0)
1282
+ and not job.get("agent")
1283
+ )
1284
+ if not is_unassigned:
1285
+ continue
1286
+
1287
+ src_id = extract_id(job.get("source"), "source_id") or job.get("source_id")
1288
+ if src_id not in local_source_ids:
1289
+ continue
1290
+ tgt_id = extract_id(job.get("target"), "target_id") or job.get("target_id")
1291
+ if tgt_id is not None and tgt_id not in local_source_ids:
1292
+ continue
1293
+
1294
+ # attempt to claim
1295
+ claim_resp = send_api_request(
1296
+ request=f"/api/v2/jobs/{job['id']}",
1297
+ mode="put",
1298
+ data={
1299
+ "agent_id": agent_conf["context"]["remote"]["id"],
1300
+ },
1301
+ )
1302
+ if claim_resp.status_code != 200:
1303
+ # likely contention: someone else claimed
1304
+ continue
1305
+
1306
+ # extract version ids if present
1307
+ src_ver_id = extract_id(job.get("source_version"), "source_version_id") or job.get("source_version_id")
1308
+ tgt_ver_id = extract_id(job.get("target_version"), "target_version_id") or job.get("target_version_id")
1309
+ pack_id = extract_id(job.get("pack"), "pack_id") or job.get("pack_id")
1310
+ pack_ver_id = extract_id(job.get("pack_version"), "pack_version_id") or job.get("pack_version_id")
1311
+
1312
+ logger.info(f"Claimed unassigned job {job['id']} for source {src_id} pack {pack_id}")
1313
+ job_run(
1314
+ src_id,
1315
+ src_ver_id,
1316
+ tgt_id,
1317
+ tgt_ver_id,
1318
+ pack_id,
1319
+ pack_ver_id,
1320
+ job=job,
1321
+ )
1322
+ # claim and run only one per loop
1323
+ return
1324
+ except Exception as _:
1325
+ # Be resilient; don't break the worker loop on any unexpected job shape
1326
+ continue
1327
+ except Exception as _:
1328
+ return
qalita/commands/pack.py CHANGED
@@ -241,7 +241,7 @@ def check_name(name):
241
241
  @click.option("-p", "--pack", type=int, help="Pack ID")
242
242
  @click.pass_context
243
243
  def pack(ctx, pack):
244
- """Manage Qalita Platform Packs"""
244
+ """Manage QALITA Platform Packs"""
245
245
  ctx.ensure_object(dict)
246
246
  ctx.obj["PACK"] = pack
247
247
 
@@ -416,7 +416,7 @@ def validate_pack_directory(pack_directory: str) -> int:
416
416
  @click.option(
417
417
  "-n",
418
418
  "--name",
419
- help="The name of the package, it will be used to identify the package in the Qalita platform",
419
+ help="The name of the package, it will be used to identify the package in the QALITA platform",
420
420
  envvar="QALITA_PACK_NAME",
421
421
  )
422
422
  @pass_config
@@ -586,20 +586,37 @@ def publish_new_pack_version(api_url, pack_id, pack_version, registry_id, pack_n
586
586
  source_dir=source_dir,
587
587
  config=config,
588
588
  )
589
- # Best-effort: also update compatibility metadata if provided in properties.yaml
589
+ # Best-effort: also update metadata (avatar, description, url, visibility, config, readme)
590
+ # and compatibility if provided in properties.yaml so the new version push also refreshes pack details.
590
591
  try:
591
592
  pack_dir = source_dir or f"./{pack_name}_pack"
592
593
  props = load_pack_properties(pack_dir) or {}
594
+ pack_icon = load_base64_encoded_image(os.path.join(pack_dir, "icon.png"))
595
+ readme = load_base64_encoded_text(os.path.join(pack_dir, "README.md"))
596
+ pack_config = load_json_config(os.path.join(pack_dir, "pack_conf.json"))
597
+ pack_type = props.get("type", "")
598
+ pack_description = props.get("description", "")
599
+ pack_url = props.get("url", "")
600
+ pack_visibility = props.get("visibility", "private")
593
601
  compat = props.get("compatible_sources")
594
- if isinstance(compat, builtins.list) and all(isinstance(x, str) for x in compat):
595
- _request_with_optional_config(
596
- config,
597
- api_url,
598
- f"/api/v2/packs/{pack_id}",
599
- "put",
600
- data={"compatible_sources": compat},
601
- )
602
+
603
+ # Update full metadata
604
+ update_pack_metadata(
605
+ api_url,
606
+ pack_id,
607
+ pack_icon,
608
+ pack_config,
609
+ pack_type,
610
+ pack_description,
611
+ pack_url,
612
+ pack_version,
613
+ pack_visibility,
614
+ readme,
615
+ compatible_sources=compat,
616
+ config=config,
617
+ )
602
618
  except Exception:
619
+ # Non-fatal if metadata refresh fails; continue to publish version
603
620
  pass
604
621
  publish_response = _request_with_optional_config(
605
622
  config,
@@ -689,11 +706,89 @@ def handle_version_matching(existing_versions, new_version):
689
706
  return None
690
707
 
691
708
 
709
+ def _push_with_context(agent_conf, pack_properties, pack_directory, config):
710
+ """Shared push routine used by CLI and Web UI.
711
+
712
+ Expects absolute or relative `pack_directory` and a loaded `pack_properties` dict.
713
+ """
714
+ # Extract pack details
715
+ pack_name = pack_properties.get("name")
716
+ pack_version = pack_properties.get("version")
717
+ pack_description = pack_properties.get("description", "")
718
+ pack_url = pack_properties.get("url", "")
719
+ pack_type = pack_properties.get("type", "")
720
+ pack_visibility = pack_properties.get("visibility", "private")
721
+
722
+ # Handle pack icon and README/config
723
+ pack_icon = load_base64_encoded_image(os.path.join(pack_directory, "icon.png"))
724
+ readme = load_base64_encoded_text(os.path.join(pack_directory, "README.md"))
725
+ pack_config = load_json_config(os.path.join(pack_directory, "pack_conf.json"))
726
+
727
+ # Check existing packs and versions
728
+ pack_id, existing_versions = find_existing_pack(
729
+ agent_conf["context"]["local"]["url"], pack_name, config=config
730
+ )
731
+
732
+ if pack_id:
733
+ new_version_entry = handle_version_matching(existing_versions, pack_version)
734
+ if not new_version_entry:
735
+ # Try to load compatible_sources from properties.yaml (optional)
736
+ compat = (
737
+ pack_properties.get("compatible_sources")
738
+ if isinstance(pack_properties, dict)
739
+ else None
740
+ )
741
+ update_pack_metadata(
742
+ agent_conf["context"]["local"]["url"],
743
+ pack_id,
744
+ pack_icon,
745
+ pack_config,
746
+ pack_type,
747
+ pack_description,
748
+ pack_url,
749
+ pack_version,
750
+ pack_visibility,
751
+ readme,
752
+ compatible_sources=compat,
753
+ config=config,
754
+ )
755
+ logger.success(
756
+ "Pack metadata updated successfully ! \nIf you wanted to upload a new pack version, you must change the pack [version] attribute in properties.yaml"
757
+ )
758
+ else:
759
+ publish_new_pack_version(
760
+ agent_conf["context"]["local"]["url"],
761
+ pack_id,
762
+ pack_version,
763
+ agent_conf["registries"][0]["id"],
764
+ pack_name,
765
+ source_dir=pack_directory,
766
+ config=config,
767
+ )
768
+ else:
769
+ create_new_pack(
770
+ agent_conf["context"]["local"]["url"],
771
+ agent_conf["registries"][0]["id"],
772
+ pack_name,
773
+ pack_icon,
774
+ pack_config,
775
+ pack_type,
776
+ pack_description,
777
+ pack_url,
778
+ pack_version,
779
+ pack_visibility,
780
+ readme,
781
+ source_dir=pack_directory,
782
+ config=config,
783
+ )
784
+ logger.success("New pack created successfully!")
785
+
786
+
692
787
  @pack.command()
693
788
  @click.option("-n", "--name", help="Name of the package", envvar="QALITA_PACK_NAME")
694
789
  @pass_config
695
790
  def push(config, name):
696
- """Pushes a package to the Qalita Platform"""
791
+ """Pushes a package to the QALITA Platform"""
697
792
 
698
793
  try:
699
794
  name = check_name(name)
@@ -709,7 +804,7 @@ def push(config, name):
709
804
  return
710
805
 
711
806
  logger.info("---------------- Pack Push ----------------")
712
- logger.info(f"Pushing pack '{name}' to Qalita Platform...")
807
+ logger.info(f"Pushing pack '{name}' to QALITA Platform...")
713
808
 
714
809
  pack_directory = f"./{name}_pack" if not name.endswith("_pack") else f"./{name}"
715
810
 
@@ -725,78 +820,14 @@ def push(config, name):
725
820
  logger.error("Failed to load agent configuration.")
726
821
  return
727
822
 
728
- # Extract pack details
729
- pack_name = pack_properties.get("name")
730
- pack_version = pack_properties.get("version")
731
- pack_description = pack_properties.get("description", "")
732
- pack_url = pack_properties.get("url", "")
733
- pack_type = pack_properties.get("type", "")
734
- pack_visibility = pack_properties.get("visibility", "private")
735
-
736
- # Handle pack icon
737
- pack_icon = load_base64_encoded_image(f"{pack_directory}/icon.png")
738
-
739
- # Handle README file
740
- readme = load_base64_encoded_text(f"{pack_directory}/README.md")
741
-
742
- # Load pack config
743
- pack_config = load_json_config(f"{pack_directory}/pack_conf.json")
744
-
745
- # Check existing packs and versions
746
- pack_id, existing_versions = find_existing_pack(
747
- agent_conf["context"]["local"]["url"], pack_name, config=config
823
+ # Shared push routine
824
+ _push_with_context(
825
+ agent_conf,
826
+ pack_properties,
827
+ os.path.abspath(pack_directory),
828
+ config,
748
829
  )
749
830
 
750
- if pack_id:
751
- # Handle version matching and decide whether to add a new asset or update metadata
752
- new_version_entry = handle_version_matching(existing_versions, pack_version)
753
-
754
- if not new_version_entry:
755
- # Try to load compatible_sources from properties.yaml (optional)
756
- compat = pack_properties.get("compatible_sources") if isinstance(pack_properties, dict) else None
757
- update_pack_metadata(
758
- agent_conf["context"]["local"]["url"],
759
- pack_id,
760
- pack_icon,
761
- pack_config,
762
- pack_type,
763
- pack_description,
764
- pack_url,
765
- pack_version,
766
- pack_visibility,
767
- readme,
768
- compatible_sources=compat,
769
- config=config,
770
- )
771
- logger.success("Pack metadata updated successfully ! \nIf you wanted to upload a new pack version, you must change the pack [version] attribute in properties.yaml")
772
- else:
773
- publish_new_pack_version(
774
- agent_conf["context"]["local"]["url"],
775
- pack_id,
776
- pack_version,
777
- agent_conf["registries"][0]["id"],
778
- pack_name,
779
- source_dir=os.path.abspath(pack_directory),
780
- config=config,
781
- )
782
- else:
783
- create_new_pack(
784
- agent_conf["context"]["local"]["url"],
785
- agent_conf["registries"][0]["id"],
786
- pack_name,
787
- pack_icon,
788
- pack_config,
789
- pack_type,
790
- pack_description,
791
- pack_url,
792
- pack_version,
793
- pack_visibility,
794
- readme,
795
- source_dir=os.path.abspath(pack_directory),
796
- config=config,
797
- )
798
- logger.success("New pack created successfully!")
799
-
800
831
  logger.info("Pack pushed successfully.")
801
832
 
802
833
  except Exception as e:
@@ -842,72 +873,14 @@ def push_from_directory(config, pack_directory):
842
873
  logger.error(msg)
843
874
  return False, msg
844
875
 
845
- # Extract pack details
846
- pack_name = pack_properties.get("name")
847
- pack_version = pack_properties.get("version")
848
- pack_description = pack_properties.get("description", "")
849
- pack_url = pack_properties.get("url", "")
850
- pack_type = pack_properties.get("type", "")
851
- pack_visibility = pack_properties.get("visibility", "private")
852
-
853
- # Handle pack icon and README
854
- pack_icon = load_base64_encoded_image(os.path.join(pack_directory, "icon.png"))
855
- readme = load_base64_encoded_text(os.path.join(pack_directory, "README.md"))
856
- pack_config = load_json_config(os.path.join(pack_directory, "pack_conf.json"))
857
-
858
- # Check existing packs and versions
859
- pack_id, existing_versions = find_existing_pack(
860
- agent_conf["context"]["local"]["url"], pack_name, config=config
876
+ # Shared push routine
877
+ _push_with_context(
878
+ agent_conf,
879
+ pack_properties,
880
+ pack_directory,
881
+ config,
861
882
  )
862
883
 
863
- if pack_id:
864
- new_version_entry = handle_version_matching(existing_versions, pack_version)
865
- if not new_version_entry:
866
- # Try to load compatible_sources from properties.yaml (optional)
867
- compat = pack_properties.get("compatible_sources") if isinstance(pack_properties, dict) else None
868
- update_pack_metadata(
869
- agent_conf["context"]["local"]["url"],
870
- pack_id,
871
- pack_icon,
872
- pack_config,
873
- pack_type,
874
- pack_description,
875
- pack_url,
876
- pack_version,
877
- pack_visibility,
878
- readme,
879
- compatible_sources=compat,
880
- config=config,
881
- )
882
- logger.success("Pack metadata updated successfully ! \nIf you wanted to upload a new pack version, you must change the pack [version] attribute in properties.yaml")
883
- else:
884
- publish_new_pack_version(
885
- agent_conf["context"]["local"]["url"],
886
- pack_id,
887
- pack_version,
888
- agent_conf["registries"][0]["id"],
889
- pack_name,
890
- source_dir=pack_directory,
891
- config=config,
892
- )
893
- else:
894
- create_new_pack(
895
- agent_conf["context"]["local"]["url"],
896
- agent_conf["registries"][0]["id"],
897
- pack_name,
898
- pack_icon,
899
- pack_config,
900
- pack_type,
901
- pack_description,
902
- pack_url,
903
- pack_version,
904
- pack_visibility,
905
- readme,
906
- source_dir=pack_directory,
907
- config=config,
908
- )
909
- logger.success("New pack created successfully!")
910
-
911
884
  logger.info("Pack pushed successfully.")
912
885
  return True, "Pack pushed successfully."
913
886
  except Exception as e:
@@ -920,7 +893,7 @@ def push_from_directory(config, pack_directory):
920
893
  @click.option(
921
894
  "-n",
922
895
  "--name",
923
- help="The name of the package, it will be used to identify the package in the Qalita platform",
896
+ help="The name of the package, it will be used to identify the package in the QALITA platform",
924
897
  envvar="QALITA_PACK_NAME",
925
898
  )
926
899
  def run(name):
@@ -969,7 +942,7 @@ def run(name):
969
942
  @click.option(
970
943
  "-n",
971
944
  "--name",
972
- help="The name of the package, it will be used to identify the package in the Qalita platform",
945
+ help="The name of the package, it will be used to identify the package in the QALITA platform",
973
946
  envvar="QALITA_PACK_NAME",
974
947
  )
975
948
  @pass_config
qalita/commands/source.py CHANGED
@@ -15,7 +15,7 @@ from qalita.internal.request import send_api_request
15
15
  @click.option("-s", "--source", type=int, help="Source ID")
16
16
  @click.pass_context
17
17
  def source(ctx, source):
18
- """Manage Qalita Platform Sources"""
18
+ """Manage QALITA Platform Sources"""
19
19
  ctx.ensure_object(dict)
20
20
  ctx.obj["SOURCE"] = source
21
21
 
@@ -264,13 +264,13 @@ def validate():
264
264
  )
265
265
  @pass_config
266
266
  def push(config, skip_validate):
267
- """Publish a source to the Qalita Platform"""
267
+ """Publish a source to the QALITA Platform"""
268
268
  if not skip_validate:
269
269
  validate_source()
270
270
  else:
271
271
  logger.warning("Skipping source validation as requested.")
272
272
  logger.info("------------- Source Publishing -------------")
273
- logger.info("Publishing sources to the Qalita Platform...")
273
+ logger.info("Publishing sources to the QALITA Platform...")
274
274
 
275
275
  invalid_count = 0 # To count failed publishing sources
276
276
  agent_conf = config.load_agent_config()
@@ -638,7 +638,7 @@ def push_single_programmatic(config, source_name: str, approve_public: bool = Fa
638
638
  @source.command()
639
639
  @pass_config
640
640
  def add(config):
641
- """Add a source to the local Qalita Config"""
641
+ """Add a source to the local QALITA Config"""
642
642
 
643
643
  # initialize the source dict
644
644
  source = {}
qalita/internal/utils.py CHANGED
@@ -14,7 +14,7 @@ logger = init_logging()
14
14
 
15
15
 
16
16
  def get_version():
17
- return "2.2.9"
17
+ return "2.3.1"
18
18
 
19
19
 
20
20
  def make_tarfile(output_filename, source_dir):
qalita/web/app.py CHANGED
@@ -7,7 +7,7 @@ from flask import Flask
7
7
  from waitress import serve
8
8
 
9
9
  def create_app(config_obj) -> Flask:
10
- """Application factory for the Qalita CLI UI."""
10
+ """Application factory for the QALITA CLI UI."""
11
11
  app = Flask(
12
12
  __name__,
13
13
  static_folder=os.path.join(os.path.dirname(__file__), "public"),
@@ -36,5 +36,5 @@ def create_app(config_obj) -> Flask:
36
36
  def run_dashboard_ui(config_obj, host: str = "localhost", port: int = 7070):
37
37
  app = create_app(config_obj)
38
38
  url = f"http://{host}:{port}"
39
- print(f"Qalita CLI UI is running. Open {url}")
39
+ print(f"QALITA CLI UI is running. Open {url}")
40
40
  serve(app, host=host, port=port)
@@ -375,7 +375,7 @@ def open_agent_run(run_name: str):
375
375
  <div class="footer">
376
376
  <div class="inner">
377
377
  <div>
378
- <span>&copy; QALITA</span> — Qalita CLI
378
+ <span>&copy; QALITA</span> — QALITA CLI
379
379
  </div>
380
380
  <div>
381
381
  <span id="cli_version"></span>
@@ -411,7 +411,7 @@ def open_agent_run(run_name: str):
411
411
  <div class="footer">
412
412
  <div class="inner">
413
413
  <div>
414
- <span>&copy; QALITA</span> — Qalita CLI
414
+ <span>&copy; QALITA</span> — QALITA CLI
415
415
  </div>
416
416
  <div>
417
417
  <span id="cli_version"></span>
@@ -451,7 +451,7 @@ def open_agent_run(run_name: str):
451
451
  <div class="footer">
452
452
  <div class="inner">
453
453
  <div>
454
- <span>&copy; QALITA</span> — Qalita CLI
454
+ <span>&copy; QALITA</span> — QALITA CLI
455
455
  </div>
456
456
  <div>
457
457
  <span id="cli_version"></span>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - Dashboard</title>
7
+ <title>QALITA CLI - Dashboard</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -88,10 +88,10 @@
88
88
  <h3>Documentation</h3>
89
89
  </div>
90
90
  </div>
91
- <p>Learn how to use Qalita and its features.</p>
91
+ <p>Learn how to use QALITA and its features.</p>
92
92
  <div>
93
93
  <a href="https://doc.qalita.io" target="_blank" rel="noopener noreferrer"><button class="btn black-white"
94
- type="button" style="width:100%;padding:12px 16px;">Qalita Docs</button></a>
94
+ type="button" style="width:100%;padding:12px 16px;">QALITA Docs</button></a>
95
95
  </div>
96
96
  </div>
97
97
  </div>
@@ -322,7 +322,7 @@
322
322
  <div class="footer">
323
323
  <div class="inner">
324
324
  <div>
325
- <span>&copy; QALITA</span> — Qalita CLI
325
+ <span>&copy; QALITA</span> — QALITA CLI
326
326
  </div>
327
327
  <div>
328
328
  <span id="cli_version"></span>
@@ -2,7 +2,7 @@
2
2
  <div class="brand">
3
3
  <div class="left">
4
4
  <a href="/" style="display:flex;align-items:center;gap:8px;text-decoration:none;color:inherit;">
5
- <img src="/static/logo-no-slogan.png" alt="Qalita" />
5
+ <img src="/static/logo-no-slogan.png" alt="QALITA" />
6
6
  <span>CLI</span>
7
7
  </a>
8
8
  </div>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - Source added</title>
7
+ <title>QALITA CLI - Source added</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -36,7 +36,7 @@
36
36
  <div class="footer">
37
37
  <div class="inner">
38
38
  <div>
39
- <span>&copy; QALITA</span> — Qalita CLI
39
+ <span>&copy; QALITA</span> — QALITA CLI
40
40
  </div>
41
41
  <div>
42
42
  <span id="cli_version"></span>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - {{ title }}</title>
7
+ <title>QALITA CLI - {{ title }}</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -393,7 +393,7 @@
393
393
  <div class="footer">
394
394
  <div class="inner">
395
395
  <div>
396
- <span>&copy; QALITA</span> — Qalita CLI
396
+ <span>&copy; QALITA</span> — QALITA CLI
397
397
  </div>
398
398
  <div>
399
399
  <span id="cli_version"></span>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - Select source</title>
7
+ <title>QALITA CLI - Select source</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
  {% endfor %}
102
102
  <div class="actions" style="margin-top:16px;">
103
- <a class="btn" href="mailto:contact@qalita.io?subject=Suggest%20a%20new%20source%20type&body=Hi%20Qalita%20team%2C%0A%0AI%27d%20like%20to%20suggest%20support%20for%20this%20source%20type%3A%20%5Bplease%20describe%5D%0A%0AThanks!">Suggest a new source type</a>
103
+ <a class="btn" href="mailto:contact@qalita.io?subject=Suggest%20a%20new%20source%20type&body=Hi%20QALITA%20team%2C%0A%0AI%27d%20like%20to%20suggest%20support%20for%20this%20source%20type%3A%20%5Bplease%20describe%5D%0A%0AThanks!">Suggest a new source type</a>
104
104
  <a class="btn secondary" href="/">Cancel</a>
105
105
  </div>
106
106
  </div>
@@ -108,7 +108,7 @@
108
108
  <div class="footer">
109
109
  <div class="inner">
110
110
  <div>
111
- <span>&copy; QALITA</span> — Qalita CLI
111
+ <span>&copy; QALITA</span> — QALITA CLI
112
112
  </div>
113
113
  <div>
114
114
  <span id="cli_version"></span>
@@ -18,7 +18,7 @@
18
18
  <div>
19
19
  <div class="studio-setup-title">Setup platform</div>
20
20
  <div class="studio-setup-text">
21
- Your current context doesn't provide Qalita platform credentials.<br><br>
21
+ Your current context doesn't provide QALITA platform credentials.<br><br>
22
22
  To use contextual data quality metadata, configure your Platform endpoint and token.
23
23
  </div>
24
24
  <div class="studio-setup-actions">
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita Studio</title>
7
+ <title>QALITA Studio</title>
8
8
  <link rel="icon" href="/static/studio.png" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  <link rel="stylesheet" href="/static/studio.css" />
@@ -2,7 +2,7 @@
2
2
  <div class="brand" style="max-width:100%; padding: 6px 23px;">
3
3
  <div class="left">
4
4
  <a href="/" style="display:flex;align-items:flex-end;gap:5px;text-decoration:none;color:inherit;">
5
- <img src="/static/logo-white-no-slogan.svg" alt="Logo Qalita" width="25" height="25"
5
+ <img src="/static/logo-white-no-slogan.svg" alt="Logo QALITA" width="25" height="25"
6
6
  style="height:25px;" />
7
7
  <span style="font-size: 20px; font-weight: 300; color: #ffffff;">Studio</span>
8
8
  <span class="badge"
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: qalita
3
- Version: 2.2.9
3
+ Version: 2.3.1
4
4
  Summary: QALITA Platform Command Line Interface
5
+ License-File: LICENSE
5
6
  Author: QALITA SAS
6
7
  Author-email: contact@qalita.io
7
8
  Requires-Python: >=3.10,<4.0
@@ -17,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
17
18
  Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
20
22
  Classifier: Topic :: Software Development :: Quality Assurance
21
23
  Requires-Dist: azure-storage-blob (>=12.19.1,<13.0.0)
22
24
  Requires-Dist: boto3 (>=1.34.81,<2.0.0)
@@ -1,18 +1,18 @@
1
1
  qalita/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- qalita/__main__.py,sha256=NzpokI5DXvS9GY4fxZ_evNZ_6vkfT6Ni9nvnw11_Kbw,2522
2
+ qalita/__main__.py,sha256=mUdL2kKMsr47UP2GIJwBNcDR4yZv-ApcSH-tfcRL03g,2518
3
3
  qalita/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- qalita/commands/agent.py,sha256=wQ3h6THv8W2TvLraeW8xZ1S8sOua-vJaPhA40oISZls,47113
5
- qalita/commands/pack.py,sha256=SPBMpbSCnwmXsCRwZGK_-q2jkZL0DBsDMMtTpVTox8k,39029
6
- qalita/commands/source.py,sha256=q1peZCzd6lX3b3bAJ4M8Te22tjji3qXQ-fyn-JQ3RYM,30945
4
+ qalita/commands/agent.py,sha256=t4SzLnAOsthAeNU2DCmWEkOexKQb2QQ1xhEzazyMdeM,50660
5
+ qalita/commands/pack.py,sha256=Eu1h-JJEtUBqr6OKPnwE8EuJOQcHpJtZBvKe0XFQaDg,37224
6
+ qalita/commands/source.py,sha256=ObRD2CcDynGbMrmj__FhWvPvR0H6HEn5QSLNR8awQUQ,30945
7
7
  qalita/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  qalita/internal/config.py,sha256=P9UU3BH-CIH68-qZjmnk8juzZZ5HJ701hrY6EvrPFOA,4081
9
9
  qalita/internal/error_patterns.py,sha256=QDFNZEoTmqVOHkiGFljstY6VOhux7d4p8FIL3pKzwtQ,1447
10
10
  qalita/internal/logger.py,sha256=4xWy2BZII89nUw4tKrLXFPOlVGONm8KUBgzX2XZ3u7g,1868
11
11
  qalita/internal/request.py,sha256=s-rE9kKRhV9IEveclB2YjAY8FRevKb6qjblM8-PbV20,6209
12
- qalita/internal/utils.py,sha256=6pM6p90mfvTcYu6czWyVeLFiv_tgrUuOmDFugtSCOlU,5746
12
+ qalita/internal/utils.py,sha256=UIXH_BS2ZiP0crARISYHuJMnvajaTSHchpXoP_sZXXs,5746
13
13
  qalita/web/__init__.py,sha256=NRcQjZSizkqN0a-LutsN7X9LBQ8MhyazXBSuqzUEmXE,62
14
- qalita/web/app.py,sha256=4srnqeTYsn8PAGcnDDTyjiKcwETNpzlAr20U138LXC8,1323
15
- qalita/web/blueprints/agents.py,sha256=fmOnBRZVvVVMzJtYzWvSP1Q_IcIj4qRDN2n6NrK1K-g,17367
14
+ qalita/web/app.py,sha256=92M2K7vxDIYaI81D-zvdj4VfCsaTTDs6KJZu6dy5s6U,1323
15
+ qalita/web/blueprints/agents.py,sha256=q_SqdSzzHMsstSzEjHGtq75jFt3wQ6p3atjOSzKgiUw,17367
16
16
  qalita/web/blueprints/context.py,sha256=wIcfBtu3l9qwMe5IPa0VQShELsY3ENPt4Q9OO3L8EsE,6451
17
17
  qalita/web/blueprints/dashboard.py,sha256=R_1_oAM-Ol0kx5GZkKTaB8c5vjdz-iIK-SGu2RIHE_w,7454
18
18
  qalita/web/blueprints/helpers.py,sha256=Hnulyrd-YrHoz2LtGCKCq9MgUeoNoNECTyGDap2DFYI,12724
@@ -84,18 +84,18 @@ qalita/web/public/studio-logo.svg,sha256=NCFJM0rw6XxKcjCJ7bzih1aGudHAjYB1bWUXcF9
84
84
  qalita/web/public/studio.css,sha256=bHWyfPUbtYU8jDUKepNY6K0Am4qeG7ewQ_nnKnh4M6M,5060
85
85
  qalita/web/public/studio.png,sha256=9kLYN5c8nqK7TKT8UHjfPSKBI60zDFsIcYFbWw3cVfY,461702
86
86
  qalita/web/public/styles.css,sha256=xmy_c0fmUKBEgPF2L_qrQ2eC1erw-zcAndpMQMjHJbM,10486
87
- qalita/web/templates/dashboard.html,sha256=I3oQz8nlHCAvoH4cZdfZESig_bWeESuzWkY6R77gJ40,17045
88
- qalita/web/templates/navbar.html,sha256=j3w3t60Qtg3D53EQ9RHXcEz226Sorkd4SNNJ795q9po,1916
89
- qalita/web/templates/sources/added.html,sha256=kQ37fVzv4mjLDQmJwBhZ81zf-89ZYXNsKz6Vglmr5Rs,1938
90
- qalita/web/templates/sources/edit.html,sha256=LzsgUa6NWAHfF7lOB7utbFT3hw_9brEQKZiK0R2J-TI,19723
91
- qalita/web/templates/sources/select-source.html,sha256=2lEbV2XLybv9wvolEblSC12PAlth-9ms87Xz9X0wwxI,6179
87
+ qalita/web/templates/dashboard.html,sha256=pAuWMRaSjInqNitecf4mkI2eX-UeqpC37Jbc_tGCeuk,17045
88
+ qalita/web/templates/navbar.html,sha256=W0eBuH_vrs4GyxkSzxsppOchkgtvnKM-uc07mP5mkdA,1916
89
+ qalita/web/templates/sources/added.html,sha256=uTu5jofRi9t9pvWRnc9AtD9B396DvnqDo6HoajVU3DA,1938
90
+ qalita/web/templates/sources/edit.html,sha256=DM5i3Y__MMG0PzJm--OXQSo5PbI4fcRo4UYHm2qGMxA,19723
91
+ qalita/web/templates/sources/select-source.html,sha256=dBTEpCu8KTjmiOG_gBIUFEdGAnGmnV8EFQid7chsVA0,6179
92
92
  qalita/web/templates/studio/agent-panel.html,sha256=cc_zcUgkQHwxBz2_Nkvw3BCO3L_zhQDcrnp0woMwI_A,38790
93
- qalita/web/templates/studio/context-panel.html,sha256=jcR3Bbm27DqrvOLXUuHnP59Lhc6YxcnwNzock5Sdfw0,15312
94
- qalita/web/templates/studio/index.html,sha256=f1CaIa0azGXLGHDMMXo5_oapkZQoJ8XrGBzKgtCqNHc,2823
95
- qalita/web/templates/studio/navbar.html,sha256=-iGwG-FLLvgH3E_QuuttkYgqxDSYcrxZczEERVBHn7s,746
93
+ qalita/web/templates/studio/context-panel.html,sha256=M8yfYcJQ_2WSwnOLlCTQETzctzL-rjlKLF7PlAUV0PU,15312
94
+ qalita/web/templates/studio/index.html,sha256=NI7zF-4cHQ3id-a_R3GNQ8gQ2Bw4A6liyEZ53AO0QOU,2823
95
+ qalita/web/templates/studio/navbar.html,sha256=IQZ7TFOXv3r5yZmP9f1v7BMUCQU8mOajMV82UPeY3cg,746
96
96
  qalita/web/templates/studio/view-panel.html,sha256=JREfFIabpuAZctAzbE_mT_ZDk65MBWevjRNxQUrO8Pw,25198
97
- qalita-2.2.9.dist-info/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
98
- qalita-2.2.9.dist-info/METADATA,sha256=ZAJ-oAEr0kTHwn9m0p63Afud2a6R7Y-0X8zo6mH1a3Q,2339
99
- qalita-2.2.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
100
- qalita-2.2.9.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
101
- qalita-2.2.9.dist-info/RECORD,,
97
+ qalita-2.3.1.dist-info/METADATA,sha256=q5Rw3NHpPohDXswrcEnGPTXDc5-GwrtbCMvlOtx1_EY,2412
98
+ qalita-2.3.1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
99
+ qalita-2.3.1.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
100
+ qalita-2.3.1.dist-info/licenses/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
101
+ qalita-2.3.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any