Repository: zopefoundation/zodbpickle (language: python)

Issue:
'PURE_PYTHON=1' ignored during build
The C extension gets built willy-nilly.  This is after removing `usedevelop = true` from `tox.ini` (see https://github.com/zopefoundation/meta/pull/257):
```bash
$ ll .tox/py38-pure/lib/python3.8/site-packages/zodbpickle/
total 964
drwxrwxr-x  4 tseaver tseaver   4096 Jun 27 17:21 ./
drwxrwxr-x 17 tseaver tseaver   4096 Jun 27 17:21 ../
-rw-rw-r--  1 tseaver tseaver    891 Jun 27 17:21 fastpickle.py
-rw-rw-r--  1 tseaver tseaver     44 Jun 27 17:21 __init__.py
-rw-rw-r--  1 tseaver tseaver 205193 Jun 27 17:21 _pickle_33.c
-rw-rw-r--  1 tseaver tseaver  52163 Jun 27 17:21 pickle_3.py
-rwxrwxr-x  1 tseaver tseaver 598232 Jun 27 17:21 _pickle.cpython-38-x86_64-linux-gnu.so*
-rw-rw-r--  1 tseaver tseaver     24 Jun 27 17:21 pickle.py
-rw-rw-r--  1 tseaver tseaver  87531 Jun 27 17:21 pickletools_3.py
drwxrwxr-x  2 tseaver tseaver   4096 Jun 27 17:21 __pycache__/
-rw-rw-r--  1 tseaver tseaver   1061 Jun 27 17:21 slowpickle.py
drwxrwxr-x  3 tseaver tseaver   4096 Jun 27 17:21 tests/
```

Note that we have [tests which rely on this (undesirable) behavior](https://github.com/zopefoundation/zodbpickle/blob/5a3285cf466fc60fa55f72f1d848ac58b71366b4/src/zodbpickle/tests/test_pickle.py#L8-L11).


Discussion / hints:

Fix patch:
diff --git a/.meta.toml b/.meta.toml
index 27e6ad5..ac47e1f 100644
--- a/.meta.toml
+++ b/.meta.toml
@@ -2,7 +2,7 @@
 # https://github.com/zopefoundation/meta/tree/master/config/c-code
 [meta]
 template = "c-code"
-commit-id = "b4846e99"
+commit-id = "c412f00f"
 
 [python]
 with-appveyor = true
diff --git a/setup.py b/setup.py
index de7f204..46ce239 100644
--- a/setup.py
+++ b/setup.py
@@ -36,7 +36,7 @@ def read(fname):
 is_pypy = py_impl() == 'PyPy'
 is_jython = py_impl() == 'Jython'
 is_pure = int(os.environ.get('PURE_PYTHON', '0'))
-if is_pypy or is_jython:
+if is_pure or is_pypy or is_jython:
     ext_modules = []
 else:
     ext_modules = [Extension(name='zodbpickle._pickle',
diff --git a/src/zodbpickle/fastpickle.py b/src/zodbpickle/fastpickle.py
index 9075916..299a3a9 100644
--- a/src/zodbpickle/fastpickle.py
+++ b/src/zodbpickle/fastpickle.py
@@ -17,6 +17,7 @@
 
 
 import sys
+import warnings
 
 from .pickle_3 import *
 
@@ -26,4 +27,7 @@
 
 # isort: off
 # also make sure that we really have the fast version
-from ._pickle import *  # noqa: E402 module level import not at top of file
+if is_pure:  # noqa: F405
+    warnings.warn("fastpickle imported under 'PURE_PYTHON' environment")
+else:
+    from ._pickle import *  # noqa: E402 module level import not at top of file
diff --git a/src/zodbpickle/pickle_3.py b/src/zodbpickle/pickle_3.py
index 4db1aa1..36eff5a 100644
--- a/src/zodbpickle/pickle_3.py
+++ b/src/zodbpickle/pickle_3.py
@@ -26,6 +26,7 @@
 import codecs
 import io
 import marshal
+import os
 import re
 import struct
 import sys
@@ -42,6 +43,8 @@
 __all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler",
            "Unpickler", "dump", "dumps", "load", "loads"]
 
+is_pure = int(os.environ.get('PURE_PYTHON', '0'))
+
 # Shortcut for use in isinstance testing
 bytes_types = (bytes, bytearray)
 __all__.append('bytes_types')
@@ -1506,11 +1509,15 @@ def _loads(s, *, fix_imports=True, encoding="ASCII", errors="strict"):
 
 
 # Use the faster _pickle if possible
-try:
-    from zodbpickle._pickle import *
-except ImportError:
+if is_pure:
     Pickler, Unpickler = _Pickler, _Unpickler
     dump, dumps, load, loads = _dump, _dumps, _load, _loads
+else:
+    try:
+        from zodbpickle._pickle import *
+    except ImportError:
+        Pickler, Unpickler = _Pickler, _Unpickler
+        dump, dumps, load, loads = _dump, _dumps, _load, _loads
 
 # Doctest
 
diff --git a/tox.ini b/tox.ini
index 8346703..df69637 100644
--- a/tox.ini
+++ b/tox.ini
@@ -15,7 +15,6 @@ envlist =
     coverage
 
 [testenv]
-usedevelop = true
 pip_pre = py313: true
 deps =
     setuptools < 69
@@ -42,6 +41,7 @@ commands =
     coverage run -m zope.testrunner --test-path=src {posargs:-vc}
     coverage html -i
     coverage report -i -m --fail-under=63
+
 [testenv:release-check]
 description = ensure that the distribution is ready to release
 basepython = python3


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c922335..f729c1c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -384,7 +384,7 @@ jobs:
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        python-version: ["3.9"]
+        python-version: ["3.11"]
         os: [ubuntu-latest]
 
     steps:
@@ -452,7 +452,7 @@ jobs:
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        python-version: ["3.9"]
+        python-version: ["3.11"]
         os: [ubuntu-latest]
 
     steps:
@@ -520,7 +520,7 @@ jobs:
     # We use a regular Python matrix entry to share as much code as possible.
     strategy:
       matrix:
-        python-version: ["3.9"]
+        python-version: ["3.11"]
         image: [manylinux2014_x86_64, manylinux2014_i686, manylinux2014_aarch64]
 
     steps:
@@ -601,6 +601,8 @@ jobs:
           name: manylinux_${{ matrix.image }}_wheels.zip
       - name: Restore pip cache permissions
         run: sudo chown -R $(whoami) ${{ steps.pip-cache-default.outputs.dir }}
+      - name: Prevent publishing wheels for unreleased Python versions
+        run: VER=$(echo '3.13' | tr -d .) && ls -al wheelhouse && sudo rm -f wheelhouse/*-cp${VER}*.whl && ls -al wheelhouse
       - name: Publish package to PyPI
         uses: pypa/gh-action-pypi-publish@release/v1
         if: >
diff --git a/src/zodbpickle/tests/pickle_3_tests.py b/src/zodbpickle/tests/pickle_3_tests.py
index a1296c9..f40c0d2 100644
--- a/src/zodbpickle/tests/pickle_3_tests.py
+++ b/src/zodbpickle/tests/pickle_3_tests.py
@@ -18,10 +18,14 @@
 from .pickletester_3 import BigmemPickleTests
 
 
-try:
-    from zodbpickle import _pickle
-    has_c_implementation = not _is_pypy and not _is_pure
-except ImportError:
+if not _is_pypy and not _is_pure:
+    try:
+        from zodbpickle import _pickle
+    except ImportError:
+        has_c_implementation = False
+    else:
+        has_c_implementation = True
+else:
     has_c_implementation = False
 
 
diff --git a/src/zodbpickle/tests/test_pickle.py b/src/zodbpickle/tests/test_pickle.py
index 9f12598..b322205 100644
--- a/src/zodbpickle/tests/test_pickle.py
+++ b/src/zodbpickle/tests/test_pickle.py
@@ -2,15 +2,17 @@
 import types
 import unittest
 
+from . import _is_pure
 from . import _is_pypy
 
 
-if _is_pypy:
+if _is_pure or _is_pypy:
     function_type = types.FunctionType
 else:
     function_type = types.BuiltinFunctionType
 del sys
 del _is_pypy
+del _is_pure
 
 
 class TestImportability(unittest.TestCase):