11import jinja2
22import os
33import shutil
4+ import zipfile
45
56requirements = [
67 "pandas" ,
78 "fuzzywuzzy" ,
89 "openpyxl" ,
9- # TODO: remove this once the package is published
10- "https://plasmogenepi.github.io/pmotool-app-web/assets/pmotools_python-0.1.0-py3-none-any.whl"
10+ # pmotools is extracted from wheel and included directly in filesystem
1111]
1212
13+
1314entrypoint = "PMO_Builder.py"
1415build_dir = "docs"
1516
@@ -19,34 +20,97 @@ def build_site():
1920 with open (template_path , "r" ) as f :
2021 template = jinja2 .Template (f .read ())
2122
22- # Load the python files in all subdirectories
23+ # Copy Python and JSON files from submodule to docs/app/ directory
24+ app_dir = os .path .join (build_dir , "app" )
2325 parsed_files = []
26+
27+ # Copy Python files
2428 for root , dirs , files in os .walk ("pmotools-app" ):
2529 for file in files :
2630 if file .endswith (".py" ):
27- with open (os .path .join (root , file ), "r" ) as f :
28- file_name = os .path .join (root , file ).replace ("pmotools-app/" , "" )
29- parsed_files .append ({"name" : file_name , "content" : f"`{ f .read ()} `" })
31+ src_path = os .path .join (root , file )
32+ # Preserve directory structure relative to pmotools-app
33+ rel_path = os .path .relpath (src_path , "pmotools-app" )
34+ dst_path = os .path .join (app_dir , rel_path )
35+
36+ # Create destination directory
37+ os .makedirs (os .path .dirname (dst_path ), exist_ok = True )
38+ shutil .copy (src_path , dst_path )
39+
40+ # Store file path for template
41+ file_name = rel_path .replace ("\\ " , "/" ) # Normalize path separators
42+ parsed_files .append ({"name" : file_name , "url" : f"app/{ file_name } " })
3043
31- # Add the images to the parsed files
32- for root , dirs , files in os .walk ("pmotools-app" ):
33- for file in files :
34- if file .endswith (".png" ):
35- file_name = os .path .join (root , file ).replace ("pmotools-app/" , "" )
36- # copy the file to the build directory
37- os .makedirs (os .path .join (build_dir , "images" ), exist_ok = True )
38- shutil .copy (os .path .join (root , file ), os .path .join (build_dir , "images" , file ))
39- build_url = f"images/{ file } "
40- parsed_files .append ({"name" : file_name , "content" : {"url" : build_url }})
41-
42- # Add conf files to the parsed files
44+ # Copy JSON config files
4345 for root , dirs , files in os .walk ("pmotools-app" ):
4446 for file in files :
4547 if file .endswith (".json" ):
46- with open (os .path .join (root , file ), "r" ) as f :
47- file_name = os .path .join (root , file ).replace ("pmotools-app/" , "" )
48- parsed_files .append ({"name" : file_name , "content" : f"`{ f .read ()} `" })
48+ src_path = os .path .join (root , file )
49+ # Preserve directory structure relative to pmotools-app
50+ rel_path = os .path .relpath (src_path , "pmotools-app" )
51+ dst_path = os .path .join (app_dir , rel_path )
52+
53+ # Create destination directory
54+ os .makedirs (os .path .dirname (dst_path ), exist_ok = True )
55+ shutil .copy (src_path , dst_path )
56+
57+ # Store file path for template
58+ file_name = rel_path .replace ("\\ " , "/" ) # Normalize path separators
59+ parsed_files .append ({"name" : file_name , "url" : f"app/{ file_name } " })
4960
61+ # Extract pmotools package from wheel and add to filesystem
62+ # This avoids installing dependencies that are already in requirements
63+ wheel_path = os .path .join (build_dir , "assets" , "pmotools-0.1.0-py3-none-any.whl" )
64+ if os .path .exists (wheel_path ):
65+ with zipfile .ZipFile (wheel_path , 'r' ) as wheel :
66+ # Extract only pmotools package files (not dist-info)
67+ for member in wheel .namelist ():
68+ if member .startswith ('pmotools/' ) and not member .endswith ('/' ):
69+ # Extract to app directory (which is in Python path in stlite)
70+ # Store as site-packages/pmotools/... for proper Python import
71+ relative_path = member # This is already pmotools/...
72+ dst_path = os .path .join (app_dir , "site-packages" , relative_path )
73+ os .makedirs (os .path .dirname (dst_path ), exist_ok = True )
74+
75+ # Extract and write the file
76+ with wheel .open (member ) as source :
77+ with open (dst_path , 'wb' ) as target :
78+ target .write (source .read ())
79+
80+ # Add to parsed files for template
81+ file_name = relative_path .replace ("\\ " , "/" )
82+ parsed_files .append ({"name" : file_name , "url" : f"app/site-packages/{ file_name } " })
83+
84+ # Create __init__.py for site-packages if needed
85+ site_packages_init = os .path .join (app_dir , "site-packages" , "__init__.py" )
86+ if not os .path .exists (site_packages_init ):
87+ os .makedirs (os .path .dirname (site_packages_init ), exist_ok = True )
88+ with open (site_packages_init , 'w' ) as f :
89+ f .write ("" )
90+
91+ # Create a setup file to add site-packages to sys.path
92+ setup_file = os .path .join (app_dir , "_setup_pmotools.py" )
93+ with open (setup_file , 'w' ) as f :
94+ f .write ("""import sys
95+ import os
96+ # Add site-packages to Python path so pmotools can be imported
97+ site_packages = os.path.join(os.path.dirname(__file__), 'site-packages')
98+ if site_packages not in sys.path:
99+ sys.path.insert(0, site_packages)
100+ """ )
101+ # Add setup file to parsed files
102+ parsed_files .append ({"name" : "_setup_pmotools.py" , "url" : "app/_setup_pmotools.py" })
103+
104+ # Modify PMO_Builder.py to import setup first
105+ pmo_builder_path = os .path .join (app_dir , "PMO_Builder.py" )
106+ if os .path .exists (pmo_builder_path ):
107+ with open (pmo_builder_path , 'r' ) as f :
108+ content = f .read ()
109+ # Add import at the very beginning if not already present
110+ if "import _setup_pmotools" not in content :
111+ content = "import _setup_pmotools\n " + content
112+ with open (pmo_builder_path , 'w' ) as f :
113+ f .write (content )
50114
51115 # Render the template
52116 rendered = template .render (files = parsed_files , requirements = requirements , entrypoint = entrypoint )
0 commit comments