|
import unicodedata |
|
import sys |
|
from configparser import ConfigParser |
|
|
|
from .compat import py39 |
|
from .warnings import SetuptoolsDeprecationWarning |
|
|
|
|
|
|
|
def decompose(path): |
|
if isinstance(path, str): |
|
return unicodedata.normalize('NFD', path) |
|
try: |
|
path = path.decode('utf-8') |
|
path = unicodedata.normalize('NFD', path) |
|
path = path.encode('utf-8') |
|
except UnicodeError: |
|
pass |
|
return path |
|
|
|
|
|
def filesys_decode(path): |
|
""" |
|
Ensure that the given path is decoded, |
|
``None`` when no expected encoding works |
|
""" |
|
|
|
if isinstance(path, str): |
|
return path |
|
|
|
fs_enc = sys.getfilesystemencoding() or 'utf-8' |
|
candidates = fs_enc, 'utf-8' |
|
|
|
for enc in candidates: |
|
try: |
|
return path.decode(enc) |
|
except UnicodeDecodeError: |
|
continue |
|
|
|
return None |
|
|
|
|
|
def try_encode(string, enc): |
|
"turn unicode encoding into a functional routine" |
|
try: |
|
return string.encode(enc) |
|
except UnicodeEncodeError: |
|
return None |
|
|
|
|
|
def _read_utf8_with_fallback(file: str, fallback_encoding=py39.LOCALE_ENCODING) -> str: |
|
""" |
|
First try to read the file with UTF-8, if there is an error fallback to a |
|
different encoding ("locale" by default). Returns the content of the file. |
|
Also useful when reading files that might have been produced by an older version of |
|
setuptools. |
|
""" |
|
try: |
|
with open(file, "r", encoding="utf-8") as f: |
|
return f.read() |
|
except UnicodeDecodeError: |
|
_Utf8EncodingNeeded.emit(file=file, fallback_encoding=fallback_encoding) |
|
with open(file, "r", encoding=fallback_encoding) as f: |
|
return f.read() |
|
|
|
|
|
def _cfg_read_utf8_with_fallback( |
|
cfg: ConfigParser, file: str, fallback_encoding=py39.LOCALE_ENCODING |
|
) -> None: |
|
"""Same idea as :func:`_read_utf8_with_fallback`, but for the |
|
:meth:`ConfigParser.read` method. |
|
|
|
This method may call ``cfg.clear()``. |
|
""" |
|
try: |
|
cfg.read(file, encoding="utf-8") |
|
except UnicodeDecodeError: |
|
_Utf8EncodingNeeded.emit(file=file, fallback_encoding=fallback_encoding) |
|
cfg.clear() |
|
cfg.read(file, encoding=fallback_encoding) |
|
|
|
|
|
class _Utf8EncodingNeeded(SetuptoolsDeprecationWarning): |
|
_SUMMARY = """ |
|
`encoding="utf-8"` fails with {file!r}, trying `encoding={fallback_encoding!r}`. |
|
""" |
|
|
|
_DETAILS = """ |
|
Fallback behaviour for UTF-8 is considered **deprecated** and future versions of |
|
`setuptools` may not implement it. |
|
|
|
Please encode {file!r} with "utf-8" to ensure future builds will succeed. |
|
|
|
If this file was produced by `setuptools` itself, cleaning up the cached files |
|
and re-building/re-installing the package with a newer version of `setuptools` |
|
(e.g. by updating `build-system.requires` in its `pyproject.toml`) |
|
might solve the problem. |
|
""" |
|
|
|
|
|
|
|
|
|
|