charset-normalizer includes the module charset_normalizer.md, native wheels provide it as both
- a native extension, e.g. charset_normalizer/md.cpython-314-darwin.so
- a pure python file, charset_normalizer/md.py
Is this an intended/documented way to ship an extension module with a pure python fallback, or a quirk of one project’s packaging that I’ve read too much into?
Python’s importlib appears to transparently use the native extension if it’s compatible (by platform, major.minor, …) and fallback to the pure python if necessary. There’s no explicit try: import …; except ImportError: import …_fallback as … in charset_normalizer that I could spot.
For example if I manually create a situation where the .so is compiled for a non-matching Python version (3.14 vs 3.13) then the import succeeds without complaint/warning, using the pure Python
alex@d13:~$ unzip charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
...
inflating: charset_normalizer/md.cpython-314-x86_64-linux-gnu.so
inflating: charset_normalizer/md.py
inflating: charset_normalizer/md__mypyc.cpython-314-x86_64-linux-gnu.so
...
alex@d13:~$ python3
Python 3.13.5 (main, Jun 25 2025, 18:55:22) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import charset_normalizer.md
>>> charset_normalizer.md
<module 'charset_normalizer.md' from '/home/alex/charset_normalizer/md.py'>
Context: I’m investigating fixes for RequestsDependencyWarning: Unable to find acceptable character detection dependency (chardet or charset_normalizer). · Issue #1405 · mitogen-hq/mitogen · GitHub and might end up using this behaviour in a fix. Mitogen serves pure python modules over the wire to child processes as they import them.