|
|
from typing import Optional, Dict, List, Type, Any |
|
|
from dataclasses import dataclass, field, asdict, fields, is_dataclass |
|
|
|
|
|
|
|
|
ENTITY_TYPE_MAP = {} |
|
|
|
|
|
def register_entity(cls): |
|
|
ENTITY_TYPE_MAP[cls.__name__] = cls |
|
|
return cls |
|
|
|
|
|
def _entity_to_dict(obj): |
|
|
if isinstance(obj, list): |
|
|
return [_entity_to_dict(item) for item in obj] |
|
|
elif isinstance(obj, dict): |
|
|
return {(_entity_to_dict(k) if isinstance(k, Entity) else k): _entity_to_dict(v) for k, v in obj.items()} |
|
|
elif isinstance(obj, Entity): |
|
|
return obj.to_dict() |
|
|
elif hasattr(obj, 'to_dict'): |
|
|
return obj.to_dict() |
|
|
else: |
|
|
return obj |
|
|
|
|
|
def _entity_from_dict(data): |
|
|
if isinstance(data, list): |
|
|
return [_entity_from_dict(item) for item in data] |
|
|
elif isinstance(data, dict) and 'entity_type' in data: |
|
|
cls = ENTITY_TYPE_MAP.get(data['entity_type'].capitalize(), Entity) |
|
|
return cls.from_dict(data) |
|
|
else: |
|
|
return data |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class Entity: |
|
|
entity_type: str |
|
|
entity_name: str |
|
|
defined_chunk_id: str |
|
|
entity_dtype: str |
|
|
|
|
|
def to_dict(self): |
|
|
d = asdict(self) |
|
|
d['entity_type'] = self.entity_type |
|
|
d['__class__'] = self.__class__.__name__ |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
|
|
|
data = dict(data) |
|
|
data.pop('__class__', None) |
|
|
return cls(**data) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class Variable(Entity): |
|
|
entity_type = 'variable' |
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
return super().from_dict(data) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class Parameter(Entity): |
|
|
entity_type = 'parameter' |
|
|
entity_dtype: str |
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
return super().from_dict(data) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class Method(Entity): |
|
|
entity_type = 'method' |
|
|
parameters: List['Parameter'] = field(default_factory=list) |
|
|
associated_class: Optional['Class'] = None |
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['parameters'] = _entity_to_dict(self.parameters) |
|
|
d['associated_class'] = self.associated_class.to_dict() if self.associated_class else None |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
params = [_entity_from_dict(p) for p in data.get('parameters', [])] |
|
|
assoc_cls = Class.from_dict(data['associated_class']) if data.get('associated_class') else None |
|
|
base = {k: v for k, v in data.items() if k not in ['parameters', 'parameters_pairs', 'associated_class']} |
|
|
return cls(parameters=params, associated_class=assoc_cls, **base) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class Class(Entity): |
|
|
entity_type = 'class' |
|
|
defined_methods: List['Method'] = field(default_factory=list) |
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['defined_methods'] = _entity_to_dict(self.defined_methods) |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
methods = [_entity_from_dict(m) for m in data.get('defined_methods', [])] |
|
|
base = {k: v for k, v in data.items() if k != 'defined_methods'} |
|
|
return cls(defined_methods=methods, **base) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class Function(Entity): |
|
|
entity_type = 'function' |
|
|
parameters: List[Parameter] = field(default_factory=list) |
|
|
parameters_pairs: List[tuple] = field(default_factory=list) |
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['parameters'] = _entity_to_dict(self.parameters) |
|
|
d['parameters_pairs'] = [ (p.to_dict(), v.to_dict()) for p, v in self.parameters_pairs ] |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
params = [_entity_from_dict(p) for p in data.get('parameters', [])] |
|
|
parameters_pairs = [(Parameter.from_dict(p), Variable.from_dict(v)) for p, v in data.get('parameters_pairs', [])] |
|
|
base = {k: v for k, v in data.items() if k not in ['parameters', 'parameters_pairs']} |
|
|
return cls(parameters=params, parameters_pairs=parameters_pairs, **base) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class FunctionCall(Entity): |
|
|
entity_type: str = 'function_call' |
|
|
entity_name: str = '' |
|
|
defined_chunk_id: str = '' |
|
|
entity_dtype: str = '' |
|
|
arguments: List[tuple] = field(default_factory=list) |
|
|
associated_functions: Optional[Function] = field(default_factory=list) |
|
|
|
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['arguments'] = [ (p.to_dict(), v.to_dict()) for p, v in self.arguments ] |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
arguments = [(Parameter.from_dict(p), Variable.from_dict(v)) for p, v in data.get('arguments', [])] |
|
|
base = {k: v for k, v in data.items() if k != 'arguments'} |
|
|
return cls(arguments=arguments, **base) |
|
|
|
|
|
@register_entity |
|
|
@dataclass |
|
|
class MethodCall(Entity): |
|
|
entity_type: str = 'method_call' |
|
|
entity_name: str = '' |
|
|
defined_chunk_id: str = '' |
|
|
entity_dtype: str = '' |
|
|
arguments: List[tuple] = field(default_factory=list) |
|
|
associated_class: Optional[Class] = None |
|
|
associated_method: Optional[Method] = None |
|
|
|
|
|
def to_dict(self): |
|
|
d = super().to_dict() |
|
|
d['arguments'] = [ (p.to_dict(), v.to_dict()) for p, v in self.arguments ] |
|
|
d['associated_class'] = self.associated_class.to_dict() if self.associated_class else None |
|
|
d['entity_type'] = self.entity_type |
|
|
return d |
|
|
|
|
|
@classmethod |
|
|
def from_dict(cls, data): |
|
|
arguments = [(Parameter.from_dict(p), Variable.from_dict(v)) for p, v in data.get('arguments', [])] |
|
|
assoc_cls = Class.from_dict(data['associated_class']) if data.get('associated_class') else None |
|
|
base = {k: v for k, v in data.items() if k not in ['arguments', 'associated_class']} |
|
|
return cls(arguments=arguments, associated_class=assoc_cls, **base) |