orchestrata_tools.parser.json_loader

Reference › orchestrata_tools › parser › json_loader

JSONASTLoader reads the JSON snapshot written by the AST serializer into the orchestrata_tools models of ast_models. The JSON format is defined by orchestrata_ast.models. The loader is used by the package CLI __main__, the backcompat wrappers and the script scripts.add_traces_from_evidence.

load opens a path, parses the JSON and calls load_from_dict, which is also usable on an already-parsed dictionary. Private helpers (_parse_module, _parse_class, _parse_method, _parse_function, _parse_import, _parse_param, _parse_class_var) convert each node. _parse_class also accepts a plain string for inner classes. Fields in the snapshot that the orchestrata_tools models do not have, such as body hashes, are not carried over. A missing or invalid file raises the underlying file or JSON error.

At a glance

Source src/orchestrata_tools/parser/json_loader.py
Lines of code 154
Classes 1
Functions 0
Imports (internal) orchestrata_tools.models.ast_models
Imported by orchestrata_tools, orchestrata_tools.parser, scripts.add_traces_from_evidence
Tests that import it tests/test_orchestrata_ast_analyzer.py

Class diagram

Class diagram orchestrata_tools.parser.json_loader

Dependency diagram

Dependency diagram orchestrata_tools.parser.json_loader

API

Classes

JSONASTLoader

Line 21

Load ASTCodebase from JSON produced by serialize_codebase_ast.py.

Method Signature Summary
load load(path: Path | str) -> ASTCodebase
load_from_dict load_from_dict(data: dict[str, Any]) -> ASTCodebase
_parse_module _parse_module(data: dict[str, Any]) -> ModuleInfo
_parse_class _parse_class(data: dict[str, Any] | str, module_path: str = '', file_path: str = '') -> ClassInfo
_parse_method _parse_method(data: dict[str, Any]) -> MethodInfo
_parse_function _parse_function(data: dict[str, Any]) -> FunctionInfo
_parse_import _parse_import(data: dict[str, Any]) -> ImportInfo
_parse_param _parse_param(data: dict[str, Any]) -> ParamInfo
_parse_class_var _parse_class_var(data: dict[str, Any]) -> ClassVarInfo

Source

Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/src/orchestrata_tools/parser/json_loader.py

"""Load ASTCodebase from serialize_codebase_ast JSON output."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from orchestrata_tools.models.ast_models import (
    ASTCodebase,
    ClassInfo,
    ClassVarInfo,
    FunctionInfo,
    ImportInfo,
    MethodInfo,
    ModuleInfo,
    ParamInfo,
)


class JSONASTLoader:
    """Load ASTCodebase from JSON produced by serialize_codebase_ast.py."""

    def load(self, path: Path | str) -> ASTCodebase:
        with open(path) as f:
            data = json.load(f)
        return self.load_from_dict(data)

    def load_from_dict(self, data: dict[str, Any]) -> ASTCodebase:
        modules = [self._parse_module(m) for m in data.get("modules", [])]
        return ASTCodebase(
            name=data.get("name", ""),
            root_path=data.get("root_path", ""),
            modules=modules,
            inheritance_graph=data.get("inheritance_graph", {}),
            dependency_graph=data.get("dependency_graph", {}),
            total_classes=data.get("total_classes", 0),
            total_functions=data.get("total_functions", 0),
            total_methods=data.get("total_methods", 0),
            total_loc=data.get("total_loc", 0),
        )

    def _parse_module(self, data: dict[str, Any]) -> ModuleInfo:
        return ModuleInfo(
            path=data.get("path", ""),
            file_path=data.get("file_path", ""),
            line_count=data.get("line_count", 0),
            classes=[
                self._parse_class(c, data.get("path", ""), data.get("file_path", ""))
                for c in data.get("classes", [])
            ],
            functions=[self._parse_function(f) for f in data.get("functions", [])],
            imports=[self._parse_import(i) for i in data.get("imports", [])],
            module_vars=data.get("module_vars", []),
            docstring=data.get("docstring"),
            all_exports=data.get("all_exports", []),
        )

    def _parse_class(
        self, data: dict[str, Any] | str, module_path: str = "", file_path: str = ""
    ) -> ClassInfo:
        if isinstance(data, str):
            return ClassInfo(
                name=data,
                qualified_name=f"{module_path}.{data}",
                module_path=module_path,
                file_path=file_path,
                line=0,
            )
        return ClassInfo(
            name=data.get("name", ""),
            qualified_name=data.get("qualified_name", ""),
            module_path=data.get("module_path", module_path),
            file_path=data.get("file_path", file_path),
            line=data.get("line", 0),
            bases=data.get("bases", []),
            decorators=data.get("decorators", []),
            methods=[self._parse_method(m) for m in data.get("methods", [])],
            class_vars=[self._parse_class_var(v) for v in data.get("class_vars", [])],
            docstring=data.get("docstring"),
            is_abstract=data.get("is_abstract", False),
            is_dataclass=data.get("is_dataclass", False),
            is_pydantic=data.get("is_pydantic", False),
            is_protocol=data.get("is_protocol", False),
            is_enum=data.get("is_enum", False),
            inner_classes=[
                self._parse_class(
                    c,
                    data.get("module_path", module_path),
                    data.get("file_path", file_path),
                )
                for c in data.get("inner_classes", [])
            ],
        )

    def _parse_method(self, data: dict[str, Any]) -> MethodInfo:
        return MethodInfo(
            name=data.get("name", ""),
            qualified_name=data.get("qualified_name", ""),
            module_path=data.get("module_path", ""),
            file_path=data.get("file_path", ""),
            line=data.get("line", 0),
            is_async=data.get("is_async", False),
            is_method=data.get("is_method", True),
            is_classmethod=data.get("is_classmethod", False),
            is_staticmethod=data.get("is_staticmethod", False),
            is_property=data.get("is_property", False),
            is_abstract=data.get("is_abstract", False),
            decorators=data.get("decorators", []),
            parameters=[self._parse_param(p) for p in data.get("parameters", [])],
            return_type=data.get("return_type"),
            docstring=data.get("docstring"),
            class_name=data.get("class_name", ""),
            calls=data.get("calls", []),
        )

    def _parse_function(self, data: dict[str, Any]) -> FunctionInfo:
        return FunctionInfo(
            name=data.get("name", ""),
            qualified_name=data.get("qualified_name", ""),
            module_path=data.get("module_path", ""),
            file_path=data.get("file_path", ""),
            line=data.get("line", 0),
            is_async=data.get("is_async", False),
            decorators=data.get("decorators", []),
            parameters=[self._parse_param(p) for p in data.get("parameters", [])],
            return_type=data.get("return_type"),
            docstring=data.get("docstring"),
        )

    def _parse_import(self, data: dict[str, Any]) -> ImportInfo:
        return ImportInfo(
            module=data.get("module", ""),
            names=data.get("names", []),
            alias=data.get("alias"),
            is_from=data.get("is_from", False),
            is_relative=data.get("is_relative", False),
            level=data.get("level", 0),
        )

    def _parse_param(self, data: dict[str, Any]) -> ParamInfo:
        return ParamInfo(
            name=data.get("name", ""),
            type_annotation=data.get("type_annotation"),
            default=data.get("default"),
            kind=data.get("kind", "positional"),
        )

    def _parse_class_var(self, data: dict[str, Any]) -> ClassVarInfo:
        return ClassVarInfo(
            name=data.get("name", ""),
            type_annotation=data.get("type_annotation"),
            default=data.get("default"),
        )