Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
1
venv/Lib/site-packages/ipython_genutils/__init__.py
Normal file
1
venv/Lib/site-packages/ipython_genutils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from ._version import __version__, version_info
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
venv/Lib/site-packages/ipython_genutils/_version.py
Normal file
2
venv/Lib/site-packages/ipython_genutils/_version.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
version_info = (0, 2, 0)
|
||||
__version__ = '.'.join(map(str, version_info))
|
71
venv/Lib/site-packages/ipython_genutils/encoding.py
Normal file
71
venv/Lib/site-packages/ipython_genutils/encoding.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
# coding: utf-8
|
||||
"""
|
||||
Utilities for dealing with text encodings
|
||||
"""
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2008-2012 The IPython Development Team
|
||||
#
|
||||
# Distributed under the terms of the BSD License. The full license is in
|
||||
# the file COPYING, distributed as part of this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
import sys
|
||||
import locale
|
||||
import warnings
|
||||
|
||||
# to deal with the possibility of sys.std* not being a stream at all
|
||||
def get_stream_enc(stream, default=None):
|
||||
"""Return the given stream's encoding or a default.
|
||||
|
||||
There are cases where ``sys.std*`` might not actually be a stream, so
|
||||
check for the encoding attribute prior to returning it, and return
|
||||
a default if it doesn't exist or evaluates as False. ``default``
|
||||
is None if not provided.
|
||||
"""
|
||||
if not hasattr(stream, 'encoding') or not stream.encoding:
|
||||
return default
|
||||
else:
|
||||
return stream.encoding
|
||||
|
||||
# Less conservative replacement for sys.getdefaultencoding, that will try
|
||||
# to match the environment.
|
||||
# Defined here as central function, so if we find better choices, we
|
||||
# won't need to make changes all over IPython.
|
||||
def getdefaultencoding(prefer_stream=True):
|
||||
"""Return IPython's guess for the default encoding for bytes as text.
|
||||
|
||||
If prefer_stream is True (default), asks for stdin.encoding first,
|
||||
to match the calling Terminal, but that is often None for subprocesses.
|
||||
|
||||
Then fall back on locale.getpreferredencoding(),
|
||||
which should be a sensible platform default (that respects LANG environment),
|
||||
and finally to sys.getdefaultencoding() which is the most conservative option,
|
||||
and usually ASCII on Python 2 or UTF8 on Python 3.
|
||||
"""
|
||||
enc = None
|
||||
if prefer_stream:
|
||||
enc = get_stream_enc(sys.stdin)
|
||||
if not enc or enc=='ascii':
|
||||
try:
|
||||
# There are reports of getpreferredencoding raising errors
|
||||
# in some cases, which may well be fixed, but let's be conservative here.
|
||||
enc = locale.getpreferredencoding()
|
||||
except Exception:
|
||||
pass
|
||||
enc = enc or sys.getdefaultencoding()
|
||||
# On windows `cp0` can be returned to indicate that there is no code page.
|
||||
# Since cp0 is an invalid encoding return instead cp1252 which is the
|
||||
# Western European default.
|
||||
if enc == 'cp0':
|
||||
warnings.warn(
|
||||
"Invalid code page cp0 detected - using cp1252 instead."
|
||||
"If cp1252 is incorrect please ensure a valid code page "
|
||||
"is defined for the process.", RuntimeWarning)
|
||||
return 'cp1252'
|
||||
return enc
|
||||
|
||||
DEFAULT_ENCODING = getdefaultencoding()
|
39
venv/Lib/site-packages/ipython_genutils/importstring.py
Normal file
39
venv/Lib/site-packages/ipython_genutils/importstring.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# encoding: utf-8
|
||||
"""
|
||||
A simple utility to import something by its string name.
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
def import_item(name):
|
||||
"""Import and return ``bar`` given the string ``foo.bar``.
|
||||
|
||||
Calling ``bar = import_item("foo.bar")`` is the functional equivalent of
|
||||
executing the code ``from foo import bar``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : string
|
||||
The fully qualified name of the module/package being imported.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mod : module object
|
||||
The module that was imported.
|
||||
"""
|
||||
|
||||
parts = name.rsplit('.', 1)
|
||||
if len(parts) == 2:
|
||||
# called with 'foo.bar....'
|
||||
package, obj = parts
|
||||
module = __import__(package, fromlist=[obj])
|
||||
try:
|
||||
pak = getattr(module, obj)
|
||||
except AttributeError:
|
||||
raise ImportError('No module named %s' % obj)
|
||||
return pak
|
||||
else:
|
||||
# called with un-dotted string
|
||||
return __import__(parts[0])
|
376
venv/Lib/site-packages/ipython_genutils/ipstruct.py
Normal file
376
venv/Lib/site-packages/ipython_genutils/ipstruct.py
Normal file
|
@ -0,0 +1,376 @@
|
|||
# encoding: utf-8
|
||||
"""A dict subclass that supports attribute style access.
|
||||
|
||||
Can probably be replaced by types.SimpleNamespace from Python 3.3
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
__all__ = ['Struct']
|
||||
|
||||
|
||||
class Struct(dict):
|
||||
"""A dict subclass with attribute style access.
|
||||
|
||||
This dict subclass has a a few extra features:
|
||||
|
||||
* Attribute style access.
|
||||
* Protection of class members (like keys, items) when using attribute
|
||||
style access.
|
||||
* The ability to restrict assignment to only existing keys.
|
||||
* Intelligent merging.
|
||||
* Overloaded operators.
|
||||
"""
|
||||
_allownew = True
|
||||
def __init__(self, *args, **kw):
|
||||
"""Initialize with a dictionary, another Struct, or data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
args : dict, Struct
|
||||
Initialize with one dict or Struct
|
||||
kw : dict
|
||||
Initialize with key, value pairs.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct(a=10,b=30)
|
||||
>>> s.a
|
||||
10
|
||||
>>> s.b
|
||||
30
|
||||
>>> s2 = Struct(s,c=30)
|
||||
>>> sorted(s2.keys())
|
||||
['a', 'b', 'c']
|
||||
"""
|
||||
object.__setattr__(self, '_allownew', True)
|
||||
dict.__init__(self, *args, **kw)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""Set an item with check for allownew.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct()
|
||||
>>> s['a'] = 10
|
||||
>>> s.allow_new_attr(False)
|
||||
>>> s['a'] = 10
|
||||
>>> s['a']
|
||||
10
|
||||
>>> try:
|
||||
... s['b'] = 20
|
||||
... except KeyError:
|
||||
... print('this is not allowed')
|
||||
...
|
||||
this is not allowed
|
||||
"""
|
||||
if not self._allownew and key not in self:
|
||||
raise KeyError(
|
||||
"can't create new attribute %s when allow_new_attr(False)" % key)
|
||||
dict.__setitem__(self, key, value)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
"""Set an attr with protection of class members.
|
||||
|
||||
This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
|
||||
:exc:`AttributeError`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct()
|
||||
>>> s.a = 10
|
||||
>>> s.a
|
||||
10
|
||||
>>> try:
|
||||
... s.get = 10
|
||||
... except AttributeError:
|
||||
... print("you can't set a class member")
|
||||
...
|
||||
you can't set a class member
|
||||
"""
|
||||
# If key is an str it might be a class member or instance var
|
||||
if isinstance(key, str):
|
||||
# I can't simply call hasattr here because it calls getattr, which
|
||||
# calls self.__getattr__, which returns True for keys in
|
||||
# self._data. But I only want keys in the class and in
|
||||
# self.__dict__
|
||||
if key in self.__dict__ or hasattr(Struct, key):
|
||||
raise AttributeError(
|
||||
'attr %s is a protected member of class Struct.' % key
|
||||
)
|
||||
try:
|
||||
self.__setitem__(key, value)
|
||||
except KeyError as e:
|
||||
raise AttributeError(e)
|
||||
|
||||
def __getattr__(self, key):
|
||||
"""Get an attr by calling :meth:`dict.__getitem__`.
|
||||
|
||||
Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
|
||||
:exc:`AttributeError`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct(a=10)
|
||||
>>> s.a
|
||||
10
|
||||
>>> type(s.get)
|
||||
<... 'builtin_function_or_method'>
|
||||
>>> try:
|
||||
... s.b
|
||||
... except AttributeError:
|
||||
... print("I don't have that key")
|
||||
...
|
||||
I don't have that key
|
||||
"""
|
||||
try:
|
||||
result = self[key]
|
||||
except KeyError:
|
||||
raise AttributeError(key)
|
||||
else:
|
||||
return result
|
||||
|
||||
def __iadd__(self, other):
|
||||
"""s += s2 is a shorthand for s.merge(s2).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct(a=10,b=30)
|
||||
>>> s2 = Struct(a=20,c=40)
|
||||
>>> s += s2
|
||||
>>> sorted(s.keys())
|
||||
['a', 'b', 'c']
|
||||
"""
|
||||
self.merge(other)
|
||||
return self
|
||||
|
||||
def __add__(self,other):
|
||||
"""s + s2 -> New Struct made from s.merge(s2).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s1 = Struct(a=10,b=30)
|
||||
>>> s2 = Struct(a=20,c=40)
|
||||
>>> s = s1 + s2
|
||||
>>> sorted(s.keys())
|
||||
['a', 'b', 'c']
|
||||
"""
|
||||
sout = self.copy()
|
||||
sout.merge(other)
|
||||
return sout
|
||||
|
||||
def __sub__(self,other):
|
||||
"""s1 - s2 -> remove keys in s2 from s1.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s1 = Struct(a=10,b=30)
|
||||
>>> s2 = Struct(a=40)
|
||||
>>> s = s1 - s2
|
||||
>>> s
|
||||
{'b': 30}
|
||||
"""
|
||||
sout = self.copy()
|
||||
sout -= other
|
||||
return sout
|
||||
|
||||
def __isub__(self,other):
|
||||
"""Inplace remove keys from self that are in other.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s1 = Struct(a=10,b=30)
|
||||
>>> s2 = Struct(a=40)
|
||||
>>> s1 -= s2
|
||||
>>> s1
|
||||
{'b': 30}
|
||||
"""
|
||||
for k in other.keys():
|
||||
if k in self:
|
||||
del self[k]
|
||||
return self
|
||||
|
||||
def __dict_invert(self, data):
|
||||
"""Helper function for merge.
|
||||
|
||||
Takes a dictionary whose values are lists and returns a dict with
|
||||
the elements of each list as keys and the original keys as values.
|
||||
"""
|
||||
outdict = {}
|
||||
for k,lst in data.items():
|
||||
if isinstance(lst, str):
|
||||
lst = lst.split()
|
||||
for entry in lst:
|
||||
outdict[entry] = k
|
||||
return outdict
|
||||
|
||||
def dict(self):
|
||||
return self
|
||||
|
||||
def copy(self):
|
||||
"""Return a copy as a Struct.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct(a=10,b=30)
|
||||
>>> s2 = s.copy()
|
||||
>>> type(s2) is Struct
|
||||
True
|
||||
"""
|
||||
return Struct(dict.copy(self))
|
||||
|
||||
def hasattr(self, key):
|
||||
"""hasattr function available as a method.
|
||||
|
||||
Implemented like has_key.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
>>> s = Struct(a=10)
|
||||
>>> s.hasattr('a')
|
||||
True
|
||||
>>> s.hasattr('b')
|
||||
False
|
||||
>>> s.hasattr('get')
|
||||
False
|
||||
"""
|
||||
return key in self
|
||||
|
||||
def allow_new_attr(self, allow = True):
|
||||
"""Set whether new attributes can be created in this Struct.
|
||||
|
||||
This can be used to catch typos by verifying that the attribute user
|
||||
tries to change already exists in this Struct.
|
||||
"""
|
||||
object.__setattr__(self, '_allownew', allow)
|
||||
|
||||
def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
|
||||
"""Merge two Structs with customizable conflict resolution.
|
||||
|
||||
This is similar to :meth:`update`, but much more flexible. First, a
|
||||
dict is made from data+key=value pairs. When merging this dict with
|
||||
the Struct S, the optional dictionary 'conflict' is used to decide
|
||||
what to do.
|
||||
|
||||
If conflict is not given, the default behavior is to preserve any keys
|
||||
with their current value (the opposite of the :meth:`update` method's
|
||||
behavior).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
__loc_data : dict, Struct
|
||||
The data to merge into self
|
||||
__conflict_solve : dict
|
||||
The conflict policy dict. The keys are binary functions used to
|
||||
resolve the conflict and the values are lists of strings naming
|
||||
the keys the conflict resolution function applies to. Instead of
|
||||
a list of strings a space separated string can be used, like
|
||||
'a b c'.
|
||||
kw : dict
|
||||
Additional key, value pairs to merge in
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
The `__conflict_solve` dict is a dictionary of binary functions which will be used to
|
||||
solve key conflicts. Here is an example::
|
||||
|
||||
__conflict_solve = dict(
|
||||
func1=['a','b','c'],
|
||||
func2=['d','e']
|
||||
)
|
||||
|
||||
In this case, the function :func:`func1` will be used to resolve
|
||||
keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
|
||||
keys 'd' and 'e'. This could also be written as::
|
||||
|
||||
__conflict_solve = dict(func1='a b c',func2='d e')
|
||||
|
||||
These functions will be called for each key they apply to with the
|
||||
form::
|
||||
|
||||
func1(self['a'], other['a'])
|
||||
|
||||
The return value is used as the final merged value.
|
||||
|
||||
As a convenience, merge() provides five (the most commonly needed)
|
||||
pre-defined policies: preserve, update, add, add_flip and add_s. The
|
||||
easiest explanation is their implementation::
|
||||
|
||||
preserve = lambda old,new: old
|
||||
update = lambda old,new: new
|
||||
add = lambda old,new: old + new
|
||||
add_flip = lambda old,new: new + old # note change of order!
|
||||
add_s = lambda old,new: old + ' ' + new # only for str!
|
||||
|
||||
You can use those four words (as strings) as keys instead
|
||||
of defining them as functions, and the merge method will substitute
|
||||
the appropriate functions for you.
|
||||
|
||||
For more complicated conflict resolution policies, you still need to
|
||||
construct your own functions.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
This show the default policy:
|
||||
|
||||
>>> s = Struct(a=10,b=30)
|
||||
>>> s2 = Struct(a=20,c=40)
|
||||
>>> s.merge(s2)
|
||||
>>> sorted(s.items())
|
||||
[('a', 10), ('b', 30), ('c', 40)]
|
||||
|
||||
Now, show how to specify a conflict dict:
|
||||
|
||||
>>> s = Struct(a=10,b=30)
|
||||
>>> s2 = Struct(a=20,b=40)
|
||||
>>> conflict = {'update':'a','add':'b'}
|
||||
>>> s.merge(s2,conflict)
|
||||
>>> sorted(s.items())
|
||||
[('a', 20), ('b', 70)]
|
||||
"""
|
||||
|
||||
data_dict = dict(__loc_data__,**kw)
|
||||
|
||||
# policies for conflict resolution: two argument functions which return
|
||||
# the value that will go in the new struct
|
||||
preserve = lambda old,new: old
|
||||
update = lambda old,new: new
|
||||
add = lambda old,new: old + new
|
||||
add_flip = lambda old,new: new + old # note change of order!
|
||||
add_s = lambda old,new: old + ' ' + new
|
||||
|
||||
# default policy is to keep current keys when there's a conflict
|
||||
conflict_solve = dict.fromkeys(self, preserve)
|
||||
|
||||
# the conflict_solve dictionary is given by the user 'inverted': we
|
||||
# need a name-function mapping, it comes as a function -> names
|
||||
# dict. Make a local copy (b/c we'll make changes), replace user
|
||||
# strings for the three builtin policies and invert it.
|
||||
if __conflict_solve:
|
||||
inv_conflict_solve_user = __conflict_solve.copy()
|
||||
for name, func in [('preserve',preserve), ('update',update),
|
||||
('add',add), ('add_flip',add_flip),
|
||||
('add_s',add_s)]:
|
||||
if name in inv_conflict_solve_user.keys():
|
||||
inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
|
||||
del inv_conflict_solve_user[name]
|
||||
conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
|
||||
for key in data_dict:
|
||||
if key not in self:
|
||||
self[key] = data_dict[key]
|
||||
else:
|
||||
self[key] = conflict_solve[key](self[key],data_dict[key])
|
||||
|
172
venv/Lib/site-packages/ipython_genutils/path.py
Normal file
172
venv/Lib/site-packages/ipython_genutils/path.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
# encoding: utf-8
|
||||
"""
|
||||
Utilities for path handling.
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import errno
|
||||
import shutil
|
||||
import random
|
||||
|
||||
from . import py3compat
|
||||
|
||||
|
||||
fs_encoding = sys.getfilesystemencoding()
|
||||
|
||||
|
||||
def filefind(filename, path_dirs=None):
|
||||
"""Find a file by looking through a sequence of paths.
|
||||
|
||||
This iterates through a sequence of paths looking for a file and returns
|
||||
the full, absolute path of the first occurence of the file. If no set of
|
||||
path dirs is given, the filename is tested as is, after running through
|
||||
:func:`expandvars` and :func:`expanduser`. Thus a simple call::
|
||||
|
||||
filefind('myfile.txt')
|
||||
|
||||
will find the file in the current working dir, but::
|
||||
|
||||
filefind('~/myfile.txt')
|
||||
|
||||
Will find the file in the users home directory. This function does not
|
||||
automatically try any paths, such as the cwd or the user's home directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
The filename to look for.
|
||||
path_dirs : str, None or sequence of str
|
||||
The sequence of paths to look for the file in. If None, the filename
|
||||
need to be absolute or be in the cwd. If a string, the string is
|
||||
put into a sequence and the searched. If a sequence, walk through
|
||||
each element and join with ``filename``, calling :func:`expandvars`
|
||||
and :func:`expanduser` before testing for existence.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Raises :exc:`IOError` or returns absolute path to file.
|
||||
"""
|
||||
|
||||
# If paths are quoted, abspath gets confused, strip them...
|
||||
filename = filename.strip('"').strip("'")
|
||||
# If the input is an absolute path, just check it exists
|
||||
if os.path.isabs(filename) and os.path.isfile(filename):
|
||||
return filename
|
||||
|
||||
if path_dirs is None:
|
||||
path_dirs = ("",)
|
||||
elif isinstance(path_dirs, py3compat.string_types):
|
||||
path_dirs = (path_dirs,)
|
||||
|
||||
for path in path_dirs:
|
||||
if path == '.': path = py3compat.getcwd()
|
||||
testname = expand_path(os.path.join(path, filename))
|
||||
if os.path.isfile(testname):
|
||||
return os.path.abspath(testname)
|
||||
|
||||
raise IOError("File %r does not exist in any of the search paths: %r" %
|
||||
(filename, path_dirs) )
|
||||
|
||||
|
||||
def expand_path(s):
|
||||
"""Expand $VARS and ~names in a string, like a shell
|
||||
|
||||
:Examples:
|
||||
|
||||
In [2]: os.environ['FOO']='test'
|
||||
|
||||
In [3]: expand_path('variable FOO is $FOO')
|
||||
Out[3]: 'variable FOO is test'
|
||||
"""
|
||||
# This is a pretty subtle hack. When expand user is given a UNC path
|
||||
# on Windows (\\server\share$\%username%), os.path.expandvars, removes
|
||||
# the $ to get (\\server\share\%username%). I think it considered $
|
||||
# alone an empty var. But, we need the $ to remains there (it indicates
|
||||
# a hidden share).
|
||||
if os.name=='nt':
|
||||
s = s.replace('$\\', 'IPYTHON_TEMP')
|
||||
s = os.path.expandvars(os.path.expanduser(s))
|
||||
if os.name=='nt':
|
||||
s = s.replace('IPYTHON_TEMP', '$\\')
|
||||
return s
|
||||
|
||||
|
||||
try:
|
||||
ENOLINK = errno.ENOLINK
|
||||
except AttributeError:
|
||||
ENOLINK = 1998
|
||||
|
||||
def link(src, dst):
|
||||
"""Hard links ``src`` to ``dst``, returning 0 or errno.
|
||||
|
||||
Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
|
||||
supported by the operating system.
|
||||
"""
|
||||
|
||||
if not hasattr(os, "link"):
|
||||
return ENOLINK
|
||||
link_errno = 0
|
||||
try:
|
||||
os.link(src, dst)
|
||||
except OSError as e:
|
||||
link_errno = e.errno
|
||||
return link_errno
|
||||
|
||||
|
||||
def link_or_copy(src, dst):
|
||||
"""Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
|
||||
|
||||
Attempts to maintain the semantics of ``shutil.copy``.
|
||||
|
||||
Because ``os.link`` does not overwrite files, a unique temporary file
|
||||
will be used if the target already exists, then that file will be moved
|
||||
into place.
|
||||
"""
|
||||
|
||||
if os.path.isdir(dst):
|
||||
dst = os.path.join(dst, os.path.basename(src))
|
||||
|
||||
link_errno = link(src, dst)
|
||||
if link_errno == errno.EEXIST:
|
||||
if os.stat(src).st_ino == os.stat(dst).st_ino:
|
||||
# dst is already a hard link to the correct file, so we don't need
|
||||
# to do anything else. If we try to link and rename the file
|
||||
# anyway, we get duplicate files - see http://bugs.python.org/issue21876
|
||||
return
|
||||
|
||||
new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
|
||||
try:
|
||||
link_or_copy(src, new_dst)
|
||||
except:
|
||||
try:
|
||||
os.remove(new_dst)
|
||||
except OSError:
|
||||
pass
|
||||
raise
|
||||
os.rename(new_dst, dst)
|
||||
elif link_errno != 0:
|
||||
# Either link isn't supported, or the filesystem doesn't support
|
||||
# linking, or 'src' and 'dst' are on different filesystems.
|
||||
shutil.copy(src, dst)
|
||||
|
||||
|
||||
def ensure_dir_exists(path, mode=0o755):
|
||||
"""ensure that a directory exists
|
||||
|
||||
If it doesn't exist, try to create it and protect against a race condition
|
||||
if another process is doing the same.
|
||||
|
||||
The default permissions are 755, which differ from os.makedirs default of 777.
|
||||
"""
|
||||
if not os.path.exists(path):
|
||||
try:
|
||||
os.makedirs(path, mode=mode)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
elif not os.path.isdir(path):
|
||||
raise IOError("%r exists but is not a directory" % path)
|
333
venv/Lib/site-packages/ipython_genutils/py3compat.py
Normal file
333
venv/Lib/site-packages/ipython_genutils/py3compat.py
Normal file
|
@ -0,0 +1,333 @@
|
|||
# coding: utf-8
|
||||
"""Compatibility tricks for Python 3. Mainly to do with unicode."""
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import shutil
|
||||
import types
|
||||
|
||||
from .encoding import DEFAULT_ENCODING
|
||||
|
||||
def no_code(x, encoding=None):
|
||||
return x
|
||||
|
||||
def decode(s, encoding=None):
|
||||
encoding = encoding or DEFAULT_ENCODING
|
||||
return s.decode(encoding, "replace")
|
||||
|
||||
def encode(u, encoding=None):
|
||||
encoding = encoding or DEFAULT_ENCODING
|
||||
return u.encode(encoding, "replace")
|
||||
|
||||
|
||||
def cast_unicode(s, encoding=None):
|
||||
if isinstance(s, bytes):
|
||||
return decode(s, encoding)
|
||||
return s
|
||||
|
||||
def cast_bytes(s, encoding=None):
|
||||
if not isinstance(s, bytes):
|
||||
return encode(s, encoding)
|
||||
return s
|
||||
|
||||
def buffer_to_bytes(buf):
|
||||
"""Cast a buffer or memoryview object to bytes"""
|
||||
if isinstance(buf, memoryview):
|
||||
return buf.tobytes()
|
||||
if not isinstance(buf, bytes):
|
||||
return bytes(buf)
|
||||
return buf
|
||||
|
||||
def _modify_str_or_docstring(str_change_func):
|
||||
@functools.wraps(str_change_func)
|
||||
def wrapper(func_or_str):
|
||||
if isinstance(func_or_str, string_types):
|
||||
func = None
|
||||
doc = func_or_str
|
||||
else:
|
||||
func = func_or_str
|
||||
doc = func.__doc__
|
||||
|
||||
doc = str_change_func(doc)
|
||||
|
||||
if func:
|
||||
func.__doc__ = doc
|
||||
return func
|
||||
return doc
|
||||
return wrapper
|
||||
|
||||
def safe_unicode(e):
|
||||
"""unicode(e) with various fallbacks. Used for exceptions, which may not be
|
||||
safe to call unicode() on.
|
||||
"""
|
||||
try:
|
||||
return unicode_type(e)
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return str_to_unicode(str(e))
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return str_to_unicode(repr(e))
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
return u'Unrecoverably corrupt evalue'
|
||||
|
||||
# shutil.which from Python 3.4
|
||||
def _shutil_which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||
"""Given a command, mode, and a PATH string, return the path which
|
||||
conforms to the given mode on the PATH, or None if there is no such
|
||||
file.
|
||||
|
||||
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||||
of os.environ.get("PATH"), or can be overridden with a custom search
|
||||
path.
|
||||
|
||||
This is a backport of shutil.which from Python 3.4
|
||||
"""
|
||||
# Check that a given file can be accessed with the correct mode.
|
||||
# Additionally check that `file` is not a directory, as on Windows
|
||||
# directories pass the os.access check.
|
||||
def _access_check(fn, mode):
|
||||
return (os.path.exists(fn) and os.access(fn, mode)
|
||||
and not os.path.isdir(fn))
|
||||
|
||||
# If we're given a path with a directory part, look it up directly rather
|
||||
# than referring to PATH directories. This includes checking relative to the
|
||||
# current directory, e.g. ./script
|
||||
if os.path.dirname(cmd):
|
||||
if _access_check(cmd, mode):
|
||||
return cmd
|
||||
return None
|
||||
|
||||
if path is None:
|
||||
path = os.environ.get("PATH", os.defpath)
|
||||
if not path:
|
||||
return None
|
||||
path = path.split(os.pathsep)
|
||||
|
||||
if sys.platform == "win32":
|
||||
# The current directory takes precedence on Windows.
|
||||
if not os.curdir in path:
|
||||
path.insert(0, os.curdir)
|
||||
|
||||
# PATHEXT is necessary to check on Windows.
|
||||
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||||
# See if the given file matches any of the expected path extensions.
|
||||
# This will allow us to short circuit when given "python.exe".
|
||||
# If it does match, only test that one, otherwise we have to try
|
||||
# others.
|
||||
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
||||
files = [cmd]
|
||||
else:
|
||||
files = [cmd + ext for ext in pathext]
|
||||
else:
|
||||
# On other platforms you don't have things like PATHEXT to tell you
|
||||
# what file suffixes are executable, so just pass on cmd as-is.
|
||||
files = [cmd]
|
||||
|
||||
seen = set()
|
||||
for dir in path:
|
||||
normdir = os.path.normcase(dir)
|
||||
if not normdir in seen:
|
||||
seen.add(normdir)
|
||||
for thefile in files:
|
||||
name = os.path.join(dir, thefile)
|
||||
if _access_check(name, mode):
|
||||
return name
|
||||
return None
|
||||
|
||||
import platform
|
||||
if sys.version_info[0] >= 3 or platform.python_implementation() == 'IronPython':
|
||||
str_to_unicode = no_code
|
||||
unicode_to_str = no_code
|
||||
str_to_bytes = encode
|
||||
bytes_to_str = decode
|
||||
cast_bytes_py2 = no_code
|
||||
cast_unicode_py2 = no_code
|
||||
buffer_to_bytes_py2 = no_code
|
||||
|
||||
string_types = (str,)
|
||||
unicode_type = str
|
||||
else:
|
||||
str_to_unicode = decode
|
||||
unicode_to_str = encode
|
||||
str_to_bytes = no_code
|
||||
bytes_to_str = no_code
|
||||
cast_bytes_py2 = cast_bytes
|
||||
cast_unicode_py2 = cast_unicode
|
||||
buffer_to_bytes_py2 = buffer_to_bytes
|
||||
|
||||
string_types = (str, unicode)
|
||||
unicode_type = unicode
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
PY3 = True
|
||||
|
||||
# keep reference to builtin_mod because the kernel overrides that value
|
||||
# to forward requests to a frontend.
|
||||
def input(prompt=''):
|
||||
return builtin_mod.input(prompt)
|
||||
|
||||
builtin_mod_name = "builtins"
|
||||
import builtins as builtin_mod
|
||||
|
||||
which = shutil.which
|
||||
|
||||
def isidentifier(s, dotted=False):
|
||||
if dotted:
|
||||
return all(isidentifier(a) for a in s.split("."))
|
||||
return s.isidentifier()
|
||||
|
||||
xrange = range
|
||||
def iteritems(d): return iter(d.items())
|
||||
def itervalues(d): return iter(d.values())
|
||||
getcwd = os.getcwd
|
||||
|
||||
MethodType = types.MethodType
|
||||
|
||||
def execfile(fname, glob, loc=None, compiler=None):
|
||||
loc = loc if (loc is not None) else glob
|
||||
with open(fname, 'rb') as f:
|
||||
compiler = compiler or compile
|
||||
exec(compiler(f.read(), fname, 'exec'), glob, loc)
|
||||
|
||||
# Refactor print statements in doctests.
|
||||
_print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
|
||||
def _print_statement_sub(match):
|
||||
expr = match.groups('expr')
|
||||
return "print(%s)" % expr
|
||||
|
||||
@_modify_str_or_docstring
|
||||
def doctest_refactor_print(doc):
|
||||
"""Refactor 'print x' statements in a doctest to print(x) style. 2to3
|
||||
unfortunately doesn't pick up on our doctests.
|
||||
|
||||
Can accept a string or a function, so it can be used as a decorator."""
|
||||
return _print_statement_re.sub(_print_statement_sub, doc)
|
||||
|
||||
# Abstract u'abc' syntax:
|
||||
@_modify_str_or_docstring
|
||||
def u_format(s):
|
||||
""""{u}'abc'" --> "'abc'" (Python 3)
|
||||
|
||||
Accepts a string or a function, so it can be used as a decorator."""
|
||||
return s.format(u='')
|
||||
|
||||
def get_closure(f):
|
||||
"""Get a function's closure attribute"""
|
||||
return f.__closure__
|
||||
|
||||
else:
|
||||
PY3 = False
|
||||
|
||||
# keep reference to builtin_mod because the kernel overrides that value
|
||||
# to forward requests to a frontend.
|
||||
def input(prompt=''):
|
||||
return builtin_mod.raw_input(prompt)
|
||||
|
||||
builtin_mod_name = "__builtin__"
|
||||
import __builtin__ as builtin_mod
|
||||
|
||||
import re
|
||||
_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
def isidentifier(s, dotted=False):
|
||||
if dotted:
|
||||
return all(isidentifier(a) for a in s.split("."))
|
||||
return bool(_name_re.match(s))
|
||||
|
||||
xrange = xrange
|
||||
def iteritems(d): return d.iteritems()
|
||||
def itervalues(d): return d.itervalues()
|
||||
getcwd = os.getcwdu
|
||||
|
||||
def MethodType(func, instance):
|
||||
return types.MethodType(func, instance, type(instance))
|
||||
|
||||
def doctest_refactor_print(func_or_str):
|
||||
return func_or_str
|
||||
|
||||
def get_closure(f):
|
||||
"""Get a function's closure attribute"""
|
||||
return f.func_closure
|
||||
|
||||
which = _shutil_which
|
||||
|
||||
# Abstract u'abc' syntax:
|
||||
@_modify_str_or_docstring
|
||||
def u_format(s):
|
||||
""""{u}'abc'" --> "u'abc'" (Python 2)
|
||||
|
||||
Accepts a string or a function, so it can be used as a decorator."""
|
||||
return s.format(u='u')
|
||||
|
||||
if sys.platform == 'win32':
|
||||
def execfile(fname, glob=None, loc=None, compiler=None):
|
||||
loc = loc if (loc is not None) else glob
|
||||
scripttext = builtin_mod.open(fname).read()+ '\n'
|
||||
# compile converts unicode filename to str assuming
|
||||
# ascii. Let's do the conversion before calling compile
|
||||
if isinstance(fname, unicode):
|
||||
filename = unicode_to_str(fname)
|
||||
else:
|
||||
filename = fname
|
||||
compiler = compiler or compile
|
||||
exec(compiler(scripttext, filename, 'exec'), glob, loc)
|
||||
|
||||
else:
|
||||
def execfile(fname, glob=None, loc=None, compiler=None):
|
||||
if isinstance(fname, unicode):
|
||||
filename = fname.encode(sys.getfilesystemencoding())
|
||||
else:
|
||||
filename = fname
|
||||
where = [ns for ns in [glob, loc] if ns is not None]
|
||||
if compiler is None:
|
||||
builtin_mod.execfile(filename, *where)
|
||||
else:
|
||||
scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
|
||||
exec(compiler(scripttext, filename, 'exec'), glob, loc)
|
||||
|
||||
|
||||
def annotate(**kwargs):
|
||||
"""Python 3 compatible function annotation for Python 2."""
|
||||
if not kwargs:
|
||||
raise ValueError('annotations must be provided as keyword arguments')
|
||||
def dec(f):
|
||||
if hasattr(f, '__annotations__'):
|
||||
for k, v in kwargs.items():
|
||||
f.__annotations__[k] = v
|
||||
else:
|
||||
f.__annotations__ = kwargs
|
||||
return f
|
||||
return dec
|
||||
|
||||
|
||||
# Parts below taken from six:
|
||||
# Copyright (c) 2010-2013 Benjamin Peterson
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
"""Create a base class with a metaclass."""
|
||||
return meta("_NewBase", bases, {})
|
150
venv/Lib/site-packages/ipython_genutils/tempdir.py
Normal file
150
venv/Lib/site-packages/ipython_genutils/tempdir.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
"""TemporaryDirectory class, copied from Python 3
|
||||
|
||||
This is copied from the stdlib and will be standard in Python 3.2 and onwards.
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os as _os
|
||||
import warnings as _warnings
|
||||
import sys as _sys
|
||||
|
||||
# This code should only be used in Python versions < 3.2, since after that we
|
||||
# can rely on the stdlib itself.
|
||||
try:
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
except ImportError:
|
||||
from tempfile import mkdtemp, template
|
||||
|
||||
class TemporaryDirectory(object):
|
||||
"""Create and return a temporary directory. This has the same
|
||||
behavior as mkdtemp but can be used as a context manager. For
|
||||
example:
|
||||
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
...
|
||||
|
||||
Upon exiting the context, the directory and everthing contained
|
||||
in it are removed.
|
||||
"""
|
||||
|
||||
def __init__(self, suffix="", prefix=template, dir=None):
|
||||
self.name = mkdtemp(suffix, prefix, dir)
|
||||
self._closed = False
|
||||
|
||||
def __enter__(self):
|
||||
return self.name
|
||||
|
||||
def cleanup(self, _warn=False):
|
||||
if self.name and not self._closed:
|
||||
try:
|
||||
self._rmtree(self.name)
|
||||
except (TypeError, AttributeError) as ex:
|
||||
# Issue #10188: Emit a warning on stderr
|
||||
# if the directory could not be cleaned
|
||||
# up due to missing globals
|
||||
if "None" not in str(ex):
|
||||
raise
|
||||
print("ERROR: {!r} while cleaning up {!r}".format(ex, self,),
|
||||
file=_sys.stderr)
|
||||
return
|
||||
self._closed = True
|
||||
if _warn:
|
||||
self._warn("Implicitly cleaning up {!r}".format(self),
|
||||
Warning)
|
||||
|
||||
def __exit__(self, exc, value, tb):
|
||||
self.cleanup()
|
||||
|
||||
def __del__(self):
|
||||
# Issue a ResourceWarning if implicit cleanup needed
|
||||
self.cleanup(_warn=True)
|
||||
|
||||
|
||||
# XXX (ncoghlan): The following code attempts to make
|
||||
# this class tolerant of the module nulling out process
|
||||
# that happens during CPython interpreter shutdown
|
||||
# Alas, it doesn't actually manage it. See issue #10188
|
||||
_listdir = staticmethod(_os.listdir)
|
||||
_path_join = staticmethod(_os.path.join)
|
||||
_isdir = staticmethod(_os.path.isdir)
|
||||
_remove = staticmethod(_os.remove)
|
||||
_rmdir = staticmethod(_os.rmdir)
|
||||
_os_error = _os.error
|
||||
_warn = _warnings.warn
|
||||
|
||||
def _rmtree(self, path):
|
||||
# Essentially a stripped down version of shutil.rmtree. We can't
|
||||
# use globals because they may be None'ed out at shutdown.
|
||||
for name in self._listdir(path):
|
||||
fullname = self._path_join(path, name)
|
||||
try:
|
||||
isdir = self._isdir(fullname)
|
||||
except self._os_error:
|
||||
isdir = False
|
||||
if isdir:
|
||||
self._rmtree(fullname)
|
||||
else:
|
||||
try:
|
||||
self._remove(fullname)
|
||||
except self._os_error:
|
||||
pass
|
||||
try:
|
||||
self._rmdir(path)
|
||||
except self._os_error:
|
||||
pass
|
||||
|
||||
# extra temp-dir-related context managers
|
||||
|
||||
class NamedFileInTemporaryDirectory(object):
|
||||
|
||||
def __init__(self, filename, mode='w+b', bufsize=-1, **kwds):
|
||||
"""
|
||||
Open a file named `filename` in a temporary directory.
|
||||
|
||||
This context manager is preferred over `NamedTemporaryFile` in
|
||||
stdlib `tempfile` when one needs to reopen the file.
|
||||
|
||||
Arguments `mode` and `bufsize` are passed to `open`.
|
||||
Rest of the arguments are passed to `TemporaryDirectory`.
|
||||
|
||||
"""
|
||||
self._tmpdir = TemporaryDirectory(**kwds)
|
||||
path = _os.path.join(self._tmpdir.name, filename)
|
||||
self.file = open(path, mode, bufsize)
|
||||
|
||||
def cleanup(self):
|
||||
self.file.close()
|
||||
self._tmpdir.cleanup()
|
||||
|
||||
__del__ = cleanup
|
||||
|
||||
def __enter__(self):
|
||||
return self.file
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.cleanup()
|
||||
|
||||
|
||||
class TemporaryWorkingDirectory(TemporaryDirectory):
|
||||
"""
|
||||
Creates a temporary directory and sets the cwd to that directory.
|
||||
Automatically reverts to previous cwd upon cleanup.
|
||||
Usage example:
|
||||
|
||||
with TemporaryWorkingDirectory() as tmpdir:
|
||||
...
|
||||
"""
|
||||
def __enter__(self):
|
||||
self.old_wd = _os.getcwd()
|
||||
_os.chdir(self.name)
|
||||
return super(TemporaryWorkingDirectory, self).__enter__()
|
||||
|
||||
def __exit__(self, exc, value, tb):
|
||||
_os.chdir(self.old_wd)
|
||||
return super(TemporaryWorkingDirectory, self).__exit__(exc, value, tb)
|
||||
|
Binary file not shown.
Binary file not shown.
342
venv/Lib/site-packages/ipython_genutils/testing/decorators.py
Normal file
342
venv/Lib/site-packages/ipython_genutils/testing/decorators.py
Normal file
|
@ -0,0 +1,342 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Decorators for labeling test objects.
|
||||
|
||||
Decorators that merely return a modified version of the original function
|
||||
object are straightforward. Decorators that return a new function object need
|
||||
to use nose.tools.make_decorator(original_function)(decorator) in returning the
|
||||
decorator, in order to preserve metadata such as function name, setup and
|
||||
teardown functions and so on - see nose.tools for more information.
|
||||
|
||||
This module provides a set of useful decorators meant to be ready to use in
|
||||
your own tests. See the bottom of the file for the ready-made ones, and if you
|
||||
find yourself writing a new one that may be of generic use, add it here.
|
||||
|
||||
Included decorators:
|
||||
|
||||
|
||||
Lightweight testing that remains unittest-compatible.
|
||||
|
||||
- An @as_unittest decorator can be used to tag any normal parameter-less
|
||||
function as a unittest TestCase. Then, both nose and normal unittest will
|
||||
recognize it as such. This will make it easier to migrate away from Nose if
|
||||
we ever need/want to while maintaining very lightweight tests.
|
||||
|
||||
NOTE: This file contains IPython-specific decorators. Using the machinery in
|
||||
IPython.external.decorators, we import either numpy.testing.decorators if numpy is
|
||||
available, OR use equivalent code in IPython.external._decorators, which
|
||||
we've copied verbatim from numpy.
|
||||
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
# For onlyif_cmd_exists decorator
|
||||
from ..py3compat import string_types, which
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Classes and functions
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Simple example of the basic idea
|
||||
def as_unittest(func):
|
||||
"""Decorator to make a simple function into a normal test via unittest."""
|
||||
class Tester(unittest.TestCase):
|
||||
def test(self):
|
||||
func()
|
||||
|
||||
Tester.__name__ = func.__name__
|
||||
|
||||
return Tester
|
||||
|
||||
# Utility functions
|
||||
|
||||
|
||||
|
||||
def make_label_dec(label,ds=None):
|
||||
"""Factory function to create a decorator that applies one or more labels.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
label : string or sequence
|
||||
One or more labels that will be applied by the decorator to the functions
|
||||
it decorates. Labels are attributes of the decorated function with their
|
||||
value set to True.
|
||||
|
||||
ds : string
|
||||
An optional docstring for the resulting decorator. If not given, a
|
||||
default docstring is auto-generated.
|
||||
|
||||
Returns
|
||||
-------
|
||||
A decorator.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
A simple labeling decorator:
|
||||
|
||||
>>> slow = make_label_dec('slow')
|
||||
>>> slow.__doc__
|
||||
"Labels a test as 'slow'."
|
||||
|
||||
And one that uses multiple labels and a custom docstring:
|
||||
|
||||
>>> rare = make_label_dec(['slow','hard'],
|
||||
... "Mix labels 'slow' and 'hard' for rare tests.")
|
||||
>>> rare.__doc__
|
||||
"Mix labels 'slow' and 'hard' for rare tests."
|
||||
|
||||
Now, let's test using this one:
|
||||
>>> @rare
|
||||
... def f(): pass
|
||||
...
|
||||
>>>
|
||||
>>> f.slow
|
||||
True
|
||||
>>> f.hard
|
||||
True
|
||||
"""
|
||||
|
||||
if isinstance(label, string_types):
|
||||
labels = [label]
|
||||
else:
|
||||
labels = label
|
||||
|
||||
# Validate that the given label(s) are OK for use in setattr() by doing a
|
||||
# dry run on a dummy function.
|
||||
tmp = lambda : None
|
||||
for label in labels:
|
||||
setattr(tmp,label,True)
|
||||
|
||||
# This is the actual decorator we'll return
|
||||
def decor(f):
|
||||
for label in labels:
|
||||
setattr(f,label,True)
|
||||
return f
|
||||
|
||||
# Apply the user's docstring, or autogenerate a basic one
|
||||
if ds is None:
|
||||
ds = "Labels a test as %r." % label
|
||||
decor.__doc__ = ds
|
||||
|
||||
return decor
|
||||
|
||||
|
||||
# Inspired by numpy's skipif, but uses the full apply_wrapper utility to
|
||||
# preserve function metadata better and allows the skip condition to be a
|
||||
# callable.
|
||||
def skipif(skip_condition, msg=None):
|
||||
''' Make function raise SkipTest exception if skip_condition is true
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
skip_condition : bool or callable
|
||||
Flag to determine whether to skip test. If the condition is a
|
||||
callable, it is used at runtime to dynamically make the decision. This
|
||||
is useful for tests that may require costly imports, to delay the cost
|
||||
until the test suite is actually executed.
|
||||
msg : string
|
||||
Message to give on raising a SkipTest exception.
|
||||
|
||||
Returns
|
||||
-------
|
||||
decorator : function
|
||||
Decorator, which, when applied to a function, causes SkipTest
|
||||
to be raised when the skip_condition was True, and the function
|
||||
to be called normally otherwise.
|
||||
|
||||
Notes
|
||||
-----
|
||||
You will see from the code that we had to further decorate the
|
||||
decorator with the nose.tools.make_decorator function in order to
|
||||
transmit function name, and various other metadata.
|
||||
'''
|
||||
|
||||
def skip_decorator(f):
|
||||
# Local import to avoid a hard nose dependency and only incur the
|
||||
# import time overhead at actual test-time.
|
||||
import nose
|
||||
|
||||
# Allow for both boolean or callable skip conditions.
|
||||
if callable(skip_condition):
|
||||
skip_val = skip_condition
|
||||
else:
|
||||
skip_val = lambda : skip_condition
|
||||
|
||||
def get_msg(func,msg=None):
|
||||
"""Skip message with information about function being skipped."""
|
||||
if msg is None: out = 'Test skipped due to test condition.'
|
||||
else: out = msg
|
||||
return "Skipping test: %s. %s" % (func.__name__,out)
|
||||
|
||||
# We need to define *two* skippers because Python doesn't allow both
|
||||
# return with value and yield inside the same function.
|
||||
def skipper_func(*args, **kwargs):
|
||||
"""Skipper for normal test functions."""
|
||||
if skip_val():
|
||||
raise nose.SkipTest(get_msg(f,msg))
|
||||
else:
|
||||
return f(*args, **kwargs)
|
||||
|
||||
def skipper_gen(*args, **kwargs):
|
||||
"""Skipper for test generators."""
|
||||
if skip_val():
|
||||
raise nose.SkipTest(get_msg(f,msg))
|
||||
else:
|
||||
for x in f(*args, **kwargs):
|
||||
yield x
|
||||
|
||||
# Choose the right skipper to use when building the actual generator.
|
||||
if nose.util.isgenerator(f):
|
||||
skipper = skipper_gen
|
||||
else:
|
||||
skipper = skipper_func
|
||||
|
||||
return nose.tools.make_decorator(f)(skipper)
|
||||
|
||||
return skip_decorator
|
||||
|
||||
# A version with the condition set to true, common case just to attach a message
|
||||
# to a skip decorator
|
||||
def skip(msg=None):
|
||||
"""Decorator factory - mark a test function for skipping from test suite.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
msg : string
|
||||
Optional message to be added.
|
||||
|
||||
Returns
|
||||
-------
|
||||
decorator : function
|
||||
Decorator, which, when applied to a function, causes SkipTest
|
||||
to be raised, with the optional message added.
|
||||
"""
|
||||
|
||||
return skipif(True,msg)
|
||||
|
||||
|
||||
def onlyif(condition, msg):
|
||||
"""The reverse from skipif, see skipif for details."""
|
||||
|
||||
if callable(condition):
|
||||
skip_condition = lambda : not condition()
|
||||
else:
|
||||
skip_condition = lambda : not condition
|
||||
|
||||
return skipif(skip_condition, msg)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Utility functions for decorators
|
||||
def module_not_available(module):
|
||||
"""Can module be imported? Returns true if module does NOT import.
|
||||
|
||||
This is used to make a decorator to skip tests that require module to be
|
||||
available, but delay the 'import numpy' to test execution time.
|
||||
"""
|
||||
def condition():
|
||||
try:
|
||||
mod = __import__(module)
|
||||
return False
|
||||
except ImportError:
|
||||
return True
|
||||
return condition
|
||||
|
||||
|
||||
def decorated_dummy(dec, name):
|
||||
"""Return a dummy function decorated with dec, with the given name.
|
||||
|
||||
Examples
|
||||
--------
|
||||
import IPython.testing.decorators as dec
|
||||
setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
|
||||
"""
|
||||
dummy = lambda: None
|
||||
dummy.__name__ = name
|
||||
return dec(dummy)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Decorators for public use
|
||||
|
||||
# Decorators to skip certain tests on specific platforms.
|
||||
skip_win32 = skipif(sys.platform == 'win32',
|
||||
"This test does not run under Windows")
|
||||
skip_linux = skipif(sys.platform.startswith('linux'),
|
||||
"This test does not run under Linux")
|
||||
skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
|
||||
|
||||
|
||||
# Decorators to skip tests if not on specific platforms.
|
||||
skip_if_not_win32 = skipif(sys.platform != 'win32',
|
||||
"This test only runs under Windows")
|
||||
skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
|
||||
"This test only runs under Linux")
|
||||
skip_if_not_osx = skipif(sys.platform != 'darwin',
|
||||
"This test only runs under OSX")
|
||||
|
||||
|
||||
_x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
|
||||
os.environ.get('DISPLAY', '') == '')
|
||||
_x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
|
||||
|
||||
skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
|
||||
|
||||
# not a decorator itself, returns a dummy function to be used as setup
|
||||
def skip_file_no_x11(name):
|
||||
return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
|
||||
|
||||
# Other skip decorators
|
||||
|
||||
# generic skip without module
|
||||
skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
|
||||
|
||||
skipif_not_numpy = skip_without('numpy')
|
||||
|
||||
skipif_not_matplotlib = skip_without('matplotlib')
|
||||
|
||||
skipif_not_sympy = skip_without('sympy')
|
||||
|
||||
# A null 'decorator', useful to make more readable code that needs to pick
|
||||
# between different decorators based on OS or other conditions
|
||||
null_deco = lambda f: f
|
||||
|
||||
# Some tests only run where we can use unicode paths. Note that we can't just
|
||||
# check os.path.supports_unicode_filenames, which is always False on Linux.
|
||||
try:
|
||||
f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
|
||||
except UnicodeEncodeError:
|
||||
unicode_paths = False
|
||||
else:
|
||||
unicode_paths = True
|
||||
f.close()
|
||||
|
||||
onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
|
||||
"where we can use unicode in filenames."))
|
||||
|
||||
|
||||
def onlyif_cmds_exist(*commands):
|
||||
"""
|
||||
Decorator to skip test when at least one of `commands` is not found.
|
||||
"""
|
||||
for cmd in commands:
|
||||
if not which(cmd):
|
||||
return skip("This test runs only if command '{0}' "
|
||||
"is installed".format(cmd))
|
||||
return null_deco
|
||||
|
||||
def onlyif_any_cmd_exists(*commands):
|
||||
"""
|
||||
Decorator to skip test unless at least one of `commands` is found.
|
||||
"""
|
||||
for cmd in commands:
|
||||
if which(cmd):
|
||||
return null_deco
|
||||
return skip("This test runs only if one of the commands {0} "
|
||||
"is installed".format(commands))
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
"""Tests for IPython.utils.importstring."""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import nose.tools as nt
|
||||
|
||||
from ..importstring import import_item
|
||||
|
||||
def test_import_plain():
|
||||
"Test simple imports"
|
||||
import os
|
||||
os2 = import_item('os')
|
||||
nt.assert_true(os is os2)
|
||||
|
||||
|
||||
def test_import_nested():
|
||||
"Test nested imports from the stdlib"
|
||||
from os import path
|
||||
path2 = import_item('os.path')
|
||||
nt.assert_true(path is path2)
|
||||
|
||||
|
||||
def test_import_raises():
|
||||
"Test that failing imports raise the right exception"
|
||||
nt.assert_raises(ImportError, import_item, 'IPython.foobar')
|
||||
|
108
venv/Lib/site-packages/ipython_genutils/tests/test_path.py
Normal file
108
venv/Lib/site-packages/ipython_genutils/tests/test_path.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
# encoding: utf-8
|
||||
"""Tests for genutils.path"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import nose.tools as nt
|
||||
|
||||
from ..testing.decorators import skip_if_not_win32, skip_win32
|
||||
from .. import path
|
||||
from .. import py3compat
|
||||
from ..tempdir import TemporaryDirectory
|
||||
|
||||
|
||||
def test_filefind():
|
||||
f = tempfile.NamedTemporaryFile()
|
||||
t = path.filefind(f.name, '.')
|
||||
|
||||
|
||||
def test_ensure_dir_exists():
|
||||
with TemporaryDirectory() as td:
|
||||
d = os.path.join(td, u'∂ir')
|
||||
path.ensure_dir_exists(d) # create it
|
||||
assert os.path.isdir(d)
|
||||
path.ensure_dir_exists(d) # no-op
|
||||
f = os.path.join(td, u'ƒile')
|
||||
open(f, 'w').close() # touch
|
||||
with nt.assert_raises(IOError):
|
||||
path.ensure_dir_exists(f)
|
||||
|
||||
|
||||
class TestLinkOrCopy(object):
|
||||
def setUp(self):
|
||||
self.tempdir = TemporaryDirectory()
|
||||
self.src = self.dst("src")
|
||||
with open(self.src, "w") as f:
|
||||
f.write("Hello, world!")
|
||||
|
||||
def tearDown(self):
|
||||
self.tempdir.cleanup()
|
||||
|
||||
def dst(self, *args):
|
||||
return os.path.join(self.tempdir.name, *args)
|
||||
|
||||
def assert_inode_not_equal(self, a, b):
|
||||
nt.assert_not_equals(os.stat(a).st_ino, os.stat(b).st_ino,
|
||||
"%r and %r do reference the same indoes" %(a, b))
|
||||
|
||||
def assert_inode_equal(self, a, b):
|
||||
nt.assert_equals(os.stat(a).st_ino, os.stat(b).st_ino,
|
||||
"%r and %r do not reference the same indoes" %(a, b))
|
||||
|
||||
def assert_content_equal(self, a, b):
|
||||
with open(a) as a_f:
|
||||
with open(b) as b_f:
|
||||
nt.assert_equals(a_f.read(), b_f.read())
|
||||
|
||||
@skip_win32
|
||||
def test_link_successful(self):
|
||||
dst = self.dst("target")
|
||||
path.link_or_copy(self.src, dst)
|
||||
self.assert_inode_equal(self.src, dst)
|
||||
|
||||
@skip_win32
|
||||
def test_link_into_dir(self):
|
||||
dst = self.dst("some_dir")
|
||||
os.mkdir(dst)
|
||||
path.link_or_copy(self.src, dst)
|
||||
expected_dst = self.dst("some_dir", os.path.basename(self.src))
|
||||
self.assert_inode_equal(self.src, expected_dst)
|
||||
|
||||
@skip_win32
|
||||
def test_target_exists(self):
|
||||
dst = self.dst("target")
|
||||
open(dst, "w").close()
|
||||
path.link_or_copy(self.src, dst)
|
||||
self.assert_inode_equal(self.src, dst)
|
||||
|
||||
@skip_win32
|
||||
def test_no_link(self):
|
||||
real_link = os.link
|
||||
try:
|
||||
del os.link
|
||||
dst = self.dst("target")
|
||||
path.link_or_copy(self.src, dst)
|
||||
self.assert_content_equal(self.src, dst)
|
||||
self.assert_inode_not_equal(self.src, dst)
|
||||
finally:
|
||||
os.link = real_link
|
||||
|
||||
@skip_if_not_win32
|
||||
def test_windows(self):
|
||||
dst = self.dst("target")
|
||||
path.link_or_copy(self.src, dst)
|
||||
self.assert_content_equal(self.src, dst)
|
||||
|
||||
def test_link_twice(self):
|
||||
# Linking the same file twice shouldn't leave duplicates around.
|
||||
# See https://github.com/ipython/ipython/issues/6450
|
||||
dst = self.dst('target')
|
||||
path.link_or_copy(self.src, dst)
|
||||
path.link_or_copy(self.src, dst)
|
||||
self.assert_inode_equal(self.src, dst)
|
||||
nt.assert_equal(sorted(os.listdir(self.tempdir.name)), ['src', 'target'])
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
import os
|
||||
|
||||
from ..tempdir import NamedFileInTemporaryDirectory
|
||||
from ..tempdir import TemporaryWorkingDirectory
|
||||
|
||||
|
||||
def test_named_file_in_temporary_directory():
|
||||
with NamedFileInTemporaryDirectory('filename') as file:
|
||||
name = file.name
|
||||
assert not file.closed
|
||||
assert os.path.exists(name)
|
||||
file.write(b'test')
|
||||
assert file.closed
|
||||
assert not os.path.exists(name)
|
||||
|
||||
def test_temporary_working_directory():
|
||||
with TemporaryWorkingDirectory() as dir:
|
||||
assert os.path.exists(dir)
|
||||
assert os.path.realpath(os.curdir) == os.path.realpath(dir)
|
||||
assert not os.path.exists(dir)
|
||||
assert os.path.abspath(os.curdir) != dir
|
59
venv/Lib/site-packages/ipython_genutils/tests/test_text.py
Normal file
59
venv/Lib/site-packages/ipython_genutils/tests/test_text.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
# encoding: utf-8
|
||||
"""Tests for IPython.utils.text"""
|
||||
from __future__ import print_function
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import os
|
||||
import math
|
||||
import random
|
||||
import sys
|
||||
|
||||
import nose.tools as nt
|
||||
|
||||
from .. import text
|
||||
|
||||
|
||||
def test_columnize():
|
||||
"""Basic columnize tests."""
|
||||
size = 5
|
||||
items = [l*size for l in 'abc']
|
||||
out = text.columnize(items, displaywidth=80)
|
||||
nt.assert_equal(out, 'aaaaa bbbbb ccccc\n')
|
||||
out = text.columnize(items, displaywidth=12)
|
||||
nt.assert_equal(out, 'aaaaa ccccc\nbbbbb\n')
|
||||
out = text.columnize(items, displaywidth=10)
|
||||
nt.assert_equal(out, 'aaaaa\nbbbbb\nccccc\n')
|
||||
|
||||
def test_columnize_random():
|
||||
"""Test with random input to hopfully catch edge case """
|
||||
for nitems in [random.randint(2,70) for i in range(2,20)]:
|
||||
displaywidth = random.randint(20,200)
|
||||
rand_len = [random.randint(2,displaywidth) for i in range(nitems)]
|
||||
items = ['x'*l for l in rand_len]
|
||||
out = text.columnize(items, displaywidth=displaywidth)
|
||||
longer_line = max([len(x) for x in out.split('\n')])
|
||||
longer_element = max(rand_len)
|
||||
if longer_line > displaywidth:
|
||||
print("Columnize displayed something lager than displaywidth : %s " % longer_line)
|
||||
print("longer element : %s " % longer_element)
|
||||
print("displaywidth : %s " % displaywidth)
|
||||
print("number of element : %s " % nitems)
|
||||
print("size of each element :\n %s" % rand_len)
|
||||
assert False
|
||||
|
||||
def test_columnize_medium():
|
||||
"""Test with inputs than shouldn't be wider tahn 80 """
|
||||
size = 40
|
||||
items = [l*size for l in 'abc']
|
||||
out = text.columnize(items, displaywidth=80)
|
||||
nt.assert_equal(out, '\n'.join(items+['']))
|
||||
|
||||
def test_columnize_long():
|
||||
"""Test columnize with inputs longer than the display window"""
|
||||
size = 11
|
||||
items = [l*size for l in 'abc']
|
||||
out = text.columnize(items, displaywidth=size-1)
|
||||
nt.assert_equal(out, '\n'.join(items+['']))
|
||||
|
244
venv/Lib/site-packages/ipython_genutils/text.py
Normal file
244
venv/Lib/site-packages/ipython_genutils/text.py
Normal file
|
@ -0,0 +1,244 @@
|
|||
# encoding: utf-8
|
||||
"""
|
||||
Utilities for working with strings and text.
|
||||
|
||||
Inheritance diagram:
|
||||
|
||||
.. inheritance-diagram:: IPython.utils.text
|
||||
:parts: 3
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
from string import Formatter
|
||||
|
||||
# datetime.strftime date format for ipython
|
||||
if sys.platform == 'win32':
|
||||
date_format = "%B %d, %Y"
|
||||
else:
|
||||
date_format = "%B %-d, %Y"
|
||||
|
||||
|
||||
def indent(instr,nspaces=4, ntabs=0, flatten=False):
|
||||
"""Indent a string a given number of spaces or tabstops.
|
||||
|
||||
indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
instr : basestring
|
||||
The string to be indented.
|
||||
nspaces : int (default: 4)
|
||||
The number of spaces to be indented.
|
||||
ntabs : int (default: 0)
|
||||
The number of tabs to be indented.
|
||||
flatten : bool (default: False)
|
||||
Whether to scrub existing indentation. If True, all lines will be
|
||||
aligned to the same indentation. If False, existing indentation will
|
||||
be strictly increased.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
str|unicode : string indented by ntabs and nspaces.
|
||||
|
||||
"""
|
||||
if instr is None:
|
||||
return
|
||||
ind = '\t'*ntabs+' '*nspaces
|
||||
if flatten:
|
||||
pat = re.compile(r'^\s*', re.MULTILINE)
|
||||
else:
|
||||
pat = re.compile(r'^', re.MULTILINE)
|
||||
outstr = re.sub(pat, ind, instr)
|
||||
if outstr.endswith(os.linesep+ind):
|
||||
return outstr[:-len(ind)]
|
||||
else:
|
||||
return outstr
|
||||
|
||||
|
||||
def dedent(text):
|
||||
"""Equivalent of textwrap.dedent that ignores unindented first line.
|
||||
|
||||
This means it will still dedent strings like:
|
||||
'''foo
|
||||
is a bar
|
||||
'''
|
||||
|
||||
For use in wrap_paragraphs.
|
||||
"""
|
||||
|
||||
if text.startswith('\n'):
|
||||
# text starts with blank line, don't ignore the first line
|
||||
return textwrap.dedent(text)
|
||||
|
||||
# split first line
|
||||
splits = text.split('\n',1)
|
||||
if len(splits) == 1:
|
||||
# only one line
|
||||
return textwrap.dedent(text)
|
||||
|
||||
first, rest = splits
|
||||
# dedent everything but the first line
|
||||
rest = textwrap.dedent(rest)
|
||||
return '\n'.join([first, rest])
|
||||
|
||||
|
||||
def wrap_paragraphs(text, ncols=80):
|
||||
"""Wrap multiple paragraphs to fit a specified width.
|
||||
|
||||
This is equivalent to textwrap.wrap, but with support for multiple
|
||||
paragraphs, as separated by empty lines.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
list of complete paragraphs, wrapped to fill `ncols` columns.
|
||||
"""
|
||||
paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
|
||||
text = dedent(text).strip()
|
||||
paragraphs = paragraph_re.split(text)[::2] # every other entry is space
|
||||
out_ps = []
|
||||
indent_re = re.compile(r'\n\s+', re.MULTILINE)
|
||||
for p in paragraphs:
|
||||
# presume indentation that survives dedent is meaningful formatting,
|
||||
# so don't fill unless text is flush.
|
||||
if indent_re.search(p) is None:
|
||||
# wrap paragraph
|
||||
p = textwrap.fill(p, ncols)
|
||||
out_ps.append(p)
|
||||
return out_ps
|
||||
|
||||
|
||||
def strip_ansi(source):
|
||||
"""
|
||||
Remove ansi escape codes from text.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
source : str
|
||||
Source to remove the ansi from
|
||||
"""
|
||||
return re.sub(r'\033\[(\d|;)+?m', '', source)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Utils to columnize a list of string
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def _chunks(l, n):
|
||||
"""Yield successive n-sized chunks from l."""
|
||||
for i in range(0, len(l), n):
|
||||
yield l[i:i+n]
|
||||
|
||||
|
||||
def _find_optimal(rlist , separator_size=2 , displaywidth=80):
|
||||
"""Calculate optimal info to columnize a list of string"""
|
||||
for nrow in range(1, len(rlist)+1) :
|
||||
chk = list(map(max,_chunks(rlist, nrow)))
|
||||
sumlength = sum(chk)
|
||||
ncols = len(chk)
|
||||
if sumlength+separator_size*(ncols-1) <= displaywidth :
|
||||
break;
|
||||
return {'columns_numbers' : ncols,
|
||||
'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
|
||||
'rows_numbers' : nrow,
|
||||
'columns_width' : chk
|
||||
}
|
||||
|
||||
|
||||
def _get_or_default(mylist, i, default=None):
|
||||
"""return list item number, or default if don't exist"""
|
||||
if i >= len(mylist):
|
||||
return default
|
||||
else :
|
||||
return mylist[i]
|
||||
|
||||
|
||||
def compute_item_matrix(items, empty=None, *args, **kwargs) :
|
||||
"""Returns a nested list, and info to columnize items
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
items
|
||||
list of strings to columize
|
||||
empty : (default None)
|
||||
default value to fill list if needed
|
||||
separator_size : int (default=2)
|
||||
How much caracters will be used as a separation between each columns.
|
||||
displaywidth : int (default=80)
|
||||
The width of the area onto wich the columns should enter
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
strings_matrix
|
||||
|
||||
nested list of string, the outer most list contains as many list as
|
||||
rows, the innermost lists have each as many element as colums. If the
|
||||
total number of elements in `items` does not equal the product of
|
||||
rows*columns, the last element of some lists are filled with `None`.
|
||||
|
||||
dict_info
|
||||
some info to make columnize easier:
|
||||
|
||||
columns_numbers
|
||||
number of columns
|
||||
rows_numbers
|
||||
number of rows
|
||||
columns_width
|
||||
list of with of each columns
|
||||
optimal_separator_width
|
||||
best separator width between columns
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
|
||||
...: compute_item_matrix(l,displaywidth=12)
|
||||
Out[1]:
|
||||
([['aaa', 'f', 'k'],
|
||||
['b', 'g', 'l'],
|
||||
['cc', 'h', None],
|
||||
['d', 'i', None],
|
||||
['eeeee', 'j', None]],
|
||||
{'columns_numbers': 3,
|
||||
'columns_width': [5, 1, 1],
|
||||
'optimal_separator_width': 2,
|
||||
'rows_numbers': 5})
|
||||
"""
|
||||
info = _find_optimal(list(map(len, items)), *args, **kwargs)
|
||||
nrow, ncol = info['rows_numbers'], info['columns_numbers']
|
||||
return ([[ _get_or_default(items, c*nrow+i, default=empty) for c in range(ncol) ] for i in range(nrow) ], info)
|
||||
|
||||
|
||||
def columnize(items, separator=' ', displaywidth=80):
|
||||
""" Transform a list of strings into a single string with columns.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
items : sequence of strings
|
||||
The strings to process.
|
||||
|
||||
separator : str, optional [default is two spaces]
|
||||
The string that separates columns.
|
||||
|
||||
displaywidth : int, optional [default is 80]
|
||||
Width of the display in number of characters.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The formatted string.
|
||||
"""
|
||||
if not items :
|
||||
return '\n'
|
||||
matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
|
||||
fmatrix = [filter(None, x) for x in matrix]
|
||||
sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
|
||||
return '\n'.join(map(sjoin, fmatrix))+'\n'
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue