mirror of
https://github.com/aykhans/AzSuicideDataVisualization.git
synced 2025-07-02 06:22:25 +00:00
first commit
This commit is contained in:
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
|
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)
|
||||
|
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))
|
@ -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'
|
||||
|
Reference in New Issue
Block a user