def shareable_parameters(cells):
    """Return parameter names if the parameters are shareable among cells.

    Parameters are shareable among multiple cells when all the cells
    have the parameters in the same order if they ever have any.

    For example, if cells are foo(), bar(x), baz(x, y), then
    ('x', 'y') are shareable parameters amounts them, as 'x' and 'y'
    appear in the same order in the parameter list if they ever appear.

    Args:
        cells: An iterator yielding cells.

    Returns:
        None if parameters are not share,
        tuple of shareable parameter names,
        () if cells are all scalars.
    """
    result = []
    for c in cells.values():
        params = c.formula.parameters

        for i in range(min(len(result), len(params))):
            if params[i] != result[i]:
                return None

        for i in range(len(result), len(params)):
            result.append(params[i])

    return result

def shareable_parameters ( cells ) : result = [ ] for c in cells . values ( ) : params = c . formula . parameters for i in range ( min ( len ( result ) , len ( params ) ) ) : if params [ i ] != result [ i ] : return None for i in range ( len ( result ) , len ( params ) ) : result . append ( params [ i ] ) return result

Return parameter names if the parameters are shareable among cells .


def copy(self, space=None, name=None):
        """Make a copy of itself and return it."""
        return Cells(space=space, name=name, formula=self.formula)

def copy ( self , space = None , name = None ) : return Cells ( space = space , name = name , formula = self . formula )


def value(self):
        """Return the value of the cells."""
        if self.has_value:
            return self._impl[OBJ].get_value(self._impl[KEY])
        else:
            raise ValueError("Value not found")

def
value
(
self
)
:
if
self
.
has_value
:
return
self
.
_impl
[
OBJ
]
.
get_value
(
self
.
_impl
[
KEY
]
)
else
:
raise
ValueError
(
"Value not found"
)


def _get_col_index(name):
    """Convert column name to index."""

    index = string.ascii_uppercase.index
    col = 0
    for c in name.upper():
        col = col * 26 + index(c) + 1
    return col

def _get_col_index ( name ) : index = string . ascii_uppercase . index col = 0 for c in name . upper ( ) : col = col * 26 + index ( c ) + 1 return col


def _get_range(book, range_, sheet):
    """Return a range as nested dict of openpyxl cells."""

    filename = None
    if isinstance(book, str):
        filename = book
        book = opxl.load_workbook(book, data_only=True)
    elif isinstance(book, opxl.Workbook):
        pass
    else:
        raise TypeError

    if _is_range_address(range_):
        sheet_names = [name.upper() for name in book.sheetnames]
        index = sheet_names.index(sheet.upper())
        data = book.worksheets[index][range_]
    else:
        data = _get_namedrange(book, range_, sheet)
        if data is None:
            raise ValueError(
                "Named range '%s' not found in %s" % (range_, filename or book)
            )

    return data

def
_get_range
(
book
,
range_
,
sheet
)
:
filename
=
if
isinstance
(
book
,
str
)
:
filename
=
book
book
=
opxl
.
load_workbook
(
book
,
data_only
=
True
)
elif
isinstance
(
book
,
opxl
.
Workbook
)
:
pass
else
:
raise
TypeError
if
_is_range_address
(
range_
)
:
sheet_names
=
[
name
.
upper
(
)
for
name
in
book
.
sheetnames
]
index
=
sheet_names
.
index
(
sheet
.
upper
(
)
)
data
=
book
.
worksheets
[
index
]
[
range_
]
else
:
data
=
_get_namedrange
(
book
,
range_
,
sheet
)
if
data
is
:
raise
ValueError
(
"Named range '%s' not found in %s"
%
(
range_
,
filename
or
book
)
)
return
data

Return a range as nested dict of openpyxl cells .


def read_range(filepath, range_expr, sheet=None, dict_generator=None):
    """Read values from an Excel range into a dictionary.

    `range_expr` ie either a range address string, such as "A1", "$C$3:$E$5",
    or a defined name string for a range, such as "NamedRange1".
    If a range address is provided, `sheet` argument must also be provided.
    If a named range is provided and `sheet` is not, book level defined name
    is searched. If `sheet` is also provided, sheet level defined name for the
    specified `sheet` is searched.
    If range_expr points to a single cell, its value is returned.

    `dictgenerator` is a generator function that yields keys and values of
    the returned dictionary. the excel range, as a nested tuple of openpyxl's
    Cell objects, is passed to the generator function as its single argument.
    If not specified, default generator is used, which maps tuples of row and
    column indexes, both starting with 0, to their values.

    Args:
        filepath (str): Path to an Excel file.
        range_epxr (str): Range expression, such as "A1", "$G4:$K10",
            or named range "NamedRange1"
        sheet (str): Sheet name (case ignored).
            None if book level defined range name is passed as `range_epxr`.
        dict_generator: A generator function taking a nested tuple of cells
            as a single parameter.

    Returns:
        Nested list containing range values.
    """

    def default_generator(cells):
        for row_ind, row in enumerate(cells):
            for col_ind, cell in enumerate(row):
                yield (row_ind, col_ind), cell.value

    book = opxl.load_workbook(filepath, data_only=True)

    if _is_range_address(range_expr):
        sheet_names = [name.upper() for name in book.sheetnames]
        index = sheet_names.index(sheet.upper())
        cells = book.worksheets[index][range_expr]
    else:
        cells = _get_namedrange(book, range_expr, sheet)

    # In case of a single cell, return its value.
    if isinstance(cells, opxl.cell.Cell):
        return cells.value

    if dict_generator is None:
        dict_generator = default_generator

    gen = dict_generator(cells)
    return {keyval[0]: keyval[1] for keyval in gen}

def read_range ( filepath , range_expr , sheet = None , dict_generator = None ) : def default_generator ( cells ) : for row_ind , row in enumerate ( cells ) : for col_ind , cell in enumerate ( row ) : yield ( row_ind , col_ind ) , cell . value book = opxl . load_workbook ( filepath , data_only = True ) if _is_range_address ( range_expr ) : sheet_names = [ name . upper ( ) for name in book . sheetnames ] index = sheet_names . index ( sheet . upper ( ) ) cells = book . worksheets [ index ] [ range_expr ] else : cells = _get_namedrange ( book , range_expr , sheet ) if isinstance ( cells , opxl . cell . Cell ) : return cells . value if dict_generator is None : dict_generator = default_generator gen = dict_generator ( cells ) return { keyval [ 0 ] : keyval [ 1 ] for keyval in gen }

Read values from an Excel range into a dictionary .


def _get_namedrange(book, rangename, sheetname=None):
    """Get range from a workbook.

    A workbook can contain multiple definitions for a single name,
    as a name can be defined for the entire book or for
    a particular sheet.

    If sheet is None, the book-wide def is searched,
    otherwise sheet-local def is looked up.

    Args:
        book: An openpyxl workbook object.
        rangename (str): Range expression, such as "A1", "$G4:$K10",
            named range "NamedRange1".
        sheetname (str, optional): None for book-wide name def,
            sheet name for sheet-local named range.

    Returns:
        Range object specified by the name.

    """

    def cond(namedef):

        if namedef.type.upper() == "RANGE":
            if namedef.name.upper() == rangename.upper():

                if sheetname is None:
                    if not namedef.localSheetId:
                        return True

                else:  # sheet local name
                    sheet_id = [sht.upper() for sht in book.sheetnames].index(
                        sheetname.upper()
                    )

                    if namedef.localSheetId == sheet_id:
                        return True

        return False

    def get_destinations(name_def):
        """Workaround for the bug in DefinedName.destinations"""

        from openpyxl.formula import Tokenizer
        from openpyxl.utils.cell import SHEETRANGE_RE

        if name_def.type == "RANGE":
            tok = Tokenizer("=" + name_def.value)
            for part in tok.items:
                if part.subtype == "RANGE":
                    m = SHEETRANGE_RE.match(part.value)
                    if m.group("quoted"):
                        sheet_name = m.group("quoted")
                    else:
                        sheet_name = m.group("notquoted")

                    yield sheet_name, m.group("cells")

    namedef = next(
        (item for item in book.defined_names.definedName if cond(item)), None
    )

    if namedef is None:
        return None

    dests = get_destinations(namedef)
    xlranges = []

    sheetnames_upper = [name.upper() for name in book.sheetnames]

    for sht, addr in dests:
        if sheetname:
            sht = sheetname
        index = sheetnames_upper.index(sht.upper())
        xlranges.append(book.worksheets[index][addr])

    if len(xlranges) == 1:
        return xlranges[0]
    else:
        return xlranges

def _get_namedrange ( book , rangename , sheetname = None ) : def cond ( namedef ) : if namedef . type . upper ( ) == "RANGE" : if namedef . name . upper ( ) == rangename . upper ( ) : if sheetname is None : if not namedef . localSheetId : return True else : sheet_id = [ sht . upper ( ) for sht in book . sheetnames ] . index ( sheetname . upper ( ) ) if namedef . localSheetId == sheet_id : return True return False def get_destinations ( name_def ) : from openpyxl . formula import Tokenizer from openpyxl . utils . cell import SHEETRANGE_RE if name_def . type == "RANGE" : tok = Tokenizer ( "=" + name_def . value ) for part in tok . items : if part . subtype == "RANGE" : m = SHEETRANGE_RE . match ( part . value ) if m . group ( "quoted" ) : sheet_name = m . group ( "quoted" ) else : sheet_name = m . group ( "notquoted" ) yield sheet_name , m . group ( "cells" ) namedef = next ( ( item for item in book . defined_names . definedName if cond ( item ) ) , None ) if namedef is None : return None dests = get_destinations ( namedef ) xlranges = [ ] sheetnames_upper = [ name . upper ( ) for name in book . sheetnames ] for sht , addr in dests : if sheetname : sht = sheetname index = sheetnames_upper . index ( sht . upper ( ) ) xlranges . append ( book . worksheets [ index ] [ addr ] ) if len ( xlranges ) == 1 : return xlranges [ 0 ] else : return xlranges


def get_mro(self, space):
        """Calculate the Method Resolution Order of bases using the C3 algorithm.

        Code modified from
        http://code.activestate.com/recipes/577748-calculate-the-mro-of-a-class/

        Args:
            bases: sequence of direct base spaces.

        Returns:
            mro as a list of bases including node itself
        """
        seqs = [self.get_mro(base) for base
                in self.get_bases(space)] + [list(self.get_bases(space))]
        res = []
        while True:
            non_empty = list(filter(None, seqs))

            if not non_empty:
                # Nothing left to process, we're done.
                res.insert(0, space)
                return res

            for seq in non_empty:  # Find merge candidates among seq heads.
                candidate = seq[0]
                not_head = [s for s in non_empty if candidate in s[1:]]
                if not_head:
                    # Reject the candidate.
                    candidate = None
                else:
                    break

            if not candidate:
                raise TypeError(
                    "inconsistent hierarchy, no C3 MRO is possible")

            res.append(candidate)

            for seq in non_empty:
                # Remove candidate.
                if seq[0] == candidate:
                    del seq[0]

Calculate the Method Resolution Order of bases using the C3 algorithm .


def _alter_code(code, **attrs):
    """Create a new code object by altering some of ``code`` attributes

    Args:
        code: code objcect
        attrs: a mapping of names of code object attrs to their values
    """

    PyCode_New = ctypes.pythonapi.PyCode_New

    PyCode_New.argtypes = (
        ctypes.c_int,
        ctypes.c_int,
        ctypes.c_int,
        ctypes.c_int,
        ctypes.c_int,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.py_object,
        ctypes.c_int,
        ctypes.py_object)

    PyCode_New.restype = ctypes.py_object

    args = [
        [code.co_argcount, 'co_argcount'],
        [code.co_kwonlyargcount, 'co_kwonlyargcount'],
        [code.co_nlocals, 'co_nlocals'],
        [code.co_stacksize, 'co_stacksize'],
        [code.co_flags, 'co_flags'],
        [code.co_code, 'co_code'],
        [code.co_consts, 'co_consts'],
        [code.co_names, 'co_names'],
        [code.co_varnames, 'co_varnames'],
        [code.co_freevars, 'co_freevars'],
        [code.co_cellvars, 'co_cellvars'],
        [code.co_filename, 'co_filename'],
        [code.co_name, 'co_name'],
        [code.co_firstlineno, 'co_firstlineno'],
        [code.co_lnotab, 'co_lnotab']]

    for arg in args:
        if arg[1] in attrs:
            arg[0] = attrs[arg[1]]

    return PyCode_New(
        args[0][0],  # code.co_argcount,
        args[1][0],  # code.co_kwonlyargcount,
        args[2][0],  # code.co_nlocals,
        args[3][0],  # code.co_stacksize,
        args[4][0],  # code.co_flags,
        args[5][0],  # code.co_code,
        args[6][0],  # code.co_consts,
        args[7][0],  # code.co_names,
        args[8][0],  # code.co_varnames,
        args[9][0],  # code.co_freevars,
        args[10][0],  # code.co_cellvars,
        args[11][0],  # code.co_filename,
        args[12][0],  # code.co_name,
        args[13][0],  # code.co_firstlineno,
        args[14][0])

def _alter_code ( code , ** attrs ) : PyCode_New = ctypes . pythonapi . PyCode_New PyCode_New . argtypes = ( ctypes . c_int , ctypes . c_int , ctypes . c_int , ctypes . c_int , ctypes . c_int , ctypes . py_object , ctypes . py_object , ctypes . py_object , ctypes . py_object , ctypes . py_object , ctypes . py_object , ctypes . py_object , ctypes . py_object , ctypes . c_int , ctypes . py_object ) PyCode_New . restype = ctypes . py_object args = [ [ code . co_argcount , 'co_argcount' ] , [ code . co_kwonlyargcount , 'co_kwonlyargcount' ] , [ code . co_nlocals , 'co_nlocals' ] , [ code . co_stacksize , 'co_stacksize' ] , [ code . co_flags , 'co_flags' ] , [ code . co_code , 'co_code' ] , [ code . co_consts , 'co_consts' ] , [ code . co_names , 'co_names' ] , [ code . co_varnames , 'co_varnames' ] , [ code . co_freevars , 'co_freevars' ] , [ code . co_cellvars , 'co_cellvars' ] , [ code . co_filename , 'co_filename' ] , [ code . co_name , 'co_name' ] , [ code . co_firstlineno , 'co_firstlineno' ] , [ code . co_lnotab , 'co_lnotab' ] ] for arg in args : if arg [ 1 ] in attrs : arg [ 0 ] = attrs [ arg [ 1 ] ] return PyCode_New ( args [ 0 ] [ 0 ] , args [ 1 ] [ 0 ] , args [ 2 ] [ 0 ] , args [ 3 ] [ 0 ] , args [ 4 ] [ 0 ] , args [ 5 ] [ 0 ] , args [ 6 ] [ 0 ] , args [ 7 ] [ 0 ] , args [ 8 ] [ 0 ] , args [ 9 ] [ 0 ] , args [ 10 ] [ 0 ] , args [ 11 ] [ 0 ] , args [ 12 ] [ 0 ] , args [ 13 ] [ 0 ] , args [ 14 ] [ 0 ] )

Create a new code object by altering some of code attributes


def alter_freevars(func, globals_=None, **vars):
    """Replace local variables with free variables

    Warnings:
        This function does not work.
    """

    if globals_ is None:
        globals_ = func.__globals__

    frees = tuple(vars.keys())
    oldlocs = func.__code__.co_names
    newlocs = tuple(name for name in oldlocs if name not in frees)

    code = _alter_code(func.__code__,
                       co_freevars=frees,
                       co_names=newlocs,
                       co_flags=func.__code__.co_flags | inspect.CO_NESTED)
    closure = _create_closure(*vars.values())

    return FunctionType(code, globals_, closure=closure)

def alter_freevars ( func , globals_ = None , ** vars ) : if globals_ is None : globals_ = func . __globals__ frees = tuple ( vars . keys ( ) ) oldlocs = func . __code__ . co_names newlocs = tuple ( name for name in oldlocs if name not in frees ) code = _alter_code ( func . __code__ , co_freevars = frees , co_names = newlocs , co_flags = func . __code__ . co_flags | inspect . CO_NESTED ) closure = _create_closure ( * vars . values ( ) ) return FunctionType ( code , globals_ , closure = closure )


def fix_lamdaline(source):
    """Remove the last redundant token from lambda expression

    lambda x: return x)
                      ^
    Return string without irrelevant tokens
    returned from inspect.getsource on lamda expr returns
    """

    # Using undocumented generate_tokens due to a tokenize.tokenize bug
    # See https://bugs.python.org/issue23297
    strio = io.StringIO(source)
    gen = tokenize.generate_tokens(strio.readline)

    tkns = []
    try:
        for t in gen:
            tkns.append(t)
    except tokenize.TokenError:
        pass

    # Find the position of 'lambda'
    lambda_pos = [(t.type, t.string) for t in tkns].index(
        (tokenize.NAME, "lambda")
    )

    # Ignore tokes before 'lambda'
    tkns = tkns[lambda_pos:]

    # Find the position of th las OP
    lastop_pos = (
        len(tkns) - 1 - [t.type for t in tkns[::-1]].index(tokenize.OP)
    )
    lastop = tkns[lastop_pos]

    # Remove OP from the line
    fiedlineno = lastop.start[0]
    fixedline = lastop.line[: lastop.start[1]] + lastop.line[lastop.end[1] :]

    tkns = tkns[:lastop_pos]

    fixedlines = ""
    last_lineno = 0
    for t in tkns:
        if last_lineno == t.start[0]:
            continue
        elif t.start[0] == fiedlineno:
            fixedlines += fixedline
            last_lineno = t.start[0]
        else:
            fixedlines += t.line
            last_lineno = t.start[0]

    return fixedlines

def fix_lamdaline ( source ) : strio = io . StringIO ( source ) gen = tokenize . generate_tokens ( strio . readline ) tkns = [ ] try : for t in gen : tkns . append ( t ) except tokenize . TokenError : pass lambda_pos = [ ( t . type , t . string ) for t in tkns ] . index ( ( tokenize . NAME , "lambda" ) ) tkns = tkns [ lambda_pos : ] lastop_pos = ( len ( tkns ) - 1 - [ t . type for t in tkns [ : : - 1 ] ] . index ( tokenize . OP ) ) lastop = tkns [ lastop_pos ] fiedlineno = lastop . start [ 0 ] fixedline = lastop . line [ : lastop . start [ 1 ] ] + lastop . line [ lastop . end [ 1 ] : ] tkns = tkns [ : lastop_pos ] fixedlines = "" last_lineno = 0 for t in tkns : if last_lineno == t . start [ 0 ] : continue elif t . start [ 0 ] == fiedlineno : fixedlines += fixedline last_lineno = t . start [ 0 ] else : fixedlines += t . line last_lineno = t . start [ 0 ] return fixedlines


def find_funcdef(source):
    """Find the first FuncDef ast object in source"""

    try:
        module_node = compile(
            source, "<string>", mode="exec", flags=ast.PyCF_ONLY_AST
        )
    except SyntaxError:
        return find_funcdef(fix_lamdaline(source))

    for node in ast.walk(module_node):
        if isinstance(node, ast.FunctionDef) or isinstance(node, ast.Lambda):
            return node

    raise ValueError("function definition not found")

def
find_funcdef
(
source
)
:
try
:
module_node
=
compile
(
source
,
"<string>"
,
mode
=
"exec"
,
flags
=
ast
.
PyCF_ONLY_AST
)
except
SyntaxError
:
return
find_funcdef
(
fix_lamdaline
(
source
)
)
for
node
in
ast
.
walk
(
module_node
)
:
if
isinstance
(
node
,
ast
.
FunctionDef
)
or
isinstance
(
node
,
ast
.
Lambda
)
:
return
node
raise
ValueError
(
"function definition not found"
)


def extract_params(source):
    """Extract parameters from a function definition"""

    funcdef = find_funcdef(source)
    params = []
    for node in ast.walk(funcdef.args):
        if isinstance(node, ast.arg):
            if node.arg not in params:
                params.append(node.arg)

    return params

def extract_params ( source ) : funcdef = find_funcdef ( source ) params = [ ] for node in ast . walk ( funcdef . args ) : if isinstance ( node , ast . arg ) : if node . arg not in params : params . append ( node . arg ) return params


def extract_names(source):
    """Extract names from a function definition

    Looks for a function definition in the source.
    Only the first function definition is examined.

    Returns:
         a list names(identifiers) used in the body of the function
         excluding function parameters.
    """
    if source is None:
        return None

    source = dedent(source)
    funcdef = find_funcdef(source)
    params = extract_params(source)
    names = []

    if isinstance(funcdef, ast.FunctionDef):
        stmts = funcdef.body
    elif isinstance(funcdef, ast.Lambda):
        stmts = [funcdef.body]
    else:
        raise ValueError("must not happen")

    for stmt in stmts:
        for node in ast.walk(stmt):
            if isinstance(node, ast.Name):
                if node.id not in names and node.id not in params:
                    names.append(node.id)

    return names

def
extract_names
(
source
)
:
if
source
is
:
return
source
=
dedent
(
source
)
funcdef
=
find_funcdef
(
source
)
params
=
extract_params
(
source
)
names
=
[
]
if
isinstance
(
funcdef
,
ast
.
FunctionDef
)
:
stmts
=
funcdef
.
body
elif
isinstance
(
funcdef
,
ast
.
Lambda
)
:
stmts
=
[
funcdef
.
body
]
else
:
raise
ValueError
(
"must not happen"
)
for
stmt
in
stmts
:
for
node
in
ast
.
walk
(
stmt
)
:
if
isinstance
(
node
,
ast
.
Name
)
:
if
node
.
id
not
in
names
and
node
.
id
not
in
params
:
names
.
append
(
node
.
id
)
return
names


def is_funcdef(src):
    """True if src is a function definition"""

    module_node = ast.parse(dedent(src))

    if len(module_node.body) == 1 and isinstance(
            module_node.body[0], ast.FunctionDef
    ):
        return True
    else:
        return False

def is_funcdef ( src ) : module_node = ast . parse ( dedent ( src ) ) if len ( module_node . body ) == 1 and isinstance ( module_node . body [ 0 ] , ast . FunctionDef ) : return True else : return False


def remove_decorator(source: str):
    """Remove decorators from function definition"""
    lines = source.splitlines()
    atok = asttokens.ASTTokens(source, parse=True)

    for node in ast.walk(atok.tree):
        if isinstance(node, ast.FunctionDef):
            break

    if node.decorator_list:
        deco_first = node.decorator_list[0]
        deco_last = node.decorator_list[-1]
        line_first = atok.tokens[deco_first.first_token.index - 1].start[0]
        line_last = atok.tokens[deco_last.last_token.index + 1].start[0]

        lines = lines[:line_first - 1] + lines[line_last:]

    return "\n".join(lines) + "\n"

def remove_decorator ( source : str ) : lines = source . splitlines ( ) atok = asttokens . ASTTokens ( source , parse = True ) for node in ast . walk ( atok . tree ) : if isinstance ( node , ast . FunctionDef ) : break if node . decorator_list : deco_first = node . decorator_list [ 0 ] deco_last = node . decorator_list [ - 1 ] line_first = atok . tokens [ deco_first . first_token . index - 1 ] . start [ 0 ] line_last = atok . tokens [ deco_last . last_token . index + 1 ] . start [ 0 ] lines = lines [ : line_first - 1 ] + lines [ line_last : ] return "\n" . join ( lines ) + "\n"


def replace_funcname(source: str, name: str):
    """Replace function name"""

    lines = source.splitlines()
    atok = asttokens.ASTTokens(source, parse=True)

    for node in ast.walk(atok.tree):
        if isinstance(node, ast.FunctionDef):
            break

    i = node.first_token.index
    for i in range(node.first_token.index, node.last_token.index):
        if (atok.tokens[i].type == token.NAME
                and atok.tokens[i].string == "def"):
            break

    lineno, col_begin = atok.tokens[i + 1].start
    lineno_end, col_end = atok.tokens[i + 1].end

    assert lineno == lineno_end

    lines[lineno-1] = (
            lines[lineno-1][:col_begin] + name + lines[lineno-1][col_end:]
    )

    return "\n".join(lines) + "\n"

def replace_funcname ( source : str , name : str ) : lines = source . splitlines ( ) atok = asttokens . ASTTokens ( source , parse = True ) for node in ast . walk ( atok . tree ) : if isinstance ( node , ast . FunctionDef ) : break i = node . first_token . index for i in range ( node . first_token . index , node . last_token . index ) : if ( atok . tokens [ i ] . type == token . NAME and atok . tokens [ i ] . string == "def" ) : break lineno , col_begin = atok . tokens [ i + 1 ] . start lineno_end , col_end = atok . tokens [ i + 1 ] . end assert lineno == lineno_end lines [ lineno - 1 ] = ( lines [ lineno - 1 ] [ : col_begin ] + name + lines [ lineno - 1 ] [ col_end : ] ) return "\n" . join ( lines ) + "\n"


def has_lambda(src):
    """True if only one lambda expression is included"""

    module_node = ast.parse(dedent(src))
    lambdaexp = [node for node in ast.walk(module_node)
                 if isinstance(node, ast.Lambda)]

    return bool(lambdaexp)

def has_lambda ( src ) : module_node = ast . parse ( dedent ( src ) ) lambdaexp = [ node for node in ast . walk ( module_node ) if isinstance ( node , ast . Lambda ) ] return bool ( lambdaexp )


def _reload(self, module=None):
        """Reload the source function from the source module.

        **Internal use only**
        Update the source function of the formula.
        This method is used to updated the underlying formula
        when the source code of the module in which the source function
        is read from is modified.

        If the formula was not created from a module, an error is raised.
        If ``module_`` is not given, the source module of the formula is
        reloaded. If ``module_`` is given and matches the source module,
        then the module_ is used without being reloaded.
        If ``module_`` is given and does not match the source module of
        the formula, an error is raised.

        Args:
            module_: A ``ModuleSource`` object

        Returns:
            self
        """
        if self.module is None:
            raise RuntimeError
        elif module is None:
            import importlib

            module = ModuleSource(importlib.reload(module))
        elif module.name != self.module:
            raise RuntimeError

        if self.name in module.funcs:
            func = module.funcs[self.name]
            self.__init__(func=func)
        else:
            self.__init__(func=NULL_FORMULA)

        return self

def _reload ( self , module = None ) : if self . module is None : raise RuntimeError elif module is None : import importlib module = ModuleSource ( importlib . reload ( module ) ) elif module . name != self . module : raise RuntimeError if self . name in module . funcs : func = module . funcs [ self . name ] self . __init__ ( func = func ) else : self . __init__ ( func = NULL_FORMULA ) return self

Reload the source function from the source module .


def get_description():
    """Get long description from README."""
    with open(path.join(here, 'README.rst'), 'r') as f:
        data = f.read()
    return data

def get_description ( ) : with open ( path . join ( here , 'README.rst' ) , 'r' ) as f : data = f . read ( ) return data


def to_frame(self, *args):
        """Convert the cells in the view into a DataFrame object.

        If ``args`` is not given, this method returns a DataFrame that
        has an Index or a MultiIndex depending of the number of
        cells parameters and columns each of which corresponds to each
        cells included in the view.

        ``args`` can be given to calculate cells values and limit the
        DataFrame indexes to the given arguments.

        The cells in this view may have different number of parameters,
        but parameters shared among multiple cells
        must appear in the same position in all the parameter lists.
        For example,
        Having ``foo()``, ``bar(x)`` and ``baz(x, y=1)`` is okay
        because the shared parameter ``x`` is always the first parameter,
        but this method does not work if the view has ``quz(x, z=2, y=1)``
        cells in addition to the first three cells, because ``y`` appears
        in different positions.

        Args:
            args(optional): multiple arguments,
               or an iterator of arguments to the cells.
        """
        if sys.version_info < (3, 6, 0):
            from collections import OrderedDict

            impls = OrderedDict()
            for name, obj in self.items():
                impls[name] = obj._impl
        else:
            impls = get_impls(self)

        return _to_frame_inner(impls, args)

def to_frame ( self , * args ) : if sys . version_info < ( 3 , 6 , 0 ) : from collections import OrderedDict impls = OrderedDict ( ) for name , obj in self . items ( ) : impls [ name ] = obj . _impl else : impls = get_impls ( self ) return _to_frame_inner ( impls , args )

Convert the cells in the view into a DataFrame object .


def new_cells(self, name=None, formula=None):
        """Create a cells in the space.

        Args:
            name: If omitted, the model is named automatically ``CellsN``,
                where ``N`` is an available number.
            func: The function to define the formula of the cells.

        Returns:
            The new cells.
        """
        # Outside formulas only
        return self._impl.new_cells(name, formula).interface

def new_cells ( self , name = None , formula = None ) : return self . _impl . new_cells ( name , formula ) . interface


def import_funcs(self, module):
        """Create a cells from a module."""
        # Outside formulas only
        newcells = self._impl.new_cells_from_module(module)
        return get_interfaces(newcells)

def import_funcs ( self , module ) : newcells = self . _impl . new_cells_from_module ( module ) return get_interfaces ( newcells )


def get_object(self, name):
        """Retrieve an object by a dotted name relative to the space."""

        parts = name.split(".")
        child = parts.pop(0)

        if parts:
            return self.spaces[child].get_object(".".join(parts))
        else:
            return self._namespace_impl[child]

def get_object ( self , name ) : parts = name . split ( "." ) child = parts . pop ( 0 ) if parts : return self . spaces [ child ] . get_object ( "." . join ( parts ) ) else : return self . _namespace_impl [ child ]

Retrieve an object by a dotted name relative to the space .


def _get_dynamic_base(self, bases_):
        """Create or get the base space from a list of spaces

        if a direct base space in `bases` is dynamic, replace it with
        its base.
        """
        bases = tuple(
            base.bases[0] if base.is_dynamic() else base for base in bases_
        )

        if len(bases) == 1:
            return bases[0]

        elif len(bases) > 1:
            return self.model.get_dynamic_base(bases)

        else:
            RuntimeError("must not happen")

def
_get_dynamic_base
(
self
,
bases_
)
:
bases
=
tuple
(
base
.
bases
[
0
]
if
base
.
is_dynamic
(
)
else
base
for
base
in
bases_
)
if
len
(
bases
)
==
1
:
return
bases
[
0
]
elif
len
(
bases
)
>
1
:
return
self
.
model
.
get_dynamic_base
(
bases
)
else
:
RuntimeError
(
"must not happen"
)


def _new_dynspace(
        self,
        name=None,
        bases=None,
        formula=None,
        refs=None,
        arguments=None,
        source=None,
    ):
        """Create a new dynamic root space."""

        if name is None:
            name = self.spacenamer.get_next(self.namespace)

        if name in self.namespace:
            raise ValueError("Name '%s' already exists." % name)

        if not is_valid_name(name):
            raise ValueError("Invalid name '%s'." % name)

        space = RootDynamicSpaceImpl(
            parent=self,
            name=name,
            formula=formula,
            refs=refs,
            source=source,
            arguments=arguments,
        )
        space.is_derived = False
        self._set_space(space)

        if bases:  # i.e. not []
            dynbase = self._get_dynamic_base(bases)
            space._dynbase = dynbase
            dynbase._dynamic_subs.append(space)

        return space

def
_new_dynspace
(
self
,
name
=
,
bases
=
,
formula
=
,
refs
=
,
arguments
=
,
source
=
,
)
:
if
name
is
:
name
=
self
.
spacenamer
.
get_next
(
self
.
namespace
)
if
name
in
self
.
namespace
:
raise
ValueError
(
"Name '%s' already exists."
%
name
)
if
not
is_valid_name
(
name
)
:
raise
ValueError
(
"Invalid name '%s'."
%
name
)
space
=
RootDynamicSpaceImpl
(
parent
=
self
,
name
=
name
,
formula
=
formula
,
refs
=
refs
,
source
=
source
,
arguments
=
arguments
,
)
space
.
is_derived
=
False
self
.
_set_space
(
space
)
if
bases
:
dynbase
=
self
.
_get_dynamic_base
(
bases
)
space
.
_dynbase
=
dynbase
dynbase
.
_dynamic_subs
.
append
(
space
)
return
space


def get_dynspace(self, args, kwargs=None):
        """Create a dynamic root space

        Called from interface methods
        """

        node = get_node(self, *convert_args(args, kwargs))
        key = node[KEY]

        if key in self.param_spaces:
            return self.param_spaces[key]

        else:
            last_self = self.system.self
            self.system.self = self

            try:
                space_args = self.eval_formula(node)

            finally:
                self.system.self = last_self

            if space_args is None:
                space_args = {"bases": [self]}  # Default
            else:
                if "bases" in space_args:
                    bases = get_impls(space_args["bases"])
                    if isinstance(bases, StaticSpaceImpl):
                        space_args["bases"] = [bases]
                    elif bases is None:
                        space_args["bases"] = [self]  # Default
                    else:
                        space_args["bases"] = bases
                else:
                    space_args["bases"] = [self]

            space_args["arguments"] = node_get_args(node)
            space = self._new_dynspace(**space_args)
            self.param_spaces[key] = space
            space.inherit(clear_value=False)
            return space

def get_dynspace ( self , args , kwargs = None ) : node = get_node ( self , * convert_args ( args , kwargs ) ) key = node [ KEY ] if key in self . param_spaces : return self . param_spaces [ key ] else : last_self = self . system . self self . system . self = self try : space_args = self . eval_formula ( node ) finally : self . system . self = last_self if space_args is None : space_args = { "bases" : [ self ] } else : if "bases" in space_args : bases = get_impls ( space_args [ "bases" ] ) if isinstance ( bases , StaticSpaceImpl ) : space_args [ "bases" ] = [ bases ] elif bases is None : space_args [ "bases" ] = [ self ] else : space_args [ "bases" ] = bases else : space_args [ "bases" ] = [ self ] space_args [ "arguments" ] = node_get_args ( node ) space = self . _new_dynspace ( ** space_args ) self . param_spaces [ key ] = space space . inherit ( clear_value = False ) return space


def set_attr(self, name, value):
        """Implementation of attribute setting

        ``space.name = value`` by user script
        Called from ``Space.__setattr__``
        """
        if not is_valid_name(name):
            raise ValueError("Invalid name '%s'" % name)

        if name in self.namespace:
            if name in self.refs:
                if name in self.self_refs:
                    self.new_ref(name, value)
                else:
                    raise KeyError("Ref '%s' cannot be changed" % name)

            elif name in self.cells:
                if self.cells[name].is_scalar():
                    self.cells[name].set_value((), value)
                else:
                    raise AttributeError("Cells '%s' is not a scalar." % name)
            else:
                raise ValueError
        else:
            self.new_ref(name, value)

def
set_attr
(
self
,
name
,
value
)
:
if
not
is_valid_name
(
name
)
:
raise
ValueError
(
"Invalid name '%s'"
%
name
)
if
name
in
self
.
namespace
:
if
name
in
self
.
refs
:
if
name
in
self
.
self_refs
:
self
.
new_ref
(
name
,
value
)
else
:
raise
KeyError
(
"Ref '%s' cannot be changed"
%
name
)
elif
name
in
self
.
cells
:
if
self
.
cells
[
name
]
.
is_scalar
(
)
:
self
.
cells
[
name
]
.
set_value
(
(
)
,
value
)
else
:
raise
AttributeError
(
"Cells '%s' is not a scalar."
%
name
)
else
:
raise
ValueError
else
:
self
.
new_ref
(
name
,
value
)


def del_attr(self, name):
        """Implementation of attribute deletion

        ``del space.name`` by user script
        Called from ``StaticSpace.__delattr__``
        """
        if name in self.namespace:
            if name in self.cells:
                self.del_cells(name)
            elif name in self.spaces:
                self.del_space(name)
            elif name in self.refs:
                self.del_ref(name)
            else:
                raise RuntimeError("Must not happen")
        else:
            raise KeyError("'%s' not found in Space '%s'" % (name, self.name))

def
del_attr
(
self
,
name
)
:
if
name
in
self
.
namespace
:
if
name
in
self
.
cells
:
self
.
del_cells
(
name
)
elif
name
in
self
.
spaces
:
self
.
del_space
(
name
)
elif
name
in
self
.
refs
:
self
.
del_ref
(
name
)
else
:
raise
RuntimeError
(
"Must not happen"
)
else
:
raise
KeyError
(
"'%s' not found in Space '%s'"
%
(
name
,
self
.
name
)
)


def del_space(self, name):
        """Delete a space."""
        if name not in self.spaces:
            raise ValueError("Space '%s' does not exist" % name)

        if name in self.static_spaces:
            space = self.static_spaces[name]
            if space.is_derived:
                raise ValueError(
                    "%s has derived spaces" % repr(space.interface)
                )
            else:
                self.static_spaces.del_item(name)
                self.model.spacegraph.remove_node(space)
                self.inherit()
                self.model.spacegraph.update_subspaces(self)
                # TODO: Destroy space

        elif name in self.dynamic_spaces:
            # TODO: Destroy space
            self.dynamic_spaces.del_item(name)

        else:
            raise ValueError("Derived cells cannot be deleted")

def
del_space
(
self
,
name
)
:
if
name
not
in
self
.
spaces
:
raise
ValueError
(
"Space '%s' does not exist"
%
name
)
if
name
in
self
.
static_spaces
:
space
=
self
.
static_spaces
[
name
]
if
space
.
is_derived
:
raise
ValueError
(
"%s has derived spaces"
%
repr
(
space
.
interface
)
)
else
:
self
.
static_spaces
.
del_item
(
name
)
self
.
model
.
spacegraph
.
remove_node
(
space
)
self
.
inherit
(
)
self
.
model
.
spacegraph
.
update_subspaces
(
self
)
elif
name
in
self
.
dynamic_spaces
:
self
.
dynamic_spaces
.
del_item
(
name
)
else
:
raise
ValueError
(
"Derived cells cannot be deleted"
)


def del_cells(self, name):
        """Implementation of cells deletion

        ``del space.name`` where name is a cells, or
        ``del space.cells['name']``
        """
        if name in self.cells:
            cells = self.cells[name]
            self.cells.del_item(name)
            self.inherit()
            self.model.spacegraph.update_subspaces(self)

        elif name in self.dynamic_spaces:
            cells = self.dynamic_spaces.pop(name)
            self.dynamic_spaces.set_update()

        else:
            raise KeyError("Cells '%s' does not exist" % name)

        NullImpl(cells)

def
del_cells
(
self
,
name
)
:
if
name
in
self
.
cells
:
cells
=
self
.
cells
[
name
]
self
.
cells
.
del_item
(
name
)
self
.
inherit
(
)
self
.
model
.
spacegraph
.
update_subspaces
(
self
)
elif
name
in
self
.
dynamic_spaces
:
cells
=
self
.
dynamic_spaces
.
pop
(
name
)
self
.
dynamic_spaces
.
set_update
(
)
else
:
raise
KeyError
(
"Cells '%s' does not exist"
%
name
)
NullImpl
(
cells
)


def cellsiter_to_dataframe(cellsiter, args, drop_allna=True):
    """Convert multiple cells to a frame.

    If args is an empty sequence, all values are included.
    If args is specified, cellsiter must have shareable parameters.

    Args:
        cellsiter: A mapping from cells names to CellsImpl objects.
        args: A sequence of arguments
    """
    from modelx.core.cells import shareable_parameters

    if len(args):
        indexes = shareable_parameters(cellsiter)
    else:
        indexes = get_all_params(cellsiter.values())

    result = None

    for cells in cellsiter.values():
        df = cells_to_dataframe(cells, args)

        if drop_allna and df.isnull().all().all():
            continue  #  Ignore all NA or empty

        if df.index.names != [None]:
            if isinstance(df.index, pd.MultiIndex):
                if _pd_ver < (0, 20):
                    df = _reset_naindex(df)

            df = df.reset_index()

        missing_params = set(indexes) - set(df)

        for params in missing_params:
            df[params] = np.nan

        if result is None:
            result = df
        else:
            try:
                result = pd.merge(result, df, how="outer")
            except MergeError:
                # When no common column exists, i.e. all cells are scalars.
                result = pd.concat([result, df], axis=1)
            except ValueError:
                # When common columns are not coercible (numeric vs object),
                # Make the numeric column object type
                cols = set(result.columns) & set(df.columns)
                for col in cols:

                    # When only either of them has object dtype
                    if (
                        len(
                            [
                                str(frame[col].dtype)
                                for frame in (result, df)
                                if str(frame[col].dtype) == "object"
                            ]
                        )
                        == 1
                    ):

                        if str(result[col].dtype) == "object":
                            frame = df
                        else:
                            frame = result
                        frame[[col]] = frame[col].astype("object")

                # Try again
                result = pd.merge(result, df, how="outer")

    if result is None:
        return pd.DataFrame()
    else:
        return result.set_index(indexes) if indexes else result

def cellsiter_to_dataframe ( cellsiter , args , drop_allna = True ) : from modelx . core . cells import shareable_parameters if len ( args ) : indexes = shareable_parameters ( cellsiter ) else : indexes = get_all_params ( cellsiter . values ( ) ) result = None for cells in cellsiter . values ( ) : df = cells_to_dataframe ( cells , args ) if drop_allna and df . isnull ( ) . all ( ) . all ( ) : continue if df . index . names != [ None ] : if isinstance ( df . index , pd . MultiIndex ) : if _pd_ver < ( 0 , 20 ) : df = _reset_naindex ( df ) df = df . reset_index ( ) missing_params = set ( indexes ) - set ( df ) for params in missing_params : df [ params ] = np . nan if result is None : result = df else : try : result = pd . merge ( result , df , how = "outer" ) except MergeError : result = pd . concat ( [ result , df ] , axis = 1 ) except ValueError : cols = set ( result . columns ) & set ( df . columns ) for col in cols : if ( len ( [ str ( frame [ col ] . dtype ) for frame in ( result , df ) if str ( frame [ col ] . dtype ) == "object" ] ) == 1 ) : if str ( result [ col ] . dtype ) == "object" : frame = df else : frame = result frame [ [ col ] ] = frame [ col ] . astype ( "object" ) result = pd . merge ( result , df , how = "outer" ) if result is None : return pd . DataFrame ( ) else : return result . set_index ( indexes ) if indexes else result


def cells_to_series(cells, args):
    """Convert a CellImpl into a Series.

    `args` must be a sequence of argkeys.

    `args` can be longer or shorter then the number of cell's parameters.
    If shorter, then defaults are filled if any, else raise error.
    If longer, then redundant args are ignored.
    """

    paramlen = len(cells.formula.parameters)
    is_multidx = paramlen > 1

    if len(cells.data) == 0:
        data = {}
        indexes = None

    elif paramlen == 0:  # Const Cells
        data = list(cells.data.values())
        indexes = [np.nan]

    else:

        if len(args) > 0:
            defaults = tuple(
                param.default
                for param in cells.formula.signature.parameters.values()
            )
            updated_args = []
            for arg in args:

                if len(arg) > paramlen:
                    arg = arg[:paramlen]
                elif len(arg) < paramlen:
                    arg += defaults[len(arg) :]

                updated_args.append(arg)

            items = [
                (arg, cells.data[arg])
                for arg in updated_args
                if arg in cells.data
            ]
        else:
            items = [(key, value) for key, value in cells.data.items()]

        if not is_multidx:  # Peel 1-element tuple
            items = [(key[0], value) for key, value in items]

        if len(items) == 0:
            indexes, data = None, {}
        else:
            indexes, data = zip(*items)
            if is_multidx:
                indexes = pd.MultiIndex.from_tuples(indexes)

    result = pd.Series(data=data, name=cells.name, index=indexes)

    if indexes is not None and any(i is not np.nan for i in indexes):
        result.index.names = list(cells.formula.parameters)

    return result

def cells_to_series ( cells , args ) : paramlen = len ( cells . formula . parameters ) is_multidx = paramlen > 1 if len ( cells . data ) == 0 : data = { } indexes = None elif paramlen == 0 : data = list ( cells . data . values ( ) ) indexes = [ np . nan ] else : if len ( args ) > 0 : defaults = tuple ( param . default for param in cells . formula . signature . parameters . values ( ) ) updated_args = [ ] for arg in args : if len ( arg ) > paramlen : arg = arg [ : paramlen ] elif len ( arg ) < paramlen : arg += defaults [ len ( arg ) : ] updated_args . append ( arg ) items = [ ( arg , cells . data [ arg ] ) for arg in updated_args if arg in cells . data ] else : items = [ ( key , value ) for key , value in cells . data . items ( ) ] if not is_multidx : items = [ ( key [ 0 ] , value ) for key , value in items ] if len ( items ) == 0 : indexes , data = None , { } else : indexes , data = zip ( * items ) if is_multidx : indexes = pd . MultiIndex . from_tuples ( indexes ) result = pd . Series ( data = data , name = cells . name , index = indexes ) if indexes is not None and any ( i is not np . nan for i in indexes ) : result . index . names = list ( cells . formula . parameters ) return result


def clear_obj(self, obj):
        """"Remove all nodes with `obj` and their descendants."""
        obj_nodes = self.get_nodes_with(obj)
        removed = set()
        for node in obj_nodes:
            if self.has_node(node):
                removed.update(self.clear_descendants(node))
        return removed

def clear_obj ( self , obj ) : obj_nodes = self . get_nodes_with ( obj ) removed = set ( ) for node in obj_nodes : if self . has_node ( node ) : removed . update ( self . clear_descendants ( node ) ) return removed

Remove all nodes with obj and their descendants .


def get_nodes_with(self, obj):
        """Return nodes with `obj`."""
        result = set()

        if nx.__version__[0] == "1":
            nodes = self.nodes_iter()
        else:
            nodes = self.nodes

        for node in nodes:
            if node[OBJ] == obj:
                result.add(node)
        return result

def get_nodes_with ( self , obj ) : result = set ( ) if nx . __version__ [ 0 ] == "1" : nodes = self . nodes_iter ( ) else : nodes = self . nodes for node in nodes : if node [ OBJ ] == obj : result . add ( node ) return result


def add_path(self, nodes, **attr):
        """In replacement for Deprecated add_path method"""
        if nx.__version__[0] == "1":
            return super().add_path(nodes, **attr)
        else:
            return nx.add_path(self, nodes, **attr)

def add_path ( self , nodes , ** attr ) : if nx . __version__ [ 0 ] == "1" : return super ( ) . add_path ( nodes , ** attr ) else : return nx . add_path ( self , nodes , ** attr )


def rename(self, name):
        """Rename the model itself"""
        self._impl.system.rename_model(new_name=name, old_name=self.name)

def rename ( self , name ) : self . _impl . system . rename_model ( new_name = name , old_name = self . name )


def rename(self, name):
        """Rename self. Must be called only by its system."""
        if is_valid_name(name):
            if name not in self.system.models:
                self.name = name
                return True  # Rename success
            else:  # Model name already exists
                return False
        else:
            raise ValueError("Invalid name '%s'." % name)

def
rename
(
self
,
name
)
:
if
is_valid_name
(
name
)
:
if
name
not
in
self
.
system
.
models
:
self
.
name
=
name
return
True
else
:
return
False
else
:
raise
ValueError
(
"Invalid name '%s'."
%
name
)

Rename self . Must be called only by its system .


def clear_descendants(self, source, clear_source=True):
        """Clear values and nodes calculated from `source`."""
        removed = self.cellgraph.clear_descendants(source, clear_source)
        for node in removed:
            del node[OBJ].data[node[KEY]]

def clear_descendants ( self , source , clear_source = True ) : removed = self . cellgraph . clear_descendants ( source , clear_source ) for node in removed : del node [ OBJ ] . data [ node [ KEY ] ]

Clear values and nodes calculated from source .


def clear_obj(self, obj):
        """Clear values and nodes of `obj` and their dependants."""
        removed = self.cellgraph.clear_obj(obj)
        for node in removed:
            del node[OBJ].data[node[KEY]]

def clear_obj ( self , obj ) : removed = self . cellgraph . clear_obj ( obj ) for node in removed : del node [ OBJ ] . data [ node [ KEY ] ]

Clear values and nodes of obj and their dependants .


def get_object(self, name):
        """Retrieve an object by a dotted name relative to the model."""
        parts = name.split(".")
        space = self.spaces[parts.pop(0)]
        if parts:
            return space.get_object(".".join(parts))
        else:
            return space

def get_object ( self , name ) : parts = name . split ( "." ) space = self . spaces [ parts . pop ( 0 ) ] if parts : return space . get_object ( "." . join ( parts ) ) else : return space

Retrieve an object by a dotted name relative to the model .


def get_dynamic_base(self, bases: tuple):
        """Create of get a base space for a tuple of bases"""

        try:
            return self._dynamic_bases_inverse[bases]
        except KeyError:
            name = self._dynamic_base_namer.get_next(self._dynamic_bases)
            base = self._new_space(name=name)
            self.spacegraph.add_space(base)
            self._dynamic_bases[name] = base
            self._dynamic_bases_inverse[bases] = base
            base.add_bases(bases)
            return base

def get_dynamic_base ( self , bases : tuple ) : try : return self . _dynamic_bases_inverse [ bases ] except KeyError : name = self . _dynamic_base_namer . get_next ( self . _dynamic_bases ) base = self . _new_space ( name = name ) self . spacegraph . add_space ( base ) self . _dynamic_bases [ name ] = base self . _dynamic_bases_inverse [ bases ] = base base . add_bases ( bases ) return base


def check_mro(self, bases):
        """Check if C3 MRO is possible with given bases"""

        try:
            self.add_node("temp")
            for base in bases:
                nx.DiGraph.add_edge(self, base, "temp")
            result = self.get_mro("temp")[1:]

        finally:
            self.remove_node("temp")

        return result

def check_mro ( self , bases ) : try : self . add_node ( "temp" ) for base in bases : nx . DiGraph . add_edge ( self , base , "temp" ) result = self . get_mro ( "temp" ) [ 1 : ] finally : self . remove_node ( "temp" ) return result


def get_command_names():
    """
    Returns a list of command names supported
    """
    ret = []
    for f in os.listdir(COMMAND_MODULE_PATH):
        if os.path.isfile(os.path.join(COMMAND_MODULE_PATH, f)) and f.endswith(COMMAND_MODULE_SUFFIX):
            ret.append(f[:-len(COMMAND_MODULE_SUFFIX)])
    return ret

def get_command_names ( ) : ret = [ ] for f in os . listdir ( COMMAND_MODULE_PATH ) : if os . path . isfile ( os . path . join ( COMMAND_MODULE_PATH , f ) ) and f . endswith ( COMMAND_MODULE_SUFFIX ) : ret . append ( f [ : - len ( COMMAND_MODULE_SUFFIX ) ] ) return ret


def get(vals, key, default_val=None):
    """
    Returns a dictionary value
    """
    val = vals
    for part in key.split('.'):
        if isinstance(val, dict):
            val = val.get(part, None)
            if val is None:
                return default_val
        else:
            return default_val
    return val

def get ( vals , key , default_val = None ) : val = vals for part in key . split ( '.' ) : if isinstance ( val , dict ) : val = val . get ( part , None ) if val is None : return default_val else : return default_val return val


def parse_option_settings(option_settings):
    """
    Parses option_settings as they are defined in the configuration file
    """
    ret = []
    for namespace, params in list(option_settings.items()):
        for key, value in list(params.items()):
            ret.append((namespace, key, value))
    return ret

def parse_option_settings ( option_settings ) : ret = [ ] for namespace , params in list ( option_settings . items ( ) ) : for key , value in list ( params . items ( ) ) : ret . append ( ( namespace , key , value ) ) return ret


def parse_env_config(config, env_name):
    """
    Parses an environment config
    """
    all_env = get(config, 'app.all_environments', {})
    env = get(config, 'app.environments.' + str(env_name), {})
    return merge_dict(all_env, env)

def parse_env_config ( config , env_name ) : all_env = get ( config , 'app.all_environments' , { } ) env = get ( config , 'app.environments.' + str ( env_name ) , { } ) return merge_dict ( all_env , env )


def create_archive(directory, filename, config={}, ignore_predicate=None, ignored_files=['.git', '.svn']):
    """
    Creates an archive from a directory and returns
    the file that was created.
    """
    with zipfile.ZipFile(filename, 'w', compression=zipfile.ZIP_DEFLATED) as zip_file:
        root_len = len(os.path.abspath(directory))

        # create it
        out("Creating archive: " + str(filename))
        for root, dirs, files in os.walk(directory, followlinks=True):
            archive_root = os.path.abspath(root)[root_len + 1:]
            for f in files:
                fullpath = os.path.join(root, f)
                archive_name = os.path.join(archive_root, f)

                # ignore the file we're creating
                if filename in fullpath:
                    continue

                # ignored files
                if ignored_files is not None:
                    for name in ignored_files:
                        if fullpath.endswith(name):
                            out("Skipping: " + str(name))
                            continue

                # do predicate
                if ignore_predicate is not None:
                    if not ignore_predicate(archive_name):
                        out("Skipping: " + str(archive_name))
                        continue

                out("Adding: " + str(archive_name))
                zip_file.write(fullpath, archive_name, zipfile.ZIP_DEFLATED)

    return filename

def
create_archive
(
directory
,
filename
,
config
=
{
}
,
ignore_predicate
=
,
ignored_files
=
[
'.git'
,
'.svn'
]
)
:
with
zipfile
.
ZipFile
(
filename
,
'w'
,
compression
=
zipfile
.
ZIP_DEFLATED
)
as
zip_file
:
root_len
=
len
(
os
.
path
.
abspath
(
directory
)
)
out
(
"Creating archive: "
+
str
(
filename
)
)
for
root
,
dirs
,
files
in
os
.
walk
(
directory
,
followlinks
=
True
)
:
archive_root
=
os
.
path
.
abspath
(
root
)
[
root_len
+
1
:
]
for
f
in
files
:
fullpath
=
os
.
path
.
join
(
root
,
f
)
archive_name
=
os
.
path
.
join
(
archive_root
,
f
)
if
filename
in
fullpath
:
continue
if
ignored_files
is
not
:
for
name
in
ignored_files
:
if
fullpath
.
endswith
(
name
)
:
out
(
"Skipping: "
+
str
(
name
)
)
continue
if
ignore_predicate
is
not
:
if
not
ignore_predicate
(
archive_name
)
:
out
(
"Skipping: "
+
str
(
archive_name
)
)
continue
out
(
"Adding: "
+
str
(
archive_name
)
)
zip_file
.
write
(
fullpath
,
archive_name
,
zipfile
.
ZIP_DEFLATED
)
return
filename

Creates an archive from a directory and returns the file that was created .


def add_config_files_to_archive(directory, filename, config={}):
    """
    Adds configuration files to an existing archive
    """
    with zipfile.ZipFile(filename, 'a') as zip_file:
        for conf in config:
            for conf, tree in list(conf.items()):
                if 'yaml' in tree:
                    content = yaml.dump(tree['yaml'], default_flow_style=False)
                else:
                    content = tree.get('content', '')
                out("Adding file " + str(conf) + " to archive " + str(filename))
                file_entry = zipfile.ZipInfo(conf)
                file_entry.external_attr = tree.get('permissions', 0o644) << 16
                zip_file.writestr(file_entry, content)

    return filename

def
add_config_files_to_archive
(
directory
,
filename
,
config
=
{
}
)
:
with
zipfile
.
ZipFile
(
filename
,
'a'
)
as
zip_file
:
for
conf
in
config
:
for
conf
,
tree
in
list
(
conf
.
items
(
)
)
:
if
'yaml'
in
tree
:
content
=
yaml
.
dump
(
tree
[
'yaml'
]
,
default_flow_style
=
False
)
else
:
content
=
tree
.
get
(
'content'
,
''
)
out
(
"Adding file "
+
str
(
conf
)
+
" to archive "
+
str
(
filename
)
)
file_entry
=
zipfile
.
ZipInfo
(
conf
)
file_entry
.
external_attr
=
tree
.
get
(
'permissions'
,
0o644
)
<<
16
zip_file
.
writestr
(
file_entry
,
content
)
return
filename


def swap_environment_cnames(self, from_env_name, to_env_name):
        """
        Swaps cnames for an environment
        """
        self.ebs.swap_environment_cnames(source_environment_name=from_env_name,
                                         destination_environment_name=to_env_name)

def swap_environment_cnames ( self , from_env_name , to_env_name ) : self . ebs . swap_environment_cnames ( source_environment_name = from_env_name , destination_environment_name = to_env_name )


def upload_archive(self, filename, key, auto_create_bucket=True):
        """
        Uploads an application archive version to s3
        """
        try:
            bucket = self.s3.get_bucket(self.aws.bucket)
            if ((
                  self.aws.region != 'us-east-1' and self.aws.region != 'eu-west-1') and bucket.get_location() != self.aws.region) or (
                  self.aws.region == 'us-east-1' and bucket.get_location() != '') or (
                  self.aws.region == 'eu-west-1' and bucket.get_location() != 'eu-west-1'):
                raise Exception("Existing bucket doesn't match region")
        except S3ResponseError:
            bucket = self.s3.create_bucket(self.aws.bucket, location=self.aws.region)

        def __report_upload_progress(sent, total):
            if not sent:
                sent = 0
            if not total:
                total = 0
            out("Uploaded " + str(sent) + " bytes of " + str(total) \
                + " (" + str(int(float(max(1, sent)) / float(total) * 100)) + "%)")

        # upload the new version
        k = Key(bucket)
        k.key = self.aws.bucket_path + key
        k.set_metadata('time', str(time()))
        k.set_contents_from_filename(filename, cb=__report_upload_progress, num_cb=10)

def
upload_archive
(
self
,
filename
,
key
,
auto_create_bucket
=
True
)
:
try
:
bucket
=
self
.
s3
.
get_bucket
(
self
.
aws
.
bucket
)
if
(
(
self
.
aws
.
region
!=
'us-east-1'
and
self
.
aws
.
region
!=
'eu-west-1'
)
and
bucket
.
get_location
(
)
!=
self
.
aws
.
region
)
or
(
self
.
aws
.
region
==
'us-east-1'
and
bucket
.
get_location
(
)
!=
''
)
or
(
self
.
aws
.
region
==
'eu-west-1'
and
bucket
.
get_location
(
)
!=
'eu-west-1'
)
:
raise
Exception
(
"Existing bucket doesn't match region"
)
except
S3ResponseError
:
bucket
=
self
.
s3
.
create_bucket
(
self
.
aws
.
bucket
,
location
=
self
.
aws
.
region
)
def
__report_upload_progress
(
sent
,
total
)
:
if
not
sent
:
sent
=
0
if
not
total
:
total
=
0
out
(
"Uploaded "
+
str
(
sent
)
+
" bytes of "
+
str
(
total
)
+
" ("
+
str
(
int
(
float
(
max
(
1
,
sent
)
)
/
float
(
total
)
*
100
)
)
+
"%)"
)
k
=
Key
(
bucket
)
k
.
key
=
self
.
aws
.
bucket_path
+
key
k
.
set_metadata
(
'time'
,
str
(
time
(
)
)
)
k
.
set_contents_from_filename
(
filename
,
cb
=
__report_upload_progress
,
num_cb
=
10
)


def application_exists(self):
        """
        Returns whether or not the given app_name exists
        """
        response = self.ebs.describe_applications(application_names=[self.app_name])
        return len(response['DescribeApplicationsResponse']['DescribeApplicationsResult']['Applications']) > 0

def application_exists ( self ) : response = self . ebs . describe_applications ( application_names = [ self . app_name ] ) return len ( response [ 'DescribeApplicationsResponse' ] [ 'DescribeApplicationsResult' ] [ 'Applications' ] ) > 0


def create_environment(self, env_name, version_label=None,
                           solution_stack_name=None, cname_prefix=None, description=None,
                           option_settings=None, tier_name='WebServer', tier_type='Standard', tier_version='1.1'):
        """
        Creates a new environment
        """
        out("Creating environment: " + str(env_name) + ", tier_name:" + str(tier_name) + ", tier_type:" + str(tier_type))
        self.ebs.create_environment(self.app_name, env_name,
                                    version_label=version_label,
                                    solution_stack_name=solution_stack_name,
                                    cname_prefix=cname_prefix,
                                    description=description,
                                    option_settings=option_settings,
                                    tier_type=tier_type,
                                    tier_name=tier_name,
                                    tier_version=tier_version)

def
create_environment
(
self
,
env_name
,
version_label
=
,
solution_stack_name
=
,
cname_prefix
=
,
description
=
,
option_settings
=
,
tier_name
=
'WebServer'
,
tier_type
=
'Standard'
,
tier_version
=
'1.1'
)
:
out
(
"Creating environment: "
+
str
(
env_name
)
+
", tier_name:"
+
str
(
tier_name
)
+
", tier_type:"
+
str
(
tier_type
)
)
self
.
ebs
.
create_environment
(
self
.
app_name
,
env_name
,
version_label
=
version_label
,
solution_stack_name
=
solution_stack_name
,
cname_prefix
=
cname_prefix
,
description
=
description
,
option_settings
=
option_settings
,
tier_type
=
tier_type
,
tier_name
=
tier_name
,
tier_version
=
tier_version
)


def environment_exists(self, env_name):
        """
        Returns whether or not the given environment exists
        """
        response = self.ebs.describe_environments(application_name=self.app_name, environment_names=[env_name],
                                                  include_deleted=False)
        return len(response['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments']) > 0 \
               and response['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'][0][
                       'Status'] != 'Terminated'

def environment_exists ( self , env_name ) : response = self . ebs . describe_environments ( application_name = self . app_name , environment_names = [ env_name ] , include_deleted = False ) return len ( response [ 'DescribeEnvironmentsResponse' ] [ 'DescribeEnvironmentsResult' ] [ 'Environments' ] ) > 0 and response [ 'DescribeEnvironmentsResponse' ] [ 'DescribeEnvironmentsResult' ] [ 'Environments' ] [ 0 ] [ 'Status' ] != 'Terminated'


def get_environments(self):
        """
        Returns the environments
        """
        response = self.ebs.describe_environments(application_name=self.app_name, include_deleted=False)
        return response['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments']

def get_environments ( self ) : response = self . ebs . describe_environments ( application_name = self . app_name , include_deleted = False ) return response [ 'DescribeEnvironmentsResponse' ] [ 'DescribeEnvironmentsResult' ] [ 'Environments' ]


def update_environment(self, environment_name, description=None, option_settings=[], tier_type=None, tier_name=None,
                           tier_version='1.0'):
        """
        Updates an application version
        """
        out("Updating environment: " + str(environment_name))
        messages = self.ebs.validate_configuration_settings(self.app_name, option_settings,
                                                            environment_name=environment_name)
        messages = messages['ValidateConfigurationSettingsResponse']['ValidateConfigurationSettingsResult']['Messages']
        ok = True
        for message in messages:
            if message['Severity'] == 'error':
                ok = False
            out("[" + message['Severity'] + "] " + str(environment_name) + " - '" \
                + message['Namespace'] + ":" + message['OptionName'] + "': " + message['Message'])
        self.ebs.update_environment(
            environment_name=environment_name,
            description=description,
            option_settings=option_settings,
            tier_type=tier_type,
            tier_name=tier_name,
            tier_version=tier_version)

def
update_environment
(
self
,
environment_name
,
description
=
,
option_settings
=
[
]
,
tier_type
=
,
tier_name
=
,
tier_version
=
'1.0'
)
:
out
(
"Updating environment: "
+
str
(
environment_name
)
)
messages
=
self
.
ebs
.
validate_configuration_settings
(
self
.
app_name
,
option_settings
,
environment_name
=
environment_name
)
messages
=
messages
[
'ValidateConfigurationSettingsResponse'
]
[
'ValidateConfigurationSettingsResult'
]
[
'Messages'
]
ok
=
True
for
message
in
messages
:
if
message
[
'Severity'
]
==
'error'
:
ok
=
False
out
(
"["
+
message
[
'Severity'
]
+
"] "
+
str
(
environment_name
)
+
" - '"
+
message
[
'Namespace'
]
+
":"
+
message
[
'OptionName'
]
+
"': "
+
message
[
'Message'
]
)
self
.
ebs
.
update_environment
(
environment_name
=
environment_name
,
description
=
description
,
option_settings
=
option_settings
,
tier_type
=
tier_type
,
tier_name
=
tier_name
,
tier_version
=
tier_version
)


def environment_name_for_cname(self, env_cname):
        """
        Returns an environment name for the given cname
        """
        envs = self.get_environments()
        for env in envs:
            if env['Status'] != 'Terminated' \
                and 'CNAME' in env \
                and env['CNAME'] \
                and env['CNAME'].lower().startswith(env_cname.lower() + '.'):
                return env['EnvironmentName']
        return None

def environment_name_for_cname ( self , env_cname ) : envs = self . get_environments ( ) for env in envs : if env [ 'Status' ] != 'Terminated' and 'CNAME' in env and env [ 'CNAME' ] and env [ 'CNAME' ] . lower ( ) . startswith ( env_cname . lower ( ) + '.' ) : return env [ 'EnvironmentName' ] return None


def deploy_version(self, environment_name, version_label):
        """
        Deploys a version to an environment
        """
        out("Deploying " + str(version_label) + " to " + str(environment_name))
        self.ebs.update_environment(environment_name=environment_name, version_label=version_label)

def
deploy_version
(
self
,
environment_name
,
version_label
)
:
out
(
"Deploying "
+
str
(
version_label
)
+
" to "
+
str
(
environment_name
)
)
self
.
ebs
.
update_environment
(
environment_name
=
environment_name
,
version_label
=
version_label
)


def get_versions(self):
        """
        Returns the versions available
        """
        response = self.ebs.describe_application_versions(application_name=self.app_name)
        return response['DescribeApplicationVersionsResponse']['DescribeApplicationVersionsResult']['ApplicationVersions']

def get_versions ( self ) : response = self . ebs . describe_application_versions ( application_name = self . app_name ) return response [ 'DescribeApplicationVersionsResponse' ] [ 'DescribeApplicationVersionsResult' ] [ 'ApplicationVersions' ]


def create_application_version(self, version_label, key):
        """
        Creates an application version
        """
        out("Creating application version " + str(version_label) + " for " + str(key))
        self.ebs.create_application_version(self.app_name, version_label,
                                            s3_bucket=self.aws.bucket, s3_key=self.aws.bucket_path+key)

def
create_application_version
(
self
,
version_label
,
key
)
:
out
(
"Creating application version "
+
str
(
version_label
)
+
" for "
+
str
(
key
)
)
self
.
ebs
.
create_application_version
(
self
.
app_name
,
version_label
,
s3_bucket
=
self
.
aws
.
bucket
,
s3_key
=
self
.
aws
.
bucket_path
+
key
)


def delete_unused_versions(self, versions_to_keep=10):
        """
        Deletes unused versions
        """

        # get versions in use
        environments = self.ebs.describe_environments(application_name=self.app_name, include_deleted=False)
        environments = environments['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments']
        versions_in_use = []
        for env in environments:
            versions_in_use.append(env['VersionLabel'])

        # get all versions
        versions = self.ebs.describe_application_versions(application_name=self.app_name)
        versions = versions['DescribeApplicationVersionsResponse']['DescribeApplicationVersionsResult'][
            'ApplicationVersions']
        versions = sorted(versions, reverse=True, key=functools.cmp_to_key(lambda x, y: (x['DateCreated'] > y['DateCreated']) - (x['DateCreated'] < y['DateCreated'])))

        # delete versions in use
        for version in versions[versions_to_keep:]:
            if version['VersionLabel'] in versions_in_use:
                out("Not deleting " + version["VersionLabel"] + " because it is in use")
            else:
                out("Deleting unused version: " + version["VersionLabel"])
                self.ebs.delete_application_version(application_name=self.app_name,
                                                    version_label=version['VersionLabel'])
                sleep(2)

def
delete_unused_versions
(
self
,
versions_to_keep
=
10
)
:
environments
=
self
.
ebs
.
describe_environments
(
application_name
=
self
.
app_name
,
include_deleted
=
False
)
environments
=
environments
[
'DescribeEnvironmentsResponse'
]
[
'DescribeEnvironmentsResult'
]
[
'Environments'
]
versions_in_use
=
[
]
for
env
in
environments
:
versions_in_use
.
append
(
env
[
'VersionLabel'
]
)
versions
=
self
.
ebs
.
describe_application_versions
(
application_name
=
self
.
app_name
)
versions
=
versions
[
'DescribeApplicationVersionsResponse'
]
[
'DescribeApplicationVersionsResult'
]
[
'ApplicationVersions'
]
versions
=
sorted
(
versions
,
reverse
=
True
,
key
=
functools
.
cmp_to_key
(
lambda
x
,
y
:
(
x
[
'DateCreated'
]
>
y
[
'DateCreated'
]
)
(
x
[
'DateCreated'
]
<
y
[
'DateCreated'
]
)
)
)
for
version
in
versions
[
versions_to_keep
:
]
:
if
version
[
'VersionLabel'
]
in
versions_in_use
:
out
(
"Not deleting "
+
version
[
"VersionLabel"
]
+
" because it is in use"
)
else
:
out
(
"Deleting unused version: "
+
version
[
"VersionLabel"
]
)
self
.
ebs
.
delete_application_version
(
application_name
=
self
.
app_name
,
version_label
=
version
[
'VersionLabel'
]
)
sleep
(
2
)


def describe_events(self, environment_name, next_token=None, start_time=None):
        """
        Describes events from the given environment
        """
        events = self.ebs.describe_events(
            application_name=self.app_name,
            environment_name=environment_name,
            next_token=next_token,
            start_time=start_time + 'Z')

        return (events['DescribeEventsResponse']['DescribeEventsResult']['Events'], events['DescribeEventsResponse']['DescribeEventsResult']['NextToken'])

def describe_events ( self , environment_name , next_token = None , start_time = None ) : events = self . ebs . describe_events ( application_name = self . app_name , environment_name = environment_name , next_token = next_token , start_time = start_time + 'Z' ) return ( events [ 'DescribeEventsResponse' ] [ 'DescribeEventsResult' ] [ 'Events' ] , events [ 'DescribeEventsResponse' ] [ 'DescribeEventsResult' ] [ 'NextToken' ] )


def add_arguments(parser):
    """
    adds arguments for the swap urls command
    """
    parser.add_argument('-o', '--old-environment', help='Old environment name', required=True)
    parser.add_argument('-n', '--new-environment', help='New environment name', required=True)

def
add_arguments
(
parser
)
:
parser
.
add_argument
(
'-o'
,
'--old-environment'
,
help
=
'Old environment name'
,
required
=
True
)
parser
.
add_argument
(
'-n'
,
'--new-environment'
,
help
=
'New environment name'
,
required
=
True
)


def execute(helper, config, args):
    """
    Swaps old and new URLs.
    If old_environment was active, new_environment will become the active environment
    """
    old_env_name = args.old_environment
    new_env_name = args.new_environment

    # swap C-Names
    out("Assuming that {} is the currently active environment...".format(old_env_name))
    out("Swapping environment cnames: {} will become active, {} will become inactive.".format(new_env_name,
                                                                                old_env_name))
    helper.swap_environment_cnames(old_env_name, new_env_name)
    helper.wait_for_environments([old_env_name, new_env_name], status='Ready', include_deleted=False)

Swaps old and new URLs . If old_environment was active new_environment will become the active environment


def execute(helper, config, args):
    """
    dump command dumps things
    """
    env = parse_env_config(config, args.environment)
    option_settings = env.get('option_settings', {})
    settings = parse_option_settings(option_settings)
    for setting in settings:
        out(str(setting))

def execute ( helper , config , args ) : env = parse_env_config ( config , args . environment ) option_settings = env . get ( 'option_settings' , { } ) settings = parse_option_settings ( option_settings ) for setting in settings : out ( str ( setting ) )


def execute(helper, config, args):
    """
    The init command
    """

    # check to see if the application exists
    if not helper.application_exists():
        helper.create_application(get(config, 'app.description'))
    else:
        out("Application "+get(config, 'app.app_name')+" exists")

    # create environments
    environment_names = []
    environments_to_wait_for_green = []
    for env_name, env_config in list(get(config, 'app.environments').items()):
        environment_names.append(env_name)
        env_config = parse_env_config(config, env_name)
        if not helper.environment_exists(env_name):
            option_settings = parse_option_settings(env_config.get('option_settings', {}))
            helper.create_environment(env_name,
                solution_stack_name=env_config.get('solution_stack_name'),
                cname_prefix=env_config.get('cname_prefix', None),
                description=env_config.get('description', None),
                option_settings=option_settings,
                tier_name=env_config.get('tier_name'),
                tier_type=env_config.get('tier_type'),
                tier_version=env_config.get('tier_version'),
                version_label=args.version_label)
            environments_to_wait_for_green.append(env_name)
        else:
            out("Environment "+env_name)

    # get the environments
    environments_to_wait_for_term = []
    if args.delete:
        environments = helper.get_environments()
        for env in environments:
            if env['EnvironmentName'] not in environment_names:
                if env['Status'] != 'Ready':
                    out("Unable to delete "+env['EnvironmentName']+" because it's not in status Ready ("+env['Status']+")")
                else:
                    out("Deleting environment: "+env['EnvironmentName'])
                    helper.delete_environment(env['EnvironmentName'])
                    environments_to_wait_for_term.append(env['EnvironmentName'])

    # wait
    if not args.dont_wait and len(environments_to_wait_for_green)>0:
        helper.wait_for_environments(environments_to_wait_for_green, status='Ready', include_deleted=False)
    if not args.dont_wait and len(environments_to_wait_for_term)>0:
        helper.wait_for_environments(environments_to_wait_for_term, status='Terminated', include_deleted=False)

    out("Application initialized")
    return 0

def
execute
(
helper
,
config
,
args
)
:
if
not
helper
.
application_exists
(
)
:
helper
.
create_application
(
get
(
config
,
'app.description'
)
)
else
:
out
(
"Application "
+
get
(
config
,
'app.app_name'
)
+
" exists"
)
environment_names
=
[
]
environments_to_wait_for_green
=
[
]
for
env_name
,
env_config
in
list
(
get
(
config
,
'app.environments'
)
.
items
(
)
)
:
environment_names
.
append
(
env_name
)
env_config
=
parse_env_config
(
config
,
env_name
)
if
not
helper
.
environment_exists
(
env_name
)
:
option_settings
=
parse_option_settings
(
env_config
.
get
(
'option_settings'
,
{
}
)
)
helper
.
create_environment
(
env_name
,
solution_stack_name
=
env_config
.
get
(
'solution_stack_name'
)
,
cname_prefix
=
env_config
.
get
(
'cname_prefix'
,
)
,
description
=
env_config
.
get
(
'description'
,
)
,
option_settings
=
option_settings
,
tier_name
=
env_config
.
get
(
'tier_name'
)
,
tier_type
=
env_config
.
get
(
'tier_type'
)
,
tier_version
=
env_config
.
get
(
'tier_version'
)
,
version_label
=
args
.
version_label
)
environments_to_wait_for_green
.
append
(
env_name
)
else
:
out
(
"Environment "
+
env_name
)
environments_to_wait_for_term
=
[
]
if
args
.
delete
:
environments
=
helper
.
get_environments
(
)
for
env
in
environments
:
if
env
[
'EnvironmentName'
]
not
in
environment_names
:
if
env
[
'Status'
]
!=
'Ready'
:
out
(
"Unable to delete "
+
env
[
'EnvironmentName'
]
+
" because it's not in status Ready ("
+
env
[
'Status'
]
+
")"
)
else
:
out
(
"Deleting environment: "
+
env
[
'EnvironmentName'
]
)
helper
.
delete_environment
(
env
[
'EnvironmentName'
]
)
environments_to_wait_for_term
.
append
(
env
[
'EnvironmentName'
]
)
if
not
args
.
dont_wait
and
len
(
environments_to_wait_for_green
)
>
0
:
helper
.
wait_for_environments
(
environments_to_wait_for_green
,
status
=
'Ready'
,
include_deleted
=
False
)
if
not
args
.
dont_wait
and
len
(
environments_to_wait_for_term
)
>
0
:
helper
.
wait_for_environments
(
environments_to_wait_for_term
,
status
=
'Terminated'
,
include_deleted
=
False
)
out
(
"Application initialized"
)
return
0


def join_phonemes(*args):
    """Joins a Hangul letter from Korean phonemes."""
    # Normalize arguments as onset, nucleus, coda.
    if len(args) == 1:
        # tuple of (onset, nucleus[, coda])
        args = args[0]
    if len(args) == 2:
        args += (CODAS[0],)
    try:
        onset, nucleus, coda = args
    except ValueError:
        raise TypeError('join_phonemes() takes at most 3 arguments')
    offset = (
        (ONSETS.index(onset) * NUM_NUCLEUSES + NUCLEUSES.index(nucleus)) *
        NUM_CODAS + CODAS.index(coda)
    )
    return unichr(FIRST_HANGUL_OFFSET + offset)

Joins a Hangul letter from Korean phonemes .


def execute(helper, config, args):
    """
    Waits for an environment to be healthy
    """
    helper.wait_for_environments(args.environment, health=args.health)

def execute ( helper , config , args ) : helper . wait_for_environments ( args . environment , health = args . health )


def add_arguments(parser):
    """
    Args for the init command
    """
    parser.add_argument('-e', '--environment',  help='Environment name', required=False, nargs='+')
    parser.add_argument('-w', '--dont-wait', help='Skip waiting for the app to be deleted', action='store_true')


def execute(helper, config, args):
    """
    Describes recent events for an environment.
    """
    environment_name = args.environment

    (events, next_token) = helper.describe_events(environment_name, start_time=datetime.now().isoformat())

    # swap C-Names
    for event in events:
        print(("["+event['Severity']+"] "+event['Message']))

def
execute
(
helper
,
config
,
args
)
:
environment_name
=
args
.
environment
(
events
,
next_token
)
=
helper
.
describe_events
(
environment_name
,
start_time
=
datetime
.
now
(
)
.
isoformat
(
)
)
for
event
in
events
:
print
(
(
"["
+
event
[
'Severity'
]
+
"] "
+
event
[
'Message'
]
)
)

Describes recent events for an environment .


def execute(helper, config, args):
    """
    Lists solution stacks
    """
    out("Available solution stacks")
    for stack in helper.list_available_solution_stacks():
        out("    "+str(stack))
    return 0

def
execute
(
helper
,
config
,
args
)
:
out
(
"Available solution stacks"
)
for
stack
in
helper
.
list_available_solution_stacks
(
)
:
out
(
"    "
+
str
(
stack
)
)
return
0


def pick_coda_from_letter(letter):
    """Picks only a coda from a Hangul letter.  It returns ``None`` if the
    given letter is not Hangul.
    """
    try:
        __, __, coda = \
            split_phonemes(letter, onset=False, nucleus=False, coda=True)
    except ValueError:
        return None
    else:
        return coda

def pick_coda_from_letter ( letter ) : try : __ , __ , coda = split_phonemes ( letter , onset = False , nucleus = False , coda = True ) except ValueError : return None else : return coda

Picks only a coda from a Hangul letter . It returns None if the given letter is not Hangul .


def pick_coda_from_decimal(decimal):
    """Picks only a coda from a decimal."""
    decimal = Decimal(decimal)
    __, digits, exp = decimal.as_tuple()
    if exp < 0:
        return DIGIT_CODAS[digits[-1]]
    __, digits, exp = decimal.normalize().as_tuple()
    index = bisect_right(EXP_INDICES, exp) - 1
    if index < 0:
        return DIGIT_CODAS[digits[-1]]
    else:
        return EXP_CODAS[EXP_INDICES[index]]

def pick_coda_from_decimal ( decimal ) : decimal = Decimal ( decimal ) __ , digits , exp = decimal . as_tuple ( ) if exp < 0 : return DIGIT_CODAS [ digits [ - 1 ] ] __ , digits , exp = decimal . normalize ( ) . as_tuple ( ) index = bisect_right ( EXP_INDICES , exp ) - 1 if index < 0 : return DIGIT_CODAS [ digits [ - 1 ] ] else : return EXP_CODAS [ EXP_INDICES [ index ] ]


def deposit_fetcher(record_uuid, data):
    """Fetch a deposit identifier.

    :param record_uuid: Record UUID.
    :param data: Record content.
    :returns: A :class:`invenio_pidstore.fetchers.FetchedPID` that contains
        data['_deposit']['id'] as pid_value.
    """
    return FetchedPID(
        provider=DepositProvider,
        pid_type=DepositProvider.pid_type,
        pid_value=str(data['_deposit']['id']),
    )

def deposit_fetcher ( record_uuid , data ) : return FetchedPID ( provider = DepositProvider , pid_type = DepositProvider . pid_type , pid_value = str ( data [ '_deposit' ] [ 'id' ] ) , )


def deposit_minter(record_uuid, data):
    """Mint a deposit identifier.

    A PID with the following characteristics is created:

    .. code-block:: python

        {
            "object_type": "rec",
            "object_uuid": record_uuid,
            "pid_value": "<new-pid-value>",
            "pid_type": "depid",
        }

    The following deposit meta information are updated:

    .. code-block:: python

        deposit['_deposit'] = {
            "id": "<new-pid-value>",
            "status": "draft",
        }

    :param record_uuid: Record UUID.
    :param data: Record content.
    :returns: A :class:`invenio_pidstore.models.PersistentIdentifier` object.
    """
    provider = DepositProvider.create(
        object_type='rec',
        object_uuid=record_uuid,
        pid_value=uuid.uuid4().hex,
    )
    data['_deposit'] = {
        'id': provider.pid.pid_value,
        'status': 'draft',
    }
    return provider.pid

def deposit_minter ( record_uuid , data ) : provider = DepositProvider . create ( object_type = 'rec' , object_uuid = record_uuid , pid_value = uuid . uuid4 ( ) . hex , ) data [ '_deposit' ] = { 'id' : provider . pid . pid_value , 'status' : 'draft' , } return provider . pid


def admin_permission_factory():
    """Factory for creating a permission for an admin `deposit-admin-access`.

    If `invenio-access` module is installed, it returns a
    :class:`invenio_access.permissions.DynamicPermission` object.
    Otherwise, it returns a :class:`flask_principal.Permission` object.

    :returns: Permission instance.
    """
    try:
        pkg_resources.get_distribution('invenio-access')
        from invenio_access.permissions import DynamicPermission as Permission
    except pkg_resources.DistributionNotFound:
        from flask_principal import Permission

    return Permission(action_admin_access)

def admin_permission_factory ( ) : try : pkg_resources . get_distribution ( 'invenio-access' ) from invenio_access . permissions import DynamicPermission as Permission except pkg_resources . DistributionNotFound : from flask_principal import Permission return Permission ( action_admin_access )

Factory for creating a permission for an admin deposit - admin - access .


def create_blueprint(endpoints):
    """Create Invenio-Deposit-UI blueprint.

    See: :data:`invenio_deposit.config.DEPOSIT_RECORDS_UI_ENDPOINTS`.

    :param endpoints: List of endpoints configuration.
    :returns: The configured blueprint.
    """
    from invenio_records_ui.views import create_url_rule

    blueprint = Blueprint(
        'invenio_deposit_ui',
        __name__,
        static_folder='../static',
        template_folder='../templates',
        url_prefix='',
    )

    @blueprint.errorhandler(PIDDeletedError)
    def tombstone_errorhandler(error):
        """Render tombstone page."""
        return render_template(
            current_app.config['DEPOSIT_UI_TOMBSTONE_TEMPLATE'],
            pid=error.pid,
            record=error.record or {},
        ), 410

    for endpoint, options in (endpoints or {}).items():
        options = deepcopy(options)
        options.pop('jsonschema', None)
        options.pop('schemaform', None)
        blueprint.add_url_rule(**create_url_rule(endpoint, **options))

    @blueprint.route('/deposit')
    @login_required
    def index():
        """List user deposits."""
        return render_template(current_app.config['DEPOSIT_UI_INDEX_TEMPLATE'])

    @blueprint.route('/deposit/new')
    @login_required
    def new():
        """Create new deposit."""
        deposit_type = request.values.get('type')
        return render_template(
            current_app.config['DEPOSIT_UI_NEW_TEMPLATE'],
            record={'_deposit': {'id': None}},
            jsonschema=current_deposit.jsonschemas[deposit_type],
            schemaform=current_deposit.schemaforms[deposit_type],
        )

    return blueprint

def create_blueprint ( endpoints ) : from invenio_records_ui . views import create_url_rule blueprint = Blueprint ( 'invenio_deposit_ui' , __name__ , static_folder = '../static' , template_folder = '../templates' , url_prefix = '' , ) @ blueprint . errorhandler ( PIDDeletedError ) def tombstone_errorhandler ( error ) : return render_template ( current_app . config [ 'DEPOSIT_UI_TOMBSTONE_TEMPLATE' ] , pid = error . pid , record = error . record or { } , ) , 410 for endpoint , options in ( endpoints or { } ) . items ( ) : options = deepcopy ( options ) options . pop ( 'jsonschema' , None ) options . pop ( 'schemaform' , None ) blueprint . add_url_rule ( ** create_url_rule ( endpoint , ** options ) ) @ blueprint . route ( '/deposit' ) @ login_required def index ( ) : return render_template ( current_app . config [ 'DEPOSIT_UI_INDEX_TEMPLATE' ] ) @ blueprint . route ( '/deposit/new' ) @ login_required def new ( ) : deposit_type = request . values . get ( 'type' ) return render_template ( current_app . config [ 'DEPOSIT_UI_NEW_TEMPLATE' ] , record = { '_deposit' : { 'id' : None } } , jsonschema = current_deposit . jsonschemas [ deposit_type ] , schemaform = current_deposit . schemaforms [ deposit_type ] , ) return blueprint

Create Invenio - Deposit - UI blueprint .


def default_view_method(pid, record, template=None):
    """Default view method.

    Sends ``record_viewed`` signal and renders template.
    """
    record_viewed.send(
        current_app._get_current_object(),
        pid=pid,
        record=record,
    )

    deposit_type = request.values.get('type')

    return render_template(
        template,
        pid=pid,
        record=record,
        jsonschema=current_deposit.jsonschemas[deposit_type],
        schemaform=current_deposit.schemaforms[deposit_type],
    )

def default_view_method ( pid , record , template = None ) : record_viewed . send ( current_app . _get_current_object ( ) , pid = pid , record = record , ) deposit_type = request . values . get ( 'type' ) return render_template ( template , pid = pid , record = record , jsonschema = current_deposit . jsonschemas [ deposit_type ] , schemaform = current_deposit . schemaforms [ deposit_type ] , )


def create(cls, object_type=None, object_uuid=None, **kwargs):
        """Create a new deposit identifier.

        :param object_type: The object type (Default: ``None``)
        :param object_uuid: The object UUID (Default: ``None``)
        :param kwargs: It contains the pid value.
        """
        assert 'pid_value' in kwargs
        kwargs.setdefault('status', cls.default_status)
        return super(DepositProvider, cls).create(
            object_type=object_type, object_uuid=object_uuid, **kwargs)

def create ( cls , object_type = None , object_uuid = None , ** kwargs ) : assert 'pid_value' in kwargs kwargs . setdefault ( 'status' , cls . default_status ) return super ( DepositProvider , cls ) . create ( object_type = object_type , object_uuid = object_uuid , ** kwargs )


def extract_actions_from_class(record_class):
    """Extract actions from class."""
    for name in dir(record_class):
        method = getattr(record_class, name, None)
        if method and getattr(method, '__deposit_action__', False):
            yield method.__name__

def extract_actions_from_class ( record_class ) : for name in dir ( record_class ) : method = getattr ( record_class , name , None ) if method and getattr ( method , '__deposit_action__' , False ) : yield method . __name__


def check_oauth2_scope(can_method, *myscopes):
    """Base permission factory that check OAuth2 scope and can_method.

    :param can_method: Permission check function that accept a record in input
        and return a boolean.
    :param myscopes: List of scopes required to permit the access.
    :returns: A :class:`flask_principal.Permission` factory.
    """
    def check(record, *args, **kwargs):
        @require_api_auth()
        @require_oauth_scopes(*myscopes)
        def can(self):
            return can_method(record)

        return type('CheckOAuth2Scope', (), {'can': can})()
    return check

def check_oauth2_scope ( can_method , * myscopes ) : def check ( record , * args , ** kwargs ) : @ require_api_auth ( ) @ require_oauth_scopes ( * myscopes ) def can ( self ) : return can_method ( record ) return type ( 'CheckOAuth2Scope' , ( ) , { 'can' : can } ) ( ) return check

Base permission factory that check OAuth2 scope and can_method .


def can_elasticsearch(record):
    """Check if a given record is indexed.

    :param record: A record object.
    :returns: If the record is indexed returns `True`, otherwise `False`.
    """
    search = request._methodview.search_class()
    search = search.get_record(str(record.id))
    return search.count() == 1

def can_elasticsearch ( record ) : search = request . _methodview . search_class ( ) search = search . get_record ( str ( record . id ) ) return search . count ( ) == 1


def create_error_handlers(blueprint):
    """Create error handlers on blueprint."""
    blueprint.errorhandler(PIDInvalidAction)(create_api_errorhandler(
        status=403, message='Invalid action'
    ))
    records_rest_error_handlers(blueprint)

def
create_error_handlers
(
blueprint
)
:
blueprint
.
errorhandler
(
PIDInvalidAction
)
(
create_api_errorhandler
(
status
=
403
,
message
=
'Invalid action'
)
)
records_rest_error_handlers
(
blueprint
)