[Python-modules-commits] [mutagen] 02/07: Import mutagen_1.35.1.orig.tar.gz
Tristan Seligmann
mithrandi at moszumanska.debian.org
Fri Dec 16 09:33:40 UTC 2016
This is an automated email from the git hooks/post-receive script.
mithrandi pushed a commit to branch master
in repository mutagen.
commit c4d908388c34fb66492a01316b4933c29776c5cb
Author: Tristan Seligmann <mithrandi at debian.org>
Date: Fri Dec 16 11:14:43 2016 +0200
Import mutagen_1.35.1.orig.tar.gz
---
MANIFEST.in | 2 +
NEWS | 22 +
PKG-INFO | 25 +-
README.rst | 15 +-
docs/conf.py | 4 +-
docs/id3_frames_gen.py | 10 +-
docs/index.rst | 15 +-
mutagen/__init__.py | 2 +-
mutagen/_senf/README.rst | 1 +
mutagen/_senf/__init__.py | 82 ++++
mutagen/_senf/_argv.py | 46 ++
mutagen/_senf/_compat.py | 52 +++
mutagen/_senf/_environ.py | 238 +++++++++++
mutagen/_senf/_fsnative.py | 420 +++++++++++++++++++
mutagen/_senf/_print.py | 352 ++++++++++++++++
mutagen/_senf/_stdlib.py | 146 +++++++
mutagen/_senf/_temp.py | 90 ++++
mutagen/_senf/_winansi.py | 311 ++++++++++++++
mutagen/_senf/_winapi.py | 183 ++++++++
mutagen/_tools/__init__.py | 6 +
mutagen/_tools/_util.py | 94 +++++
tools/mid3cp => mutagen/_tools/mid3cp.py | 17 +-
tools/mid3iconv => mutagen/_tools/mid3iconv.py | 19 +-
tools/mid3v2 => mutagen/_tools/mid3v2.py | 100 +++--
tools/moggsplit => mutagen/_tools/moggsplit.py | 16 +-
.../_tools/mutagen_inspect.py | 20 +-
.../mutagen-pony => mutagen/_tools/mutagen_pony.py | 13 +-
mutagen/_toolsutil.py | 231 ----------
mutagen/_util.py | 2 +-
mutagen/asf/__init__.py | 5 +-
mutagen/asf/_util.py | 2 +-
mutagen/id3/_frames.py | 66 +--
mutagen/id3/_specs.py | 37 +-
mutagen/id3/_tags.py | 61 ++-
mutagen/mp3/__init__.py | 10 +-
mutagen/mp4/__init__.py | 1 -
setup.py | 55 ++-
tests/__init__.py | 130 +-----
tests/quality/test_pep8.py | 46 +-
tests/quality/test_pyflakes.py | 18 +-
tests/test___init__.py | 14 +-
tests/test__id3frames.py | 40 +-
tests/test_asf.py | 10 +-
tests/test_encoding.py | 2 +-
tests/test_id3.py | 43 +-
tests/test_mp4.py | 2 +-
tests/test_tools.py | 22 +-
tests/test_tools_mid3cp.py | 8 +-
tests/test_tools_mid3iconv.py | 2 +-
tests/test_tools_mid3v2.py | 4 +-
tests/test_tools_moggsplit.py | 2 +-
tests/test_tools_mutagen_inspect.py | 2 +-
tests/test_tools_mutagen_pony.py | 4 +-
tests/{test__toolsutil.py => test_tools_util.py} | 12 +-
tools/mid3cp | 116 +-----
tools/mid3iconv | 159 +------
tools/mid3v2 | 463 +--------------------
tools/moggsplit | 66 +--
tools/mutagen-inspect | 36 +-
tools/mutagen-pony | 107 +----
60 files changed, 2494 insertions(+), 1585 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index e48dc4c..e466433 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,10 +1,12 @@
include COPYING
include NEWS
include README.rst
+include setup.cfg
include MANIFEST.in
include tests/data/*
include tests/quality/*
include tests/*.py
include man/*.1
+recursive-include mutagen README.rst
recursive-include docs *.py Makefile *.rst *.png *.svg *.ico
prune docs/_build
diff --git a/NEWS b/NEWS
index 6f1c44b..0d629b8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,25 @@
+1.35.1 - 2016.11.09
+-------------------
+
+* Revert back to distutils :bug:`273`
+
+
+1.35 - 2016.11.02
+-----------------
+
+* Tests: Require pytest
+* Tools: Install .exe launchers on Windows
+* setup.py: Require setuptools
+* ID3:
+
+ * Fix loading files with CRM frames :bug:`239`
+ * Fix loading AENC, LINK, GRID frames with no payload
+ * Merge duplicate text frames with same key on load :bug:`172`
+ * Allow parsing of duplicate APIC frames :bug:`172`
+ * Parse utf-16 text fields with missing BOM :bug:`267`
+ * Increase max resyncs for the mpeg frame search :bug:`268`
+
+
1.34.1 - 2016.08.13
-------------------
diff --git a/PKG-INFO b/PKG-INFO
index fb7bc61..96d39af 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,19 +1,26 @@
Metadata-Version: 1.1
Name: mutagen
-Version: 1.34.1
+Version: 1.35.1
Summary: read and write audio tags for many formats
Home-page: https://github.com/quodlibet/mutagen
Author: Michael Urman
Author-email: quod-libet-development at groups.google.com
License: GNU GPL v2
-Description: Mutagen is a Python module to handle audio metadata. It supports ASF,
- FLAC, M4A, Monkey's Audio, MP3, Musepack, Ogg FLAC, Ogg Speex, Ogg
- Theora, Ogg Vorbis, True Audio, WavPack and OptimFROG audio files. All
- versions of ID3v2 are supported, and all standard ID3v2.4 frames are
- parsed. It can read Xing headers to accurately calculate the bitrate
- and length of MP3s. ID3 and APEv2 tags can be edited regardless of
- audio format. It can also manipulate Ogg streams on an individual
- packet/page level.
+Description: Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC,
+ MP4, Monkey's Audio, MP3, Musepack, Ogg Opus, Ogg FLAC, Ogg Speex, Ogg Theora,
+ Ogg Vorbis, True Audio, WavPack, OptimFROG, and AIFF audio files. All
+ versions of ID3v2 are supported, and all standard ID3v2.4 frames are parsed.
+ It can read Xing headers to accurately calculate the bitrate and length of
+ MP3s. ID3 and APEv2 tags can be edited regardless of audio format. It can also
+ manipulate Ogg streams on an individual packet/page level.
+
+ Mutagen works with Python 2.7, 3.3+ (CPython and PyPy) on Linux, Windows and
+ macOS, and has no dependencies outside the Python standard library.
+
+ For more information visit https://mutagen.readthedocs.org
+
+ .. image:: https://travis-ci.org/quodlibet/mutagen.svg?branch=master
+ :target: https://travis-ci.org/quodlibet/mutagen
Platform: UNKNOWN
Classifier: Operating System :: OS Independent
diff --git a/README.rst b/README.rst
index 1affc6a..7293508 100644
--- a/README.rst
+++ b/README.rst
@@ -1,8 +1,15 @@
-Mutagen
-=======
+Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC,
+MP4, Monkey's Audio, MP3, Musepack, Ogg Opus, Ogg FLAC, Ogg Speex, Ogg Theora,
+Ogg Vorbis, True Audio, WavPack, OptimFROG, and AIFF audio files. All
+versions of ID3v2 are supported, and all standard ID3v2.4 frames are parsed.
+It can read Xing headers to accurately calculate the bitrate and length of
+MP3s. ID3 and APEv2 tags can be edited regardless of audio format. It can also
+manipulate Ogg streams on an individual packet/page level.
-Mutagen is a Python module to handle audio metadata. For more information
-visit http://mutagen.readthedocs.org
+Mutagen works with Python 2.7, 3.3+ (CPython and PyPy) on Linux, Windows and
+macOS, and has no dependencies outside the Python standard library.
+
+For more information visit https://mutagen.readthedocs.org
.. image:: https://travis-ci.org/quodlibet/mutagen.svg?branch=master
:target: https://travis-ci.org/quodlibet/mutagen
diff --git a/docs/conf.py b/docs/conf.py
index f2fc667..40faa34 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -6,7 +6,6 @@ import sys
dir_ = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, dir_)
sys.path.insert(0, os.path.abspath(os.path.join(dir_, "..")))
-import mutagen
needs_sphinx = "1.3"
@@ -25,8 +24,7 @@ master_doc = 'index'
project = 'mutagen'
copyright = u'2016, Joe Wreschnig, Michael Urman, Lukáš Lalinský, ' \
u'Christoph Reiter, Ben Ockmore & others'
-version = mutagen.version_string
-release = mutagen.version_string
+html_title = project
exclude_patterns = ['_build']
bug_url_template = "https://github.com/quodlibet/mutagen/issues/%s"
pr_url_template = "https://github.com/quodlibet/mutagen/pull/%s"
diff --git a/docs/id3_frames_gen.py b/docs/id3_frames_gen.py
index 68848ce..162085f 100755
--- a/docs/id3_frames_gen.py
+++ b/docs/id3_frames_gen.py
@@ -26,9 +26,9 @@ BaseFrames = dict([(k, v) for (k, v) in vars(mutagen.id3).items()
def print_header(header, type_="-"):
- print header
- print type_ * len(header)
- print
+ print(header)
+ print(type_ * len(header))
+ print("")
def print_frames(frames, sort_mro=False):
@@ -39,11 +39,11 @@ def print_frames(frames, sort_mro=False):
sort_func = lambda x: x
for name, cls in sorted(frames.items(), key=sort_func):
- print """
+ print("""
.. autoclass:: mutagen.id3.%s
:show-inheritance:
:members:
-""" % repr(cls())
+""" % repr(cls()))
if __name__ == "__main__":
diff --git a/docs/index.rst b/docs/index.rst
index d14c9fc..4956d1d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,16 +13,11 @@
man/index
contact
-Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC,
-MP4, Monkey's Audio, MP3, Musepack, Ogg Opus, Ogg FLAC, Ogg Speex, Ogg Theora,
-Ogg Vorbis, True Audio, WavPack, OptimFROG, and AIFF audio files. All
-versions of ID3v2 are supported, and all standard ID3v2.4 frames are parsed.
-It can read Xing headers to accurately calculate the bitrate and length of
-MP3s. ID3 and APEv2 tags can be edited regardless of audio format. It can also
-manipulate Ogg streams on an individual packet/page level.
-
-Mutagen works with Python 2.7, 3.3+ (CPython and PyPy) on Linux, Windows and
-macOS, and has no dependencies outside the Python standard library.
+.. title:: Overview
+
+.. include:: ../README.rst
+
+----
There is a :doc:`brief tutorial with several API examples.
<user/index>`
diff --git a/mutagen/__init__.py b/mutagen/__init__.py
index 824952e..c996b77 100644
--- a/mutagen/__init__.py
+++ b/mutagen/__init__.py
@@ -24,7 +24,7 @@ from mutagen._util import MutagenError
from mutagen._file import FileType, StreamInfo, File
from mutagen._tags import Tags, Metadata, PaddingInfo
-version = (1, 34, 1)
+version = (1, 35, 1)
"""Version tuple."""
version_string = ".".join(map(str, version))
diff --git a/mutagen/_senf/README.rst b/mutagen/_senf/README.rst
new file mode 100644
index 0000000..49ff928
--- /dev/null
+++ b/mutagen/_senf/README.rst
@@ -0,0 +1 @@
+Don't change things here, this is a copy of https://github.com/lazka/senf
diff --git a/mutagen/_senf/__init__.py b/mutagen/_senf/__init__.py
new file mode 100644
index 0000000..f2fcb4f
--- /dev/null
+++ b/mutagen/_senf/__init__.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 Christoph Reiter
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+import os
+
+if os.name != "nt":
+ # make imports work
+ _winapi = object()
+
+from ._fsnative import fsnative, path2fsn, fsn2text, fsn2bytes, \
+ bytes2fsn, uri2fsn, fsn2uri, text2fsn
+from ._print import print_, input_
+from ._stdlib import sep, pathsep, curdir, pardir, altsep, extsep, devnull, \
+ defpath, getcwd, expanduser, expandvars
+from ._argv import argv
+from ._environ import environ, getenv, unsetenv, putenv
+from ._temp import mkstemp, gettempdir, gettempprefix, mkdtemp
+
+
+fsnative, print_, getcwd, getenv, unsetenv, putenv, environ, expandvars, \
+ path2fsn, fsn2text, fsn2bytes, bytes2fsn, uri2fsn, fsn2uri, mkstemp, \
+ gettempdir, gettempprefix, mkdtemp, input_, expanduser, text2fsn
+
+
+version = (1, 0, 1)
+"""Tuple[`int`, `int`, `int`]: The version tuple (major, minor, micro)"""
+
+
+version_string = ".".join(map(str, version))
+"""`str`: A version string"""
+
+
+argv = argv
+"""List[`fsnative`]: Like `sys.argv` but contains unicode under
+Windows + Python 2
+"""
+
+
+sep = sep
+"""`fsnative`: Like `os.sep` but a `fsnative`"""
+
+
+pathsep = pathsep
+"""`fsnative`: Like `os.pathsep` but a `fsnative`"""
+
+
+curdir = curdir
+"""`fsnative`: Like `os.curdir` but a `fsnative`"""
+
+
+pardir = pardir
+"""`fsnative`: Like `os.pardir` but a fsnative"""
+
+
+altsep = altsep
+"""`fsnative` or `None`: Like `os.altsep` but a `fsnative` or `None`"""
+
+
+extsep = extsep
+"""`fsnative`: Like `os.extsep` but a `fsnative`"""
+
+
+devnull = devnull
+"""`fsnative`: Like `os.devnull` but a `fsnative`"""
+
+
+defpath = defpath
+"""`fsnative`: Like `os.defpath` but a `fsnative`"""
+
+
+__all__ = []
diff --git a/mutagen/_senf/_argv.py b/mutagen/_senf/_argv.py
new file mode 100644
index 0000000..14df5c6
--- /dev/null
+++ b/mutagen/_senf/_argv.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 Christoph Reiter
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+import sys
+import ctypes
+
+from ._compat import PY2
+from ._fsnative import is_unix
+from . import _winapi as winapi
+
+
+def create_argv():
+ """Returns a unicode argv under Windows and standard sys.argv otherwise"""
+
+ if is_unix or not PY2:
+ return sys.argv
+
+ argc = ctypes.c_int()
+ try:
+ argv = winapi.CommandLineToArgvW(
+ winapi.GetCommandLineW(), ctypes.byref(argc))
+ except WindowsError:
+ return []
+
+ if not argv:
+ return []
+
+ res = argv[max(0, argc.value - len(sys.argv)):argc.value]
+
+ winapi.LocalFree(argv)
+
+ return res
+
+
+argv = create_argv()
diff --git a/mutagen/_senf/_compat.py b/mutagen/_senf/_compat.py
new file mode 100644
index 0000000..6a1c9cc
--- /dev/null
+++ b/mutagen/_senf/_compat.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 Christoph Reiter
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+import sys
+
+
+PY2 = sys.version_info[0] == 2
+PY3 = not PY2
+
+
+if PY2:
+ from urlparse import urlparse
+ urlparse
+ from urllib import pathname2url, url2pathname, quote, unquote
+ pathname2url, url2pathname, quote, unquote
+
+ from StringIO import StringIO
+ BytesIO = StringIO
+ from io import StringIO as TextIO
+ TextIO
+
+ string_types = (str, unicode)
+ text_type = unicode
+
+ iteritems = lambda d: d.iteritems()
+elif PY3:
+ from urllib.parse import urlparse, quote, unquote
+ urlparse, quote, unquote
+ from urllib.request import pathname2url, url2pathname
+ pathname2url, url2pathname
+
+ from io import StringIO
+ StringIO = StringIO
+ TextIO = StringIO
+ from io import BytesIO
+ BytesIO = BytesIO
+
+ string_types = (str,)
+ text_type = str
+
+ iteritems = lambda d: iter(d.items())
diff --git a/mutagen/_senf/_environ.py b/mutagen/_senf/_environ.py
new file mode 100644
index 0000000..5903783
--- /dev/null
+++ b/mutagen/_senf/_environ.py
@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 Christoph Reiter
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+import os
+import ctypes
+import collections
+
+from ._compat import text_type, PY2
+from ._fsnative import path2fsn, is_win
+from . import _winapi as winapi
+
+
+def get_windows_env_var(key):
+ """Get an env var.
+
+ Raises:
+ WindowsError
+ """
+
+ if not isinstance(key, text_type):
+ raise TypeError("%r not of type %r" % (key, text_type))
+
+ buf = ctypes.create_unicode_buffer(32767)
+
+ stored = winapi.GetEnvironmentVariableW(key, buf, 32767)
+ if stored == 0:
+ raise ctypes.WinError()
+ return buf[:stored]
+
+
+def set_windows_env_var(key, value):
+ """Set an env var.
+
+ Raises:
+ WindowsError
+ """
+
+ if not isinstance(key, text_type):
+ raise TypeError("%r not of type %r" % (key, text_type))
+
+ if not isinstance(value, text_type):
+ raise TypeError("%r not of type %r" % (value, text_type))
+
+ status = winapi.SetEnvironmentVariableW(key, value)
+ if status == 0:
+ raise ctypes.WinError()
+
+
+def del_windows_env_var(key):
+ """Delete an env var.
+
+ Raises:
+ WindowsError
+ """
+
+ if not isinstance(key, text_type):
+ raise TypeError("%r not of type %r" % (key, text_type))
+
+ status = winapi.SetEnvironmentVariableW(key, None)
+ if status == 0:
+ raise ctypes.WinError()
+
+
+def read_windows_environ():
+ """Returns a unicode dict of the Windows environment.
+
+ Raises:
+ WindowsEnvironError
+ """
+
+ res = winapi.GetEnvironmentStringsW()
+ if not res:
+ raise ctypes.WinError()
+
+ res = ctypes.cast(res, ctypes.POINTER(ctypes.c_wchar))
+
+ done = []
+ current = u""
+ i = 0
+ while 1:
+ c = res[i]
+ i += 1
+ if c == u"\x00":
+ if not current:
+ break
+ done.append(current)
+ current = u""
+ continue
+ current += c
+
+ dict_ = {}
+ for entry in done:
+ try:
+ key, value = entry.split(u"=", 1)
+ except ValueError:
+ continue
+ dict_[key] = value
+
+ status = winapi.FreeEnvironmentStringsW(res)
+ if status == 0:
+ raise ctypes.WinError()
+
+ return dict_
+
+
+class Environ(collections.MutableMapping):
+ """Dict[`fsnative`, `fsnative`]: Like `os.environ` but contains unicode
+ keys and values under Windows + Python 2
+ """
+
+ def __init__(self):
+ if is_win and PY2:
+ try:
+ env = read_windows_environ()
+ except WindowsError:
+ env = {}
+ else:
+ env = os.environ
+ self._env = env
+
+ def __getitem__(self, key):
+ key = path2fsn(key)
+ return self._env[key]
+
+ def __setitem__(self, key, value):
+ key = path2fsn(key)
+ value = path2fsn(value)
+
+ if is_win and PY2:
+ try:
+ set_windows_env_var(key, value)
+ except WindowsError:
+ # py3+win fails for invalid keys. try to do the same
+ raise ValueError
+ try:
+ self._env[key] = value
+ except OSError:
+ raise ValueError
+
+ def __delitem__(self, key):
+ key = path2fsn(key)
+
+ if is_win and PY2:
+ try:
+ del_windows_env_var(key)
+ except WindowsError:
+ pass
+
+ del self._env[key]
+
+ def __iter__(self):
+ return iter(self._env)
+
+ def __len__(self):
+ return len(self._env)
+
+ def __repr__(self):
+ return repr(self._env)
+
+ def copy(self):
+ return self._env.copy()
+
+
+environ = Environ()
+
+
+def getenv(key, value=None):
+ """Like `os.getenv` but returns unicode under Windows + Python 2
+
+ Args:
+ key (pathlike): The env var to get
+ value (object): The value to return if the env var does not exist
+ Returns:
+ `fsnative` or `object`:
+ The env var or the passed value if it doesn't exist
+ """
+
+ key = path2fsn(key)
+ if is_win and PY2:
+ return environ.get(key, value)
+ return os.getenv(key, value)
+
+
+def unsetenv(key):
+ """Like `os.unsetenv` but takes unicode under Windows + Python 2
+
+ Args:
+ key (pathlike): The env var to unset
+ """
+
+ key = path2fsn(key)
+ if is_win:
+ # python 3 has no unsetenv under Windows -> use our ctypes one as well
+ try:
+ del_windows_env_var(key)
+ except WindowsError:
+ pass
+ else:
+ os.unsetenv(key)
+
+
+def putenv(key, value):
+ """Like `os.putenv` but takes unicode under Windows + Python 2
+
+ Args:
+ key (pathlike): The env var to get
+ value (pathlike): The value to set
+ Raises:
+ ValueError
+ """
+
+ key = path2fsn(key)
+ value = path2fsn(value)
+
+ if is_win and PY2:
+ try:
+ set_windows_env_var(key, value)
+ except WindowsError:
+ # py3 + win fails here
+ raise ValueError
+ else:
+ try:
+ os.putenv(key, value)
+ except OSError:
+ # win + py3 raise here for invalid keys which is probably a bug.
+ # ValueError seems better
+ raise ValueError
diff --git a/mutagen/_senf/_fsnative.py b/mutagen/_senf/_fsnative.py
new file mode 100644
index 0000000..7b62bc6
--- /dev/null
+++ b/mutagen/_senf/_fsnative.py
@@ -0,0 +1,420 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 Christoph Reiter
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+import os
+import sys
+import ctypes
+import codecs
+
+from . import _winapi as winapi
+from ._compat import text_type, PY3, PY2, url2pathname, urlparse, quote, \
+ unquote
+
+
+is_win = os.name == "nt"
+is_unix = not is_win
+is_darwin = sys.platform == "darwin"
+
+_surrogatepass = "strict" if PY2 else "surrogatepass"
+
+
+def _decode_surrogatepass(data, codec):
+ """Like data.decode(codec, 'surrogatepass') but makes utf-16-le work
+ on Python < 3.4 + Windows
+
+ https://bugs.python.org/issue27971
+
+ Raises UnicodeDecodeError, LookupError
+ """
+
+ try:
+ return data.decode(codec, _surrogatepass)
+ except UnicodeDecodeError:
+ if os.name == "nt" and sys.version_info[:2] < (3, 4) and \
+ codecs.lookup(codec).name == "utf-16-le":
+ buffer_ = ctypes.create_string_buffer(data + b"\x00\x00")
+ value = ctypes.wstring_at(buffer_, len(data) // 2)
+ if value.encode("utf-16-le", _surrogatepass) != data:
+ raise
+ return value
+ else:
+ raise
+
+
+def _fsnative(text):
+ if not isinstance(text, text_type):
+ raise TypeError("%r needs to be a text type (%r)" % (text, text_type))
+
+ if is_unix:
+ # First we go to bytes so we can be sure we have a valid source.
+ # Theoretically we should fail here in case we have a non-unicode
+ # encoding. But this would make everything complicated and there is
+ # no good way to handle a failure from the user side. Instead
+ # fall back to utf-8 which is the most likely the right choice in
+ # a mis-configured environment
+ encoding = _encoding
+ try:
+ path = text.encode(encoding, _surrogatepass)
+ except UnicodeEncodeError:
+ path = text.encode("utf-8", _surrogatepass)
+ if PY3:
+ return path.decode(_encoding, "surrogateescape")
+ return path
+ else:
+ return text
+
+
+def _create_fsnative(type_):
+ # a bit of magic to make fsnative(u"foo") and isinstance(path, fsnative)
+ # work
+
+ class meta(type):
+
+ def __instancecheck__(self, instance):
+ # XXX: invalid str on Unix + Py3 still returns True here, but
+ # might fail when passed to fsnative API. We could be more strict
+ # here and call _validate_fsnative(), but then we could
+ # have a value not being an instance of fsnative, while its type
+ # is still a subclass of fsnative.. and this is enough magic
+ # already.
+ return isinstance(instance, type_)
+
+ def __subclasscheck__(self, subclass):
+ return issubclass(subclass, type_)
+
+ class impl(object):
+ """fsnative(text=u"")
+
+ Args:
+ text (text): The text to convert to a path
+ Returns:
+ fsnative: The new path.
+ Raises:
+ TypeError: In case something other then `text` has been passed
+
+ This type is a virtual base class for the real path type.
+ Instantiating it returns an instance of the real path type and it
+ overrides instance and subclass checks so that `isinstance` and
+ `issubclass` checks work:
+
+ ::
+
+ isinstance(fsnative(u"foo"), fsnative) == True
+ issubclass(type(fsnative(u"foo")), fsnative) == True
+
+ The real returned type is:
+
+ - Python 2 + Windows: :obj:`python:unicode` with ``surrogates``
+ - Python 2 + Unix: :obj:`python:str`
+ - Python 3 + Windows: :obj:`python3:str` with ``surrogates``
+ - Python 3 + Unix: :obj:`python3:str` with ``surrogates`` (only
+ containing code points which can be encoded with the locale encoding)
+
+ Constructing a `fsnative` can't fail.
+ """
+
+ def __new__(cls, text=u""):
+ return _fsnative(text)
+
+ new_type = meta("fsnative", (object,), dict(impl.__dict__))
+ new_type.__module__ = "senf"
+ return new_type
+
+
+fsnative_type = text_type if is_win or PY3 else bytes
+fsnative = _create_fsnative(fsnative_type)
+
+
+def _validate_fsnative(path):
+ """
+ Args:
+ path (fsnative)
+ Returns:
+ `text` on Windows, `bytes` on Unix
+ Raises:
+ TypeError: in case the type is wrong or the ´str` on Py3 + Unix
+ can't be converted to `bytes`
+
+ This helper allows to validate the type and content of a path.
+ To reduce overhead the encoded value for Py3 + Unix is returned so
+ it can be reused.
+ """
+
+ if not isinstance(path, fsnative_type):
+ raise TypeError("path needs to be %s, not %s" % (
+ fsnative_type.__name__, type(path).__name__))
+
+ if PY3 and is_unix:
+ try:
+ return path.encode(_encoding, "surrogateescape")
+ except UnicodeEncodeError:
+ # This look more like ValueError, but raising only one error
+ # makes things simpler... also one could say str + surrogates
+ # is its own type
+ raise TypeError("path contained Unicode code points not valid in"
+ "the current path encoding. To create a valid "
+ "path from Unicode use text2fsn()")
+
+ return path
+
+
+def _get_encoding():
+ """The encoding used for paths, argv, environ, stdout and stdin"""
+
+ encoding = sys.getfilesystemencoding()
+ if encoding is None:
+ if is_darwin:
+ return "utf-8"
+ elif is_win:
+ return "mbcs"
+ else:
+ return "ascii"
+ return encoding
+
+_encoding = _get_encoding()
+
+
+def path2fsn(path):
+ """
+ Args:
+ path (pathlike): The path to convert
+ Returns:
+ `fsnative`
+ Raises:
+ TypeError: In case the type can't be converted to a `fsnative`
+ ValueError: In case conversion fails
+
+ Returns a `fsnative` path for a `pathlike`.
+ """
+
+ # allow mbcs str on py2+win and bytes on py3
+ if PY2:
+ if is_win:
+ if isinstance(path, str):
+ path = path.decode(_encoding)
+ else:
+ if isinstance(path, unicode):
+ path = path.encode(_encoding)
+ else:
+ path = getattr(os, "fspath", lambda x: x)(path)
+ if isinstance(path, bytes):
+ path = path.decode(_encoding, "surrogateescape")
+ elif is_unix and isinstance(path, str):
+ # make sure we can encode it and this is not just some random
+ # unicode string
+ path.encode(_encoding, "surrogateescape")
+
+ if not isinstance(path, fsnative_type):
+ raise TypeError("path needs to be %s", fsnative_type.__name__)
+
+ return path
+
+
+def fsn2text(path):
+ """
+ Args:
+ path (fsnative): The path to convert
+ Returns:
+ `text`
+ Raises:
+ TypeError: In case no `fsnative` has been passed
+
+ Converts a `fsnative` path to `text`.
+
+ This process is not reversible and should only be used for display
+ purposes.
+ Encoding with a Unicode encoding will always succeed with the result.
+ """
+
+ path = _validate_fsnative(path)
+
+ if is_win:
+ return path.encode("utf-16-le", _surrogatepass).decode("utf-16-le",
+ "replace")
+ else:
+ return path.decode(_encoding, "replace")
+
+
+def text2fsn(text):
+ """
+ Args:
+ text (text): The text to convert
+ Returns:
+ `fsnative`
+ Raises:
+ TypeError: In case no `text` has been passed
+
+ Takes `text` and converts it to a `fsnative`.
+
+ This operation is not reversible and can't fail.
+ """
+
+ return fsnative(text)
+
+
+def fsn2bytes(path, encoding):
+ """
+ Args:
+ path (fsnative): The path to convert
+ encoding (`str` or `None`): `None` if you don't care about Windows
+ Returns:
+ `bytes`
+ Raises:
+ TypeError: If no `fsnative` path is passed
... 4450 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/mutagen.git
More information about the Python-modules-commits
mailing list