1+ # -*- mode: python ; coding: utf-8 -*-
2+ #
3+ # Licensed to the Apache Software Foundation (ASF) under one
4+ # or more contributor license agreements. See the NOTICE file
5+ # distributed with this work for additional information
6+ # regarding copyright ownership. The ASF licenses this file
7+ # to you under the Apache License, Version 2.0 (the
8+ # "License"); you may not use this file except in compliance
9+ # with the License. You may obtain a copy of the License at
10+ #
11+ # http://www.apache.org/licenses/LICENSE-2.0
12+ #
13+ # Unless required by applicable law or agreed to in writing,
14+ # software distributed under this License is distributed on an
15+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+ # KIND, either express or implied. See the License for the
17+ # specific language governing permissions and limitations
18+ # under the License.
19+ #
20+
21+ from pathlib import Path
22+
23+ # Get project root directory
24+ project_root = Path (SPECPATH ).parent
25+
26+ block_cipher = None
27+
28+ # Auto-collect all submodules of large dependency libraries
29+ # Using collect_all automatically includes all dependencies and avoids manual maintenance of hiddenimports
30+ from PyInstaller .utils .hooks import collect_all , collect_submodules , collect_data_files
31+
32+ # Collect only essential data files and binaries for large libraries
33+ # Using collect_all for all submodules slows down startup significantly.
34+ # However, for certain libraries with many dynamic imports (e.g., torch, transformers, safetensors),
35+ # collect_all is necessary to ensure all required modules are included.
36+ # For other libraries, we use lighter-weight collection methods to improve startup time.
37+ all_datas = []
38+ all_binaries = []
39+ all_hiddenimports = []
40+
41+ # Only collect essential data files and binaries for critical libraries
42+ # This reduces startup time by avoiding unnecessary module imports
43+ essential_libraries = {
44+ 'torch' : True , # Keep collect_all for torch as it has many dynamic imports
45+ 'transformers' : True , # Keep collect_all for transformers
46+ 'safetensors' : True , # Keep collect_all for safetensors
47+ }
48+
49+ # For other libraries, use selective collection to speed up startup
50+ other_libraries = ['sktime' , 'scipy' , 'pandas' , 'sklearn' , 'statsmodels' , 'optuna' ]
51+
52+ for lib in essential_libraries :
53+ try :
54+ lib_datas , lib_binaries , lib_hiddenimports = collect_all (lib )
55+ all_datas .extend (lib_datas )
56+ all_binaries .extend (lib_binaries )
57+ all_hiddenimports .extend (lib_hiddenimports )
58+ except Exception :
59+ pass
60+
61+ # For other libraries, only collect submodules (lighter weight)
62+ # This relies on PyInstaller's dependency analysis to include what's actually used
63+ for lib in other_libraries :
64+ try :
65+ submodules = collect_submodules (lib )
66+ all_hiddenimports .extend (submodules )
67+ # Only collect essential data files and binaries, not all submodules
68+ # This significantly reduces startup time
69+ try :
70+ lib_datas , lib_binaries , _ = collect_all (lib )
71+ all_datas .extend (lib_datas )
72+ all_binaries .extend (lib_binaries )
73+ except Exception :
74+ # If collect_all fails, try collect_data_files for essential data only
75+ try :
76+ lib_datas = collect_data_files (lib )
77+ all_datas .extend (lib_datas )
78+ except Exception :
79+ pass
80+ except Exception :
81+ pass
82+
83+ # Project-specific packages that need their submodules collected
84+ # Only list top-level packages - collect_submodules will recursively collect all submodules
85+ TOP_LEVEL_PACKAGES = [
86+ 'iotdb.ainode.core' , # This will include all sub-packages: manager, model, inference, etc.
87+ 'iotdb.thrift' , # This will include all thrift sub-packages
88+ ]
89+
90+ # Collect all submodules for project packages automatically
91+ # Using top-level packages avoids duplicate collection
92+ for package in TOP_LEVEL_PACKAGES :
93+ try :
94+ submodules = collect_submodules (package )
95+ all_hiddenimports .extend (submodules )
96+ except Exception :
97+ # If package doesn't exist or collection fails, add the package itself
98+ all_hiddenimports .append (package )
99+
100+ # Add parent packages to ensure they are included
101+ all_hiddenimports .extend (['iotdb' , 'iotdb.ainode' ])
102+
103+ # Multiprocessing support for PyInstaller
104+ # When using multiprocessing with PyInstaller, we need to ensure proper handling
105+ multiprocessing_modules = [
106+ 'multiprocessing' ,
107+ 'multiprocessing.spawn' ,
108+ 'multiprocessing.popen_spawn_posix' ,
109+ 'multiprocessing.popen_spawn_win32' ,
110+ 'multiprocessing.popen_fork' ,
111+ 'multiprocessing.popen_forkserver' ,
112+ 'multiprocessing.context' ,
113+ 'multiprocessing.reduction' ,
114+ 'multiprocessing.util' ,
115+ 'torch.multiprocessing' ,
116+ 'torch.multiprocessing.spawn' ,
117+ ]
118+
119+ # Additional dependencies that may need explicit import
120+ # These are external libraries that might use dynamic imports
121+ external_dependencies = [
122+ 'huggingface_hub' ,
123+ 'tokenizers' ,
124+ 'hf_xet' ,
125+ 'einops' ,
126+ 'dynaconf' ,
127+ 'tzlocal' ,
128+ 'thrift' ,
129+ 'psutil' ,
130+ 'requests' ,
131+ ]
132+
133+ all_hiddenimports .extend (multiprocessing_modules )
134+ all_hiddenimports .extend (external_dependencies )
135+
136+ # Analyze main entry file
137+ # Note: Do NOT add virtual environment site-packages to pathex manually.
138+ # When PyInstaller is run from the virtual environment's Python, it automatically
139+ # detects and uses the virtual environment's site-packages.
140+ a = Analysis (
141+ ['iotdb/ainode/core/script.py' ],
142+ pathex = [str (project_root )],
143+ binaries = all_binaries ,
144+ datas = all_datas ,
145+ hiddenimports = all_hiddenimports ,
146+ hookspath = [],
147+ hooksconfig = {},
148+ runtime_hooks = [],
149+ excludes = [
150+ # Exclude unnecessary modules to reduce size and improve startup time
151+ # Note: Do not exclude unittest, as torch and other libraries require it
152+ # Only exclude modules that are definitely not used and not required by dependencies
153+ 'matplotlib' ,
154+ 'IPython' ,
155+ 'jupyter' ,
156+ 'notebook' ,
157+ 'pytest' ,
158+ 'test' ,
159+ 'tests'
160+ ],
161+ win_no_prefer_redirects = False ,
162+ win_private_assemblies = False ,
163+ cipher = block_cipher ,
164+ noarchive = True , # Set to True to speed up startup - files are not archived into PYZ
165+ )
166+
167+ # Package all PYZ files
168+ pyz = PYZ (a .pure , a .zipped_data , cipher = block_cipher )
169+
170+ # Create executable (onedir mode for faster startup)
171+ exe = EXE (
172+ pyz ,
173+ a .scripts ,
174+ [],
175+ exclude_binaries = True ,
176+ name = 'ainode' ,
177+ debug = False ,
178+ bootloader_ignore_signals = False ,
179+ strip = False ,
180+ upx = True ,
181+ console = True ,
182+ disable_windowed_traceback = False ,
183+ argv_emulation = False ,
184+ target_arch = None ,
185+ codesign_identity = None ,
186+ entitlements_file = None ,
187+ )
188+
189+ # Collect all files into a directory (onedir mode)
190+ coll = COLLECT (
191+ exe ,
192+ a .binaries ,
193+ a .zipfiles ,
194+ a .datas ,
195+ strip = False ,
196+ upx = True ,
197+ upx_exclude = [],
198+ name = 'ainode' ,
199+ )
0 commit comments