diff --git a/graphify/extract.py b/graphify/extract.py index 20e697e9..c611de5b 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -1017,6 +1017,106 @@ def _swift_property_type_node(property_node): return None +# ── C / C++ type-ref helpers ───────────────────────────────────────────────── + +_C_PRIMITIVE_TYPE_NODES = frozenset({ + "primitive_type", "sized_type_specifier", "auto", "placeholder_type_specifier", +}) + + +def _c_collect_type_refs(node, source: bytes, generic: bool, out: list[tuple[str, str]]) -> None: + """Walk a C type expression; append (name, role) tuples for user-defined types. + Skips primitive types and qualifiers; recognises type_identifier.""" + if node is None or node.type in _C_PRIMITIVE_TYPE_NODES: + return + t = node.type + if t == "type_identifier": + text = _read_text(node, source) + if text: + out.append((text, "generic_arg" if generic else "type")) + return + if t in ("pointer_declarator", "reference_declarator", "array_declarator", + "type_qualifier", "type_descriptor", "abstract_pointer_declarator", + "abstract_reference_declarator", "abstract_array_declarator"): + for c in node.children: + if c.is_named: + _c_collect_type_refs(c, source, generic, out) + + +def _cpp_collect_type_refs(node, source: bytes, generic: bool, out: list[tuple[str, str]]) -> None: + """Walk a C++ type expression; append (name, role) tuples. + Resolves qualified_identifier tails (std::string → string) and template_type + base + arguments (std::vector → vector + HttpClient as generic_arg).""" + if node is None or node.type in _C_PRIMITIVE_TYPE_NODES: + return + t = node.type + if t == "type_identifier": + text = _read_text(node, source) + if text: + out.append((text, "generic_arg" if generic else "type")) + return + if t == "qualified_identifier": + name_node = node.child_by_field_name("name") + if name_node is not None: + _cpp_collect_type_refs(name_node, source, generic, out) + return + if t == "template_type": + name_node = node.child_by_field_name("name") + if name_node is not None: + text = _read_text(name_node, source) + if text: + out.append((text, "generic_arg" if generic else "type")) + args_node = node.child_by_field_name("arguments") + if args_node is not None: + for c in args_node.children: + if c.is_named: + _cpp_collect_type_refs(c, source, True, out) + return + if t in ("type_descriptor", "pointer_declarator", "reference_declarator", + "array_declarator", "type_qualifier", "abstract_pointer_declarator", + "abstract_reference_declarator", "abstract_array_declarator"): + for c in node.children: + if c.is_named: + _cpp_collect_type_refs(c, source, generic, out) + + +# ── Scala type-ref helpers ─────────────────────────────────────────────────── + +def _scala_collect_type_refs(node, source: bytes, generic: bool, out: list[tuple[str, str]]) -> None: + """Walk a Scala type expression; append (name, role) tuples. + Handles type_identifier, generic_type (List[T]), and common type wrappers.""" + if node is None: + return + t = node.type + if t == "type_identifier": + text = _read_text(node, source) + if text: + out.append((text, "generic_arg" if generic else "type")) + return + if t == "generic_type": + base = node.child_by_field_name("type") + if base is None: + for c in node.children: + if c.type == "type_identifier": + base = c + break + if base is not None and base.type == "type_identifier": + text = _read_text(base, source) + if text: + out.append((text, "generic_arg" if generic else "type")) + for c in node.children: + if c.type == "type_arguments": + for arg in c.children: + if arg.is_named: + _scala_collect_type_refs(arg, source, True, out) + return + if t in ("compound_type", "infix_type", "function_type", "tuple_type", + "annotated_type", "projected_type"): + for c in node.children: + if c.is_named: + _scala_collect_type_refs(c, source, generic, out) + + def _python_collect_param_refs(params_node, source: bytes) -> list[tuple[str, str]]: """Collect type refs from each typed parameter under a `parameters` node.""" out: list[tuple[str, str]] = [] @@ -2370,6 +2470,55 @@ def _extract_generic(path: Path, config: LanguageConfig) -> dict: if tid.type == "type_identifier": _emit_java_parent(_read_text(tid, source), "inherits", line) + # Scala: extends_clause carries `extends Base with Trait1 with Trait2`. + # The first base after `extends` is `inherits`; each subsequent + # type after `with` is `mixes_in`. Also walk class_parameters for + # constructor-as-field type references. + if config.ts_module == "tree_sitter_scala": + extend = node.child_by_field_name("extend") + if extend is None: + for c in node.children: + if c.type == "extends_clause": + extend = c + break + if extend is not None: + bases: list[tuple[str, int]] = [] + for c in extend.children: + if c.type == "type_identifier": + bases.append((_read_text(c, source), c.start_point[0] + 1)) + elif c.type == "generic_type": + base = c.child_by_field_name("type") + if base is None: + for sc in c.children: + if sc.type == "type_identifier": + base = sc + break + if base is not None: + bases.append((_read_text(base, source), c.start_point[0] + 1)) + for idx, (base_name, base_line) in enumerate(bases): + rel = "inherits" if idx == 0 else "mixes_in" + base_nid = ensure_named_node(base_name, base_line) + if base_nid != class_nid: + add_edge(class_nid, base_nid, rel, base_line) + for c in node.children: + if c.type != "class_parameters": + continue + for cp in c.children: + if cp.type != "class_parameter": + continue + ptype = cp.child_by_field_name("type") + if ptype is None: + continue + cp_line = cp.start_point[0] + 1 + refs: list[tuple[str, str]] = [] + _scala_collect_type_refs(ptype, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "field" + target_nid = ensure_named_node(ref_name, cp_line) + if target_nid != class_nid: + add_edge(class_nid, target_nid, "references", + cp_line, context=ctx) + # C++-specific: inheritance via base_class_clause (class and struct). # tree-sitter-cpp shape: # class_specifier / struct_specifier @@ -2541,15 +2690,52 @@ def _extract_generic(path: Path, config: LanguageConfig) -> dict: add_edge(parent_class_nid, target_nid, "references", line, context=ctx) return + if (config.ts_module == "tree_sitter_scala" + and t == "val_definition" + and parent_class_nid): + type_node = node.child_by_field_name("type") + if type_node is not None: + line = node.start_point[0] + 1 + refs: list[tuple[str, str]] = [] + _scala_collect_type_refs(type_node, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "field" + target_nid = ensure_named_node(ref_name, line) + if target_nid != parent_class_nid: + add_edge(parent_class_nid, target_nid, "references", + line, context=ctx) + # fall through so any call expressions in the initializer get walked + if (config.ts_module == "tree_sitter_cpp" and t == "field_declaration" and parent_class_nid): + # Skip method prototypes (field_declaration with a function_declarator + # is a member-function declaration, not a data member). + decls = list(node.children_by_field_name("declarator")) + is_method = any( + d.type == "function_declarator" + or (d.type in ("pointer_declarator", "reference_declarator") + and any(c.type == "function_declarator" for c in d.children)) + for d in decls + ) + if not is_method: + type_node = node.child_by_field_name("type") + if type_node is not None: + line = node.start_point[0] + 1 + refs: list[tuple[str, str]] = [] + _cpp_collect_type_refs(type_node, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "field" + target_nid = ensure_named_node(ref_name, line) + if target_nid != parent_class_nid: + add_edge(parent_class_nid, target_nid, "references", + line, context=ctx) # Emit a node for each data member. Use children_by_field_name so we # only visit declarator children, not the type node (which would give # us the type name, not the field name). Handles int x, y; via # multiple declarator fields and static const int MAX = 100; via the # init_declarator → field_identifier recursion in _get_cpp_func_name. - for decl in node.children_by_field_name("declarator"): + for decl in decls: name = _get_cpp_func_name(decl, source) if name: line = decl.start_point[0] + 1 @@ -2757,6 +2943,73 @@ def _extract_generic(path: Path, config: LanguageConfig) -> dict: if target_nid != func_nid: add_edge(func_nid, target_nid, "references", line, context=ctx) + if config.ts_module in ("tree_sitter_c", "tree_sitter_cpp"): + collect = (_cpp_collect_type_refs if config.ts_module == "tree_sitter_cpp" + else _c_collect_type_refs) + return_node = node.child_by_field_name("type") + if return_node is not None: + refs: list[tuple[str, str]] = [] + collect(return_node, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "return_type" + target_nid = ensure_named_node(ref_name, line) + if target_nid != func_nid: + add_edge(func_nid, target_nid, "references", line, context=ctx) + # function_declarator may be wrapped in pointer/reference declarators + decl = node.child_by_field_name("declarator") + while decl is not None and decl.type in ( + "pointer_declarator", "reference_declarator"): + decl = decl.child_by_field_name("declarator") + if decl is not None and decl.type == "function_declarator": + params_node = decl.child_by_field_name("parameters") + if params_node is not None: + for p in params_node.children: + if p.type != "parameter_declaration": + continue + ptype = p.child_by_field_name("type") + if ptype is None: + continue + refs = [] + collect(ptype, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "parameter_type" + target_nid = ensure_named_node(ref_name, line) + if target_nid != func_nid: + add_edge(func_nid, target_nid, "references", + line, context=ctx) + + if config.ts_module == "tree_sitter_scala": + params_node = None + for c in node.children: + if c.type == "parameters": + params_node = c + break + if params_node is not None: + for p in params_node.children: + if p.type != "parameter": + continue + ptype = p.child_by_field_name("type") + if ptype is None: + continue + refs: list[tuple[str, str]] = [] + _scala_collect_type_refs(ptype, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "parameter_type" + target_nid = ensure_named_node(ref_name, line) + if target_nid != func_nid: + add_edge(func_nid, target_nid, "references", + line, context=ctx) + return_node = node.child_by_field_name("return_type") + if return_node is not None: + refs = [] + _scala_collect_type_refs(return_node, source, False, refs) + for ref_name, role in refs: + ctx = "generic_arg" if role == "generic_arg" else "return_type" + target_nid = ensure_named_node(ref_name, line) + if target_nid != func_nid: + add_edge(func_nid, target_nid, "references", + line, context=ctx) + body = _find_body(node, config) if body: function_bodies.append((func_nid, body)) @@ -4257,6 +4510,15 @@ def extract_julia(path: Path) -> dict: file_nid = _make_id(str(path)) add_node(file_nid, path.name, 1) + def ensure_named_node(name: str, line: int) -> str: + nid = _make_id(stem, name) + if nid in seen_ids: + return nid + nid = _make_id(name) + if nid not in seen_ids: + add_node(nid, name, line) + return nid + def _func_name_from_signature(sig_node) -> str | None: """Extract function name from a Julia signature node (call_expression > identifier).""" for child in sig_node.children: @@ -4310,29 +4572,40 @@ def extract_julia(path: Path) -> dict: if t == "struct_definition": # type_head may contain: identifier (simple) or binary_expression (Foo <: Bar) type_head = next((c for c in node.children if c.type == "type_head"), None) - if type_head: - bin_expr = next((c for c in type_head.children if c.type == "binary_expression"), None) - if bin_expr: - # First identifier is the struct name, last is the supertype - identifiers = [c for c in bin_expr.children if c.type == "identifier"] - if identifiers: - struct_name = _read_text(identifiers[0], source) - struct_nid = _make_id(stem, struct_name) - line = node.start_point[0] + 1 - add_node(struct_nid, struct_name, line) - add_edge(scope_nid, struct_nid, "defines", line) - if len(identifiers) >= 2: - super_name = _read_text(identifiers[-1], source) - add_edge(struct_nid, _make_id(stem, super_name), "inherits", - line, confidence="EXTRACTED") - else: - name_node = next((c for c in type_head.children if c.type == "identifier"), None) - if name_node: - struct_name = _read_text(name_node, source) - struct_nid = _make_id(stem, struct_name) - line = node.start_point[0] + 1 - add_node(struct_nid, struct_name, line) - add_edge(scope_nid, struct_nid, "defines", line) + if not type_head: + return + struct_name: str | None = None + super_name: str | None = None + bin_expr = next((c for c in type_head.children if c.type == "binary_expression"), None) + if bin_expr: + identifiers = [c for c in bin_expr.children if c.type == "identifier"] + if identifiers: + struct_name = _read_text(identifiers[0], source) + if len(identifiers) >= 2: + super_name = _read_text(identifiers[-1], source) + else: + name_node = next((c for c in type_head.children if c.type == "identifier"), None) + if name_node: + struct_name = _read_text(name_node, source) + if not struct_name: + return + struct_nid = _make_id(stem, struct_name) + line = node.start_point[0] + 1 + add_node(struct_nid, struct_name, line) + add_edge(scope_nid, struct_nid, "defines", line) + if super_name: + add_edge(struct_nid, ensure_named_node(super_name, line), + "inherits", line, confidence="EXTRACTED") + # Field types: each `name::Type` lowers to a typed_expression child of struct_definition + for child in node.children: + if child.type == "typed_expression": + type_ids = [c for c in child.children if c.type == "identifier"] + if len(type_ids) >= 2: + field_line = child.start_point[0] + 1 + type_name = _read_text(type_ids[-1], source) + type_nid = ensure_named_node(type_name, field_line) + edges.append(_semantic_reference_edge( + struct_nid, type_nid, "field", str_path, field_line)) return # Abstract type @@ -4516,6 +4789,62 @@ def extract_fortran(path: Path) -> dict: return _read_text(child, source).lower() return None + def ensure_named_node(name: str, line: int) -> str: + nid = _make_id(stem, name) + if nid in seen_ids: + return nid + nid = _make_id(name) + if nid not in seen_ids: + add_node(nid, name, line) + return nid + + def emit_signature_refs(scope_node, fn_nid: str, is_function: bool) -> None: + """Emit references[parameter_type] / references[return_type] edges for + a subroutine/function based on its variable_declaration siblings.""" + stmt_type = "function_statement" if is_function else "subroutine_statement" + stmt = next((c for c in scope_node.children if c.type == stmt_type), None) + if stmt is None: + return + param_names: set[str] = set() + params_node = next((c for c in stmt.children if c.type == "parameters"), None) + if params_node is not None: + for c in params_node.children: + if c.type == "identifier": + param_names.add(_read_text(c, source).lower()) + result_name: str | None = None + if is_function: + result_node = next((c for c in stmt.children if c.type == "function_result"), None) + if result_node is not None: + res_id = next((c for c in result_node.children if c.type == "identifier"), None) + if res_id is not None: + result_name = _read_text(res_id, source).lower() + else: + # implicit result variable: same name as the function + result_name = _fortran_name(stmt) + for child in scope_node.children: + if child.type != "variable_declaration": + continue + derived = next((c for c in child.children if c.type == "derived_type"), None) + if derived is None: + continue + type_name_node = next((c for c in derived.children if c.type == "type_name"), None) + if type_name_node is None: + continue + type_name = _read_text(type_name_node, source).lower() + for var in child.children: + if var.type != "identifier": + continue + var_name = _read_text(var, source).lower() + var_line = var.start_point[0] + 1 + if var_name in param_names: + tgt = ensure_named_node(type_name, var_line) + if tgt != fn_nid: + add_edge(fn_nid, tgt, "references", var_line, context="parameter_type") + elif is_function and var_name == result_name: + tgt = ensure_named_node(type_name, var_line) + if tgt != fn_nid: + add_edge(fn_nid, tgt, "references", var_line, context="return_type") + def walk_calls(node, scope_nid: str) -> None: if node is None: return @@ -4567,6 +4896,18 @@ def extract_fortran(path: Path) -> dict: walk(child, scope_nid) return + if t == "derived_type_definition": + stmt = next((c for c in node.children if c.type == "derived_type_statement"), None) + if stmt is not None: + name_node = next((c for c in stmt.children if c.type == "type_name"), None) + if name_node is not None: + type_name = _read_text(name_node, source).lower() + type_nid = _make_id(stem, type_name) + line = node.start_point[0] + 1 + add_node(type_nid, type_name, line) + add_edge(scope_nid, type_nid, "defines", line) + return + if t == "subroutine": stmt = next((c for c in node.children if c.type == "subroutine_statement"), None) name = _fortran_name(stmt) if stmt else None @@ -4576,6 +4917,7 @@ def extract_fortran(path: Path) -> dict: add_node(nid, f"{name}()", line) add_edge(scope_nid, nid, "defines", line) scope_bodies.append((nid, node)) + emit_signature_refs(node, nid, is_function=False) for child in node.children: walk(child, nid) return @@ -4589,6 +4931,7 @@ def extract_fortran(path: Path) -> dict: add_node(nid, f"{name}()", line) add_edge(scope_nid, nid, "defines", line) scope_bodies.append((nid, node)) + emit_signature_refs(node, nid, is_function=True) for child in node.children: walk(child, nid) return @@ -5474,6 +5817,30 @@ def extract_powershell(path: Path) -> dict: return child return None + def ensure_named_node(name: str, line: int) -> str: + nid = _make_id(stem, name) + if nid in seen_ids: + return nid + nid = _make_id(name) + if nid not in seen_ids: + add_node(nid, name, line) + return nid + + def _ps_type_name(type_literal_node) -> str | None: + """Drill into a type_literal node and return the inner type_identifier text.""" + if type_literal_node is None: + return None + for spec in type_literal_node.children: + if spec.type != "type_spec": + continue + for tname in spec.children: + if tname.type != "type_name": + continue + for tid in tname.children: + if tid.type == "type_identifier": + return _read_text(tid, source) + return None + def walk(node, parent_class_nid: str | None = None) -> None: t = node.type @@ -5502,6 +5869,17 @@ def extract_powershell(path: Path) -> dict: walk(child, parent_class_nid=class_nid) return + if t == "class_property_definition" and parent_class_nid: + type_literal = next((c for c in node.children if c.type == "type_literal"), None) + type_name = _ps_type_name(type_literal) + if type_name: + line = node.start_point[0] + 1 + target_nid = ensure_named_node(type_name, line) + if target_nid != parent_class_nid: + add_edge(parent_class_nid, target_nid, "references", + line, context="field") + return + if t == "class_method_definition": name_node = next((c for c in node.children if c.type == "simple_name"), None) if name_node: @@ -5515,6 +5893,32 @@ def extract_powershell(path: Path) -> dict: method_nid = _make_id(stem, method_name) add_node(method_nid, f"{method_name}()", line) add_edge(file_nid, method_nid, "contains", line) + # Return type: type_literal sibling of simple_name + return_type_literal = next( + (c for c in node.children if c.type == "type_literal"), None) + return_type_name = _ps_type_name(return_type_literal) + if return_type_name: + target_nid = ensure_named_node(return_type_name, line) + if target_nid != method_nid: + add_edge(method_nid, target_nid, "references", + line, context="return_type") + # Parameter types: class_method_parameter_list + param_list = next( + (c for c in node.children if c.type == "class_method_parameter_list"), None) + if param_list is not None: + for p in param_list.children: + if p.type != "class_method_parameter": + continue + ptype_literal = next( + (c for c in p.children if c.type == "type_literal"), None) + ptype_name = _ps_type_name(ptype_literal) + if not ptype_name: + continue + p_line = p.start_point[0] + 1 + target_nid = ensure_named_node(ptype_name, p_line) + if target_nid != method_nid: + add_edge(method_nid, target_nid, "references", + p_line, context="parameter_type") body = _find_script_block_body(node) if body: function_bodies.append((method_nid, body)) @@ -7005,6 +7409,15 @@ def extract_objc(path: Path) -> dict: n = node.child_by_field_name(field) return _read(n) if n else None + def ensure_named_node(name: str, line: int) -> str: + nid = _make_id(stem, name) + if nid in seen_ids: + return nid + nid = _make_id(name) + if nid not in seen_ids: + add_node(nid, name, line) + return nid + def walk(node, parent_nid: str | None = None) -> None: t = node.type line = node.start_point[0] + 1 @@ -7047,17 +7460,27 @@ def extract_objc(path: Path) -> dict: if child.type == ":": colon_seen = True elif colon_seen and child.type == "identifier": - super_nid = _make_id(_read(child)) + super_nid = ensure_named_node(_read(child), line) add_edge(cls_nid, super_nid, "inherits", line) colon_seen = False elif child.type == "parameterized_arguments": - # protocols adopted + # protocols adopted: @interface Foo : Bar for sub in child.children: if sub.type == "type_name": for s in sub.children: if s.type == "type_identifier": - proto_nid = _make_id(_read(s)) - add_edge(cls_nid, proto_nid, "imports", line, context="import") + proto_nid = ensure_named_node(_read(s), line) + add_edge(cls_nid, proto_nid, "implements", line) + elif child.type == "property_declaration": + prop_line = child.start_point[0] + 1 + for sub in child.children: + if sub.type == "struct_declaration": + for s in sub.children: + if s.type == "type_identifier": + type_nid = ensure_named_node(_read(s), prop_line) + edges.append(_semantic_reference_edge( + cls_nid, type_nid, "field", str_path, prop_line)) + break elif child.type == "method_declaration": walk(child, cls_nid) return diff --git a/pyproject.toml b/pyproject.toml index 1b860ab7..0ef08f80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ svg = ["matplotlib"] leiden = ["graspologic; python_version < '3.13'"] office = ["python-docx", "openpyxl"] google = ["openpyxl"] -video = ["faster-whisper", "yt-dlp"] +video = ["faster-whisper; python_version >= '3.11'", "yt-dlp"] kimi = ["openai", "tiktoken"] ollama = ["openai"] bedrock = ["boto3"] @@ -65,7 +65,7 @@ gemini = ["openai", "tiktoken"] openai = ["openai", "tiktoken"] chinese = ["jieba"] sql = ["tree-sitter-sql"] -all = ["mcp", "neo4j", "pypdf", "markdownify", "watchdog", "graspologic; python_version < '3.13'", "python-docx", "openpyxl", "faster-whisper", "yt-dlp", "matplotlib", "openai", "tiktoken", "boto3", "tree-sitter-sql", "jieba"] +all = ["mcp", "neo4j", "pypdf", "markdownify", "watchdog", "graspologic; python_version < '3.13'", "python-docx", "openpyxl", "faster-whisper; python_version >= '3.11'", "yt-dlp", "matplotlib", "openai", "tiktoken", "boto3", "tree-sitter-sql", "jieba"] [project.scripts] graphify = "graphify.__main__:main" diff --git a/tests/fixtures/sample.c b/tests/fixtures/sample.c index 0768cac2..256dadae 100644 --- a/tests/fixtures/sample.c +++ b/tests/fixtures/sample.c @@ -4,6 +4,11 @@ #define MAX_SIZE 256 +typedef struct { + int width; + int height; +} Rectangle; + static int validate(const char *input) { return input != NULL && strlen(input) > 0; } @@ -17,6 +22,15 @@ char *process(const char *input) { return result; } +Rectangle *make_rect(Rectangle *defaults) { + Rectangle *r = malloc(sizeof(Rectangle)); + if (defaults) { + r->width = defaults->width; + r->height = defaults->height; + } + return r; +} + int main(int argc, char *argv[]) { char *out = process("hello"); if (out) { diff --git a/tests/fixtures/sample.cpp b/tests/fixtures/sample.cpp index 7cf274a0..f48f8335 100644 --- a/tests/fixtures/sample.cpp +++ b/tests/fixtures/sample.cpp @@ -16,6 +16,7 @@ public: private: std::string baseUrl_; + std::vector tags_; std::string buildRequest(const std::string& method, const std::string& path) { return method + " " + baseUrl_ + path; diff --git a/tests/fixtures/sample.f90 b/tests/fixtures/sample.f90 index 0eaeff60..a78e18f2 100644 --- a/tests/fixtures/sample.f90 +++ b/tests/fixtures/sample.f90 @@ -4,6 +4,11 @@ module geometry real, parameter :: PI = 3.14159 + type :: Point + real :: x + real :: y + end type Point + contains subroutine circle_area(radius, area) @@ -18,6 +23,19 @@ contains d = sqrt((x2 - x1)**2 + (y2 - y1)**2) end function distance + subroutine translate(p, dx, dy) + type(Point), intent(inout) :: p + real, intent(in) :: dx, dy + p%x = p%x + dx + p%y = p%y + dy + end subroutine translate + + function origin() result(p) + type(Point) :: p + p%x = 0.0 + p%y = 0.0 + end function origin + subroutine print_area(radius) real, intent(in) :: radius real :: area diff --git a/tests/fixtures/sample.scala b/tests/fixtures/sample.scala index fe23724f..95755a87 100644 --- a/tests/fixtures/sample.scala +++ b/tests/fixtures/sample.scala @@ -2,7 +2,12 @@ import scala.collection.mutable.ListBuffer case class Config(baseUrl: String, timeout: Int) -class HttpClient(config: Config) { +trait Loggable +abstract class BaseClient + +class HttpClient(config: Config) extends BaseClient with Loggable { + val source: Config = config + def get(path: String): String = { buildRequest("GET", path) } diff --git a/tests/test_languages.py b/tests/test_languages.py index 65fbf5a7..747ed8c0 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -8,6 +8,7 @@ from graphify.extract import ( extract_swift, extract_go, extract_julia, extract_js, extract_fortran, extract_groovy, extract_sln, extract_csproj, extract_razor, extract_dm, extract_dmi, extract_dmm, extract_dmf, + extract_powershell, ) FIXTURES = Path(__file__).parent / "fixtures" @@ -138,6 +139,12 @@ def test_c_import_edges_have_import_context(): assert all(e.get("context") == "import" for e in import_edges) +def test_c_parameter_and_return_type_contexts(): + r = extract_c(FIXTURES / "sample.c") + assert ("make_rect", "Rectangle") in _edge_labels(r, "references", "parameter_type") + assert ("make_rect", "Rectangle") in _edge_labels(r, "references", "return_type") + + def test_c_call_edges_have_call_context(): r = extract_c(FIXTURES / "sample.c") call_edges = _edges_with_relation(r, "calls") @@ -173,6 +180,19 @@ def test_cpp_import_edges_have_import_context(): assert all(e.get("context") == "import" for e in import_edges) +def test_cpp_method_parameter_and_return_type_contexts(): + r = extract_cpp(FIXTURES / "sample.cpp") + assert ("get", "string") in _edge_labels(r, "references", "parameter_type") + assert ("get", "string") in _edge_labels(r, "references", "return_type") + + +def test_cpp_field_and_template_argument_contexts(): + r = extract_cpp(FIXTURES / "sample.cpp") + assert ("HttpClient", "string") in _edge_labels(r, "references", "field") + assert ("HttpClient", "vector") in _edge_labels(r, "references", "field") + assert ("HttpClient", "string") in _edge_labels(r, "references", "generic_arg") + + def test_cpp_class_inherits_edge(): """Regression for #915: `class Derived : public Base {}` should emit an inherits edge.""" r = extract_cpp(FIXTURES / "sample.cpp") @@ -390,6 +410,27 @@ def test_scala_import_edges_have_import_context(): assert all(e.get("context") == "import" for e in import_edges) +def test_scala_splits_inherits_and_mixes_in(): + r = extract_scala(FIXTURES / "sample.scala") + assert ("HttpClient", "BaseClient") in _edge_labels(r, "inherits") + assert ("HttpClient", "Loggable") in _edge_labels(r, "mixes_in") + + +def test_scala_constructor_parameter_field_context(): + r = extract_scala(FIXTURES / "sample.scala") + assert ("HttpClient", "Config") in _edge_labels(r, "references", "field") + + +def test_scala_val_definition_field_context(): + r = extract_scala(FIXTURES / "sample.scala") + assert ("HttpClient", "Config") in _edge_labels(r, "references", "field") + + +def test_scala_method_return_type_context(): + r = extract_scala(FIXTURES / "sample.scala") + assert ("create", "HttpClient") in _edge_labels(r, "references", "return_type") + + def test_scala_call_edges_have_call_context(): r = extract_scala(FIXTURES / "sample.scala") call_edges = _edges_with_relation(r, "calls") @@ -740,6 +781,18 @@ def test_objc_inherits_edge(): assert len(inherits) >= 1 +def test_objc_splits_inherits_and_implements(): + r = extract_objc(FIXTURES / "sample.m") + assert ("Animal", "NSObject") in _edge_labels(r, "inherits") + assert ("Dog", "Animal") in _edge_labels(r, "inherits") + assert ("Animal", "SampleDelegate") in _edge_labels(r, "implements") + + +def test_objc_property_type_context(): + r = extract_objc(FIXTURES / "sample.m") + assert ("Animal", "NSString") in _edge_labels(r, "references", "field") + + def test_objc_no_dangling_edges(): r = extract_objc(FIXTURES / "sample.m") node_ids = {n["id"] for n in r["nodes"]} @@ -822,6 +875,19 @@ def test_julia_finds_inherits(): assert len(inherits) >= 1 +def test_julia_abstract_concrete_hierarchy_inherits(): + r = extract_julia(FIXTURES / "sample.jl") + assert ("Point", "Shape") in _edge_labels(r, "inherits") + assert ("Circle", "Shape") in _edge_labels(r, "inherits") + + +def test_julia_struct_field_type_context(): + r = extract_julia(FIXTURES / "sample.jl") + assert ("Point", "Float64") in _edge_labels(r, "references", "field") + assert ("Circle", "Point") in _edge_labels(r, "references", "field") + assert ("Circle", "Float64") in _edge_labels(r, "references", "field") + + def test_julia_finds_calls(): r = extract_julia(FIXTURES / "sample.jl") call_edges = [e for e in r["edges"] if e["relation"] == "calls"] @@ -896,6 +962,18 @@ def test_fortran_case_insensitive_names(): assert "main" in labels +def test_fortran_finds_derived_type(): + r = extract_fortran(FIXTURES / "sample.f90") + labels = [n["label"] for n in r["nodes"]] + assert "point" in labels + + +def test_fortran_parameter_and_return_type_contexts(): + r = extract_fortran(FIXTURES / "sample.f90") + assert ("translate", "point") in _edge_labels(r, "references", "parameter_type") + assert ("origin", "point") in _edge_labels(r, "references", "return_type") + + def test_fortran_no_dangling_edges(): r = extract_fortran(FIXTURES / "sample.f90") node_ids = {n["id"] for n in r["nodes"]} @@ -911,6 +989,32 @@ def test_fortran_capital_F_parses_preprocessed(): assert any("compute_volume" in l for l in labels) +# ── PowerShell ─────────────────────────────────────────────────────────────── + +def test_powershell_no_error(): + r = extract_powershell(FIXTURES / "sample.ps1") + assert "error" not in r + + +def test_powershell_finds_class_and_method(): + r = extract_powershell(FIXTURES / "sample.ps1") + labels = [n["label"] for n in r["nodes"]] + assert "DataProcessor" in labels + assert any("Transform" in l for l in labels) + + +def test_powershell_property_field_type_context(): + r = extract_powershell(FIXTURES / "sample.ps1") + assert ("DataProcessor", "string") in _edge_labels(r, "references", "field") + + +def test_powershell_method_parameter_and_return_type_contexts(): + r = extract_powershell(FIXTURES / "sample.ps1") + assert ("Transform", "string") in _edge_labels(r, "references", "parameter_type") + assert ("Transform", "string") in _edge_labels(r, "references", "return_type") + assert ("Save", "void") in _edge_labels(r, "references", "return_type") + + # ── TypeScript dynamic imports ─────────────────────────────────────────────── def test_ts_dynamic_import_no_error(): diff --git a/uv.lock b/uv.lock index a6bea3d5..706979f7 100644 --- a/uv.lock +++ b/uv.lock @@ -828,9 +828,9 @@ name = "ctranslate2" version = "4.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "pyyaml" }, - { name = "setuptools" }, + { name = "numpy", marker = "python_full_version >= '3.11'" }, + { name = "pyyaml", marker = "python_full_version >= '3.11'" }, + { name = "setuptools", marker = "python_full_version >= '3.11'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/cb/e0/b69c40c3d739b213a78d327071240590792071b4f890e34088b03b95bb1e/ctranslate2-4.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9017a355dd7c6d29dc3bca6e9fc74827306c61b702c66bb1f6b939655e7de3fa", size = 1255773, upload-time = "2026-02-04T06:11:04.769Z" }, @@ -970,13 +970,12 @@ name = "faster-whisper" version = "1.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "av" }, - { name = "ctranslate2" }, - { name = "huggingface-hub" }, - { name = "onnxruntime", version = "1.24.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "onnxruntime", version = "1.26.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "tokenizers" }, - { name = "tqdm" }, + { name = "av", marker = "python_full_version >= '3.11'" }, + { name = "ctranslate2", marker = "python_full_version >= '3.11'" }, + { name = "huggingface-hub", marker = "python_full_version >= '3.11'" }, + { name = "onnxruntime", marker = "python_full_version >= '3.11'" }, + { name = "tokenizers", marker = "python_full_version >= '3.11'" }, + { name = "tqdm", marker = "python_full_version >= '3.11'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/05/99/49ee85903dee060d9f08297b4a342e5e0bcfca2f027a07b4ee0a38ab13f9/faster_whisper-1.2.1-py3-none-any.whl", hash = "sha256:79a66ad50688c0b794dd501dc340a736992a6342f7f95e5811be60b5224a26a7", size = 1118909, upload-time = "2025-10-31T11:35:47.794Z" }, @@ -1149,7 +1148,7 @@ dependencies = [ [package.optional-dependencies] all = [ { name = "boto3" }, - { name = "faster-whisper" }, + { name = "faster-whisper", marker = "python_full_version >= '3.11'" }, { name = "graspologic", marker = "python_full_version < '3.13'" }, { name = "jieba" }, { name = "markdownify" }, @@ -1213,7 +1212,7 @@ svg = [ { name = "matplotlib" }, ] video = [ - { name = "faster-whisper" }, + { name = "faster-whisper", marker = "python_full_version >= '3.11'" }, { name = "yt-dlp" }, ] watch = [ @@ -1243,8 +1242,8 @@ requires-dist = [ { name = "boto3", marker = "extra == 'all'" }, { name = "boto3", marker = "extra == 'bedrock'" }, { name = "datasketch" }, - { name = "faster-whisper", marker = "extra == 'all'" }, - { name = "faster-whisper", marker = "extra == 'video'" }, + { name = "faster-whisper", marker = "python_full_version >= '3.11' and extra == 'all'" }, + { name = "faster-whisper", marker = "python_full_version >= '3.11' and extra == 'video'" }, { name = "graspologic", marker = "python_full_version < '3.13' and extra == 'all'" }, { name = "graspologic", marker = "python_full_version < '3.13' and extra == 'leiden'" }, { name = "jieba", marker = "extra == 'all'" }, @@ -1455,15 +1454,15 @@ name = "huggingface-hub" version = "1.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, - { name = "httpx" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "tqdm" }, - { name = "typer" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "python_full_version >= '3.11'" }, + { name = "fsspec", marker = "python_full_version >= '3.11'" }, + { name = "hf-xet", marker = "(python_full_version >= '3.11' and platform_machine == 'AMD64') or (python_full_version >= '3.11' and platform_machine == 'aarch64') or (python_full_version >= '3.11' and platform_machine == 'amd64') or (python_full_version >= '3.11' and platform_machine == 'arm64') or (python_full_version >= '3.11' and platform_machine == 'x86_64')" }, + { name = "httpx", marker = "python_full_version >= '3.11'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pyyaml", marker = "python_full_version >= '3.11'" }, + { name = "tqdm", marker = "python_full_version >= '3.11'" }, + { name = "typer", marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bb/b6/e22bd20a25299c34b8c5922c1545a6320825b13906eb0f7298edfd034a0b/huggingface_hub-1.15.0.tar.gz", hash = "sha256:28abfdddda3927fd4de6a63cf26ab012498a2c24dae52baf150c5c6edf98a1d5", size = 784100, upload-time = "2026-05-15T11:42:52.149Z" } wheels = [ @@ -2240,15 +2239,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] -[[package]] -name = "mpmath" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, -] - [[package]] name = "msgpack" version = "1.1.2" @@ -2449,59 +2439,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" }, ] -[[package]] -name = "onnxruntime" -version = "1.24.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "flatbuffers", marker = "python_full_version < '3.11'" }, - { name = "numpy", marker = "python_full_version < '3.11'" }, - { name = "packaging", marker = "python_full_version < '3.11'" }, - { name = "protobuf", marker = "python_full_version < '3.11'" }, - { name = "sympy", marker = "python_full_version < '3.11'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/41/3253db975a90c3ce1d475e2a230773a21cd7998537f0657947df6fb79861/onnxruntime-1.24.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3e6456801c66b095c5cd68e690ca25db970ea5202bd0c5b84a2c3ef7731c5a3c", size = 17332766, upload-time = "2026-03-05T17:18:59.714Z" }, - { url = "https://files.pythonhosted.org/packages/7e/c5/3af6b325f1492d691b23844d88ed26844c1164620860c5efe95c0e22782d/onnxruntime-1.24.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b2ebc54c6d8281dccff78d4b06e47d4cf07535937584ab759448390a70f4978", size = 15130330, upload-time = "2026-03-05T16:34:53.831Z" }, - { url = "https://files.pythonhosted.org/packages/03/4b/f96b46c1866a293ed23ca2cf5e5a63d413ad3a951da60dd877e3c56cbbca/onnxruntime-1.24.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb56575d7794bf0781156955610c9e651c9504c64d42ec880784b6106244882d", size = 17213247, upload-time = "2026-03-05T17:17:59.812Z" }, - { url = "https://files.pythonhosted.org/packages/36/13/27cf4d8df2578747584e8758aeb0b673b60274048510257f1f084b15e80e/onnxruntime-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:c958222ef9eff54018332beecd32d5d94a3ab079d8821937b333811bf4da0d39", size = 12595530, upload-time = "2026-03-05T17:18:49.356Z" }, - { url = "https://files.pythonhosted.org/packages/19/8c/6d9f31e6bae72a8079be12ed8ba36c4126a571fad38ded0a1b96f60f6896/onnxruntime-1.24.3-cp311-cp311-win_arm64.whl", hash = "sha256:a8f761857ebaf58a85b9e42422d03207f1d39e6bb8fecfdbf613bac5b9710723", size = 12261715, upload-time = "2026-03-05T17:18:39.699Z" }, - { url = "https://files.pythonhosted.org/packages/d0/7f/dfdc4e52600fde4c02d59bfe98c4b057931c1114b701e175aee311a9bc11/onnxruntime-1.24.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:0d244227dc5e00a9ae15a7ac1eba4c4460d7876dfecafe73fb00db9f1d914d91", size = 17342578, upload-time = "2026-03-05T17:19:02.403Z" }, - { url = "https://files.pythonhosted.org/packages/1c/dc/1f5489f7b21817d4ad352bf7a92a252bd5b438bcbaa7ad20ea50814edc79/onnxruntime-1.24.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a9847b870b6cb462652b547bc98c49e0efb67553410a082fde1918a38707452", size = 15150105, upload-time = "2026-03-05T16:34:56.897Z" }, - { url = "https://files.pythonhosted.org/packages/28/7c/fd253da53594ab8efbefdc85b3638620ab1a6aab6eb7028a513c853559ce/onnxruntime-1.24.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b354afce3333f2859c7e8706d84b6c552beac39233bcd3141ce7ab77b4cabb5d", size = 17237101, upload-time = "2026-03-05T17:18:02.561Z" }, - { url = "https://files.pythonhosted.org/packages/71/5f/eaabc5699eeed6a9188c5c055ac1948ae50138697a0428d562ac970d7db5/onnxruntime-1.24.3-cp312-cp312-win_amd64.whl", hash = "sha256:44ea708c34965439170d811267c51281d3897ecfc4aa0087fa25d4a4c3eb2e4a", size = 12597638, upload-time = "2026-03-05T17:18:52.141Z" }, - { url = "https://files.pythonhosted.org/packages/cc/5c/d8066c320b90610dbeb489a483b132c3b3879b2f93f949fb5d30cfa9b119/onnxruntime-1.24.3-cp312-cp312-win_arm64.whl", hash = "sha256:48d1092b44ca2ba6f9543892e7c422c15a568481403c10440945685faf27a8d8", size = 12270943, upload-time = "2026-03-05T17:18:42.006Z" }, - { url = "https://files.pythonhosted.org/packages/51/8d/487ece554119e2991242d4de55de7019ac6e47ee8dfafa69fcf41d37f8ed/onnxruntime-1.24.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:34a0ea5ff191d8420d9c1332355644148b1bf1a0d10c411af890a63a9f662aa7", size = 17342706, upload-time = "2026-03-05T16:35:10.813Z" }, - { url = "https://files.pythonhosted.org/packages/dd/25/8b444f463c1ac6106b889f6235c84f01eec001eaf689c3eff8c69cf48fae/onnxruntime-1.24.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fd2ec7bb0fabe42f55e8337cfc9b1969d0d14622711aac73d69b4bd5abb5ed7", size = 15149956, upload-time = "2026-03-05T16:34:59.264Z" }, - { url = "https://files.pythonhosted.org/packages/34/fc/c9182a3e1ab46940dd4f30e61071f59eee8804c1f641f37ce6e173633fb6/onnxruntime-1.24.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df8e70e732fe26346faaeec9147fa38bef35d232d2495d27e93dd221a2d473a9", size = 17237370, upload-time = "2026-03-05T17:18:05.258Z" }, - { url = "https://files.pythonhosted.org/packages/05/7e/3b549e1f4538514118bff98a1bcd6481dd9a17067f8c9af77151621c9a5c/onnxruntime-1.24.3-cp313-cp313-win_amd64.whl", hash = "sha256:2d3706719be6ad41d38a2250998b1d87758a20f6ea4546962e21dc79f1f1fd2b", size = 12597939, upload-time = "2026-03-05T17:18:54.772Z" }, - { url = "https://files.pythonhosted.org/packages/80/41/9696a5c4631a0caa75cc8bc4efd30938fd483694aa614898d087c3ee6d29/onnxruntime-1.24.3-cp313-cp313-win_arm64.whl", hash = "sha256:b082f3ba9519f0a1a1e754556bc7e635c7526ef81b98b3f78da4455d25f0437b", size = 12270705, upload-time = "2026-03-05T17:18:44.774Z" }, - { url = "https://files.pythonhosted.org/packages/b7/65/a26c5e59e3b210852ee04248cf8843c81fe7d40d94cf95343b66efe7eec9/onnxruntime-1.24.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72f956634bc2e4bd2e8b006bef111849bd42c42dea37bd0a4c728404fdaf4d34", size = 15161796, upload-time = "2026-03-05T16:35:02.871Z" }, - { url = "https://files.pythonhosted.org/packages/f3/25/2035b4aa2ccb5be6acf139397731ec507c5f09e199ab39d3262b22ffa1ac/onnxruntime-1.24.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78d1f25eed4ab9959db70a626ed50ee24cf497e60774f59f1207ac8556399c4d", size = 17240936, upload-time = "2026-03-05T17:18:09.534Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a4/b3240ea84b92a3efb83d49cc16c04a17ade1ab47a6a95c4866d15bf0ac35/onnxruntime-1.24.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a6b4bce87d96f78f0a9bf5cefab3303ae95d558c5bfea53d0bf7f9ea207880a8", size = 17344149, upload-time = "2026-03-05T16:35:13.382Z" }, - { url = "https://files.pythonhosted.org/packages/bb/4a/4b56757e51a56265e8c56764d9c36d7b435045e05e3b8a38bedfc5aedba3/onnxruntime-1.24.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d48f36c87b25ab3b2b4c88826c96cf1399a5631e3c2c03cc27d6a1e5d6b18eb4", size = 15151571, upload-time = "2026-03-05T16:35:05.679Z" }, - { url = "https://files.pythonhosted.org/packages/cf/14/c6fb84980cec8f682a523fcac7c2bdd6b311e7f342c61ce48d3a9cb87fc6/onnxruntime-1.24.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e104d33a409bf6e3f30f0e8198ec2aaf8d445b8395490a80f6e6ad56da98e400", size = 17238951, upload-time = "2026-03-05T17:18:12.394Z" }, - { url = "https://files.pythonhosted.org/packages/57/14/447e1400165aca8caf35dabd46540eb943c92f3065927bb4d9bcbc91e221/onnxruntime-1.24.3-cp314-cp314-win_amd64.whl", hash = "sha256:e785d73fbd17421c2513b0bb09eb25d88fa22c8c10c3f5d6060589efa5537c5b", size = 12903820, upload-time = "2026-03-05T17:18:57.123Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ec/6b2fa5702e4bbba7339ca5787a9d056fc564a16079f8833cc6ba4798da1c/onnxruntime-1.24.3-cp314-cp314-win_arm64.whl", hash = "sha256:951e897a275f897a05ffbcaa615d98777882decaeb80c9216c68cdc62f849f53", size = 12594089, upload-time = "2026-03-05T17:18:47.169Z" }, - { url = "https://files.pythonhosted.org/packages/12/dc/cd06cba3ddad92ceb17b914a8e8d49836c79e38936e26bde6e368b62c1fe/onnxruntime-1.24.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d4e70ce578aa214c74c7a7a9226bc8e229814db4a5b2d097333b81279ecde36", size = 15162789, upload-time = "2026-03-05T16:35:08.282Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d6/413e98ab666c6fb9e8be7d1c6eb3bd403b0bea1b8d42db066dab98c7df07/onnxruntime-1.24.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02aaf6ddfa784523b6873b4176a79d508e599efe12ab0ea1a3a6e7314408b7aa", size = 17240738, upload-time = "2026-03-05T17:18:15.203Z" }, -] - [[package]] name = "onnxruntime" version = "1.26.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ { name = "flatbuffers", marker = "python_full_version >= '3.11'" }, { name = "numpy", marker = "python_full_version >= '3.11'" }, @@ -4289,18 +4230,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f5/ac/19f9941c74add59d17694930ec8105d5eddeee4ce56dd8632b765ca16d6c/stevedore-5.8.0-py3-none-any.whl", hash = "sha256:88eede9e66ca80e34085b9174e2327da2c61ac91f24f70e41c3ad76e4bb4872b", size = 54553, upload-time = "2026-05-18T09:15:25.82Z" }, ] -[[package]] -name = "sympy" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mpmath", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, -] - [[package]] name = "tenacity" version = "9.1.4" @@ -4385,7 +4314,7 @@ name = "tokenizers" version = "0.23.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "huggingface-hub" }, + { name = "huggingface-hub", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz", hash = "sha256:1feeeadf865a7915adc25445dea30e9933e593c31bb96c277cee36de227c8bfa", size = 365748, upload-time = "2026-04-27T14:43:25.606Z" } wheels = [