From dcf40837f8fb606ca1ee5fb4353f379b6f70e730 Mon Sep 17 00:00:00 2001 From: "Alexie (Boyong) Madolid" Date: Wed, 11 Sep 2024 23:05:03 +0800 Subject: [PATCH] cleanup and migration --- jac/jaclang/__init__.py | 17 +++-- jac/jaclang/plugin/builtin.py | 6 +- jac/jaclang/plugin/default.py | 2 +- jac/jaclang/plugin/feature.py | 120 +++++++++++++++++++--------------- jac/jaclang/plugin/spec.py | 22 +++++-- 5 files changed, 99 insertions(+), 68 deletions(-) diff --git a/jac/jaclang/__init__.py b/jac/jaclang/__init__.py index 9afb8c8aa9..5688f245db 100644 --- a/jac/jaclang/__init__.py +++ b/jac/jaclang/__init__.py @@ -1,17 +1,22 @@ """The Jac Programming Language.""" -from jaclang.plugin.default import ( # noqa: E402 +from jaclang.plugin.default import ( + JacAccessValidation, JacBuiltin, JacCmdDefaults, JacFeatureDefaults, + JacNode, ) -from jaclang.plugin.feature import JacFeature, pm # noqa: E402 +from jaclang.plugin.feature import JacFeature, hookmanager jac_import = JacFeature.jac_import -pm.register(JacFeatureDefaults) -pm.register(JacBuiltin) -pm.register(JacCmdDefaults) -pm.load_setuptools_entrypoints("jac") + +hookmanager.register(JacFeatureDefaults) +hookmanager.register(JacBuiltin) +hookmanager.register(JacCmdDefaults) +hookmanager.register(JacAccessValidation) +hookmanager.register(JacNode) +hookmanager.load_setuptools_entrypoints("jac") __all__ = ["jac_import"] diff --git a/jac/jaclang/plugin/builtin.py b/jac/jaclang/plugin/builtin.py index 9288d26ae7..4509937eff 100644 --- a/jac/jaclang/plugin/builtin.py +++ b/jac/jaclang/plugin/builtin.py @@ -19,9 +19,9 @@ def dotgen( dot_file: Optional[str] = None, ) -> str: """Print the dot graph.""" - from jaclang.plugin.feature import pm + from jaclang.plugin.feature import JacBuiltin as JacB, JacFeature as Jac - root = pm.hook.get_root() + root = Jac.get_root() node = node if node is not None else root depth = depth if depth is not None else -1 traverse = traverse if traverse is not None else False @@ -29,7 +29,7 @@ def dotgen( edge_limit = edge_limit if edge_limit is not None else 512 node_limit = node_limit if node_limit is not None else 512 - return pm.hook.dotgen( + return JacB.dotgen( edge_type=edge_type, node=node, depth=depth, diff --git a/jac/jaclang/plugin/default.py b/jac/jaclang/plugin/default.py index f6b003157f..5fc9b2e58f 100644 --- a/jac/jaclang/plugin/default.py +++ b/jac/jaclang/plugin/default.py @@ -856,7 +856,7 @@ def dotgen( node: NodeArchitype, depth: int, traverse: bool, - edge_type: list[str], + edge_type: Optional[list[str]], bfs: bool, edge_limit: int, node_limit: int, diff --git a/jac/jaclang/plugin/feature.py b/jac/jaclang/plugin/feature.py index 155bd9d258..c057c71eee 100644 --- a/jac/jaclang/plugin/feature.py +++ b/jac/jaclang/plugin/feature.py @@ -14,9 +14,6 @@ EdgeArchitype, EdgeDir, ExecutionContext, - JacBuiltin, - JacCmdSpec, - JacFeatureSpec, NodeAnchor, NodeArchitype, P, @@ -25,15 +22,9 @@ T, WalkerArchitype, ast, + hookmanager, ) -import pluggy - -pm = pluggy.PluginManager("jac") -pm.add_hookspecs(JacFeatureSpec) -pm.add_hookspecs(JacCmdSpec) -pm.add_hookspecs(JacBuiltin) - class JacFeature: """Jac Feature.""" @@ -41,22 +32,22 @@ class JacFeature: @staticmethod def setup() -> None: """Set Class References.""" - pm.hook.setup() + hookmanager.hook.setup() @staticmethod def get_context() -> ExecutionContext: """Get current execution context.""" - return pm.hook.get_context() + return hookmanager.hook.get_context() @staticmethod def get_object(id: str) -> Architype | None: """Get object given id.""" - return pm.hook.get_object(id=id) + return hookmanager.hook.get_object(id=id) @staticmethod def object_ref(obj: Architype) -> str: """Get object reference id.""" - return pm.hook.object_ref(obj=obj) + return hookmanager.hook.object_ref(obj=obj) @staticmethod def make_architype( @@ -66,7 +57,7 @@ def make_architype( on_exit: list[DSFunc], ) -> Type[Architype]: """Create a obj architype.""" - return pm.hook.make_architype( + return hookmanager.hook.make_architype( cls=cls, on_entry=on_entry, on_exit=on_exit, arch_base=arch_base ) @@ -75,35 +66,35 @@ def make_obj( on_entry: list[DSFunc], on_exit: list[DSFunc] ) -> Callable[[type], type]: """Create a obj architype.""" - return pm.hook.make_obj(on_entry=on_entry, on_exit=on_exit) + return hookmanager.hook.make_obj(on_entry=on_entry, on_exit=on_exit) @staticmethod def make_node( on_entry: list[DSFunc], on_exit: list[DSFunc] ) -> Callable[[type], type]: """Create a node architype.""" - return pm.hook.make_node(on_entry=on_entry, on_exit=on_exit) + return hookmanager.hook.make_node(on_entry=on_entry, on_exit=on_exit) @staticmethod def make_edge( on_entry: list[DSFunc], on_exit: list[DSFunc] ) -> Callable[[type], type]: """Create a edge architype.""" - return pm.hook.make_edge(on_entry=on_entry, on_exit=on_exit) + return hookmanager.hook.make_edge(on_entry=on_entry, on_exit=on_exit) @staticmethod def make_walker( on_entry: list[DSFunc], on_exit: list[DSFunc] ) -> Callable[[type], type]: """Create a walker architype.""" - return pm.hook.make_walker(on_entry=on_entry, on_exit=on_exit) + return hookmanager.hook.make_walker(on_entry=on_entry, on_exit=on_exit) @staticmethod def impl_patch_filename( file_loc: str, ) -> Callable[[Callable[P, T]], Callable[P, T]]: """Update impl file location.""" - return pm.hook.impl_patch_filename(file_loc=file_loc) + return hookmanager.hook.impl_patch_filename(file_loc=file_loc) @staticmethod def jac_import( @@ -118,7 +109,7 @@ def jac_import( reload_module: Optional[bool] = False, ) -> tuple[types.ModuleType, ...]: """Core Import Process.""" - return pm.hook.jac_import( + return hookmanager.hook.jac_import( target=target, base_path=base_path, absorb=absorb, @@ -133,7 +124,7 @@ def jac_import( @staticmethod def create_test(test_fun: Callable) -> Callable: """Create a test.""" - return pm.hook.create_test(test_fun=test_fun) + return hookmanager.hook.create_test(test_fun=test_fun) @staticmethod def run_test( @@ -145,7 +136,7 @@ def run_test( verbose: bool = False, ) -> int: """Run the test suite in the specified .jac file.""" - return pm.hook.run_test( + return hookmanager.hook.run_test( filepath=filepath, filter=filter, xit=xit, @@ -157,22 +148,22 @@ def run_test( @staticmethod def elvis(op1: Optional[T], op2: T) -> T: """Jac's elvis operator feature.""" - return pm.hook.elvis(op1=op1, op2=op2) + return hookmanager.hook.elvis(op1=op1, op2=op2) @staticmethod def has_instance_default(gen_func: Callable[[], T]) -> T: """Jac's has container default feature.""" - return pm.hook.has_instance_default(gen_func=gen_func) + return hookmanager.hook.has_instance_default(gen_func=gen_func) @staticmethod def spawn_call(op1: Architype, op2: Architype) -> WalkerArchitype: """Jac's spawn operator feature.""" - return pm.hook.spawn_call(op1=op1, op2=op2) + return hookmanager.hook.spawn_call(op1=op1, op2=op2) @staticmethod def report(expr: Any) -> Any: # noqa: ANN401 """Jac's report stmt feature.""" - return pm.hook.report(expr=expr) + return hookmanager.hook.report(expr=expr) @staticmethod def ignore( @@ -186,7 +177,7 @@ def ignore( ), ) -> bool: # noqa: ANN401 """Jac's ignore stmt feature.""" - return pm.hook.ignore(walker=walker, expr=expr) + return hookmanager.hook.ignore(walker=walker, expr=expr) @staticmethod def visit_node( @@ -200,12 +191,12 @@ def visit_node( ), ) -> bool: # noqa: ANN401 """Jac's visit stmt feature.""" - return pm.hook.visit_node(walker=walker, expr=expr) + return hookmanager.hook.visit_node(walker=walker, expr=expr) @staticmethod def disengage(walker: WalkerArchitype) -> bool: # noqa: ANN401 """Jac's disengage stmt feature.""" - return pm.hook.disengage(walker=walker) + return hookmanager.hook.disengage(walker=walker) @staticmethod def edge_ref( @@ -216,7 +207,7 @@ def edge_ref( edges_only: bool = False, ) -> list[NodeArchitype] | list[EdgeArchitype]: """Jac's apply_dir stmt feature.""" - return pm.hook.edge_ref( + return hookmanager.hook.edge_ref( node_obj=node_obj, target_obj=target_obj, dir=dir, @@ -235,7 +226,7 @@ def connect( Note: connect needs to call assign compr with tuple in op """ - return pm.hook.connect( + return hookmanager.hook.connect( left=left, right=right, edge_spec=edge_spec, edges_only=edges_only ) @@ -247,7 +238,7 @@ def disconnect( filter_func: Optional[Callable[[list[EdgeArchitype]], list[EdgeArchitype]]], ) -> bool: """Jac's disconnect operator feature.""" - return pm.hook.disconnect( + return hookmanager.hook.disconnect( left=left, right=right, dir=dir, @@ -259,17 +250,17 @@ def assign_compr( target: list[T], attr_val: tuple[tuple[str], tuple[Any]] ) -> list[T]: """Jac's assign comprehension feature.""" - return pm.hook.assign_compr(target=target, attr_val=attr_val) + return hookmanager.hook.assign_compr(target=target, attr_val=attr_val) @staticmethod def get_root() -> Root: """Jac's root getter.""" - return pm.hook.get_root() + return hookmanager.hook.get_root() @staticmethod def get_root_type() -> Type[Root]: """Jac's root type getter.""" - return pm.hook.get_root_type() + return hookmanager.hook.get_root_type() @staticmethod def build_edge( @@ -278,7 +269,7 @@ def build_edge( conn_assign: Optional[tuple[tuple, tuple]], ) -> Callable[[NodeAnchor, NodeAnchor], EdgeArchitype]: """Jac's root getter.""" - return pm.hook.build_edge( + return hookmanager.hook.build_edge( is_undirected=is_undirected, conn_type=conn_type, conn_assign=conn_assign ) @@ -287,19 +278,19 @@ def get_semstr_type( file_loc: str, scope: str, attr: str, return_semstr: bool ) -> Optional[str]: """Jac's get_semstr_type feature.""" - return pm.hook.get_semstr_type( + return hookmanager.hook.get_semstr_type( file_loc=file_loc, scope=scope, attr=attr, return_semstr=return_semstr ) @staticmethod def obj_scope(file_loc: str, attr: str) -> str: """Jac's get_semstr_type feature.""" - return pm.hook.obj_scope(file_loc=file_loc, attr=attr) + return hookmanager.hook.obj_scope(file_loc=file_loc, attr=attr) @staticmethod def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]: """Jac's get_semstr_type feature.""" - return pm.hook.get_sem_type(file_loc=file_loc, attr=attr) + return hookmanager.hook.get_sem_type(file_loc=file_loc, attr=attr) @staticmethod def with_llm( @@ -316,7 +307,7 @@ def with_llm( _locals: Mapping, ) -> Any: # noqa: ANN401 """Jac's with_llm feature.""" - return pm.hook.with_llm( + return hookmanager.hook.with_llm( file_loc=file_loc, model=model, model_params=model_params, @@ -333,7 +324,7 @@ def with_llm( @staticmethod def gen_llm_body(_pass: PyastGenPass, node: ast.Ability) -> list[ast3.AST]: """Generate the by LLM body.""" - return pm.hook.gen_llm_body(_pass=_pass, node=node) + return hookmanager.hook.gen_llm_body(_pass=_pass, node=node) @staticmethod def by_llm_call( @@ -348,7 +339,7 @@ def by_llm_call( exclude_info: list[tuple[str, ast3.AST]], ) -> ast3.Call: """Return the LLM Call, e.g. _Jac.with_llm().""" - return pm.hook.by_llm_call( + return hookmanager.hook.by_llm_call( _pass=_pass, model=model, model_params=model_params, @@ -363,7 +354,34 @@ def by_llm_call( @staticmethod def get_by_llm_call_args(_pass: PyastGenPass, node: ast.FuncCall) -> dict: """Get the by LLM call args.""" - return pm.hook.get_by_llm_call_args(_pass=_pass, node=node) + return hookmanager.hook.get_by_llm_call_args(_pass=_pass, node=node) + + +class JacBuiltin: + """Jac Builtins.""" + + @staticmethod + def dotgen( + node: NodeArchitype, + depth: int, + traverse: bool, + edge_type: Optional[list[str]], + bfs: bool, + edge_limit: int, + node_limit: int, + dot_file: Optional[str], + ) -> str: + """Generate Dot file for visualizing nodes and edges.""" + return hookmanager.hook.dotgen( + node=node, + depth=depth, + traverse=traverse, + edge_type=edge_type, + bfs=bfs, + edge_limit=edge_limit, + node_limit=node_limit, + dot_file=dot_file, + ) class JacCmd: @@ -372,7 +390,7 @@ class JacCmd: @staticmethod def create_cmd() -> None: """Create Jac CLI cmds.""" - return pm.hook.create_cmd() + return hookmanager.hook.create_cmd() class JacAccessValidation: @@ -381,22 +399,22 @@ class JacAccessValidation: @staticmethod def check_read_access(to: Anchor) -> bool: """Read Access Validation.""" - return pm.hook.check_read_access(to=to) + return hookmanager.hook.check_read_access(to=to) @staticmethod def check_connect_access(to: Anchor) -> bool: """Write Access Validation.""" - return pm.hook.check_connect_access(to=to) + return hookmanager.hook.check_connect_access(to=to) @staticmethod def check_write_access(to: Anchor) -> bool: """Write Access Validation.""" - return pm.hook.check_write_access(to=to) + return hookmanager.hook.check_write_access(to=to) @staticmethod def check_access_level(to: Anchor) -> AccessLevel: """Access validation.""" - return pm.hook.check_access_level(to=to) + return hookmanager.hook.check_access_level(to=to) class JacNode: @@ -410,7 +428,7 @@ def get_edges( target_obj: Optional[list[NodeArchitype]], ) -> list[EdgeArchitype]: """Get edges connected to this node.""" - return pm.hook.get_edges( + return hookmanager.hook.get_edges( node=node, dir=dir, filter_func=filter_func, target_obj=target_obj ) @@ -422,6 +440,6 @@ def edges_to_nodes( target_obj: Optional[list[NodeArchitype]], ) -> list[NodeArchitype]: """Get set of nodes connected to this node.""" - return pm.hook.edges_to_nodes( + return hookmanager.hook.edges_to_nodes( node=node, dir=dir, filter_func=filter_func, target_obj=target_obj ) diff --git a/jac/jaclang/plugin/spec.py b/jac/jaclang/plugin/spec.py index 60585bf4d0..df7dd336d9 100644 --- a/jac/jaclang/plugin/spec.py +++ b/jac/jaclang/plugin/spec.py @@ -35,6 +35,7 @@ import pluggy hookspec = pluggy.HookspecMarker("jac") +hookmanager = pluggy.PluginManager("jac") T = TypeVar("T") P = ParamSpec("P") @@ -355,7 +356,7 @@ def dotgen( node: NodeArchitype, depth: int, traverse: bool, - edge_type: list[str], + edge_type: Optional[list[str]], bfs: bool, edge_limit: int, node_limit: int, @@ -379,25 +380,25 @@ class JacAccessValidation: """Jac Access Validation Specs.""" @staticmethod - @hookspec + @hookspec(firstresult=True) def check_read_access(to: Anchor) -> bool: """Read Access Validation.""" raise NotImplementedError @staticmethod - @hookspec + @hookspec(firstresult=True) def check_connect_access(to: Anchor) -> bool: """Write Access Validation.""" raise NotImplementedError @staticmethod - @hookspec + @hookspec(firstresult=True) def check_write_access(to: Anchor) -> bool: """Write Access Validation.""" raise NotImplementedError @staticmethod - @hookspec + @hookspec(firstresult=True) def check_access_level(to: Anchor) -> AccessLevel: """Access validation.""" raise NotImplementedError @@ -407,7 +408,7 @@ class JacNode: """Jac Node Operations.""" @staticmethod - @hookspec + @hookspec(firstresult=True) def get_edges( node: NodeAnchor, dir: EdgeDir, @@ -418,7 +419,7 @@ def get_edges( raise NotImplementedError @staticmethod - @hookspec + @hookspec(firstresult=True) def edges_to_nodes( node: NodeAnchor, dir: EdgeDir, @@ -427,3 +428,10 @@ def edges_to_nodes( ) -> list[NodeArchitype]: """Get set of nodes connected to this node.""" raise NotImplementedError + + +hookmanager.add_hookspecs(JacFeatureSpec) +hookmanager.add_hookspecs(JacCmdSpec) +hookmanager.add_hookspecs(JacBuiltin) +hookmanager.add_hookspecs(JacAccessValidation) +hookmanager.add_hookspecs(JacNode)