1111from setuptools import setup , find_packages , Extension
1212from setuptools .command .build_py import build_py
1313from setuptools .command .install import install
14+ from setuptools .command .build_ext import build_ext
1415
15- # GitHub repository information
16- GITHUB_REPO = "77axel/pycnn" # Update with your actual repo
16+ PREBUILT_DOWNLOADED = False
17+
18+ GITHUB_REPO = "77AXEL/PyCNN"
1719GITHUB_API_URL = f"https://api.github.com/repos/{ GITHUB_REPO } /releases/latest"
1820
1921def get_platform_info ():
2022 """Get current platform and Python version information"""
2123 system = platform .system ()
2224 python_version = f"{ sys .version_info .major } .{ sys .version_info .minor } "
2325
24- # Map platform names to GitHub Actions runner names
2526 platform_map = {
2627 'Linux' : 'ubuntu-latest' ,
2728 'Darwin' : 'macos-latest' ,
@@ -45,36 +46,35 @@ def get_library_extensions(system):
4546
4647def download_prebuilt_binaries ():
4748 """Download pre-built binaries from GitHub releases"""
49+ global PREBUILT_DOWNLOADED
50+ if PREBUILT_DOWNLOADED :
51+ return True
52+
4853 os_name , py_version , system = get_platform_info ()
49-
50- # Python tag format: 3.9 -> cp39
5154 py_tag = f"cp{ py_version .replace ('.' , '' )} "
5255
53- print (f"Detected platform: { os_name } , Python: { py_version } ({ py_tag } )" )
54- print (f"Attempting to download pre-built binaries from GitHub releases..." )
56+ current_version = "2.5"
57+
58+ print (f"\n [PyCNN] Checking for pre-built binaries for { system } / Python { py_version } ..." )
5559
5660 try :
57- # Get latest release information
58- # Use a User-Agent to avoid some basic blocks
5961 req = urllib .request .Request (GITHUB_API_URL , headers = {'User-Agent' : 'Mozilla/5.0' })
6062 with urllib .request .urlopen (req ) as response :
6163 release_data = json .loads (response .read ().decode ())
6264
6365 assets = release_data .get ('assets' , [])
6466 tag_name = release_data .get ('tag_name' , 'unknown' )
6567
66- print (f"Found release: { tag_name } " )
68+ print (f"[PyCNN] Latest release found: { tag_name } " )
69+
70+ if current_version not in tag_name :
71+ print (f"[PyCNN] Warning: Latest release { tag_name } does not match current version { current_version } " )
6772
68- # Prepare directories
6973 lib_dir = Path ('pycnn/lib' )
7074 modules_dir = Path ('pycnn/modules' )
7175 lib_dir .mkdir (parents = True , exist_ok = True )
7276 modules_dir .mkdir (parents = True , exist_ok = True )
7377
74- # We look for the wheel that matches:
75- # 1. Python version tag (e.g. cp39)
76- # 2. Platform tag (e.g. win_amd64, manylinux, macosx)
77-
7878 platform_keywords = {
7979 'Linux' : 'linux' ,
8080 'Darwin' : 'macos' ,
@@ -90,72 +90,70 @@ def download_prebuilt_binaries():
9090 break
9191
9292 if not matching_wheel :
93- print (f"Warning: No matching wheel found for { system } and Python { py_version } " )
93+ print (f"[PyCNN] No matching pre-built wheel found in { tag_name } . " )
9494 return False
9595
96- print (f"Downloading wheel : { matching_wheel ['name' ]} " )
96+ print (f"[PyCNN] Downloading optimized binaries from : { matching_wheel ['name' ]} " )
9797 whl_path = Path ('temp_wheel.whl' )
9898 urllib .request .urlretrieve (matching_wheel ['browser_download_url' ], whl_path )
9999
100- print ("Extracting compiled modules from wheel..." )
101100 with zipfile .ZipFile (whl_path , 'r' ) as whl_zip :
102101 for file in whl_zip .namelist ():
103- # Extract modules (*.pyd, *.so)
104102 if file .startswith ('pycnn/modules/' ) and (file .endswith ('.pyd' ) or file .endswith ('.so' )):
105- print (f" Extracting: { file } " )
103+ print (f" -> Extracting: { file } " )
106104 whl_zip .extract (file , '.' )
107-
108- # Extract native libs (*.dll, *.so, *.dylib)
109105 if file .startswith ('pycnn/lib/' ) and any (file .endswith (ext ) for ext in get_library_extensions (system )):
110- print (f" Extracting: { file } " )
106+ print (f" -> Extracting: { file } " )
111107 whl_zip .extract (file , '.' )
112108
113109 os .remove (whl_path )
114- print ("Successfully downloaded and extracted pre-built binaries!" )
110+ print ("[PyCNN] Successfully installed pre-built binaries!\n " )
111+ PREBUILT_DOWNLOADED = True
115112 return True
116113
117114 except Exception as e :
118- print (f"Failed to download pre-built binaries : { e } " )
115+ print (f"[PyCNN] Binary download skipped : { e } " )
119116 return False
120117
121118class BuildLib (build_py ):
122119 def run (self ):
123- # Try to download pre-built binaries first
124- if download_prebuilt_binaries ():
125- print ("Using pre-built binaries - skipping compilation" )
126- super ().run ()
127- return
128-
129- # Fallback to building from source
130- print ("Building from source..." )
131- lib_dir = os .path .join (os .getcwd (), 'pycnn' , 'lib' )
132-
133- make_cmd = "mingw32-make" if platform .system () == "Windows" else "make"
134-
135- print (f"--- Building optimized native library in { lib_dir } using { make_cmd } ---" )
136-
137- try :
138- subprocess .check_call ([make_cmd ], cwd = lib_dir , shell = True )
139- except subprocess .CalledProcessError as e :
140- print (f"Error: Native build failed. Ensure { make_cmd } is in your PATH." )
141- raise e
142-
120+ download_prebuilt_binaries ()
143121 super ().run ()
144122
145123class InstallWithBinaries (install ):
146124 def run (self ):
147- # Download binaries before installation
148125 download_prebuilt_binaries ()
149126 super ().run ()
150127
151- # Try to import Cython, but don't require it if binaries are available
128+ class BuildExtMaybe (build_ext ):
129+ def run (self ):
130+ if PREBUILT_DOWNLOADED :
131+ print ("[PyCNN] Skipping compilation: Pre-built binaries are in place." )
132+ return
133+
134+ print ("[PyCNN] Standard build: Compiling modules from source..." )
135+
136+ lib_dir = Path ('pycnn/lib' )
137+ system = platform .system ()
138+ lib_exts = get_library_extensions (system )
139+ lib_exists = any (Path (lib_dir ).glob (f"optimized*{ ext } " ) for ext in lib_exts )
140+
141+ if not lib_exists :
142+ make_cmd = "mingw32-make" if system == "Windows" else "make"
143+ print (f"--- Building optimized native library using { make_cmd } ---" )
144+ try :
145+ subprocess .check_call ([make_cmd ], cwd = lib_dir , shell = True )
146+ except Exception as e :
147+ print (f"Warning: Native build failed: { e } " )
148+
149+ super ().run ()
150+
152151try :
153152 from Cython .Build import cythonize
154153 CYTHON_AVAILABLE = True
155154except ImportError :
156155 CYTHON_AVAILABLE = False
157156 def cythonize (extensions , ** _ignore ):
158- # Return empty list if Cython not available and we're using pre-built binaries
159157 return []
160158
161159if os .environ .get ('GITHUB_ACTIONS' ):
@@ -170,7 +168,6 @@ def cythonize(extensions, **_ignore):
170168 "max_pooling"
171169]
172170
173- # Only define extensions if Cython is available (for source builds)
174171extensions = []
175172if CYTHON_AVAILABLE :
176173 extensions = [
@@ -192,6 +189,7 @@ def cythonize(extensions, **_ignore):
192189 cmdclass = {
193190 'build_py' : BuildLib ,
194191 'install' : InstallWithBinaries ,
192+ 'build_ext' : BuildExtMaybe ,
195193 },
196194 ext_modules = cythonize (extensions , compiler_directives = {'language_level' : "3" }) if CYTHON_AVAILABLE else [],
197195 install_requires = [
@@ -200,7 +198,7 @@ def cythonize(extensions, **_ignore):
200198 "scipy" ,
201199 "matplotlib" ,
202200 ],
203- python_requires = ">=3.6 " ,
201+ python_requires = ">=3.8 " ,
204202 include_package_data = True ,
205203 zip_safe = False ,
206204)
0 commit comments