1414
1515import importlib .util
1616import os
17+ import sys
1718import shutil
1819from hatchling .builders .hooks .plugin .interface import BuildHookInterface
1920
2021
21- def load_constants (project_root ):
22- """Loads the shared constants module directly from its path in src/."""
23- constants_path = os .path .join (
24- project_root , "src" , "a2ui" , "inference" , "schema" , "constants.py"
25- )
26- if not os .path .exists (constants_path ):
27- raise RuntimeError (f"Could not find shared constants at { constants_path } " )
22+ def load_module (project_root , rel_path , filename , module_name ):
23+ """Loads a module directly from its path in src/."""
24+ path = os .path .join (project_root , "src" , rel_path .replace ("." , os .sep ), filename )
25+ if not os .path .exists (path ):
26+ raise RuntimeError (f"Could not find module at { path } " )
2827
29- spec = importlib .util .spec_from_file_location ("_constants_load" , constants_path )
28+ # Add src to sys.path so absolute imports work
29+ src_path = os .path .abspath (os .path .join (project_root , "src" ))
30+ if src_path not in sys .path :
31+ sys .path .insert (0 , src_path )
32+
33+ spec = importlib .util .spec_from_file_location (module_name , path )
3034 if spec and spec .loader :
3135 module = importlib .util .module_from_spec (spec )
36+ # Set the package context to allow relative imports if any
37+ module .__package__ = rel_path
38+ sys .modules [module_name ] = module
3239 spec .loader .exec_module (module )
3340 return module
34- raise RuntimeError (f"Could not load shared constants from { constants_path } " )
41+ raise RuntimeError (f"Could not load module from { path } " )
3542
3643
3744class PackSpecsBuildHook (BuildHookInterface ):
3845
3946 def initialize (self , version , build_data ):
4047 project_root = self .root
4148
42- # Load constants dynamically from src/a2ui/inference/schema/constants.py
43- a2ui_constants = load_constants (project_root )
49+ # Load constants and utils dynamically from src/
50+ schema_path = "a2ui.inference.schema"
51+ a2ui_constants = load_module (
52+ project_root , schema_path , "constants.py" , "_constants_load"
53+ )
54+ a2ui_utils = load_module (project_root , schema_path , "utils.py" , "_utils_load" )
55+
56+ basic_catalog_constants = load_module (
57+ project_root ,
58+ "a2ui.inference.basic_catalog" ,
59+ "constants.py" ,
60+ "_basic_catalog_constants_load" ,
61+ )
4462
4563 spec_version_map = a2ui_constants .SPEC_VERSION_MAP
4664 a2ui_asset_package = a2ui_constants .A2UI_ASSET_PACKAGE
4765 specification_dir = a2ui_constants .SPECIFICATION_DIR
4866
49- # project root is in a2a_agents/python/a2ui_agent
5067 # Dynamically find repo root by looking for specification_dir
51- repo_root = a2ui_constants .find_repo_root (project_root )
68+ repo_root = a2ui_utils .find_repo_root (project_root )
5269 if not repo_root :
5370 # Check for PKG-INFO which implies a packaged state (sdist).
5471 # If PKG-INFO is present, trust the bundled assets.
@@ -66,23 +83,40 @@ def initialize(self, version, build_data):
6683 project_root , "src" , a2ui_asset_package .replace ("." , os .sep )
6784 )
6885
69- for ver , schema_map in spec_version_map .items ():
86+ self ._pack_schemas (repo_root , spec_version_map , target_base )
87+ self ._pack_basic_catalogs (
88+ repo_root , basic_catalog_constants .BASIC_CATALOG_PATHS , target_base
89+ )
90+
91+ def _pack_schemas (self , repo_root , spec_map , target_base ):
92+ for ver , schema_map in spec_map .items ():
7093 target_dir = os .path .join (target_base , ver )
7194 os .makedirs (target_dir , exist_ok = True )
7295
7396 for _schema_key , source_rel_path in schema_map .items ():
74- source_path = os . path . join (repo_root , source_rel_path )
97+ self . _copy_schema (repo_root , source_rel_path , target_dir )
7598
76- if not os .path .exists (source_path ):
77- print (
78- f"WARNING: Source schema file not found at { source_path } . Build"
79- " might produce incomplete wheel if not running from monorepo"
80- " root."
81- )
82- continue
99+ def _pack_basic_catalogs (self , repo_root , catalog_paths , target_base ):
100+ for ver , path_map in catalog_paths .items ():
101+ target_dir = os .path .join (target_base , ver )
102+ os .makedirs (target_dir , exist_ok = True )
103+
104+ for _key , source_rel_path in path_map .items ():
105+ self ._copy_schema (repo_root , source_rel_path , target_dir )
106+
107+ def _copy_schema (self , repo_root , source_rel_path , target_dir ):
108+ source_path = os .path .join (repo_root , source_rel_path )
109+
110+ if not os .path .exists (source_path ):
111+ print (
112+ f"WARNING: Source schema file not found at { source_path } . Build"
113+ " might produce incomplete wheel if not running from monorepo"
114+ " root."
115+ )
116+ return
83117
84- filename = os .path .basename (source_path )
85- dst_file = os .path .join (target_dir , filename )
118+ filename = os .path .basename (source_path )
119+ dst_file = os .path .join (target_dir , filename )
86120
87- print (f"Copying { source_path } -> { dst_file } " )
88- shutil .copy2 (source_path , dst_file )
121+ print (f"Copying { source_path } -> { dst_file } " )
122+ shutil .copy2 (source_path , dst_file )
0 commit comments