def _broadcast_shape(*args):
    """Return the shape that would result from broadcasting the inputs"""
    #TODO: currently incorrect result if a Sequence is provided as an input
    shapes = [a.shape if hasattr(type(a), '__array_interface__')
              else () for a in args]
    ndim = max(len(sh) for sh in shapes) # new common ndim after broadcasting
    for i, sh in enumerate(shapes):
        if len(sh) < ndim:
            shapes[i] = (1,)*(ndim - len(sh)) + sh
    return tuple(max(sh[ax] for sh in shapes) for ax in range(ndim))

def _broadcast_shape ( * args ) : shapes = [ a . shape if hasattr ( type ( a ) , '__array_interface__' ) else ( ) for a in args ] ndim = max ( len ( sh ) for sh in shapes ) for i , sh in enumerate ( shapes ) : if len ( sh ) < ndim : shapes [ i ] = ( 1 , ) * ( ndim - len ( sh ) ) + sh return tuple ( max ( sh [ ax ] for sh in shapes ) for ax in range ( ndim ) )


def mean(a, axis=None, dtype=None, out=None, keepdims=False):
    """
    Compute the arithmetic mean along the specified axis.

    Returns the average of the array elements.  The average is taken over
    the flattened array by default, otherwise over the specified axis.
    `float64` intermediate and return values are used for integer inputs.

    Parameters
    ----------
    a : array_like
        Array containing numbers whose mean is desired. If `a` is not an
        array, a conversion is attempted.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the means are computed. The default is to
        compute the mean of the flattened array.
        If this is a tuple of ints, a mean is performed over multiple axes,
        instead of a single axis or all the axes as before.
    dtype : data-type, optional
        Type to use in computing the mean.  For integer inputs, the default
        is `float64`; for floating point inputs, it is the same as the
        input dtype.
    out : ndarray, optional
        Alternate output array in which to place the result.  The default
        is ``None``; if provided, it must have the same shape as the
        expected output, but the type will be cast if necessary.
        See `doc.ufuncs` for details.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the original `arr`.

    Returns
    -------
    m : ndarray, see dtype parameter above

    Notes
    -----
    np.mean fails to pass the keepdims parameter to ndarray subclasses.
    That is the main reason we implement this function.
    """
    if (isinstance(a, np.ndarray) or
            isinstance(a, RemoteArray) or
            isinstance(a, DistArray)):
        return a.mean(axis=axis, dtype=dtype, out=out, keepdims=keepdims)
    else:
        return np.mean(a, axis=axis, dtype=dtype, out=out, keepdims=keepdims)

def mean ( a , axis = None , dtype = None , out = None , keepdims = False ) : if ( isinstance ( a , np . ndarray ) or isinstance ( a , RemoteArray ) or isinstance ( a , DistArray ) ) : return a . mean ( axis = axis , dtype = dtype , out = out , keepdims = keepdims ) else : return np . mean ( a , axis = axis , dtype = dtype , out = out , keepdims = keepdims )

Compute the arithmetic mean along the specified axis .


def _valid_distaxis(shapes, ax):
        """`ax` is a valid candidate for a distributed axis if the given
        subarray shapes are all the same when ignoring axis `ax`"""
        compare_shapes = np.vstack(shapes)
        if ax < compare_shapes.shape[1]:
            compare_shapes[:, ax] = -1
        return np.count_nonzero(compare_shapes - compare_shapes[0]) == 0

def _valid_distaxis ( shapes , ax ) : compare_shapes = np . vstack ( shapes ) if ax < compare_shapes . shape [ 1 ] : compare_shapes [ : , ax ] = - 1 return np . count_nonzero ( compare_shapes - compare_shapes [ 0 ] ) == 0

ax is a valid candidate for a distributed axis if the given subarray shapes are all the same when ignoring axis ax


def run(*args, **kwargs):
    '''Returns True if successful, False if failure'''

    kwargs.setdefault('env', os.environ)
    kwargs.setdefault('shell', True)

    try:
        subprocess.check_call(' '.join(args), **kwargs)
        return True
    except subprocess.CalledProcessError:
        logger.debug('Error running: {}'.format(args))
        return False

def
run
(
*
args
,
**
kwargs
)
:
kwargs
.
setdefault
(
'env'
,
os
.
environ
)
kwargs
.
setdefault
(
'shell'
,
True
)
try
:
subprocess
.
check_call
(
' '
.
join
(
args
)
,
**
kwargs
)
return
True
except
subprocess
.
CalledProcessError
:
logger
.
debug
(
'Error running: {}'
.
format
(
args
)
)
return
False

Returns True if successful False if failure


def cmd():
    '''Return a command to launch a subshell'''

    if platform == 'win':
        return ['cmd.exe', '/K']

    elif platform == 'linux':
        ppid = os.getppid()
        ppid_cmdline_file = '/proc/{0}/cmdline'.format(ppid)
        try:
            with open(ppid_cmdline_file) as f:
                cmd = f.read()
            if cmd.endswith('\x00'):
                cmd = cmd[:-1]
            cmd = cmd.split('\x00')
            return cmd + [binpath('subshell.sh')]
        except:
            cmd = 'bash'

    else:
        cmd = 'bash'

    return [cmd, binpath('subshell.sh')]

def cmd ( ) : if platform == 'win' : return [ 'cmd.exe' , '/K' ] elif platform == 'linux' : ppid = os . getppid ( ) ppid_cmdline_file = '/proc/{0}/cmdline' . format ( ppid ) try : with open ( ppid_cmdline_file ) as f : cmd = f . read ( ) if cmd . endswith ( '\x00' ) : cmd = cmd [ : - 1 ] cmd = cmd . split ( '\x00' ) return cmd + [ binpath ( 'subshell.sh' ) ] except : cmd = 'bash' else : cmd = 'bash' return [ cmd , binpath ( 'subshell.sh' ) ]


def prompt(prefix=None, colored=True):
    '''Generate a prompt with a given prefix

    linux/osx: [prefix] user@host cwd $
          win: [prefix] cwd:
    '''

    if platform == 'win':
        return '[{0}] $P$G'.format(prefix)
    else:
        if colored:
            return (
                '[{0}] '  # White prefix
                '\\[\\033[01;32m\\]\\u@\\h\\[\\033[00m\\] '  # Green user@host
                '\\[\\033[01;34m\\]\\w $ \\[\\033[00m\\]'  # Blue cwd $
            ).format(prefix)
        return '[{0}] \\u@\\h \\w $ '.format(prefix)


def launch(prompt_prefix=None):
    '''Launch a subshell'''

    if prompt_prefix:
        os.environ['PROMPT'] = prompt(prompt_prefix)

    subprocess.call(cmd(), env=os.environ.data)

def launch ( prompt_prefix = None ) : if prompt_prefix : os . environ [ 'PROMPT' ] = prompt ( prompt_prefix ) subprocess . call ( cmd ( ) , env = os . environ . data )


def add_file(self, file, **kwargs):
        """Append a file to file repository.

        For file monitoring, monitor instance needs file.
        Please put the name of file to `file` argument.

        :param file: the name of file you want monitor.

        """

        if os.access(file, os.F_OK):

            if file in self.f_repository:
                raise DuplicationError("file already added.")

            self.f_repository.append(file)

        else:
            raise IOError("file not found.")

def
add_file
(
self
,
file
,
**
kwargs
)
:
if
os
.
access
(
file
,
os
.
F_OK
)
:
if
file
in
self
.
f_repository
:
raise
DuplicationError
(
"file already added."
)
self
.
f_repository
.
append
(
file
)
else
:
raise
IOError
(
"file not found."
)


def add_files(self, filelist, **kwargs):
        """Append files to file repository.

        ModificationMonitor can append files to repository using this.
        Please put the list of file names to `filelist` argument.

        :param filelist: the list of file nmaes
        """

        # check filelist is list type
        if not isinstance(filelist, list):
            raise TypeError("request the list type.")

        for file in filelist:
            self.add_file(file)

def
add_files
(
self
,
filelist
,
**
kwargs
)
:
if
not
isinstance
(
filelist
,
list
)
:
raise
TypeError
(
"request the list type."
)
for
file
in
filelist
:
self
.
add_file
(
file
)

Append files to file repository . ModificationMonitor can append files to repository using this . Please put the list of file names to filelist argument .


def monitor(self, sleep=5):
        """Run file modification monitor.

        The monitor can catch file modification using timestamp and file body.
        Monitor has timestamp data and file body data. And insert timestamp
        data and file body data before into while roop. In while roop, monitor
        get new timestamp and file body, and then monitor compare new timestamp
        to originaltimestamp. If new timestamp and file body differ original,
        monitor regard thease changes as `modification`. Then monitor create
        instance of FileModificationObjectManager and FileModificationObject,
        and monitor insert FileModificationObject to FileModificationObject-
        Manager. Then, yield this object.

        :param sleep: How times do you sleep in while roop.
        """

        manager = FileModificationObjectManager()

        timestamps = {}
        filebodies = {}

        # register original timestamp and filebody to dict
        for file in self.f_repository:
            timestamps[file] = self._get_mtime(file)
            filebodies[file] = open(file).read()

        while True:

            for file in self.f_repository:

                mtime = timestamps[file]
                fbody = filebodies[file]

                modified = self._check_modify(file, mtime, fbody)

                # file not modify -> continue
                if not modified:
                    continue

                # file modifies -> create the modification object

                new_mtime = self._get_mtime(file)
                new_fbody = open(file).read()

                obj = FileModificationObject(
                        file,
                        (mtime, new_mtime),
                        (fbody, new_fbody) )

                # overwrite new timestamp and filebody
                timestamps[file] = new_mtime
                filebodies[file] = new_fbody

                # append file modification object to manager
                manager.add_object(obj)

                # return new modification object
                yield obj

            time.sleep(sleep)

def monitor ( self , sleep = 5 ) : manager = FileModificationObjectManager ( ) timestamps = { } filebodies = { } for file in self . f_repository : timestamps [ file ] = self . _get_mtime ( file ) filebodies [ file ] = open ( file ) . read ( ) while True : for file in self . f_repository : mtime = timestamps [ file ] fbody = filebodies [ file ] modified = self . _check_modify ( file , mtime , fbody ) if not modified : continue new_mtime = self . _get_mtime ( file ) new_fbody = open ( file ) . read ( ) obj = FileModificationObject ( file , ( mtime , new_mtime ) , ( fbody , new_fbody ) ) timestamps [ file ] = new_mtime filebodies [ file ] = new_fbody manager . add_object ( obj ) yield obj time . sleep ( sleep )


def status_job(self, fn=None, name=None, timeout=3):
        """Decorator that invokes `add_status_job`.

        ::

            @app.status_job
            def postgresql():
                # query/ping postgres

            @app.status_job(name="Active Directory")
            def active_directory():
                # query active directory

            @app.status_job(timeout=5)
            def paypal():
                # query paypal, timeout after 5 seconds

        """
        if fn is None:
            def decorator(fn):
                self.add_status_job(fn, name, timeout)
            return decorator
        else:
            self.add_status_job(fn, name, timeout)

def status_job ( self , fn = None , name = None , timeout = 3 ) : if fn is None : def decorator ( fn ) : self . add_status_job ( fn , name , timeout ) return decorator else : self . add_status_job ( fn , name , timeout )


def _pipepager(text, cmd, color):
    """Page through text by feeding it to another program.  Invoking a
    pager through this might support colors.
    """
    import subprocess
    env = dict(os.environ)

    # If we're piping to less we might support colors under the
    # condition that
    cmd_detail = cmd.rsplit('/', 1)[-1].split()
    if color is None and cmd_detail[0] == 'less':
        less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:])
        if not less_flags:
            env['LESS'] = '-R'
            color = True
        elif 'r' in less_flags or 'R' in less_flags:
            color = True

    if not color:
        text = strip_ansi(text)

    c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
                         env=env)
    encoding = get_best_encoding(c.stdin)
    try:
        c.stdin.write(text.encode(encoding, 'replace'))
        c.stdin.close()
    except (IOError, KeyboardInterrupt):
        pass

    # Less doesn't respect ^C, but catches it for its own UI purposes (aborting
    # search or other commands inside less).
    #
    # That means when the user hits ^C, the parent process (click) terminates,
    # but less is still alive, paging the output and messing up the terminal.
    #
    # If the user wants to make the pager exit on ^C, they should set
    # `LESS='-K'`. It's not our decision to make.
    while True:
        try:
            c.wait()
        except KeyboardInterrupt:
            pass
        else:
            break

def
_pipepager
(
text
,
cmd
,
color
)
:
import
subprocess
env
=
dict
(
os
.
environ
)
cmd_detail
=
cmd
.
rsplit
(
'/'
,
1
)
[
1
]
.
split
(
)
if
color
is
and
cmd_detail
[
0
]
==
'less'
:
less_flags
=
os
.
environ
.
get
(
'LESS'
,
''
)
+
' '
.
join
(
cmd_detail
[
1
:
]
)
if
not
less_flags
:
env
[
'LESS'
]
=
'-R'
color
=
True
elif
'r'
in
less_flags
or
'R'
in
less_flags
:
color
=
True
if
not
color
:
text
=
strip_ansi
(
text
)
c
=
subprocess
.
Popen
(
cmd
,
shell
=
True
,
stdin
=
subprocess
.
PIPE
,
env
=
env
)
encoding
=
get_best_encoding
(
c
.
stdin
)
try
:
c
.
stdin
.
write
(
text
.
encode
(
encoding
,
'replace'
)
)
c
.
stdin
.
close
(
)
except
(
IOError
,
KeyboardInterrupt
)
:
pass
while
True
:
try
:
c
.
wait
(
)
except
KeyboardInterrupt
:
pass
else
:
break

Page through text by feeding it to another program . Invoking a pager through this might support colors .


def profil_annuel(df, func='mean'):
    """
    Calcul du profil annuel

    Paramètres:
    df: DataFrame de données dont l'index est une série temporelle
        (cf module xair par exemple)
    func: function permettant le calcul. Soit un nom de fonction numpy ('mean', 'max', ...)
        soit la fonction elle-même (np.mean, np.max, ...)
    Retourne:
    Un DataFrame de moyennes par mois
    """

    func = _get_funky(func)
    res = df.groupby(lambda x: x.month).aggregate(func)
    # On met des noms de mois à la place des numéros dans l'index
    res.index = [cal.month_name[i] for i in range(1,13)]
    return res

def profil_annuel ( df , func = 'mean' ) : func = _get_funky ( func ) res = df . groupby ( lambda x : x . month ) . aggregate ( func ) res . index = [ cal . month_name [ i ] for i in range ( 1 , 13 ) ] return res


def run_global_hook(hook_name, *args):
    '''Attempt to run a global hook by name with args'''

    hook_finder = HookFinder(get_global_hook_path())
    hook = hook_finder(hook_name)
    if hook:
        hook.run(*args)

def run_global_hook ( hook_name , * args ) : hook_finder = HookFinder ( get_global_hook_path ( ) ) hook = hook_finder ( hook_name ) if hook : hook . run ( * args )


def moyennes_glissantes(df, sur=8, rep=0.75):
    """
    Calcule de moyennes glissantes

    Paramètres:
    df: DataFrame de mesures sur lequel appliqué le calcul
    sur: (int, par défaut 8) Nombre d'observations sur lequel s'appuiera le
    calcul
    rep: (float, défaut 0.75) Taux de réprésentativité en dessous duquel le
    calcul renverra NaN

    Retourne:
    Un DataFrame des moyennes glissantes calculées
    """
    return pd.rolling_mean(df, window=sur, min_periods=rep * sur)

def moyennes_glissantes ( df , sur = 8 , rep = 0.75 ) : return pd . rolling_mean ( df , window = sur , min_periods = rep * sur )


def aot40_vegetation(df, nb_an):
    """
    Calcul de l'AOT40 du 1er mai au 31 juillet

    *AOT40 : AOT 40 ( exprimé en micro g/m³ par heure ) signifie la somme des
    différences entre les concentrations horaires supérieures à 40 parties par
    milliard ( 40 ppb soit 80 micro g/m³ ), durant une période donnée en
    utilisant uniquement les valeurs sur 1 heure mesurées quotidiennement
    entre 8 heures (début de la mesure) et 20 heures (pile, fin de la mesure) CET,
    ce qui correspond à de 8h à 19h TU (donnant bien 12h de mesures, 8h donnant
    la moyenne horaire de 7h01 à 8h00)

    Paramètres:
    df: DataFrame de mesures sur lequel appliqué le calcul
    nb_an: (int) Nombre d'années contenu dans le df, et servant à diviser le
    résultat retourné

    Retourne:
    Un DataFrame de résultat de calcul
    """

    return _aot(df.tshift(1), nb_an=nb_an, limite=80, mois_debut=5, mois_fin=7,
                heure_debut=8, heure_fin=19)

Calcul de l AOT40 du 1er mai au 31 juillet


def validate(self):
        '''Validate all the entries in the environment cache.'''

        for env in list(self):
            if not env.exists:
                self.remove(env)

def validate ( self ) : for env in list ( self ) : if not env . exists : self . remove ( env )

Validate all the entries in the environment cache .


def load(self):
        '''Load the environment cache from disk.'''

        if not os.path.exists(self.path):
            return

        with open(self.path, 'r') as f:
            env_data = yaml.load(f.read())

        if env_data:
            for env in env_data:
                self.add(VirtualEnvironment(env['root']))

def load ( self ) : if not os . path . exists ( self . path ) : return with open ( self . path , 'r' ) as f : env_data = yaml . load ( f . read ( ) ) if env_data : for env in env_data : self . add ( VirtualEnvironment ( env [ 'root' ] ) )


def save(self):
        '''Save the environment cache to disk.'''

        env_data = [dict(name=env.name, root=env.path) for env in self]
        encode = yaml.safe_dump(env_data, default_flow_style=False)

        with open(self.path, 'w') as f:
            f.write(encode)

def save ( self ) : env_data = [ dict ( name = env . name , root = env . path ) for env in self ] encode = yaml . safe_dump ( env_data , default_flow_style = False ) with open ( self . path , 'w' ) as f : f . write ( encode )


def prompt(text, default=None, hide_input=False,
           confirmation_prompt=False, type=None,
           value_proc=None, prompt_suffix=': ',
           show_default=True, err=False):
    """Prompts a user for input.  This is a convenience function that can
    be used to prompt a user for input later.

    If the user aborts the input by sending a interrupt signal, this
    function will catch it and raise a :exc:`Abort` exception.

    .. versionadded:: 6.0
       Added unicode support for cmd.exe on Windows.

    .. versionadded:: 4.0
       Added the `err` parameter.

    :param text: the text to show for the prompt.
    :param default: the default value to use if no input happens.  If this
                    is not given it will prompt until it's aborted.
    :param hide_input: if this is set to true then the input value will
                       be hidden.
    :param confirmation_prompt: asks for confirmation for the value.
    :param type: the type to use to check the value against.
    :param value_proc: if this parameter is provided it's a function that
                       is invoked instead of the type conversion to
                       convert a value.
    :param prompt_suffix: a suffix that should be added to the prompt.
    :param show_default: shows or hides the default value in the prompt.
    :param err: if set to true the file defaults to ``stderr`` instead of
                ``stdout``, the same as with echo.
    """
    result = None

    def prompt_func(text):
        f = hide_input and hidden_prompt_func or visible_prompt_func
        try:
            # Write the prompt separately so that we get nice
            # coloring through colorama on Windows
            echo(text, nl=False, err=err)
            return f('')
        except (KeyboardInterrupt, EOFError):
            # getpass doesn't print a newline if the user aborts input with ^C.
            # Allegedly this behavior is inherited from getpass(3).
            # A doc bug has been filed at https://bugs.python.org/issue24711
            if hide_input:
                echo(None, err=err)
            raise Abort()

    if value_proc is None:
        value_proc = convert_type(type, default)

    prompt = _build_prompt(text, prompt_suffix, show_default, default)

    while 1:
        while 1:
            value = prompt_func(prompt)
            if value:
                break
            # If a default is set and used, then the confirmation
            # prompt is always skipped because that's the only thing
            # that really makes sense.
            elif default is not None:
                return default
        try:
            result = value_proc(value)
        except UsageError as e:
            echo('Error: %s' % e.message, err=err)
            continue
        if not confirmation_prompt:
            return result
        while 1:
            value2 = prompt_func('Repeat for confirmation: ')
            if value2:
                break
        if value == value2:
            return result
        echo('Error: the two entered values do not match', err=err)

Prompts a user for input . This is a convenience function that can be used to prompt a user for input later .


def echo_via_pager(text, color=None):
    """This function takes a text and shows it via an environment specific
    pager on stdout.

    .. versionchanged:: 3.0
       Added the `color` flag.

    :param text: the text to page.
    :param color: controls if the pager supports ANSI colors or not.  The
                  default is autodetection.
    """
    color = resolve_color_default(color)
    if not isinstance(text, string_types):
        text = text_type(text)
    from ._termui_impl import pager
    return pager(text + '\n', color)

def echo_via_pager ( text , color = None ) : color = resolve_color_default ( color ) if not isinstance ( text , string_types ) : text = text_type ( text ) from . _termui_impl import pager return pager ( text + '\n' , color )

This function takes a text and shows it via an environment specific pager on stdout .


def setup_engines(client=None):
    """Prepare all iPython engines for distributed object processing.

    Args:
      client (ipyparallel.Client, optional): If None, will create a client
        using the default ipyparallel profile.
    """
    if not client:
        try:
            client = ipyparallel.Client()
        except:
            raise DistobClusterError(
                u"""Could not connect to an ipyparallel cluster. Make
                 sure a cluster is started (e.g. to use the CPUs of a
                 single computer, can type 'ipcluster start')""")
    eids = client.ids
    if not eids:
        raise DistobClusterError(
                u'No ipyparallel compute engines are available')
    nengines = len(eids)
    dv = client[eids]
    dv.use_dill()
    with dv.sync_imports(quiet=True):
        import distob
    # create global ObjectEngine distob.engine on each engine
    ars = []
    for i in eids:
        dv.targets = i
        ars.append(dv.apply_async(_remote_setup_engine, i, nengines))
    dv.wait(ars)
    for ar in ars:
        if not ar.successful():
            raise ar.r
    # create global ObjectHub distob.engine on the client host
    if distob.engine is None:
        distob.engine = ObjectHub(-1, client)

Prepare all iPython engines for distributed object processing .


def gather(obj):
    """Retrieve objects that have been distributed, making them local again"""
    if hasattr(obj, '__distob_gather__'):
        return obj.__distob_gather__()
    elif (isinstance(obj, collections.Sequence) and
            not isinstance(obj, string_types)):
        return [gather(subobj) for subobj in obj]
    else:
        return obj

def gather ( obj ) : if hasattr ( obj , '__distob_gather__' ) : return obj . __distob_gather__ ( ) elif ( isinstance ( obj , collections . Sequence ) and not isinstance ( obj , string_types ) ) : return [ gather ( subobj ) for subobj in obj ] else : return obj

Retrieve objects that have been distributed making them local again


def apply(f, obj, *args, **kwargs):
    """Apply a function in parallel to each element of the input"""
    return vectorize(f)(obj, *args, **kwargs)

def apply ( f , obj , * args , ** kwargs ) : return vectorize ( f ) ( obj , * args , ** kwargs )


def register_proxy_type(cls, real_type, proxy_type):
        """Configure engines so that remote methods returning values of type
        `real_type` will instead return by proxy, as type `proxy_type`
        """
        if distob.engine is None:
            cls._initial_proxy_types[real_type] = proxy_type
        elif isinstance(distob.engine, ObjectHub):
            distob.engine._runtime_reg_proxy_type(real_type, proxy_type)
        else:
            # TODO: remove next line after issue #58 in dill is fixed.
            distob.engine._singleeng_reg_proxy_type(real_type, proxy_type)
            pass

def register_proxy_type ( cls , real_type , proxy_type ) : if distob . engine is None : cls . _initial_proxy_types [ real_type ] = proxy_type elif isinstance ( distob . engine , ObjectHub ) : distob . engine . _runtime_reg_proxy_type ( real_type , proxy_type ) else : distob . engine . _singleeng_reg_proxy_type ( real_type , proxy_type ) pass

Configure engines so that remote methods returning values of type real_type will instead return by proxy as type proxy_type


def is_git_repo(path):
    '''Returns True if path is a git repository.'''

    if path.startswith('git@') or path.startswith('https://'):
        return True

    if os.path.exists(unipath(path, '.git')):
        return True

    return False

def is_git_repo ( path ) : if path . startswith ( 'git@' ) or path . startswith ( 'https://' ) : return True if os . path . exists ( unipath ( path , '.git' ) ) : return True return False

Returns True if path is a git repository .


def is_home_environment(path):
    '''Returns True if path is in CPENV_HOME'''

    home = unipath(os.environ.get('CPENV_HOME', '~/.cpenv'))
    path = unipath(path)

    return path.startswith(home)

def is_home_environment ( path ) : home = unipath ( os . environ . get ( 'CPENV_HOME' , '~/.cpenv' ) ) path = unipath ( path ) return path . startswith ( home )


def is_redirecting(path):
    '''Returns True if path contains a .cpenv file'''

    candidate = unipath(path, '.cpenv')
    return os.path.exists(candidate) and os.path.isfile(candidate)

def is_redirecting ( path ) : candidate = unipath ( path , '.cpenv' ) return os . path . exists ( candidate ) and os . path . isfile ( candidate )

Returns True if path contains a . cpenv file


def redirect_to_env_paths(path):
    '''Get environment path from redirect file'''

    with open(path, 'r') as f:
        redirected = f.read()

    return shlex.split(redirected)

def redirect_to_env_paths ( path ) : with open ( path , 'r' ) as f : redirected = f . read ( ) return shlex . split ( redirected )


def expandpath(path):
    '''Returns an absolute expanded path'''

    return os.path.abspath(os.path.expandvars(os.path.expanduser(path)))

def expandpath ( path ) : return os . path . abspath ( os . path . expandvars ( os . path . expanduser ( path ) ) )


def unipath(*paths):
    '''Like os.path.join but also expands and normalizes path parts.'''

    return os.path.normpath(expandpath(os.path.join(*paths)))

def unipath ( * paths ) : return os . path . normpath ( expandpath ( os . path . join ( * paths ) ) )

Like os . path . join but also expands and normalizes path parts .


def binpath(*paths):
    '''Like os.path.join but acts relative to this packages bin path.'''

    package_root = os.path.dirname(__file__)
    return os.path.normpath(os.path.join(package_root, 'bin', *paths))

def binpath ( * paths ) : package_root = os . path . dirname ( __file__ ) return os . path . normpath ( os . path . join ( package_root , 'bin' , * paths ) )

Like os . path . join but acts relative to this packages bin path .


def ensure_path_exists(path, *args):
    '''Like os.makedirs but keeps quiet if path already exists'''
    if os.path.exists(path):
        return

    os.makedirs(path, *args)

def ensure_path_exists ( path , * args ) : if os . path . exists ( path ) : return os . makedirs ( path , * args )

Like os . makedirs but keeps quiet if path already exists


def walk_dn(start_dir, depth=10):
    '''
    Walk down a directory tree. Same as os.walk but allows for a depth limit
    via depth argument
    '''

    start_depth = len(os.path.split(start_dir))
    end_depth = start_depth + depth

    for root, subdirs, files in os.walk(start_dir):
        yield root, subdirs, files

        if len(os.path.split(root)) >= end_depth:
            break

def walk_dn ( start_dir , depth = 10 ) : start_depth = len ( os . path . split ( start_dir ) ) end_depth = start_depth + depth for root , subdirs , files in os . walk ( start_dir ) : yield root , subdirs , files if len ( os . path . split ( root ) ) >= end_depth : break

Walk down a directory tree . Same as os . walk but allows for a depth limit via depth argument


def walk_up(start_dir, depth=20):
    '''
    Walk up a directory tree
    '''
    root = start_dir

    for i in xrange(depth):
        contents = os.listdir(root)
        subdirs, files = [], []
        for f in contents:
            if os.path.isdir(os.path.join(root, f)):
                subdirs.append(f)
            else:
                files.append(f)

        yield root, subdirs, files

        parent = os.path.dirname(root)
        if parent and not parent == root:
            root = parent
        else:
            break

def walk_up ( start_dir , depth = 20 ) : root = start_dir for i in xrange ( depth ) : contents = os . listdir ( root ) subdirs , files = [ ] , [ ] for f in contents : if os . path . isdir ( os . path . join ( root , f ) ) : subdirs . append ( f ) else : files . append ( f ) yield root , subdirs , files parent = os . path . dirname ( root ) if parent and not parent == root : root = parent else : break


def preprocess_dict(d):
    '''
    Preprocess a dict to be used as environment variables.

    :param d: dict to be processed
    '''

    out_env = {}
    for k, v in d.items():

        if not type(v) in PREPROCESSORS:
            raise KeyError('Invalid type in dict: {}'.format(type(v)))

        out_env[k] = PREPROCESSORS[type(v)](v)

    return out_env

def
preprocess_dict
(
d
)
:
out_env
=
{
}
for
k
,
v
in
d
.
items
(
)
:
if
not
type
(
v
)
in
PREPROCESSORS
:
raise
KeyError
(
'Invalid type in dict: {}'
.
format
(
type
(
v
)
)
)
out_env
[
k
]
=
PREPROCESSORS
[
type
(
v
)
]
(
v
)
return
out_env

Preprocess a dict to be used as environment variables .


def _join_seq(d, k, v):
    '''Add a sequence value to env dict'''

    if k not in d:
        d[k] = list(v)

    elif isinstance(d[k], list):
        for item in v:
            if item not in d[k]:
                d[k].insert(0, item)

    elif isinstance(d[k], string_types):
        v.append(d[k])
        d[k] = v

def _join_seq ( d , k , v ) : if k not in d : d [ k ] = list ( v ) elif isinstance ( d [ k ] , list ) : for item in v : if item not in d [ k ] : d [ k ] . insert ( 0 , item ) elif isinstance ( d [ k ] , string_types ) : v . append ( d [ k ] ) d [ k ] = v


def join_dicts(*dicts):
    '''Join a bunch of dicts'''

    out_dict = {}

    for d in dicts:
        for k, v in d.iteritems():

            if not type(v) in JOINERS:
                raise KeyError('Invalid type in dict: {}'.format(type(v)))

            JOINERS[type(v)](out_dict, k, v)

    return out_dict

def
join_dicts
(
*
dicts
)
:
out_dict
=
{
}
for
d
in
dicts
:
for
k
,
v
in
d
.
iteritems
(
)
:
if
not
type
(
v
)
in
JOINERS
:
raise
KeyError
(
'Invalid type in dict: {}'
.
format
(
type
(
v
)
)
)
JOINERS
[
type
(
v
)
]
(
out_dict
,
k
,
v
)
return
out_dict


def env_to_dict(env, pathsep=os.pathsep):
    '''
    Convert a dict containing environment variables into a standard dict.
    Variables containing multiple values will be split into a list based on
    the argument passed to pathsep.

    :param env: Environment dict like os.environ.data
    :param pathsep: Path separator used to split variables
    '''

    out_dict = {}

    for k, v in env.iteritems():
        if pathsep in v:
            out_dict[k] = v.split(pathsep)
        else:
            out_dict[k] = v

    return out_dict

def env_to_dict ( env , pathsep = os . pathsep ) : out_dict = { } for k , v in env . iteritems ( ) : if pathsep in v : out_dict [ k ] = v . split ( pathsep ) else : out_dict [ k ] = v return out_dict

Convert a dict containing environment variables into a standard dict . Variables containing multiple values will be split into a list based on the argument passed to pathsep .


def dict_to_env(d, pathsep=os.pathsep):
    '''
    Convert a python dict to a dict containing valid environment variable
    values.

    :param d: Dict to convert to an env dict
    :param pathsep: Path separator used to join lists(default os.pathsep)
    '''

    out_env = {}

    for k, v in d.iteritems():
        if isinstance(v, list):
            out_env[k] = pathsep.join(v)
        elif isinstance(v, string_types):
            out_env[k] = v
        else:
            raise TypeError('{} not a valid env var type'.format(type(v)))

    return out_env

def
dict_to_env
(
d
,
pathsep
=
os
.
pathsep
)
:
out_env
=
{
}
for
k
,
v
in
d
.
iteritems
(
)
:
if
isinstance
(
v
,
list
)
:
out_env
[
k
]
=
pathsep
.
join
(
v
)
elif
isinstance
(
v
,
string_types
)
:
out_env
[
k
]
=
v
else
:
raise
TypeError
(
'{} not a valid env var type'
.
format
(
type
(
v
)
)
)
return
out_env

Convert a python dict to a dict containing valid environment variable values .


def expand_envvars(env):
    '''
    Expand all environment variables in an environment dict

    :param env: Environment dict
    '''

    out_env = {}

    for k, v in env.iteritems():
        out_env[k] = Template(v).safe_substitute(env)

    # Expand twice to make sure we expand everything we possibly can
    for k, v in out_env.items():
        out_env[k] = Template(v).safe_substitute(out_env)

    return out_env

def expand_envvars ( env ) : out_env = { } for k , v in env . iteritems ( ) : out_env [ k ] = Template ( v ) . safe_substitute ( env ) for k , v in out_env . items ( ) : out_env [ k ] = Template ( v ) . safe_substitute ( out_env ) return out_env


def get_store_env_tmp():
    '''Returns an unused random filepath.'''

    tempdir = tempfile.gettempdir()
    temp_name = 'envstore{0:0>3d}'
    temp_path = unipath(tempdir, temp_name.format(random.getrandbits(9)))
    if not os.path.exists(temp_path):
        return temp_path
    else:
        return get_store_env_tmp()

def get_store_env_tmp ( ) : tempdir = tempfile . gettempdir ( ) temp_name = 'envstore{0:0>3d}' temp_path = unipath ( tempdir , temp_name . format ( random . getrandbits ( 9 ) ) ) if not os . path . exists ( temp_path ) : return temp_path else : return get_store_env_tmp ( )


def store_env(path=None):
    '''Encode current environment as yaml and store in path or a temporary
    file. Return the path to the stored environment.
    '''

    path = path or get_store_env_tmp()

    env_dict = yaml.safe_dump(os.environ.data, default_flow_style=False)

    with open(path, 'w') as f:
        f.write(env_dict)

    return path

def store_env ( path = None ) : path = path or get_store_env_tmp ( ) env_dict = yaml . safe_dump ( os . environ . data , default_flow_style = False ) with open ( path , 'w' ) as f : f . write ( env_dict ) return path

Encode current environment as yaml and store in path or a temporary file . Return the path to the stored environment .


def upstream_url(self, uri):
        "Returns the URL to the upstream data source for the given URI based on configuration"
        return self.application.options.upstream + self.request.uri


def make_upstream_request(self):
        "Return request object for calling the upstream"
        url = self.upstream_url(self.request.uri)
        return tornado.httpclient.HTTPRequest(url,
            method=self.request.method,
            headers=self.request.headers,
            body=self.request.body if self.request.body else None)


def ttl(self, response):
        """Returns time to live in seconds. 0 means no caching.

        Criteria:
        - response code 200
        - read-only method (GET, HEAD, OPTIONS)
        Plus http headers:
        - cache-control: option1, option2, ...
          where options are:
          private | public
          no-cache
          no-store
          max-age: seconds
          s-maxage: seconds
          must-revalidate
          proxy-revalidate
        - expires: Thu, 01 Dec 1983 20:00:00 GMT
        - pragma: no-cache (=cache-control: no-cache)

        See http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/

        TODO: tests

        """
        if response.code != 200: return 0
        if not self.request.method in ['GET', 'HEAD', 'OPTIONS']: return 0

        try:
            pragma = self.request.headers['pragma']
            if pragma == 'no-cache':
                return 0
        except KeyError:
            pass

        try:
            cache_control = self.request.headers['cache-control']

            # no caching options
            for option in ['private', 'no-cache', 'no-store', 'must-revalidate', 'proxy-revalidate']:
                if cache_control.find(option): return 0

            # further parsing to get a ttl
            options = parse_cache_control(cache_control)
            try:
                return int(options['s-maxage'])
            except KeyError:
                pass
            try:
                return int(options['max-age'])
            except KeyError:
                pass

            if 's-maxage' in options:
                max_age = options['s-maxage']
                if max_age < ttl: ttl = max_age
            if 'max-age' in options:
                max_age = options['max-age']
                if max_age < ttl: ttl = max_age
            return ttl
        except KeyError:
            pass

        try:
            expires = self.request.headers['expires']
            return time.mktime(time.strptime(expires, '%a, %d %b %Y %H:%M:%S')) - time.time()
        except KeyError:
            pass

def
ttl
(
self
,
response
)
:
if
response
.
code
!=
200
:
return
0
if
not
self
.
request
.
method
in
[
'GET'
,
'HEAD'
,
'OPTIONS'
]
:
return
0
try
:
pragma
=
self
.
request
.
headers
[
'pragma'
]
if
pragma
==
'no-cache'
:
return
0
except
KeyError
:
pass
try
:
cache_control
=
self
.
request
.
headers
[
'cache-control'
]
for
option
in
[
'private'
,
'no-cache'
,
'no-store'
,
'must-revalidate'
,
'proxy-revalidate'
]
:
if
cache_control
.
find
(
option
)
:
return
0
options
=
parse_cache_control
(
cache_control
)
try
:
return
int
(
options
[
's-maxage'
]
)
except
KeyError
:
pass
try
:
return
int
(
options
[
'max-age'
]
)
except
KeyError
:
pass
if
's-maxage'
in
options
:
max_age
=
options
[
's-maxage'
]
if
max_age
<
ttl
:
ttl
=
max_age
if
'max-age'
in
options
:
max_age
=
options
[
'max-age'
]
if
max_age
<
ttl
:
ttl
=
max_age
return
ttl
except
KeyError
:
pass
try
:
expires
=
self
.
request
.
headers
[
'expires'
]
return
time
.
mktime
(
time
.
strptime
(
expires
,
'%a, %d %b %Y %H:%M:%S'
)
)
time
.
time
(
)
except
KeyError
:
pass

Returns time to live in seconds . 0 means no caching .


def manifest():
    """Guarantee the existence of a basic MANIFEST.in.

    manifest doc: http://docs.python.org/distutils/sourcedist.html#manifest

    `options.paved.dist.manifest.include`: set of files (or globs) to include with the `include` directive.

    `options.paved.dist.manifest.recursive_include`: set of files (or globs) to include with the `recursive-include` directive.

    `options.paved.dist.manifest.prune`: set of files (or globs) to exclude with the `prune` directive.

    `options.paved.dist.manifest.include_sphinx_docroot`: True -> sphinx docroot is added as `graft`

    `options.paved.dist.manifest.include_sphinx_docroot`: True -> sphinx builddir is added as `prune`
    """
    prune = options.paved.dist.manifest.prune
    graft = set()

    if options.paved.dist.manifest.include_sphinx_docroot:
        docroot = options.get('docroot', 'docs')
        graft.update([docroot])

        if options.paved.dist.manifest.exclude_sphinx_builddir:
            builddir = docroot + '/' + options.get("builddir", ".build")
            prune.update([builddir])

    with open(options.paved.cwd / 'MANIFEST.in', 'w') as fo:
        for item in graft:
            fo.write('graft %s\n' % item)
        for item in options.paved.dist.manifest.include:
            fo.write('include %s\n' % item)
        for item in options.paved.dist.manifest.recursive_include:
            fo.write('recursive-include %s\n' % item)
        for item in prune:
            fo.write('prune %s\n' % item)

def
manifest
(
)
:
prune
=
options
.
paved
.
dist
.
manifest
.
prune
graft
=
set
(
)
if
options
.
paved
.
dist
.
manifest
.
include_sphinx_docroot
:
docroot
=
options
.
get
(
'docroot'
,
'docs'
)
graft
.
update
(
[
docroot
]
)
if
options
.
paved
.
dist
.
manifest
.
exclude_sphinx_builddir
:
builddir
=
docroot
+
'/'
+
options
.
get
(
"builddir"
,
".build"
)
prune
.
update
(
[
builddir
]
)
with
open
(
options
.
paved
.
cwd
/
'MANIFEST.in'
,
'w'
)
as
fo
:
for
item
in
graft
:
fo
.
write
(
'graft %s\n'
%
item
)
for
item
in
options
.
paved
.
dist
.
manifest
.
include
:
fo
.
write
(
'include %s\n'
%
item
)
for
item
in
options
.
paved
.
dist
.
manifest
.
recursive_include
:
fo
.
write
(
'recursive-include %s\n'
%
item
)
for
item
in
prune
:
fo
.
write
(
'prune %s\n'
%
item
)

Guarantee the existence of a basic MANIFEST . in .


def format_pathname(
        pathname,
        max_length):
    """
    Format a pathname

    :param str pathname: Pathname to format
    :param int max_length: Maximum length of result pathname (> 3)
    :return: Formatted pathname
    :rtype: str
    :raises ValueError: If *max_length* is not larger than 3

    This function formats a pathname so it is not longer than *max_length*
    characters. The resulting pathname is returned. It does so by replacing
    characters at the start of the *pathname* with three dots, if necessary.
    The idea is that the end of the *pathname* is the most important part
    to be able to identify the file.
    """
    if max_length <= 3:
        raise ValueError("max length must be larger than 3")

    if len(pathname) > max_length:
        pathname = "...{}".format(pathname[-(max_length-3):])

    return pathname

def
format_pathname
(
pathname
,
max_length
)
:
if
max_length
<=
3
:
raise
ValueError
(
"max length must be larger than 3"
)
if
len
(
pathname
)
>
max_length
:
pathname
=
"...{}"
.
format
(
pathname
[
(
max_length
3
)
:
]
)
return
pathname


def format_uuid(
        uuid,
        max_length=10):
    """
    Format a UUID string

    :param str uuid: UUID to format
    :param int max_length: Maximum length of result string (> 3)
    :return: Formatted UUID
    :rtype: str
    :raises ValueError: If *max_length* is not larger than 3

    This function formats a UUID so it is not longer than *max_length*
    characters. The resulting string is returned. It does so by replacing
    characters at the end of the *uuid* with three dots, if necessary.
    The idea is that the start of the *uuid* is the most important part
    to be able to identify the related entity.

    The default *max_length* is 10, which will result in a string
    containing the first 7 characters of the *uuid* passed in. Most of
    the time, such a string is still unique within a collection of UUIDs.
    """
    if max_length <= 3:
        raise ValueError("max length must be larger than 3")

    if len(uuid) > max_length:
        uuid = "{}...".format(uuid[0:max_length-3])

    return uuid

def
format_uuid
(
uuid
,
max_length
=
10
)
:
if
max_length
<=
3
:
raise
ValueError
(
"max length must be larger than 3"
)
if
len
(
uuid
)
>
max_length
:
uuid
=
"{}..."
.
format
(
uuid
[
0
:
max_length
3
]
)
return
uuid


def paginate_update(update):
    """
    attempts to get next and previous on updates
    """
    from happenings.models import Update
    time = update.pub_time
    event = update.event
    try:
        next = Update.objects.filter(
            event=event,
            pub_time__gt=time
        ).order_by('pub_time').only('title')[0]
    except:
        next = None
    try:
        previous = Update.objects.filter(
            event=event,
            pub_time__lt=time
        ).order_by('-pub_time').only('title')[0]
    except:
        previous = None
    return {'next': next, 'previous': previous, 'event': event}

def paginate_update ( update ) : from happenings . models import Update time = update . pub_time event = update . event try : next = Update . objects . filter ( event = event , pub_time__gt = time ) . order_by ( 'pub_time' ) . only ( 'title' ) [ 0 ] except : next = None try : previous = Update . objects . filter ( event = event , pub_time__lt = time ) . order_by ( '-pub_time' ) . only ( 'title' ) [ 0 ] except : previous = None return { 'next' : next , 'previous' : previous , 'event' : event }


def notify_client(
        notifier_uri,
        client_id,
        status_code,
        message=None):
    """
    Notify the client of the result of handling a request

    The payload contains two elements:

    - client_id
    - result

    The *client_id* is the id of the client to notify. It is assumed
    that the notifier service is able to identify the client by this id
    and that it can pass the *result* to it.

    The *result* always contains a *status_code* element. In case the
    message passed in is not None, it will also contain a *message*
    element.

    In case the notifier service does not exist or returns an error,
    an error message will be logged to *stderr*.
    """
    payload = {
        "client_id": client_id,
        "result": {
            "response": {
                "status_code": status_code
            }
        }
    }

    if message is not None:
        payload["result"]["response"]["message"] = message

    response = requests.post(notifier_uri, json=payload)

    if response.status_code != 201:
        sys.stderr.write("failed to notify client: {}\n".format(payload))
        sys.stderr.flush()

def
notify_client
(
notifier_uri
,
client_id
,
status_code
,
message
=
)
:
payload
=
{
"client_id"
:
client_id
,
"result"
:
{
"response"
:
{
"status_code"
:
status_code
}
}
}
if
message
is
not
:
payload
[
"result"
]
[
"response"
]
[
"message"
]
=
message
response
=
requests
.
post
(
notifier_uri
,
json
=
payload
)
if
response
.
status_code
!=
201
:
sys
.
stderr
.
write
(
"failed to notify client: {}\n"
.
format
(
payload
)
)
sys
.
stderr
.
flush
(
)


def setting(self, name_hyphen):
        """
        Retrieves the setting value whose name is indicated by name_hyphen.

        Values starting with $ are assumed to reference environment variables,
        and the value stored in environment variables is retrieved. It's an
        error if thes corresponding environment variable it not set.
        """
        if name_hyphen in self._instance_settings:
            value = self._instance_settings[name_hyphen][1]
        else:
            msg = "No setting named '%s'" % name_hyphen
            raise UserFeedback(msg)

        if hasattr(value, 'startswith') and value.startswith("$"):
            env_var = value.lstrip("$")
            if env_var in os.environ:
                return os.getenv(env_var)
            else:
                msg = "'%s' is not defined in your environment" % env_var
                raise UserFeedback(msg)

        elif hasattr(value, 'startswith') and value.startswith("\$"):
            return value.replace("\$", "$")

        else:
            return value

Retrieves the setting value whose name is indicated by name_hyphen .


def _update_settings(self, new_settings, enforce_helpstring=True):
        """
        This method does the work of updating settings. Can be passed with
        enforce_helpstring = False which you may want if allowing end users to
        add arbitrary metadata via the settings system.

        Preferable to use update_settings (without leading _) in code to do the
        right thing and always have docstrings.
        """
        for raw_setting_name, value in six.iteritems(new_settings):
            setting_name = raw_setting_name.replace("_", "-")

            setting_already_exists = setting_name in self._instance_settings
            value_is_list_len_2 = isinstance(value, list) and len(value) == 2
            treat_as_tuple = not setting_already_exists and value_is_list_len_2

            if isinstance(value, tuple) or treat_as_tuple:
                self._instance_settings[setting_name] = value

            else:
                if setting_name not in self._instance_settings:
                    if enforce_helpstring:
                        msg = "You must specify param '%s' as a tuple of (helpstring, value)"
                        raise InternalCashewException(msg % setting_name)

                    else:
                        # Create entry with blank helpstring.
                        self._instance_settings[setting_name] = ('', value,)

                else:
                    # Save inherited helpstring, replace default value.
                    orig = self._instance_settings[setting_name]
                    self._instance_settings[setting_name] = (orig[0], value,)

This method does the work of updating settings . Can be passed with enforce_helpstring = False which you may want if allowing end users to add arbitrary metadata via the settings system .


def settings_and_attributes(self):
        """Return a combined dictionary of setting values and attribute values."""
        attrs = self.setting_values()
        attrs.update(self.__dict__)
        skip = ["_instance_settings", "aliases"]
        for a in skip:
            del attrs[a]
        return attrs

def settings_and_attributes ( self ) : attrs = self . setting_values ( ) attrs . update ( self . __dict__ ) skip = [ "_instance_settings" , "aliases" ] for a in skip : del attrs [ a ] return attrs

Return a combined dictionary of setting values and attribute values .


def get_reference_to_class(cls, class_or_class_name):
        """
        Detect if we get a class or a name, convert a name to a class.
        """
        if isinstance(class_or_class_name, type):
            return class_or_class_name

        elif isinstance(class_or_class_name, string_types):
            if ":" in class_or_class_name:
                mod_name, class_name = class_or_class_name.split(":")

                if not mod_name in sys.modules:
                    __import__(mod_name)

                mod = sys.modules[mod_name]
                return mod.__dict__[class_name]

            else:
                return cls.load_class_from_locals(class_or_class_name)

        else:
            msg = "Unexpected Type '%s'" % type(class_or_class_name)
            raise InternalCashewException(msg)

def
get_reference_to_class
(
cls
,
class_or_class_name
)
:
if
isinstance
(
class_or_class_name
,
type
)
:
return
class_or_class_name
elif
isinstance
(
class_or_class_name
,
string_types
)
:
if
":"
in
class_or_class_name
:
mod_name
,
class_name
=
class_or_class_name
.
split
(
":"
)
if
not
mod_name
in
sys
.
modules
:
__import__
(
mod_name
)
mod
=
sys
.
modules
[
mod_name
]
return
mod
.
__dict__
[
class_name
]
else
:
return
cls
.
load_class_from_locals
(
class_or_class_name
)
else
:
msg
=
"Unexpected Type '%s'"
%
type
(
class_or_class_name
)
raise
InternalCashewException
(
msg
)

Detect if we get a class or a name convert a name to a class .


def check_docstring(cls):
        """
        Asserts that the class has a docstring, returning it if successful.
        """
        docstring = inspect.getdoc(cls)
        if not docstring:
            breadcrumbs = " -> ".join(t.__name__ for t in inspect.getmro(cls)[:-1][::-1])
            msg = "docstring required for plugin '%s' (%s, defined in %s)"
            args = (cls.__name__, breadcrumbs, cls.__module__)
            raise InternalCashewException(msg % args)

        max_line_length = cls._class_settings.get('max-docstring-length')
        if max_line_length:
            for i, line in enumerate(docstring.splitlines()):
                if len(line) > max_line_length:
                    msg = "docstring line %s of %s is %s chars too long"
                    args = (i, cls.__name__, len(line) - max_line_length)
                    raise Exception(msg % args)

        return docstring

Asserts that the class has a docstring returning it if successful .


def resourcePath(self, relative_path):
        """ Get absolute path to resource, works for dev and for PyInstaller """
        from os import path
        import sys

        try:
            # PyInstaller creates a temp folder and stores path in _MEIPASS
            base_path = sys._MEIPASS
        except Exception:
            base_path = path.dirname(path.abspath(__file__))
        return path.join(base_path, relative_path)

def resourcePath ( self , relative_path ) : from os import path import sys try : base_path = sys . _MEIPASS except Exception : base_path = path . dirname ( path . abspath ( __file__ ) ) return path . join ( base_path , relative_path )

Get absolute path to resource works for dev and for PyInstaller


def addLogbook(self, physDef= "LCLS", mccDef="MCC", initialInstance=False):
        '''Add new block of logbook selection windows. Only 5 allowed.'''
        if self.logMenuCount < 5:
            self.logMenus.append(LogSelectMenu(self.logui.multiLogLayout, initialInstance))
            self.logMenus[-1].addLogbooks(self.logTypeList[1], self.physics_programs, physDef)
            self.logMenus[-1].addLogbooks(self.logTypeList[0], self.mcc_programs, mccDef)
            self.logMenus[-1].show()
            self.logMenuCount += 1
            if initialInstance:
                # Initial logbook menu can add additional menus, all others can only remove themselves.
                QObject.connect(self.logMenus[-1].logButton, SIGNAL("clicked()"), self.addLogbook)
            else:
                from functools import partial
                QObject.connect(self.logMenus[-1].logButton, SIGNAL("clicked()"), partial(self.removeLogbook, self.logMenus[-1]))

def addLogbook ( self , physDef = "LCLS" , mccDef = "MCC" , initialInstance = False ) : if self . logMenuCount < 5 : self . logMenus . append ( LogSelectMenu ( self . logui . multiLogLayout , initialInstance ) ) self . logMenus [ - 1 ] . addLogbooks ( self . logTypeList [ 1 ] , self . physics_programs , physDef ) self . logMenus [ - 1 ] . addLogbooks ( self . logTypeList [ 0 ] , self . mcc_programs , mccDef ) self . logMenus [ - 1 ] . show ( ) self . logMenuCount += 1 if initialInstance : QObject . connect ( self . logMenus [ - 1 ] . logButton , SIGNAL ( "clicked()" ) , self . addLogbook ) else : from functools import partial QObject . connect ( self . logMenus [ - 1 ] . logButton , SIGNAL ( "clicked()" ) , partial ( self . removeLogbook , self . logMenus [ - 1 ] ) )

Add new block of logbook selection windows . Only 5 allowed .


def removeLogbook(self, menu=None):
        '''Remove logbook menu set.'''
        if self.logMenuCount > 1 and menu is not None:
            menu.removeMenu()
            self.logMenus.remove(menu)
            self.logMenuCount -= 1

def removeLogbook ( self , menu = None ) : if self . logMenuCount > 1 and menu is not None : menu . removeMenu ( ) self . logMenus . remove ( menu ) self . logMenuCount -= 1


def selectedLogs(self):
        '''Return selected log books by type.'''
        mcclogs = []
        physlogs = []
        for i in range(len(self.logMenus)):
            logType = self.logMenus[i].selectedType()
            log = self.logMenus[i].selectedProgram()
            if logType == "MCC":
                if log not in mcclogs:
                    mcclogs.append(log)
            elif logType == "Physics":
                if log not in physlogs:
                    physlogs.append(log)
        return mcclogs, physlogs

def selectedLogs ( self ) : mcclogs = [ ] physlogs = [ ] for i in range ( len ( self . logMenus ) ) : logType = self . logMenus [ i ] . selectedType ( ) log = self . logMenus [ i ] . selectedProgram ( ) if logType == "MCC" : if log not in mcclogs : mcclogs . append ( log ) elif logType == "Physics" : if log not in physlogs : physlogs . append ( log ) return mcclogs , physlogs


def acceptedUser(self, logType):
        '''Verify enetered user name is on accepted MCC logbook list.'''
        from urllib2 import urlopen, URLError, HTTPError
        import json

        isApproved = False

        userName = str(self.logui.userName.text())
        if userName == "":
            return False  # Must have a user name to submit entry

        if logType == "MCC":
            networkFault = False
            data = []
            log_url = "https://mccelog.slac.stanford.edu/elog/dev/mgibbs/dev_json_user_list.php/?username=" + userName
            try:
                data = urlopen(log_url, None, 5).read()
                data = json.loads(data)
            except URLError as error:
                print("URLError: " + str(error.reason))
                networkFault = True
            except HTTPError as error:
                print("HTTPError: " + str(error.reason))
                networkFault = True

            # If network fails, ask user to verify
            if networkFault:
                msgBox = QMessageBox()
                msgBox.setText("Cannot connect to MCC Log Server!")
                msgBox.setInformativeText("Use entered User name anyway?")
                msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
                msgBox.setDefaultButton(QMessageBox.Ok)
                if msgBox.exec_() == QMessageBox.Ok:
                    isApproved = True

            if data != [] and (data is not None):
                isApproved = True
        else:
            isApproved = True
        return isApproved

Verify enetered user name is on accepted MCC logbook list .


def prettify(self, elem):
        """Parse xml elements for pretty printing"""

        from xml.etree import ElementTree
        from re import sub

        rawString = ElementTree.tostring(elem, 'utf-8')
        parsedString = sub(r'(?=<[^/].*>)', '\n', rawString)  # Adds newline after each closing tag

        return parsedString[1:]

def prettify ( self , elem ) : from xml . etree import ElementTree from re import sub rawString = ElementTree . tostring ( elem , 'utf-8' ) parsedString = sub ( r'(?=<[^/].*>)' , '\n' , rawString ) return parsedString [ 1 : ]


def prepareImages(self, fileName, logType):
        """Convert supplied QPixmap object to image file."""
        import subprocess

        if self.imageType == "png":
            self.imagePixmap.save(fileName + ".png", "PNG", -1)
            if logType == "Physics":
                makePostScript = "convert " + fileName + ".png " + fileName + ".ps"
                process = subprocess.Popen(makePostScript, shell=True)
                process.wait()
                thumbnailPixmap = self.imagePixmap.scaled(500, 450, Qt.KeepAspectRatio)
                thumbnailPixmap.save(fileName + ".png", "PNG", -1)
        else:
            renameImage = "cp " + self.image + " " + fileName + ".gif"
            process = subprocess.Popen(renameImage, shell=True)
            process.wait()
            if logType == "Physics":
                thumbnailPixmap = self.imagePixmap.scaled(500, 450, Qt.KeepAspectRatio)
                thumbnailPixmap.save(fileName + ".png", "PNG", -1)

def
prepareImages
(
self
,
fileName
,
logType
)
:
import
subprocess
if
self
.
imageType
==
"png"
:
self
.
imagePixmap
.
save
(
fileName
+
".png"
,
"PNG"
,
1
)
if
logType
==
"Physics"
:
makePostScript
=
"convert "
+
fileName
+
".png "
+
fileName
+
".ps"
process
=
subprocess
.
Popen
(
makePostScript
,
shell
=
True
)
process
.
wait
(
)
thumbnailPixmap
=
self
.
imagePixmap
.
scaled
(
500
,
450
,
Qt
.
KeepAspectRatio
)
thumbnailPixmap
.
save
(
fileName
+
".png"
,
"PNG"
,
1
)
else
:
renameImage
=
"cp "
+
self
.
image
+
" "
+
fileName
+
".gif"
process
=
subprocess
.
Popen
(
renameImage
,
shell
=
True
)
process
.
wait
(
)
if
logType
==
"Physics"
:
thumbnailPixmap
=
self
.
imagePixmap
.
scaled
(
500
,
450
,
Qt
.
KeepAspectRatio
)
thumbnailPixmap
.
save
(
fileName
+
".png"
,
"PNG"
,
1
)

Convert supplied QPixmap object to image file .


def submitEntry(self):
        """Process user inputs and subit logbook entry when user clicks Submit button"""

        # logType = self.logui.logType.currentText()
        mcclogs, physlogs = self.selectedLogs()
        success = True

        if mcclogs != []:
            if not self.acceptedUser("MCC"):
                QMessageBox().warning(self, "Invalid User", "Please enter a valid user name!")
                return

            fileName = self.xmlSetup("MCC", mcclogs)
            if fileName is None:
                return

            if not self.imagePixmap.isNull():
                self.prepareImages(fileName, "MCC")
            success = self.sendToLogbook(fileName, "MCC")

        if physlogs != []:
            for i in range(len(physlogs)):
                fileName = self.xmlSetup("Physics", physlogs[i])
                if fileName is None:
                    return

                if not self.imagePixmap.isNull():
                    self.prepareImages(fileName, "Physics")
                success_phys = self.sendToLogbook(fileName, "Physics", physlogs[i])
                success = success and success_phys

        self.done(success)

def
submitEntry
(
self
)
:
mcclogs
,
physlogs
=
self
.
selectedLogs
(
)
success
=
True
if
mcclogs
!=
[
]
:
if
not
self
.
acceptedUser
(
"MCC"
)
:
QMessageBox
(
)
.
warning
(
self
,
"Invalid User"
,
"Please enter a valid user name!"
)
return
fileName
=
self
.
xmlSetup
(
"MCC"
,
mcclogs
)
if
fileName
is
:
return
if
not
self
.
imagePixmap
.
isNull
(
)
:
self
.
prepareImages
(
fileName
,
"MCC"
)
success
=
self
.
sendToLogbook
(
fileName
,
"MCC"
)
if
physlogs
!=
[
]
:
for
i
in
range
(
len
(
physlogs
)
)
:
fileName
=
self
.
xmlSetup
(
"Physics"
,
physlogs
[
i
]
)
if
fileName
is
:
return
if
not
self
.
imagePixmap
.
isNull
(
)
:
self
.
prepareImages
(
fileName
,
"Physics"
)
success_phys
=
self
.
sendToLogbook
(
fileName
,
"Physics"
,
physlogs
[
i
]
)
success
=
success
and
success_phys
self
.
done
(
success
)


def sendToLogbook(self, fileName, logType, location=None):
        '''Process log information and push to selected logbooks.'''
        import subprocess

        success = True
        if logType == "MCC":
            fileString = ""
            if not self.imagePixmap.isNull():
                fileString = fileName + "." + self.imageType

            logcmd = "xml2elog " + fileName + ".xml " + fileString
            process = subprocess.Popen(logcmd, shell=True)
            process.wait()
            if process.returncode != 0:
                success = False
        else:
            from shutil import copy

            path = "/u1/" + location.lower() + "/physics/logbook/data/"  # Prod path
            # path = "/home/softegr/alverson/log_test/"  # Dev path
            try:
                if not self.imagePixmap.isNull():
                    copy(fileName + ".png", path)
                    if self.imageType == "png":
                        copy(fileName + ".ps", path)
                    else:
                        copy(fileName + "." + self.imageType, path)

                # Copy .xml file last to ensure images will be picked up by cron job
                # print("Copying file " + fileName + " to path " + path)
                copy(fileName + ".xml", path)
            except IOError as error:
                print(error)
                success = False

        return success

def
sendToLogbook
(
self
,
fileName
,
logType
,
location
=
)
:
import
subprocess
success
=
True
if
logType
==
"MCC"
:
fileString
=
""
if
not
self
.
imagePixmap
.
isNull
(
)
:
fileString
=
fileName
+
"."
+
self
.
imageType
logcmd
=
"xml2elog "
+
fileName
+
".xml "
+
fileString
process
=
subprocess
.
Popen
(
logcmd
,
shell
=
True
)
process
.
wait
(
)
if
process
.
returncode
!=
0
:
success
=
False
else
:
from
shutil
import
copy
path
=
"/u1/"
+
location
.
lower
(
)
+
"/physics/logbook/data/"
try
:
if
not
self
.
imagePixmap
.
isNull
(
)
:
copy
(
fileName
+
".png"
,
path
)
if
self
.
imageType
==
"png"
:
copy
(
fileName
+
".ps"
,
path
)
else
:
copy
(
fileName
+
"."
+
self
.
imageType
,
path
)
copy
(
fileName
+
".xml"
,
path
)
except
IOError
as
error
:
print
(
error
)
success
=
False
return
success

Process log information and push to selected logbooks .


def setupUI(self):
        '''Create graphical objects for menus.'''

        labelSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        labelSizePolicy.setHorizontalStretch(0)
        labelSizePolicy.setVerticalStretch(0)
        menuSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        menuSizePolicy.setHorizontalStretch(0)
        menuSizePolicy.setVerticalStretch(0)

        logTypeLayout = QHBoxLayout()
        logTypeLayout.setSpacing(0)

        typeLabel = QLabel("Log Type:")
        typeLabel.setMinimumSize(QSize(65, 0))
        typeLabel.setMaximumSize(QSize(65, 16777215))
        typeLabel.setSizePolicy(labelSizePolicy)
        logTypeLayout.addWidget(typeLabel)
        self.logType = QComboBox(self)
        self.logType.setMinimumSize(QSize(100, 0))
        self.logType.setMaximumSize(QSize(150, 16777215))
        menuSizePolicy.setHeightForWidth(self.logType.sizePolicy().hasHeightForWidth())
        self.logType.setSizePolicy(menuSizePolicy)
        logTypeLayout.addWidget(self.logType)
        logTypeLayout.setStretch(1, 6)

        programLayout = QHBoxLayout()
        programLayout.setSpacing(0)

        programLabel = QLabel("Program:")
        programLabel.setMinimumSize(QSize(60, 0))
        programLabel.setMaximumSize(QSize(60, 16777215))
        programLabel.setSizePolicy(labelSizePolicy)
        programLayout.addWidget(programLabel)
        self.programName = QComboBox(self)
        self.programName.setMinimumSize(QSize(100, 0))
        self.programName.setMaximumSize(QSize(150, 16777215))
        menuSizePolicy.setHeightForWidth(self.programName.sizePolicy().hasHeightForWidth())
        self.programName.setSizePolicy(menuSizePolicy)
        programLayout.addWidget(self.programName)
        programLayout.setStretch(1, 6)

        # Initial instance allows adding additional menus, all following menus can only remove themselves.
        if self.initialInstance:
            self.logButton = QPushButton("+", self)
            self.logButton.setToolTip("Add logbook")
        else:
            self.logButton = QPushButton("-")
            self.logButton.setToolTip("Remove logbook")

        self.logButton.setMinimumSize(QSize(16, 16))  # 24x24
        self.logButton.setMaximumSize(QSize(16, 16))  # 24x24
        self.logButton.setObjectName("roundButton")
        # self.logButton.setAutoFillBackground(True)
        # region = QRegion(QRect(self.logButton.x()+15, self.logButton.y()+14, 20, 20), QRegion.Ellipse)
        # self.logButton.setMask(region)

        self.logButton.setStyleSheet("QPushButton {border-radius: 8px;}")

        self._logSelectLayout = QHBoxLayout()
        self._logSelectLayout.setSpacing(6)
        self._logSelectLayout.addLayout(logTypeLayout)
        self._logSelectLayout.addLayout(programLayout)
        self._logSelectLayout.addWidget(self.logButton)
        self._logSelectLayout.setStretch(0, 6)
        self._logSelectLayout.setStretch(1, 6)

def
setupUI
(
self
)
:
labelSizePolicy
=
QSizePolicy
(
QSizePolicy
.
Fixed
,
QSizePolicy
.
Fixed
)
labelSizePolicy
.
setHorizontalStretch
(
0
)
labelSizePolicy
.
setVerticalStretch
(
0
)
menuSizePolicy
=
QSizePolicy
(
QSizePolicy
.
Expanding
,
QSizePolicy
.
Fixed
)
menuSizePolicy
.
setHorizontalStretch
(
0
)
menuSizePolicy
.
setVerticalStretch
(
0
)
logTypeLayout
=
QHBoxLayout
(
)
logTypeLayout
.
setSpacing
(
0
)
typeLabel
=
QLabel
(
"Log Type:"
)
typeLabel
.
setMinimumSize
(
QSize
(
65
,
0
)
)
typeLabel
.
setMaximumSize
(
QSize
(
65
,
16777215
)
)
typeLabel
.
setSizePolicy
(
labelSizePolicy
)
logTypeLayout
.
addWidget
(
typeLabel
)
self
.
logType
=
QComboBox
(
self
)
self
.
logType
.
setMinimumSize
(
QSize
(
100
,
0
)
)
self
.
logType
.
setMaximumSize
(
QSize
(
150
,
16777215
)
)
menuSizePolicy
.
setHeightForWidth
(
self
.
logType
.
sizePolicy
(
)
.
hasHeightForWidth
(
)
)
self
.
logType
.
setSizePolicy
(
menuSizePolicy
)
logTypeLayout
.
addWidget
(
self
.
logType
)
logTypeLayout
.
setStretch
(
1
,
6
)
programLayout
=
QHBoxLayout
(
)
programLayout
.
setSpacing
(
0
)
programLabel
=
QLabel
(
"Program:"
)
programLabel
.
setMinimumSize
(
QSize
(
60
,
0
)
)
programLabel
.
setMaximumSize
(
QSize
(
60
,
16777215
)
)
programLabel
.
setSizePolicy
(
labelSizePolicy
)
programLayout
.
addWidget
(
programLabel
)
self
.
programName
=
QComboBox
(
self
)
self
.
programName
.
setMinimumSize
(
QSize
(
100
,
0
)
)
self
.
programName
.
setMaximumSize
(
QSize
(
150
,
16777215
)
)
menuSizePolicy
.
setHeightForWidth
(
self
.
programName
.
sizePolicy
(
)
.
hasHeightForWidth
(
)
)
self
.
programName
.
setSizePolicy
(
menuSizePolicy
)
programLayout
.
addWidget
(
self
.
programName
)
programLayout
.
setStretch
(
1
,
6
)
if
self
.
initialInstance
:
self
.
logButton
=
QPushButton
(
"+"
,
self
)
self
.
logButton
.
setToolTip
(
"Add logbook"
)
else
:
self
.
logButton
=
QPushButton
(
"-"
)
self
.
logButton
.
setToolTip
(
"Remove logbook"
)
self
.
logButton
.
setMinimumSize
(
QSize
(
16
,
16
)
)
self
.
logButton
.
setMaximumSize
(
QSize
(
16
,
16
)
)
self
.
logButton
.
setObjectName
(
"roundButton"
)
self
.
logButton
.
setStyleSheet
(
"QPushButton {border-radius: 8px;}"
)
self
.
_logSelectLayout
=
QHBoxLayout
(
)
self
.
_logSelectLayout
.
setSpacing
(
6
)
self
.
_logSelectLayout
.
addLayout
(
logTypeLayout
)
self
.
_logSelectLayout
.
addLayout
(
programLayout
)
self
.
_logSelectLayout
.
addWidget
(
self
.
logButton
)
self
.
_logSelectLayout
.
setStretch
(
0
,
6
)
self
.
_logSelectLayout
.
setStretch
(
1
,
6
)


def show(self):
        '''Display menus and connect even signals.'''
        self.parent.addLayout(self._logSelectLayout)
        self.menuCount += 1
        self._connectSlots()

def show ( self ) : self . parent . addLayout ( self . _logSelectLayout ) self . menuCount += 1 self . _connectSlots ( )

Display menus and connect even signals .


def addLogbooks(self, type=None, logs=[], default=""):
        '''Add or change list of logbooks.'''
        if type is not None and len(logs) != 0:
            if type in self.logList:
                for logbook in logs:
                    if logbook not in self.logList.get(type)[0]:
                        # print("Adding log " + " to " + type + " log type.")
                        self.logList.get(type)[0].append(logbook)
            else:
                # print("Adding log type: " + type)
                self.logList[type] = []
                self.logList[type].append(logs)

            # If default given, auto-select upon menu creation
            if len(self.logList[type]) > 1 and default != "":
                self.logList.get(type)[1] == default
            else:
                self.logList.get(type).append(default)

            self.logType.clear()
            self.logType.addItems(list(self.logList.keys()))
            self.changeLogType()

def addLogbooks ( self , type = None , logs = [ ] , default = "" ) : if type is not None and len ( logs ) != 0 : if type in self . logList : for logbook in logs : if logbook not in self . logList . get ( type ) [ 0 ] : self . logList . get ( type ) [ 0 ] . append ( logbook ) else : self . logList [ type ] = [ ] self . logList [ type ] . append ( logs ) if len ( self . logList [ type ] ) > 1 and default != "" : self . logList . get ( type ) [ 1 ] == default else : self . logList . get ( type ) . append ( default ) self . logType . clear ( ) self . logType . addItems ( list ( self . logList . keys ( ) ) ) self . changeLogType ( )


def removeLogbooks(self, type=None, logs=[]):
        '''Remove unwanted logbooks from list.'''
        if type is not None and type in self.logList:
            if len(logs) == 0 or logs == "All":
                del self.logList[type]
            else:
                for logbook in logs:
                    if logbook in self.logList[type]:
                        self.logList[type].remove(logbook)

            self.changeLogType()

def removeLogbooks ( self , type = None , logs = [ ] ) : if type is not None and type in self . logList : if len ( logs ) == 0 or logs == "All" : del self . logList [ type ] else : for logbook in logs : if logbook in self . logList [ type ] : self . logList [ type ] . remove ( logbook ) self . changeLogType ( )


def changeLogType(self):
        '''Populate log program list to correspond with log type selection.'''
        logType = self.selectedType()
        programs = self.logList.get(logType)[0]
        default = self.logList.get(logType)[1]
        if logType in self.logList:
            self.programName.clear()
            self.programName.addItems(programs)
            self.programName.setCurrentIndex(programs.index(default))

def changeLogType ( self ) : logType = self . selectedType ( ) programs = self . logList . get ( logType ) [ 0 ] default = self . logList . get ( logType ) [ 1 ] if logType in self . logList : self . programName . clear ( ) self . programName . addItems ( programs ) self . programName . setCurrentIndex ( programs . index ( default ) )

Populate log program list to correspond with log type selection .


def addMenu(self):
        '''Add menus to parent gui.'''
        self.parent.multiLogLayout.addLayout(self.logSelectLayout)
        self.getPrograms(logType, programName)

def addMenu ( self ) : self . parent . multiLogLayout . addLayout ( self . logSelectLayout ) self . getPrograms ( logType , programName )


def removeLayout(self, layout):
        '''Iteratively remove graphical objects from layout.'''
        for cnt in reversed(range(layout.count())):
            item = layout.takeAt(cnt)
            widget = item.widget()
            if widget is not None:
                widget.deleteLater()
            else:
                '''If sublayout encountered, iterate recursively.'''
                self.removeLayout(item.layout())

def removeLayout ( self , layout ) : for cnt in reversed ( range ( layout . count ( ) ) ) : item = layout . takeAt ( cnt ) widget = item . widget ( ) if widget is not None : widget . deleteLater ( ) else : self . removeLayout ( item . layout ( ) )

Iteratively remove graphical objects from layout .


def addlabel(ax=None, toplabel=None, xlabel=None, ylabel=None, zlabel=None, clabel=None, cb=None, windowlabel=None, fig=None, axes=None):
    """Adds labels to a plot."""

    if (axes is None) and (ax is not None):
        axes = ax

    if (windowlabel is not None) and (fig is not None):
        fig.canvas.set_window_title(windowlabel)

    if fig is None:
        fig = _plt.gcf()

    if fig is not None and axes is None:
        axes = fig.get_axes()
        if axes == []:
            logger.error('No axes found!')

    if axes is not None:
        if toplabel is not None:
            axes.set_title(toplabel)
        if xlabel is not None:
            axes.set_xlabel(xlabel)
        if ylabel is not None:
            axes.set_ylabel(ylabel)
        if zlabel is not None:
            axes.set_zlabel(zlabel)

    if (clabel is not None) or (cb is not None):
        if (clabel is not None) and (cb is not None):
            cb.set_label(clabel)
        else:
            if clabel is None:
                logger.error('Missing colorbar label')
            else:
                logger.error('Missing colorbar instance')

def
addlabel
(
ax
=
,
toplabel
=
,
xlabel
=
,
ylabel
=
,
zlabel
=
,
clabel
=
,
cb
=
,
windowlabel
=
,
fig
=
,
axes
=
)
:
if
(
axes
is
)
and
(
ax
is
not
)
:
axes
=
ax
if
(
windowlabel
is
not
)
and
(
fig
is
not
)
:
fig
.
canvas
.
set_window_title
(
windowlabel
)
if
fig
is
:
fig
=
_plt
.
gcf
(
)
if
fig
is
not
and
axes
is
:
axes
=
fig
.
get_axes
(
)
if
axes
==
[
]
:
logger
.
error
(
'No axes found!'
)
if
axes
is
not
:
if
toplabel
is
not
:
axes
.
set_title
(
toplabel
)
if
xlabel
is
not
:
axes
.
set_xlabel
(
xlabel
)
if
ylabel
is
not
:
axes
.
set_ylabel
(
ylabel
)
if
zlabel
is
not
:
axes
.
set_zlabel
(
zlabel
)
if
(
clabel
is
not
)
or
(
cb
is
not
)
:
if
(
clabel
is
not
)
and
(
cb
is
not
)
:
cb
.
set_label
(
clabel
)
else
:
if
clabel
is
:
logger
.
error
(
'Missing colorbar label'
)
else
:
logger
.
error
(
'Missing colorbar instance'
)


def linkcode_resolve(domain, info):
    """
    Determine the URL corresponding to Python object
    """
    if domain != 'py':
        return None

    modname = info['module']
    fullname = info['fullname']

    submod = sys.modules.get(modname)
    if submod is None:
        return None

    obj = submod
    for part in fullname.split('.'):
        try:
            obj = getattr(obj, part)
        except:
            return None

    try:
        fn = inspect.getsourcefile(obj)
    except:
        fn = None
    if not fn:
        return None

    try:
        source, lineno = inspect.getsourcelines(obj)
    except:
        lineno = None

    if lineno:
        linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1)
    else:
        linespec = ""

    fn = relpath(fn, start=dirname(scisalt.__file__))

    if 'dev' in scisalt.__version__:
        return "http://github.com/joelfrederico/SciSalt/blob/master/scisalt/%s%s" % (
            fn, linespec)
    else:
        return "http://github.com/joelfrederico/SciSalt/blob/v%s/scisalt/%s%s" % (
            scisalt.__version__, fn, linespec)


def syncdb(args):
    """Update the database with model schema. Shorthand for `paver manage syncdb`.
    """
    cmd = args and 'syncdb %s' % ' '.join(options.args) or 'syncdb --noinput'
    call_manage(cmd)
    for fixture in options.paved.django.syncdb.fixtures:
        call_manage("loaddata %s" % fixture)

def
syncdb
(
args
)
:
cmd
=
args
and
'syncdb %s'
%
' '
.
join
(
options
.
args
)
or
'syncdb --noinput'
call_manage
(
cmd
)
for
fixture
in
options
.
paved
.
django
.
syncdb
.
fixtures
:
call_manage
(
"loaddata %s"
%
fixture
)

Update the database with model schema . Shorthand for paver manage syncdb .


def start(info):
    """Run the dev server.

    Uses `django_extensions <http://pypi.python.org/pypi/django-extensions/0.5>`, if
    available, to provide `runserver_plus`.

    Set the command to use with `options.paved.django.runserver`
    Set the port to use with `options.paved.django.runserver_port`
    """
    cmd = options.paved.django.runserver

    if cmd == 'runserver_plus':
        try:
            import django_extensions
        except ImportError:
            info("Could not import django_extensions. Using default runserver.")
            cmd = 'runserver'

    port = options.paved.django.runserver_port
    if port:
        cmd = '%s %s' % (cmd, port)

    call_manage(cmd)


def schema(args):
    """Run South's schemamigration command.
    """
    try:
        import south
        cmd = args and 'schemamigration %s' % ' '.join(options.args) or 'schemamigration'
        call_manage(cmd)
    except ImportError:
        error('Could not import south.')

def
schema
(
args
)
:
try
:
import
south
cmd
=
args
and
'schemamigration %s'
%
' '
.
join
(
options
.
args
)
or
'schemamigration'
call_manage
(
cmd
)
except
ImportError
:
error
(
'Could not import south.'
)


def validate(cls, definition):
        '''
        This static method validates a BioMapMapper definition.
        It returns None on success and throws an exception otherwise.
        '''
        schema_path = os.path.join(os.path.dirname(__file__),
                                   '../../schema/mapper_definition_schema.json')
        with open(schema_path, 'r') as jsonfp:
            schema = json.load(jsonfp)
        # Validation of JSON schema
        jsonschema.validate(definition, schema)
        # Validation of JSON properties relations
        assert definition['main_key'] in definition['supported_keys'], \
               '\'main_key\' must be contained in \'supported_keys\''
        assert set(definition.get('list_valued_keys', [])) <= set(definition['supported_keys']), \
               '\'list_valued_keys\' must be a subset of \'supported_keys\''
        assert set(definition.get('disjoint', [])) <= set(definition.get('list_valued_keys', [])), \
               '\'disjoint\' must be a subset of \'list_valued_keys\''
        assert set(definition.get('key_synonyms', {}).values()) <= set(definition['supported_keys']), \
               '\'The values of the \'key_synonyms\' mapping must be in \'supported_keys\''

This static method validates a BioMapMapper definition . It returns None on success and throws an exception otherwise .


def map(self, ID_s,
                  FROM=None,
                  TO=None,
                  target_as_set=False,
                  no_match_sub=None):
        '''
        The main method of this class and the essence of the package.
        It allows to "map" stuff.

        Args:

            ID_s: Nested lists with strings as leafs (plain strings also possible)
            FROM (str): Origin key for the mapping (default: main key)
            TO (str): Destination key for the mapping (default: main key)
            target_as_set (bool): Whether to summarize the output as a set (removes duplicates)
            no_match_sub: Object representing the status of an ID not being able to be matched
                          (default: None)

        Returns:

            Mapping: a mapping object capturing the result of the mapping request
        '''
        def io_mode(ID_s):
            '''
            Handles the input/output modalities of the mapping.
            '''
            unlist_return = False
            list_of_lists = False
            if isinstance(ID_s, str):
                ID_s = [ID_s]
                unlist_return = True
            elif isinstance(ID_s, list):
                if len(ID_s) > 0 and isinstance(ID_s[0], list):
                    # assuming ID_s is a list of lists of ID strings
                    list_of_lists = True
            return ID_s, unlist_return, list_of_lists

        # interpret input
        if FROM == TO:
            return ID_s
        ID_s, unlist_return, list_of_lists = io_mode(ID_s)
        # map consistent with interpretation of input
        if list_of_lists:
            mapped_ids = [self.map(ID, FROM, TO, target_as_set, no_match_sub) for ID in ID_s]
        else:
            mapped_ids = self._map(ID_s, FROM, TO, target_as_set, no_match_sub)
        # return consistent with interpretation of input
        if unlist_return:
            return mapped_ids[0]
        return Mapping(ID_s, mapped_ids)

def map ( self , ID_s , FROM = None , TO = None , target_as_set = False , no_match_sub = None ) : def io_mode ( ID_s ) : unlist_return = False list_of_lists = False if isinstance ( ID_s , str ) : ID_s = [ ID_s ] unlist_return = True elif isinstance ( ID_s , list ) : if len ( ID_s ) > 0 and isinstance ( ID_s [ 0 ] , list ) : list_of_lists = True return ID_s , unlist_return , list_of_lists if FROM == TO : return ID_s ID_s , unlist_return , list_of_lists = io_mode ( ID_s ) if list_of_lists : mapped_ids = [ self . map ( ID , FROM , TO , target_as_set , no_match_sub ) for ID in ID_s ] else : mapped_ids = self . _map ( ID_s , FROM , TO , target_as_set , no_match_sub ) if unlist_return : return mapped_ids [ 0 ] return Mapping ( ID_s , mapped_ids )

The main method of this class and the essence of the package . It allows to map stuff .


def get_all(self, key=None):
        '''
        Returns all data entries for a particular key. Default is the main key.

        Args:

            key (str): key whose values to return (default: main key)

        Returns:

            List of all data entries for the key
        '''
        key = self.definition.main_key if key is None else key
        key = self.definition.key_synonyms.get(key, key)
        entries = self._get_all(key)
        if key in self.definition.scalar_nonunique_keys:
            return set(entries)
        return entries

def get_all ( self , key = None ) : key = self . definition . main_key if key is None else key key = self . definition . key_synonyms . get ( key , key ) entries = self . _get_all ( key ) if key in self . definition . scalar_nonunique_keys : return set ( entries ) return entries

Returns all data entries for a particular key . Default is the main key .


def line(self, line):
        """Returns list of strings split by input delimeter

        Argument:
        line - Input line to cut
        """
        # Remove empty strings in case of multiple instances of delimiter
        return [x for x in re.split(self.delimiter, line.rstrip()) if x != '']

def line ( self , line ) : return [ x for x in re . split ( self . delimiter , line . rstrip ( ) ) if x != '' ]


def get_message(self, message_id):
        """
        Get Existing Message

        http://dev.wheniwork.com/#get-existing-message
        """
        url = "/2/messages/%s" % message_id

        return self.message_from_json(self._get_resource(url)["message"])

def get_message ( self , message_id ) : url = "/2/messages/%s" % message_id return self . message_from_json ( self . _get_resource ( url ) [ "message" ] )


def create_message(self, params={}):
        """
        Creates a message

        http://dev.wheniwork.com/#create/update-message
        """
        url = "/2/messages/"
        body = params

        data = self._post_resource(url, body)
        return self.message_from_json(data["message"])

def create_message ( self , params = { } ) : url = "/2/messages/" body = params data = self . _post_resource ( url , body ) return self . message_from_json ( data [ "message" ] )


def update_message(self, message):
        """
        Modify an existing message.

        http://dev.wheniwork.com/#create/update-message
        """
        url = "/2/messages/%s" % message.message_id

        data = self._put_resource(url, message.json_data())
        return self.message_from_json(data)

def update_message ( self , message ) : url = "/2/messages/%s" % message . message_id data = self . _put_resource ( url , message . json_data ( ) ) return self . message_from_json ( data )


def delete_messages(self, messages):
        """
        Delete existing messages.

        http://dev.wheniwork.com/#delete-existing-message
        """
        url = "/2/messages/?%s" % urlencode([('ids', ",".join(messages))])

        data = self._delete_resource(url)
        return data

def delete_messages ( self , messages ) : url = "/2/messages/?%s" % urlencode ( [ ( 'ids' , "," . join ( messages ) ) ] ) data = self . _delete_resource ( url ) return data


def get_site(self, site_id):
        """
        Returns site data.

        http://dev.wheniwork.com/#get-existing-site
        """
        url = "/2/sites/%s" % site_id

        return self.site_from_json(self._get_resource(url)["site"])

def get_site ( self , site_id ) : url = "/2/sites/%s" % site_id return self . site_from_json ( self . _get_resource ( url ) [ "site" ] )


def get_sites(self):
        """
        Returns a list of sites.

        http://dev.wheniwork.com/#listing-sites
        """
        url = "/2/sites"

        data = self._get_resource(url)
        sites = []
        for entry in data['sites']:
            sites.append(self.site_from_json(entry))

        return sites

def get_sites ( self ) : url = "/2/sites" data = self . _get_resource ( url ) sites = [ ] for entry in data [ 'sites' ] : sites . append ( self . site_from_json ( entry ) ) return sites


def create_site(self, params={}):
        """
        Creates a site

        http://dev.wheniwork.com/#create-update-site
        """
        url = "/2/sites/"
        body = params

        data = self._post_resource(url, body)
        return self.site_from_json(data["site"])

def create_site ( self , params = { } ) : url = "/2/sites/" body = params data = self . _post_resource ( url , body ) return self . site_from_json ( data [ "site" ] )


def admin_link_move_up(obj, link_text='up'):
    """Returns a link to a view that moves the passed in object up in rank.

    :param obj:
        Object to move
    :param link_text:
        Text to display in the link.  Defaults to "up"
    :returns:
        HTML link code to view for moving the object
    """
    if obj.rank == 1:
        return ''

    content_type = ContentType.objects.get_for_model(obj)
    link = reverse('awl-rankedmodel-move', args=(content_type.id, obj.id,
        obj.rank - 1))

    return '%s' % (link, link_text)

def
admin_link_move_up
(
obj
,
link_text
=
'up'
)
:
if
obj
.
rank
==
1
:
return
''
content_type
=
ContentType
.
objects
.
get_for_model
(
obj
)
link
=
reverse
(
'awl-rankedmodel-move'
,
args
=
(
content_type
.
id
,
obj
.
id
,
obj
.
rank
1
)
)
return
'%s'
%
(
link
,
link_text
)

Returns a link to a view that moves the passed in object up in rank .


def admin_link_move_down(obj, link_text='down'):
    """Returns a link to a view that moves the passed in object down in rank.

    :param obj:
        Object to move
    :param link_text:
        Text to display in the link.  Defaults to "down"
    :returns:
        HTML link code to view for moving the object
    """
    if obj.rank == obj.grouped_filter().count():
        return ''

    content_type = ContentType.objects.get_for_model(obj)
    link = reverse('awl-rankedmodel-move', args=(content_type.id, obj.id,
        obj.rank + 1))

    return '%s' % (link, link_text)

def
admin_link_move_down
(
obj
,
link_text
=
'down'
)
:
if
obj
.
rank
==
obj
.
grouped_filter
(
)
.
count
(
)
:
return
''
content_type
=
ContentType
.
objects
.
get_for_model
(
obj
)
link
=
reverse
(
'awl-rankedmodel-move'
,
args
=
(
content_type
.
id
,
obj
.
id
,
obj
.
rank
+
1
)
)
return
'%s'
%
(
link
,
link_text
)

Returns a link to a view that moves the passed in object down in rank .


def showfig(fig, aspect="auto"):
    """
    Shows a figure with a typical orientation so that x and y axes are set up as expected.
    """

    ax = fig.gca()

    # Swap y axis if needed
    alim = list(ax.axis())
    if alim[3] < alim[2]:
        temp    = alim[2]
        alim[2] = alim[3]
        alim[3] = temp
        ax.axis(alim)

    ax.set_aspect(aspect)
    fig.show()

def showfig ( fig , aspect = "auto" ) : ax = fig . gca ( ) alim = list ( ax . axis ( ) ) if alim [ 3 ] < alim [ 2 ] : temp = alim [ 2 ] alim [ 2 ] = alim [ 3 ] alim [ 3 ] = temp ax . axis ( alim ) ax . set_aspect ( aspect ) fig . show ( )

Shows a figure with a typical orientation so that x and y axes are set up as expected .


def _setup_index(index):
    """Shifts indicies as needed to account for one based indexing

    Positive indicies need to be reduced by one to match with zero based
    indexing.

    Zero is not a valid input, and as such will throw a value error.

    Arguments:
        index -     index to shift
    """
    index = int(index)
    if index > 0:
        index -= 1
    elif index == 0:
        # Zero indicies should not be allowed by default.
        raise ValueError
    return index

def _setup_index ( index ) : index = int ( index ) if index > 0 : index -= 1 elif index == 0 : raise ValueError return index


def cut(self, line):
        """Returns selected positions from cut input source in desired
        arrangement.

        Argument:
            line -      input to cut
        """
        result = []
        line = self.line(line)

        for i, field in enumerate(self.positions):
            try:
                index = _setup_index(field)
                try:
                    result += line[index]
                except IndexError:
                    result.append(self.invalid_pos)
            except ValueError:
                result.append(str(field))
            except TypeError:
                result.extend(self._cut_range(line, int(field[0]), i))

        return ''.join(result)

def cut ( self , line ) : result = [ ] line = self . line ( line ) for i , field in enumerate ( self . positions ) : try : index = _setup_index ( field ) try : result += line [ index ] except IndexError : result . append ( self . invalid_pos ) except ValueError : result . append ( str ( field ) ) except TypeError : result . extend ( self . _cut_range ( line , int ( field [ 0 ] ) , i ) ) return '' . join ( result )

Returns selected positions from cut input source in desired arrangement .


def _setup_positions(self, positions):
        """Processes positions to account for ranges

        Arguments:
            positions -     list of positions and/or ranges to process
        """
        updated_positions = []

        for i, position in enumerate(positions):
            ranger = re.search(r'(?P<start>-?\d*):(?P<end>\d*)', position)

            if ranger:
                if i > 0:
                    updated_positions.append(self.separator)
                start = group_val(ranger.group('start'))
                end = group_val(ranger.group('end'))

                if start and end:
                    updated_positions.extend(self._extendrange(start, end + 1))
                # Since the number of positions on a line is unknown,
                # send input to cause exception that can be caught and call
                # _cut_range helper function
                elif ranger.group('start'):
                    updated_positions.append([start])
                else:
                    updated_positions.extend(self._extendrange(1, end + 1))
            else:
                updated_positions.append(positions[i])
                try:
                    if int(position) and int(positions[i+1]):
                        updated_positions.append(self.separator)
                except (ValueError, IndexError):
                    pass

        return updated_positions

def _setup_positions ( self , positions ) : updated_positions = [ ] for i , position in enumerate ( positions ) : ranger = re . search ( r'(?P<start>-?\d*):(?P<end>\d*)' , position ) if ranger : if i > 0 : updated_positions . append ( self . separator ) start = group_val ( ranger . group ( 'start' ) ) end = group_val ( ranger . group ( 'end' ) ) if start and end : updated_positions . extend ( self . _extendrange ( start , end + 1 ) ) elif ranger . group ( 'start' ) : updated_positions . append ( [ start ] ) else : updated_positions . extend ( self . _extendrange ( 1 , end + 1 ) ) else : updated_positions . append ( positions [ i ] ) try : if int ( position ) and int ( positions [ i + 1 ] ) : updated_positions . append ( self . separator ) except ( ValueError , IndexError ) : pass return updated_positions


def _cut_range(self, line, start, current_position):
        """Performs cut for range from start position to end

        Arguments:
            line -              input to cut
            start -             start of range
            current_position -  current position in main cut function
        """
        result = []
        try:
            for j in range(start, len(line)):
                index = _setup_index(j)
                try:
                    result.append(line[index])
                except IndexError:
                    result.append(self.invalid_pos)
                finally:
                    result.append(self.separator)
            result.append(line[-1])
        except IndexError:
            pass

        try:
            int(self.positions[current_position+1])
            result.append(self.separator)
        except (ValueError, IndexError):
            pass

        return result

def _cut_range ( self , line , start , current_position ) : result = [ ] try : for j in range ( start , len ( line ) ) : index = _setup_index ( j ) try : result . append ( line [ index ] ) except IndexError : result . append ( self . invalid_pos ) finally : result . append ( self . separator ) result . append ( line [ - 1 ] ) except IndexError : pass try : int ( self . positions [ current_position + 1 ] ) result . append ( self . separator ) except ( ValueError , IndexError ) : pass return result


def _extendrange(self, start, end):
        """Creates list of values in a range with output delimiters.

        Arguments:
            start -     range start
            end -       range end
        """
        range_positions = []
        for i in range(start, end):
            if i != 0:
                range_positions.append(str(i))
            if i < end:
                range_positions.append(self.separator)
        return range_positions

def _extendrange ( self , start , end ) : range_positions = [ ] for i in range ( start , end ) : if i != 0 : range_positions . append ( str ( i ) ) if i < end : range_positions . append ( self . separator ) return range_positions

Creates list of values in a range with output delimiters .


def lock_file(filename):
    """Locks the file by writing a '.lock' file.
       Returns True when the file is locked and
       False when the file was locked already"""

    lockfile = "%s.lock"%filename
    if isfile(lockfile):
        return False
    else:
        with open(lockfile, "w"):
            pass
    return True

def lock_file ( filename ) : lockfile = "%s.lock" % filename if isfile ( lockfile ) : return False else : with open ( lockfile , "w" ) : pass return True

Locks the file by writing a . lock file . Returns True when the file is locked and False when the file was locked already


def unlock_file(filename):
    """Unlocks the file by remove a '.lock' file.
       Returns True when the file is unlocked and
       False when the file was unlocked already"""

    lockfile = "%s.lock"%filename
    if isfile(lockfile):
        os.remove(lockfile)
        return True
    else:
        return False

def unlock_file ( filename ) : lockfile = "%s.lock" % filename if isfile ( lockfile ) : os . remove ( lockfile ) return True else : return False

Unlocks the file by remove a . lock file . Returns True when the file is unlocked and False when the file was unlocked already