codegraphcontext 0.4.10__py3-none-any.whl → 0.4.11__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.
@@ -30,6 +30,7 @@ DEFAULT_CONFIG = {
30
30
  "DEFAULT_DATABASE": "falkordb",
31
31
  "FALKORDB_PATH": str(CONFIG_DIR / "global" / "db" / "falkordb"),
32
32
  "FALKORDB_SOCKET_PATH": str(CONFIG_DIR / "global" / "db" / "falkordb.sock"),
33
+ "LADYBUGDB_PATH": str(CONFIG_DIR / "global" / "db" / "ladybugdb"),
33
34
  "INDEX_VARIABLES": "true",
34
35
  "ALLOW_DB_DELETION": "false",
35
36
  "DEBUG_LOGS": "false",
@@ -65,9 +66,10 @@ DEFAULT_CONFIG = {
65
66
 
66
67
  # Configuration key descriptions
67
68
  CONFIG_DESCRIPTIONS = {
68
- "DEFAULT_DATABASE": "Default database backend (neo4j|falkordb|kuzudb|nornic)",
69
+ "DEFAULT_DATABASE": "Default database backend (neo4j|falkordb|falkordb-remote|kuzudb|nornic|ladybugdb)",
69
70
  "FALKORDB_PATH": "Path to FalkorDB database file",
70
71
  "FALKORDB_SOCKET_PATH": "Path to FalkorDB Unix socket",
72
+ "LADYBUGDB_PATH": "Path to LadybugDB database directory",
71
73
  "INDEX_VARIABLES": "Index variable nodes in the graph (lighter graph if false)",
72
74
  "ALLOW_DB_DELETION": "Allow full database deletion commands",
73
75
  "DEBUG_LOGS": "Enable debug logging (for development/troubleshooting)",
@@ -125,7 +127,7 @@ CONFIG_DESCRIPTIONS = {
125
127
 
126
128
  # Valid values for each config key
127
129
  CONFIG_VALIDATORS = {
128
- "DEFAULT_DATABASE": ["neo4j", "falkordb", "falkordb-remote", "kuzudb", "nornic"],
130
+ "DEFAULT_DATABASE": ["neo4j", "falkordb", "falkordb-remote", "kuzudb", "nornic", "ladybugdb"],
129
131
  "INDEX_VARIABLES": ["true", "false"],
130
132
  "ALLOW_DB_DELETION": ["true", "false"],
131
133
  "DEBUG_LOGS": ["true", "false"],
@@ -445,7 +447,7 @@ def validate_config_value(key: str, value: str) -> tuple[bool, Optional[str]]:
445
447
  except Exception as e:
446
448
  return False, f"Cannot create log directory: {e}"
447
449
 
448
- if key in ("FALKORDB_PATH", "FALKORDB_SOCKET_PATH"):
450
+ if key in ("FALKORDB_PATH", "FALKORDB_SOCKET_PATH", "LADYBUGDB_PATH"):
449
451
  # Validate path is writable
450
452
  db_path = Path(normalize_config_path(value, absolute=True))
451
453
  try:
@@ -280,8 +280,15 @@ class CGCBundle:
280
280
  if hasattr(node, attr):
281
281
  repo[attr] = getattr(node, attr)
282
282
 
283
- metadata["repo"] = repo.get('name', str(repo_path))
284
- metadata["repo_path"] = repo.get('path')
283
+ metadata["repo"] = repo.get('name', str(repo_path.name if repo_path else 'unknown'))
284
+ # Clean up absolute path prefix to keep it relative
285
+ meta_path = repo.get('path', '')
286
+ if repo_path and meta_path.startswith(str(repo_path.resolve())):
287
+ repo_str = str(repo_path.resolve())
288
+ rel = meta_path[len(repo_str):].lstrip('/')
289
+ metadata["repo_path"] = "./" + rel if rel else "."
290
+ else:
291
+ metadata["repo_path"] = meta_path
285
292
  metadata["is_dependency"] = repo.get('is_dependency', False)
286
293
  else:
287
294
  # All repositories
@@ -410,6 +417,14 @@ class CGCBundle:
410
417
  elif hasattr(node, 'properties'):
411
418
  node_dict = dict(node.properties)
412
419
 
420
+ # Clean up absolute path prefix to keep it relative
421
+ if repo_path:
422
+ repo_str = str(repo_path.resolve())
423
+ for key, val in list(node_dict.items()):
424
+ if isinstance(val, str) and val.startswith(repo_str):
425
+ rel = val[len(repo_str):].lstrip('/')
426
+ node_dict[key] = "./" + rel if rel else "."
427
+
413
428
  node_dict['_labels'] = labels
414
429
 
415
430
  # Store internal ID for reference
@@ -480,6 +495,14 @@ class CGCBundle:
480
495
  elif hasattr(rel, 'properties'):
481
496
  rel_props = dict(rel.properties)
482
497
 
498
+ # Clean up absolute path prefix inside edge properties
499
+ if repo_path:
500
+ repo_str = str(repo_path.resolve())
501
+ for key, val in list(rel_props.items()):
502
+ if isinstance(val, str) and val.startswith(repo_str):
503
+ rel = val[len(repo_str):].lstrip('/')
504
+ rel_props[key] = "./" + rel if rel else "."
505
+
483
506
  # Create edge representation
484
507
  edge_dict = {
485
508
  'from': from_id,
@@ -800,7 +800,11 @@ def resolve_function_call(
800
800
  )
801
801
  for cand in filtered_candidates:
802
802
  cand_arity = function_arg_count(cand)
803
- if cand_arity is None or not any(function_arg_count(existing) == cand_arity for existing in method_candidates_by_hierarchy):
803
+ if cand_arity is None or not any(
804
+ function_arg_count(existing) == cand_arity
805
+ and function_arg_types(existing) == function_arg_types(cand)
806
+ for existing in method_candidates_by_hierarchy
807
+ ):
804
808
  method_candidates_by_hierarchy.append(cand)
805
809
 
806
810
  if not fallback_method_owner_path and method_name in class_method_names.get(current, set()):
@@ -817,7 +821,11 @@ def resolve_function_call(
817
821
  if extension_candidates:
818
822
  for cand in extension_candidates:
819
823
  cand_arity = function_arg_count(cand)
820
- if cand_arity is None or not any(function_arg_count(existing) == cand_arity for existing in extension_candidates_by_hierarchy):
824
+ if cand_arity is None or not any(
825
+ function_arg_count(existing) == cand_arity
826
+ and function_arg_types(existing) == function_arg_types(cand)
827
+ for existing in extension_candidates_by_hierarchy
828
+ ):
821
829
  extension_candidates_by_hierarchy.append(cand)
822
830
 
823
831
  for base_name in global_class_bases.get(current, []):
@@ -962,7 +970,11 @@ def resolve_function_call(
962
970
  resolved_called_context,
963
971
  ) = method_target_for_type(receiver_type, called_name)
964
972
  if resolved_path:
965
- resolution_tier = 4
973
+ fqn = (local_imports.get(receiver_type) if local_imports else None) or (receiver_type if "." in receiver_type else None)
974
+ if fqn and len(imports_map.get(fqn, [])) == 1:
975
+ resolution_tier = 3
976
+ else:
977
+ resolution_tier = 4
966
978
  else:
967
979
  receiver_resolution_failed = True
968
980
 
@@ -994,7 +1006,11 @@ def resolve_function_call(
994
1006
  resolved_called_context,
995
1007
  ) = method_target_for_type(implicit_type, called_name)
996
1008
  if resolved_path:
997
- resolution_tier = 4
1009
+ fqn = (local_imports.get(call["implicit_receiver_type"]) if local_imports else None) or (implicit_type if "." in implicit_type else None)
1010
+ if fqn and len(imports_map.get(fqn, [])) == 1:
1011
+ resolution_tier = 3
1012
+ else:
1013
+ resolution_tier = 4
998
1014
  elif unresolved_overloaded_callable_reference or unresolved_overloaded_method:
999
1015
  record_skip(
1000
1016
  "unresolved_overloaded_callable_reference"
@@ -1064,7 +1080,23 @@ def resolve_function_call(
1064
1080
  possible_paths = imports_map.get(receiver_type_for_path, []) if receiver_type_for_path else []
1065
1081
  if possible_paths:
1066
1082
  resolved_path = possible_paths[0]
1067
- resolution_tier = 4
1083
+ raw_receiver_type = (
1084
+ extension_receiver_type
1085
+ or call.get("inferred_obj_type")
1086
+ or call.get("implicit_receiver_type")
1087
+ )
1088
+ fqn = None
1089
+ if raw_receiver_type:
1090
+ raw_receiver_type = strip_type_modifiers(raw_receiver_type)
1091
+ if local_imports and raw_receiver_type in local_imports:
1092
+ fqn = local_imports[raw_receiver_type]
1093
+ elif "." in raw_receiver_type:
1094
+ fqn = raw_receiver_type
1095
+
1096
+ if fqn and len(imports_map.get(fqn, [])) == 1:
1097
+ resolution_tier = 3
1098
+ else:
1099
+ resolution_tier = 4
1068
1100
  receiver_resolution_failed = False
1069
1101
 
1070
1102
  if not resolved_path and receiver_resolution_failed:
@@ -1620,7 +1652,10 @@ def build_function_call_groups(
1620
1652
  and class_data.get("end_line") is not None
1621
1653
  and class_data["line_number"] <= line_number <= class_data["end_line"]
1622
1654
  ]
1623
- if not companion_objects or func.get("context") not in {
1655
+ func_context = func.get("context")
1656
+ if isinstance(func_context, tuple) and len(func_context) > 0:
1657
+ func_context = func_context[0]
1658
+ if not companion_objects or func_context not in {
1624
1659
  companion.get("name") for companion in companion_objects
1625
1660
  }:
1626
1661
  return []
@@ -1648,6 +1683,8 @@ def build_function_call_groups(
1648
1683
  package_name: Optional[str],
1649
1684
  ) -> List[str]:
1650
1685
  context = func.get("context") or func.get("class_context")
1686
+ if isinstance(context, tuple) and len(context) > 0:
1687
+ context = context[0]
1651
1688
  context_names = list(type_keys_for_maps(context, package_name=package_name))
1652
1689
  context_names.extend(companion_owner_context_names(fd, func, package_name))
1653
1690
  return list(dict.fromkeys(context_names))