Skip to content

Commit 39fa503

Browse files
committed
* cmd doesn't expand globs
* - diplication * - WinXP-related bits * pip erroneously considers cv2/ as installed package when in sourceroot * require CMake output entries to be found * 3.5+ uses different .pyd naming scheme * .pyd is placed differently in Linux * DLL is only in Windows
1 parent 03435a2 commit 39fa503

File tree

2 files changed

+68
-35
lines changed

2 files changed

+68
-35
lines changed

appveyor.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ build_script:
6464
"%PYTHON%/python.exe" setup.py bdist_wheel
6565
6666
before_test:
67-
- cmd: >-
67+
- ps: >-
68+
69+
cd ${Env:APPVEYOR_BUILD_FOLDER}\tests
6870
69-
cd %APPVEYOR_BUILD_FOLDER%
70-
71-
if %ENABLE_CONTRIB% EQU 1 (set PACKAGE_NAME=opencv-contrib-python) else (set PACKAGE_NAME=opencv-python)
71+
&"${Env:PYTHON}/python.exe" -m pip install --user (ls "../dist/opencv_*.whl")
7272
73-
"%PYTHON%/python.exe" -m pip install --no-index --find-links=%APPVEYOR_BUILD_FOLDER%\dist\ %PACKAGE_NAME%
73+
if ($LastExitCode -ne 0) {throw $LastExitCode}
7474
7575
test_script:
7676
- cmd: >-
@@ -93,4 +93,4 @@ deploy_script:
9393

9494
- if %ENABLE_CONTRIB% EQU 0 (echo "This is a default build. Deployment will be done to PyPI entry opencv-python.") else (echo "This is a contrib build. Deployment will be done to PyPI entry opencv-contrib-python.")
9595

96-
- if "%APPVEYOR_REPO_TAG%"=="true" ("%PYTHON%/python.exe" -m twine upload -u %USER% -p %PASS% --skip-existing dist/opencv*) else (echo "Tag not set, deployment skipped.")
96+
- if "%APPVEYOR_REPO_TAG%"=="true" ("%PYTHON%/python.exe" -m twine upload -u %USER% -p %PASS% --skip-existing dist/opencv*) else (echo "Tag not set, deployment skipped.")

setup.py

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
1+
# No 3rd-party modules here, see "3rd-party" note below
12
import io, os, os.path, sys, runpy, subprocess, re, sysconfig
23

3-
import pip, pip.vcs.git
4-
54

65
def main():
76
os.chdir(os.path.dirname(os.path.abspath(__file__)))
87

9-
build_contrib = get_build_contrib()
8+
# Only import 3rd-party modules after having installed all the build dependencies:
9+
# any of them, or their dependencies, can be updated during that process,
10+
# leading to version conflicts
11+
numpy_version = get_or_install("numpy", "1.11.3" if sys.version_info[:2] >= (3, 6) else "1.11.1")
12+
get_or_install("scikit-build")
13+
import skbuild
14+
if os.path.isdir('.git'):
15+
import pip.vcs.git
16+
pip.vcs.git.Git().update_submodules('.')
17+
del pip
18+
1019

11-
# in case of sdist
12-
if os.path.isdir('./.git'): pip.vcs.git.Git().update_submodules('.')
20+
# https://stackoverflow.com/questions/1405913/python-32bit-or-64bit-mode
21+
x64 = sys.maxsize>2**32
22+
23+
build_contrib = get_build_contrib()
1324

1425
package_name = "opencv-contrib-python" if build_contrib else "opencv-python"
1526
long_description = io.open('README_CONTRIB.rst' if build_contrib else 'README.rst', encoding="utf-8").read()
1627
package_version = get_opencv_version()
17-
numpy_version = get_or_install("numpy", "1.11.3" if sys.version_info[:2] >= (3, 6) else "1.11.1")
28+
1829
package_data = \
1930
{'cv2':
2031
['*%s' % sysconfig.get_config_var('SO')] + (['*.dll'] if os.name == 'nt' else []) +
@@ -25,26 +36,33 @@ def main():
2536
# Path regexes with forward slashes relative to CMake install dir.
2637
rearrange_cmake_output_data = \
2738
{'cv2':
28-
[r'bin/opencv_ffmpeg\d{3}%s\.dll' %
29-
# https://stackoverflow.com/questions/1405913/python-32bit-or-64bit-mode
30-
('_64' if sys.maxsize>2**32 else ''),
31-
'python/[^/]+/[^/]+/cv2%s' % sysconfig.get_config_var('SO')]
32-
39+
sum([
40+
([r'bin/opencv_ffmpeg\d{3}%s\.dll' %
41+
('_64' if x64 else '')] if os.name == 'nt' else []
42+
),
43+
# In Windows, in python/X.Y/<arch>/; in Linux, in just python/X.Y/. What gives?
44+
['python/([^/]+)/{1,2}cv2%(arch)s%(ext)s' % {
45+
'arch': (('\\.cp%d%d-[^.]+' % sys.version_info[:2])
46+
if sys.version_info[:2] >= (3, 5) else ''),
47+
'ext': re.escape(sysconfig.get_config_var('SO'))
48+
}
49+
]
50+
],[])
3351
}
3452
# Files in sourcetree outside package dir that should be copied to package.
3553
# Raw paths relative to sourcetree root.
3654
files_outside_package_dir = \
3755
{'cv2':
38-
['LICENSE.txt', 'LICENSE-3RD-PARTY.txt']
39-
}
56+
['LICENSE.txt', 'LICENSE-3RD-PARTY.txt']
57+
}
4058

41-
cmake_source_dir="opencv"
59+
cmake_source_dir = "opencv"
4260
cmake_args = ([
43-
"-G", "Visual Studio 14" + (" Win64" if sys.maxsize>2**32 else ''),
44-
"-T", "v140_xp" if sys.version_info[:2] <= (3, 4) else "v140"
61+
"-G", "Visual Studio 14" + (" Win64" if x64 else '')
4562
] if os.name == 'nt' else []) + \
4663
[
4764
# No need to specify Python paths, skbuild takes care of that
65+
"-DPYTHON%d_EXECUTABLE=%s" % (sys.version_info[0], sys.executable),
4866
"-DBUILD_opencv_python%d=ON" % sys.version_info[0],
4967
# Otherwise, opencv scripts would want to install `.pyd' right into site-packages,
5068
# and skbuild bails out on seeing that
@@ -56,16 +74,18 @@ def main():
5674
"-DBUILD_PERF_TESTS=OFF",
5775
"-DBUILD_DOCS=OFF"
5876
] + \
59-
([ "-DOPENCV_EXTRA_MODULES_PATH=" + "opencv_contrib/modules" ] if build_contrib else [])
77+
([ "-DOPENCV_EXTRA_MODULES_PATH=" + os.path.abspath("opencv_contrib/modules") ]
78+
if build_contrib else [])
79+
6080

81+
# ABI config variables are introduced in PEP 425
6182
if sys.version_info[:2] < (3, 2):
6283
import warnings
63-
# ABI config variables are introduced in PEP 425
64-
warnings.filterwarnings('ignore', r"Config variable '[^']+' is unset, Python ABI tag may be incorrect",
84+
warnings.filterwarnings('ignore', r"Config variable '[^']+' is unset, "
85+
r"Python ABI tag may be incorrect",
6586
category=RuntimeWarning)
87+
del warnings
6688

67-
get_or_install("scikit-build")
68-
import skbuild
6989

7090
# works via side effect
7191
RearrangeCMakeOutput(rearrange_cmake_output_data,
@@ -108,6 +128,7 @@ def main():
108128
cmake_source_dir=cmake_source_dir,
109129
)
110130

131+
111132
class RearrangeCMakeOutput(object):
112133
"""Patch SKBuild logic to only take files related to the Python package
113134
and construct a file hierarchy that SKBuild expects (see below)"""
@@ -117,7 +138,7 @@ class RearrangeCMakeOutput(object):
117138
# into an instance method on attr assignment
118139
import argparse
119140
wraps = argparse.Namespace(
120-
_classify_files = None)
141+
_classify_files=None)
121142
del argparse
122143

123144
package_paths_re = None
@@ -163,17 +184,21 @@ def _classify_files_override(self, install_paths,
163184
cmake_install_reldir)
164185
install_relpaths = [os.path.relpath(p, cmake_install_dir) for p in install_paths]
165186
fslash_install_relpaths = [p.replace(os.path.sep, '/') for p in install_relpaths]
166-
relpaths_zip = zip(fslash_install_relpaths, install_relpaths)
187+
relpaths_zip = list(zip(fslash_install_relpaths, install_relpaths))
188+
del install_relpaths, fslash_install_relpaths
189+
167190
final_install_relpaths = []
168191

169192
print("Copying files from CMake output")
170193
for package_name, relpaths_re in cls.package_paths_re.items():
171194
package_dest_reldir = package_name.replace('.', os.path.sep)
172195
for relpath_re in relpaths_re:
196+
found = False
173197
r = re.compile(relpath_re+'$')
174198
for fslash_relpath, relpath in relpaths_zip:
175199
m = r.match(fslash_relpath)
176200
if not m: continue
201+
found = True
177202
new_install_relpath = os.path.join(
178203
package_dest_reldir,
179204
os.path.basename(relpath))
@@ -183,9 +208,11 @@ def _classify_files_override(self, install_paths,
183208
hide_listing=False)
184209
final_install_relpaths.append(new_install_relpath)
185210
del m, fslash_relpath, new_install_relpath
186-
del r
211+
else:
212+
if not found: raise Exception("Not found: '%s'" % relpath_re)
213+
del r, found
187214

188-
del fslash_install_relpaths, install_relpaths, relpaths_zip
215+
del relpaths_zip
189216

190217
print("Copying files from non-default sourcetree locations")
191218
for package_name, paths in cls.files_outside_package.items():
@@ -250,15 +277,21 @@ def get_build_contrib():
250277

251278

252279
def get_or_install(name, version = None):
253-
"""If numpy is already installed, build against it. If not, install"""
280+
"""If a package is already installed, build against it. If not, install"""
281+
# Do not import 3rd-party modules into the current process
282+
import json
283+
js_packages = json.loads(
284+
subprocess.check_output(
285+
[sys.executable, "-m", "pip", "list", "--format=json"])
286+
.decode('ascii')) #valid names & versions are ASCII as per PEP 440
254287
try:
255-
[package] = (package for package in pip.get_installed_distributions()
256-
if package.key == name)
288+
[package] = (package for package in js_packages
289+
if package['name'] == name)
257290
except ValueError:
258291
install_packages("%s==%s"%(name, version) if version else name)
259292
return version
260293
else:
261-
return package.version
294+
return package['version']
262295

263296

264297
# This creates a list which is empty but returns a length of 1.

0 commit comments

Comments
 (0)