Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions tests/project/test_conda_windows_leg_2060.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
previous ``FOR`` loop wrote ``%A``, a syntax error in a batch file.
* :class:`TestPortableExecutable` and :class:`TestTheWindowsLayout`:
:file:`util/conda_vendor.py` reads a ``.pyd``'s PE machine, and ``--smoke``
takes a Windows package's ``Lib/site-packages``, whose path names no Python.
takes a Windows package's ``Lib/site-packages``, or from Python 3.15 its
``lib/python/site-packages`` (conda-forge's CFEP-27), whose path names no Python.

Nothing here runs on Windows; what a real Conda Update run shows is the rest.

Expand Down Expand Up @@ -318,14 +319,25 @@ def test_the_python_is_read_from_the_build_string(self) -> None:
posix = pathlib.Path('root') / 'lib' / 'python3.14' / 'site-packages'
self.assertEqual(vendor.built_for(posix, {'build': 'py39_0'}), 'python3.14')

def smoke(self, build: 'str') -> 'tuple[int, str]':
def test_the_cfep_27_layout_is_read_from_the_build_string(self) -> None:
"""conda-forge's Python 3.15 on Windows has ``lib/python/site-packages``, naming no version."""
vendor = load('conda_vendor')
site = pathlib.Path('root') / 'lib' / 'python' / 'site-packages'
self.assertEqual(vendor.built_for(site, {'build': 'py315_0'}), 'python3.15')
self.assertEqual(vendor.built_for(site, {'build': 'h1a2b3c4_0'}),
"lib/python/site-packages with build string 'h1a2b3c4_0'")
# Only under lib: anything else named python is not the layout.
other = pathlib.Path('root') / 'opt' / 'python' / 'site-packages'
self.assertEqual(vendor.built_for(other, {'build': 'py315_0'}), 'python')

def smoke(self, build: 'str', site: 'str' = 'Lib/site-packages') -> 'tuple[int, str]':
vendor = load('conda_vendor')
files = dict({'pcapkit/__init__.py': SHIM.encode()}, **DISTRIBUTION)
files['pcapkit/_extern/native/_speedups.pyd'] = pe(0x8664)
files['pcapkit/_extern/native-1.0.dist-info/RECORD'] = (
b'native/__init__.py,,\nnative/_speedups.pyd,,\nnative-1.0.dist-info/METADATA,,\n'
b'native-1.0.dist-info/RECORD,,\n')
members = {f'Lib/site-packages/{name}': data for name, data in files.items()}
members = {f'{site}/{name}': data for name, data in files.items()}
members['info/index.json'] = json.dumps({'name': 'pypcapkit', 'subdir': 'win-64', 'build': build}).encode()
with tempfile.TemporaryDirectory() as temp:
package = pathlib.Path(temp) / 'pypcapkit-0-py_0.tar.bz2'
Expand All @@ -347,6 +359,11 @@ def test_a_windows_package_for_this_python_passes(self) -> None:
self.assertEqual(status, 0, log)
self.assertIn('win-64: 1 native binaries read, none failing', log)

def test_a_cfep_27_windows_package_for_this_python_passes(self) -> None:
status, log = self.smoke(f'py{self.PYTHON.replace(".", "")}h0_0', site='lib/python/site-packages')
self.assertEqual(status, 0, log)
self.assertIn('win-64: 1 native binaries read, none failing', log)

def test_a_windows_package_for_another_python_fails(self) -> None:
status, log = self.smoke('py27_0')
self.assertEqual(status, 1, log)
Expand Down
13 changes: 10 additions & 3 deletions util/conda_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -906,19 +906,26 @@ def runner_platform() -> 'Optional[str]':
None)


#: The ``site-packages`` of a Windows package, which names no Python: conda-forge's
#: up to 3.14, and its CFEP-27 one from 3.15 on.
WINDOWS_SITES = (('Lib', 'site-packages'), ('lib', 'python', 'site-packages'))


def built_for(site: 'pathlib.Path', index: 'dict[str, Any]') -> 'str':
"""The ``pythonX.Y`` a package's ``site-packages`` at ``site`` is for, or what it is if not that.

A POSIX package names it in the path, ``lib/pythonX.Y/site-packages``. A
Windows one has ``Lib/site-packages`` for every version (#2060), so it is read
Windows one does not (#2060): ``Lib/site-packages`` up to 3.14, and from 3.15
``lib/python/site-packages``, conda-forge's CFEP-27 layout. So that is read
from the ``pyXY`` that starts the build string in ``info/index.json``.

"""
if site.parent.name != 'Lib':
layout = next((parts for parts in WINDOWS_SITES if site.parts[-len(parts):] == parts), None)
if layout is None:
return site.parent.name
match = re.match(r'py(\d)(\d+)(?![0-9])', str(index.get('build', '')))
if match is None:
return f'Lib/site-packages with build string {index.get("build")!r}'
return f'{"/".join(layout)} with build string {index.get("build")!r}'
return f'python{match.group(1)}.{match.group(2)}'


Expand Down
Loading