def poisson_disk(script, sample_num=1000, radius=0.0,
                 montecarlo_rate=20, save_montecarlo=False,
                 approx_geodesic_dist=False, subsample=False, refine=False,
                 refine_layer=0, best_sample=True, best_sample_pool=10,
                 exact_num=False, radius_variance=1.0):
    """ Create a new layer populated with a point sampling of the current mesh.

    Samples are generated according to a Poisson-disk distribution, using the
    algorithm described in:

    'Efficient and Flexible Sampling with Blue Noise Properties of Triangular Meshes'
    Massimiliano Corsini, Paolo Cignoni, Roberto Scopigno
    IEEE TVCG 2012

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        sample_num (int): The desired number of samples. The radius of the disk
            is calculated according to the sampling density.
        radius (float): If not zero this parameter overrides the previous
            parameter to allow exact radius specification.
        montecarlo_rate (int): The over-sampling rate that is used to generate
            the intial Monte Carlo samples (e.g. if this parameter is 'K' means
            that 'K * sample_num' points will be used). The generated
            Poisson-disk samples are a subset of these initial Monte Carlo
            samples. Larger numbers slow the process but make it a bit more
            accurate.
        save_montecarlo (bool): If True, it will generate an additional Layer
            with the Monte Carlo sampling that was pruned to build the Poisson
            distribution.
        approx_geodesic_dist (bool): If True Poisson-disk distances are
            computed using an approximate geodesic distance, e.g. an Euclidean
            distance weighted by a function of the difference between the
            normals of the two points.
        subsample (bool): If True the original vertices of the base mesh are
            used as base set of points. In this case the sample_num should be
            obviously much smaller than the original vertex number. Note that
            this option is very useful in the case you want to subsample a
            dense point cloud.
        refine (bool): If True the vertices of the refine_layer mesh layer are
            used as starting vertices, and they will be utterly refined by
            adding more and more points until possible.
        refine_layer (int): Used only if refine is True.
        best_sample (bool): If True it will use a simple heuristic for choosing
            the samples. At a small cost (it can slow the process a bit) it
            usually improves the maximality of the generated sampling.
        best_sample_pool (bool): Used only if best_sample is True. It controls
            the number of attempts that it makes to get the best sample. It is
            reasonable that it is smaller than the Monte Carlo oversampling
            factor.
        exact_num (bool): If True it will try to do a dicotomic search for the
            best Poisson-disk radius that will generate the requested number of
            samples with a tolerance of the 0.5%. Obviously it takes much
            longer.
        radius_variance (float): The radius of the disk is allowed to vary
            between r and r*var. If this parameter is 1 the sampling is the
            same as the Poisson-disk Sampling.

    Layer stack:
        Creates new layer 'Poisson-disk Samples'. Current layer is NOT changed
            to the new layer (see Bugs).
        If save_montecarlo is True, creates a new layer 'Montecarlo Samples'.
            Current layer is NOT changed to the new layer (see Bugs).

    MeshLab versions:
        2016.12
        1.3.4BETA

    Bugs:
        Current layer is NOT changed to the new layer, which is inconsistent
            with the majority of filters that create new layers.
    """
    filter_xml = ''.join([
        '  <filter name="Poisson-disk Sampling">\n',
        '    <Param name="SampleNum" ',
        'value="{:d}" '.format(sample_num),
        'description="Number of samples" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="Radius" ',
        'value="{}" '.format(radius),
        'description="Explicit Radius" ',
        'min="0" ',
        'max="100" ',
        'type="RichAbsPerc" ',
        '/>\n',
        '    <Param name="MontecarloRate" ',
        'value="{:d}" '.format(montecarlo_rate),
        'description="MonterCarlo OverSampling" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="SaveMontecarlo" ',
        'value="{}" '.format(str(save_montecarlo).lower()),
        'description="Save Montecarlo" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="ApproximateGeodesicDistance" ',
        'value="{}" '.format(str(approx_geodesic_dist).lower()),
        'description="Approximate Geodesic Distance" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="Subsample" ',
        'value="{}" '.format(str(subsample).lower()),
        'description="Base Mesh Subsampling" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="RefineFlag" ',
        'value="{}" '.format(str(refine).lower()),
        'description="Refine Existing Samples" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="RefineMesh" ',
        'value="{:d}" '.format(refine_layer),
        'description="Samples to be refined" ',
        'type="RichMesh" ',
        '/>\n',
        '    <Param name="BestSampleFlag" ',
        'value="{}" '.format(str(best_sample).lower()),
        'description="Best Sample Heuristic" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="BestSamplePool" ',
        'value="{:d}" '.format(best_sample_pool),
        'description="Best Sample Pool Size" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="ExactNumFlag" ',
        'value="{}" '.format(str(exact_num).lower()),
        'description="Exact number of samples" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="RadiusVariance" ',
        'value="{}" '.format(radius_variance),
        'description="Radius Variance" ',
        'type="RichFloat" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    if isinstance(script, FilterScript):
        script.add_layer('Poisson-disk Samples')
        if save_montecarlo:
            script.add_layer('Montecarlo Samples')
    return None

Create a new layer populated with a point sampling of the current mesh .


def mesh_element(script, sample_num=1000, element='VERT'):
    """ Create a new layer populated with a point sampling of the current mesh,
        at most one sample for each element of the mesh is created.

    Samples are taking in a uniform way, one for each element
    (vertex/edge/face); all the elements have the same probabilty of being
    choosen.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        sample_num (int): The desired number of elements that must be chosen.
            Being a subsampling of the original elements if this number should
            not be larger than the number of elements of the original mesh.
        element (enum in ['VERT', 'EDGE', 'FACE']): Choose what mesh element
            will be used for the subsampling. At most one point sample will
            be added for each one of the chosen elements

    Layer stack:
        Creates new layer 'Sampled Mesh'. Current layer is changed to the new
            layer.

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    if element.lower() == 'vert':
        element_num = 0
    elif element.lower() == 'edge':
        element_num = 1
    elif element.lower() == 'face':
        element_num = 2
    filter_xml = ''.join([
        '  <filter name="Mesh Element Subsampling">\n',
        '    <Param name="Sampling" ',
        'value="{:d}" '.format(element_num),
        'description="Element to sample:" ',
        'enum_val0="Vertex" ',
        'enum_val1="Edge" ',
        'enum_val2="Face" ',
        'enum_cardinality="3" ',
        'type="RichEnum" ',
        '/>\n',
        '    <Param name="SampleNum" ',
        'value="{:d}" '.format(sample_num),
        'description="Number of samples" ',
        'type="RichInt" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    if isinstance(script, FilterScript):
        script.add_layer('Sampled Mesh')
    return None

Create a new layer populated with a point sampling of the current mesh at most one sample for each element of the mesh is created .


def clustered_vert(script, cell_size=1.0, strategy='AVERAGE', selected=False):
    """ "Create a new layer populated with a subsampling of the vertexes of the
        current mesh

    The subsampling is driven by a simple one-per-gridded cell strategy.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        cell_size (float): The size of the cell of the clustering grid. Smaller the cell finer the resulting mesh. For obtaining a very coarse mesh use larger values.
        strategy (enum 'AVERAGE' or 'CENTER'): Average: for each cell we take the average of the sample falling into. The resulting point is a new point.
Closest to center: for each cell we take the sample that is closest to the center of the cell. Choosen vertices are a subset of the original ones.
        selected (bool): If true only for the filter is applied only on the selected subset of the mesh.

    Layer stack:
        Creates new layer 'Cluster Samples'. Current layer is changed to the new
            layer.

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    if strategy.lower() == 'average':
        strategy_num = 0
    elif strategy.lower() == 'center':
        strategy_num = 1

    filter_xml = ''.join([
        '  <filter name="Clustered Vertex Subsampling">\n',
        '    <Param name="Threshold" ',
        'value="{}" '.format(cell_size),
        'description="Cell Size" ',
        'min="0" ',
        'max="1000" ',
        'type="RichAbsPerc" ',
        '/>\n',
        '    <Param name="Sampling" ',
        'value="{:d}" '.format(strategy_num),
        'description="Representative Strategy:" ',
        'enum_val0="Average" ',
        'enum_val1="Closest to center" ',
        'enum_cardinality="2" ',
        'type="RichEnum" ',
        '/>\n',
        '    <Param name="Selected" ',
        'value="{}" '.format(str(selected).lower()),
        'description="Selected" ',
        'type="RichBool" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    if isinstance(script, FilterScript):
        script.add_layer('Cluster Samples')
    return None


def flat_plane(script, plane=0, aspect_ratio=False):
    """Flat plane parameterization

    """
    filter_xml = ''.join([
        '  <filter name="Parametrization: Flat Plane ">\n',
        '    <Param name="projectionPlane"',
        'value="%d"' % plane,
        'description="Projection plane"',
        'enum_val0="XY"',
        'enum_val1="XZ"',
        'enum_val2="YZ"',
        'enum_cardinality="3"',
        'type="RichEnum"',
        'tooltip="Choose the projection plane"',
        '/>\n',
        '    <Param name="aspectRatio"',
        'value="%s"' % str(aspect_ratio).lower(),
        'description="Preserve Ratio"',
        'type="RichBool"',
        'tooltip="If checked the resulting parametrization will preserve the original apsect ratio of the model otherwise it will fill up the whole 0..1 uv space"',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None


def per_triangle(script, sidedim=0, textdim=1024, border=2, method=1):
    """Trivial Per-Triangle parameterization

    """
    filter_xml = ''.join([
        '  <filter name="Parametrization: Trivial Per-Triangle ">\n',
        '    <Param name="sidedim"',
        'value="%d"' % sidedim,
        'description="Quads per line"',
        'type="RichInt"',
        'tooltip="Indicates how many triangles have to be put on each line (every quad contains two triangles). Leave 0 for automatic calculation"',
        '/>\n',
        '    <Param name="textdim"',
        'value="%d"' % textdim,
        'description="Texture Dimension (px)"',
        'type="RichInt"',
        'tooltip="Gives an indication on how big the texture is"',
        '/>\n',
        '    <Param name="border"',
        'value="%d"' % border,
        'description="Inter-Triangle border (px)"',
        'type="RichInt"',
        'tooltip="Specifies how many pixels to be left between triangles in parametrization domain"',
        '/>\n',
        '    <Param name="method"',
        'value="%d"' % method,
        'description="Method"',
        'enum_val0="Basic"',
        'enum_val1="Space-optimizing"',
        'enum_cardinality="2"',
        'type="RichEnum"',
        'tooltip="Choose space optimizing to map smaller faces into smaller triangles in parametrizazion domain"'
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None


def voronoi(script, region_num=10, overlap=False):
    """Voronoi Atlas parameterization

    """
    filter_xml = ''.join([
        '  <filter name="Parametrization: Voronoi Atlas">\n',
        '    <Param name="regionNum"',
        'value="%d"' % region_num,
        'description="Approx. Region Num"',
        'type="RichInt"',
        'tooltip="An estimation of the number of regions that must be generated. Smaller regions could lead to parametrizations with smaller distortion."',
        '/>\n',
        '    <Param name="overlapFlag"',
        'value="%s"' % str(overlap).lower(),
        'description="Overlap"',
        'type="RichBool"',
        'tooltip="If checked the resulting parametrization will be composed by overlapping regions, e.g. the resulting mesh will have duplicated faces: each region will have a ring of ovelapping duplicate faces that will ensure that border regions will be parametrized in the atlas twice. This is quite useful for building mipmap robust atlases"',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None


def measure_topology(script):
    """ Compute a set of topological measures over a mesh

    Args:
        script: the mlx.FilterScript object or script filename to write
            the filter to.

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = '  <xmlfilter name="Compute Topological Measures"/>\n'
    util.write_filter(script, filter_xml)
    if isinstance(script, mlx.FilterScript):
        script.parse_topology = True
    return None


def parse_topology(ml_log, log=None, ml_version='1.3.4BETA', print_output=False):
    """Parse the ml_log file generated by the measure_topology function.

    Args:
        ml_log (str): MeshLab log file to parse
        log (str): filename to log output

    Returns:
        dict: dictionary with the following keys:
            vert_num (int): number of vertices
            edge_num (int): number of edges
            face_num (int): number of faces
            unref_vert_num (int): number or unreferenced vertices
            boundry_edge_num (int): number of boundary edges
            part_num (int): number of parts (components) in the mesh.
            manifold (bool): True if mesh is two-manifold, otherwise false.
            non_manifold_edge (int): number of non_manifold edges.
            non_manifold_vert (int): number of non-manifold verices
            genus (int or str): genus of the mesh, either a number or
                'undefined' if the mesh is non-manifold.
            holes (int or str): number of holes in the mesh, either a number
                or 'undefined' if the mesh is non-manifold.

    """
    topology = {'manifold': True, 'non_manifold_E': 0, 'non_manifold_V': 0}
    with open(ml_log) as fread:
        for line in fread:
            if 'V:' in line:
                vert_edge_face = line.replace('V:', ' ').replace('E:', ' ').replace('F:', ' ').split()
                topology['vert_num'] = int(vert_edge_face[0])
                topology['edge_num'] = int(vert_edge_face[1])
                topology['face_num'] = int(vert_edge_face[2])
            if 'Unreferenced Vertices' in line:
                topology['unref_vert_num'] = int(line.split()[2])
            if 'Boundary Edges' in line:
                topology['boundry_edge_num'] = int(line.split()[2])
            if 'Mesh is composed by' in line:
                topology['part_num'] = int(line.split()[4])
            if 'non 2-manifold mesh' in line:
                topology['manifold'] = False
            if 'non two manifold edges' in line:
                topology['non_manifold_edge'] = int(line.split()[2])
            if 'non two manifold vertexes' in line:
                topology['non_manifold_vert'] = int(line.split()[2])
            if 'Genus is' in line:  # undefined or int
                topology['genus'] = line.split()[2]
                if topology['genus'] != 'undefined':
                    topology['genus'] = int(topology['genus'])
            if 'holes' in line:
                topology['hole_num'] = line.split()[2]
                if topology['hole_num'] == 'a':
                    topology['hole_num'] = 'undefined'
                else:
                    topology['hole_num'] = int(topology['hole_num'])
    for key, value in topology.items():
        if log is not None:
            log_file = open(log, 'a')
            log_file.write('{:16} = {}\n'.format(key, value))
            log_file.close()
        elif print_output:
            print('{:16} = {}'.format(key, value))

    return topology

def
parse_topology
(
ml_log
,
log
=
,
ml_version
=
'1.3.4BETA'
,
print_output
=
False
)
:
topology
=
{
'manifold'
:
True
,
'non_manifold_E'
:
0
,
'non_manifold_V'
:
0
}
with
open
(
ml_log
)
as
fread
:
for
line
in
fread
:
if
'V:'
in
line
:
vert_edge_face
=
line
.
replace
(
'V:'
,
' '
)
.
replace
(
'E:'
,
' '
)
.
replace
(
'F:'
,
' '
)
.
split
(
)
topology
[
'vert_num'
]
=
int
(
vert_edge_face
[
0
]
)
topology
[
'edge_num'
]
=
int
(
vert_edge_face
[
1
]
)
topology
[
'face_num'
]
=
int
(
vert_edge_face
[
2
]
)
if
'Unreferenced Vertices'
in
line
:
topology
[
'unref_vert_num'
]
=
int
(
line
.
split
(
)
[
2
]
)
if
'Boundary Edges'
in
line
:
topology
[
'boundry_edge_num'
]
=
int
(
line
.
split
(
)
[
2
]
)
if
'Mesh is composed by'
in
line
:
topology
[
'part_num'
]
=
int
(
line
.
split
(
)
[
4
]
)
if
'non 2-manifold mesh'
in
line
:
topology
[
'manifold'
]
=
False
if
'non two manifold edges'
in
line
:
topology
[
'non_manifold_edge'
]
=
int
(
line
.
split
(
)
[
2
]
)
if
'non two manifold vertexes'
in
line
:
topology
[
'non_manifold_vert'
]
=
int
(
line
.
split
(
)
[
2
]
)
if
'Genus is'
in
line
:
# undefined or int
topology
[
'genus'
]
=
line
.
split
(
)
[
2
]
if
topology
[
'genus'
]
!=
'undefined'
:
topology
[
'genus'
]
=
int
(
topology
[
'genus'
]
)
if
'holes'
in
line
:
topology
[
'hole_num'
]
=
line
.
split
(
)
[
2
]
if
topology
[
'hole_num'
]
==
'a'
:
topology
[
'hole_num'
]
=
'undefined'
else
:
topology
[
'hole_num'
]
=
int
(
topology
[
'hole_num'
]
)
for
key
,
value
in
topology
.
items
(
)
:
if
log
is
not
:
log_file
=
open
(
log
,
'a'
)
log_file
.
write
(
'{:16} = {}\n'
.
format
(
key
,
value
)
)
log_file
.
close
(
)
elif
print_output
:
print
(
'{:16} = {}'
.
format
(
key
,
value
)
)
return
topology

Parse the ml_log file generated by the measure_topology function .


def parse_hausdorff(ml_log, log=None, print_output=False):
    """Parse the ml_log file generated by the hausdorff_distance function.

    Args:
        ml_log (str): MeshLab log file to parse
        log (str): filename to log output

    Returns:
        dict: dictionary with the following keys:
            number_points (int): number of points in mesh
            min_distance (float): minimum hausdorff distance
            max_distance (float): maximum hausdorff distance
            mean_distance (float): mean hausdorff distance
            rms_distance (float): root mean square distance

    """
    hausdorff_distance = {"min_distance": 0.0,
                          "max_distance": 0.0,
                          "mean_distance": 0.0,
                          "rms_distance": 0.0,
                          "number_points": 0}
    with open(ml_log) as fread:
        result = fread.readlines()
        data = ""

        for idx, line in enumerate(result):
            m = re.match(r"\s*Sampled (\d+) pts.*", line)
            if m is not None:
                hausdorff_distance["number_points"] = int(m.group(1))
            if 'Hausdorff Distance computed' in line:
                data = result[idx + 2]

        m = re.match(r"\D+(\d+\.*\d*)\D+(\d+\.*\d*)\D+(\d+\.*\d*)\D+(\d+\.*\d*)", data)
        hausdorff_distance["min_distance"] = float(m.group(1))
        hausdorff_distance["max_distance"] = float(m.group(2))
        hausdorff_distance["mean_distance"] = float(m.group(3))
        hausdorff_distance["rms_distance"] = float(m.group(4))
        for key, value in hausdorff_distance.items():
            if log is not None:
                log_file = open(log, 'a')
                log_file.write('{:16} = {}\n'.format(key, value))
                log_file.close()
            elif print_output:
                print('{:16} = {}'.format(key, value))
        return hausdorff_distance

Parse the ml_log file generated by the hausdorff_distance function .


def function(script, red=255, green=255, blue=255, alpha=255, color=None):
    """Color function using muparser lib to generate new RGBA color for every
        vertex

    Red, Green, Blue and Alpha channels may be defined by specifying a function
    for each.

    See help(mlx.muparser_ref) for muparser reference documentation.

    It's possible to use the following per-vertex variables in the expression:

    Variables (per vertex):
        x, y, z (coordinates)
        nx, ny, nz (normal)
        r, g, b, a (color)
        q (quality)
        rad (radius)
        vi (vertex index)
        vtu, vtv (texture coordinates)
        ti (texture index)
        vsel (is the vertex selected? 1 yes, 0 no)
        and all custom vertex attributes already defined by user.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        red (str [0, 255]): function to generate red component
        green (str [0, 255]): function to generate green component
        blue (str [0, 255]): function to generate blue component
        alpha (str [0, 255]): function to generate alpha component
        color (str): name of one of the 140 HTML Color Names defined
            in CSS & SVG.
            Ref: https://en.wikipedia.org/wiki/Web_colors#X11_color_names
            If not None this will override the per component variables.

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    # TODO: add options for HSV
    # https://www.cs.rit.edu/~ncs/color/t_convert.html
    if color is not None:
        red, green, blue, _ = color_name[color.lower()]
    filter_xml = ''.join([
        '  <filter name="Per Vertex Color Function">\n',
        '    <Param name="x" ',
        'value="{}" '.format(str(red).replace('&', '&').replace('<', '<')),
        'description="func r = " ',
        'type="RichString" ',
        '/>\n',
        '    <Param name="y" ',
        'value="{}" '.format(str(green).replace('&', '&').replace('<', '<')),
        'description="func g = " ',
        'type="RichString" ',
        '/>\n',
        '    <Param name="z" ',
        'value="{}" '.format(str(blue).replace('&', '&').replace('<', '<')),
        'description="func b = " ',
        'type="RichString" ',
        '/>\n',
        '    <Param name="a" ',
        'value="{}" '.format(str(alpha).replace('&', '&').replace('<', '<')),
        'description="func alpha = " ',
        'type="RichString" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None


def voronoi(script, target_layer=0, source_layer=1, backward=True):
    """ Given a Mesh 'M' and a Pointset 'P', the filter projects each vertex of
        P over M and color M according to the geodesic distance from these
        projected points. Projection and coloring are done on a per vertex
        basis.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        target_layer (int): The mesh layer whose surface is colored. For each
            vertex of this mesh we decide the color according to the following
            arguments.
        source_layer (int): The mesh layer whose vertexes are used as seed
            points for the color computation. These seeds point are projected
            onto the target_layer mesh.
        backward (bool): If True the mesh is colored according to the distance
            from the frontier of the voronoi diagram induced by the
            source_layer seeds.

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = ''.join([
        '  <filter name="Voronoi Vertex Coloring">\n',
        '    <Param name="ColoredMesh" ',
        'value="{:d}" '.format(target_layer),
        'description="To be Colored Mesh" ',
        'type="RichMesh" ',
        '/>\n',
        '    <Param name="VertexMesh" ',
        'value="{:d}" '.format(source_layer),
        'description="Vertex Mesh" ',
        'type="RichMesh" ',
        '/>\n',
        '    <Param name="backward" ',
        'value="{}" '.format(str(backward).lower()),
        'description="BackDistance" ',
        'type="RichBool" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None

Given a Mesh M and a Pointset P the filter projects each vertex of P over M and color M according to the geodesic distance from these projected points . Projection and coloring are done on a per vertex basis .


def cyclic_rainbow(script, direction='sphere', start_pt=(0, 0, 0),
                   amplitude=255 / 2, center=255 / 2, freq=0.8,
                   phase=(0, 120, 240, 0), alpha=False):
    """ Color mesh vertices in a repeating sinusiodal rainbow pattern

    Sine wave follows the following equation for each color channel (RGBA):
    channel = sin(freq*increment + phase)*amplitude + center

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        direction (str) = the direction that the sine wave will travel; this
            and the start_pt determine the 'increment' of the sine function.
            Valid values are:
            'sphere' - radiate sine wave outward from start_pt (default)
            'x' - sine wave travels along the X axis
            'y' - sine wave travels along the Y axis
            'z' - sine wave travels along the Z axis
            or define the increment directly using a muparser function, e.g.
                '2x + y'. In this case start_pt will not be used; include it in
                the function directly.
    start_pt (3 coordinate tuple or list): start point of the sine wave. For a
        sphere this is the center of the sphere.
    amplitude (float [0, 255], single value or 4 term tuple or list): amplitude
        of the sine wave, with range between 0-255. If a single value is
        specified it will be used for all channels, otherwise specify each
        channel individually.
    center (float [0, 255], single value or 4 term tuple or list): center
        of the sine wave, with range between 0-255. If a single value is
        specified it will be used for all channels, otherwise specify each
        channel individually.
    freq (float, single value or 4 term tuple or list): frequency of the sine
        wave. If a single value is specified it will be used for all channels,
        otherwise specifiy each channel individually.
    phase (float [0, 360], single value or 4 term tuple or list): phase
        of the sine wave in degrees, with range between 0-360. If a single
        value is specified it will be used for all channels, otherwise specify
        each channel individually.
    alpha (bool): if False the alpha channel will be set to 255 (full opacity).

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    start_pt = util.make_list(start_pt, 3)
    amplitude = util.make_list(amplitude, 4)
    center = util.make_list(center, 4)
    freq = util.make_list(freq, 4)
    phase = util.make_list(phase, 4)

    if direction.lower() == 'sphere':
        increment = 'sqrt((x-{})^2+(y-{})^2+(z-{})^2)'.format(
            start_pt[0], start_pt[1], start_pt[2])
    elif direction.lower() == 'x':
        increment = 'x - {}'.format(start_pt[0])
    elif direction.lower() == 'y':
        increment = 'y - {}'.format(start_pt[1])
    elif direction.lower() == 'z':
        increment = 'z - {}'.format(start_pt[2])
    else:
        increment = direction

    red_func = '{a}*sin({f}*{i} + {p}) + {c}'.format(
        f=freq[0], i=increment, p=math.radians(phase[0]),
        a=amplitude[0], c=center[0])
    green_func = '{a}*sin({f}*{i} + {p}) + {c}'.format(
        f=freq[1], i=increment, p=math.radians(phase[1]),
        a=amplitude[1], c=center[1])
    blue_func = '{a}*sin({f}*{i} + {p}) + {c}'.format(
        f=freq[2], i=increment, p=math.radians(phase[2]),
        a=amplitude[2], c=center[2])
    if alpha:
        alpha_func = '{a}*sin({f}*{i} + {p}) + {c}'.format(
            f=freq[3], i=increment, p=math.radians(phase[3]),
            a=amplitude[3], c=center[3])
    else:
        alpha_func = 255

    function(script, red=red_func, green=green_func, blue=blue_func,
             alpha=alpha_func)
    return None

def
cyclic_rainbow
(
script
,
direction
=
'sphere'
,
start_pt
=
(
0
,
0
,
0
)
,
amplitude
=
255
/
2
,
center
=
255
/
2
,
freq
=
0.8
,
phase
=
(
0
,
120
,
240
,
0
)
,
alpha
=
False
)
:
start_pt
=
util
.
make_list
(
start_pt
,
3
)
amplitude
=
util
.
make_list
(
amplitude
,
4
)
center
=
util
.
make_list
(
center
,
4
)
freq
=
util
.
make_list
(
freq
,
4
)
phase
=
util
.
make_list
(
phase
,
4
)
if
direction
.
lower
(
)
==
'sphere'
:
increment
=
'sqrt((x-{})^2+(y-{})^2+(z-{})^2)'
.
format
(
start_pt
[
0
]
,
start_pt
[
1
]
,
start_pt
[
2
]
)
elif
direction
.
lower
(
)
==
'x'
:
increment
=
'x - {}'
.
format
(
start_pt
[
0
]
)
elif
direction
.
lower
(
)
==
'y'
:
increment
=
'y - {}'
.
format
(
start_pt
[
1
]
)
elif
direction
.
lower
(
)
==
'z'
:
increment
=
'z - {}'
.
format
(
start_pt
[
2
]
)
else
:
increment
=
direction
red_func
=
'{a}*sin({f}*{i} + {p}) + {c}'
.
format
(
f
=
freq
[
0
]
,
i
=
increment
,
p
=
math
.
radians
(
phase
[
0
]
)
,
a
=
amplitude
[
0
]
,
c
=
center
[
0
]
)
green_func
=
'{a}*sin({f}*{i} + {p}) + {c}'
.
format
(
f
=
freq
[
1
]
,
i
=
increment
,
p
=
math
.
radians
(
phase
[
1
]
)
,
a
=
amplitude
[
1
]
,
c
=
center
[
1
]
)
blue_func
=
'{a}*sin({f}*{i} + {p}) + {c}'
.
format
(
f
=
freq
[
2
]
,
i
=
increment
,
p
=
math
.
radians
(
phase
[
2
]
)
,
a
=
amplitude
[
2
]
,
c
=
center
[
2
]
)
if
alpha
:
alpha_func
=
'{a}*sin({f}*{i} + {p}) + {c}'
.
format
(
f
=
freq
[
3
]
,
i
=
increment
,
p
=
math
.
radians
(
phase
[
3
]
)
,
a
=
amplitude
[
3
]
,
c
=
center
[
3
]
)
else
:
alpha_func
=
255
function
(
script
,
red
=
red_func
,
green
=
green_func
,
blue
=
blue_func
,
alpha
=
alpha_func
)
return


def mp_atan2(y, x):
    """muparser atan2 function

    Implements an atan2(y,x) function for older muparser versions (<2.1.0);
    atan2 was added as a built-in function in muparser 2.1.0

    Args:
        y (str): y argument of the atan2(y,x) function
        x (str): x argument of the atan2(y,x) function

    Returns:
        A muparser string that calculates atan2(y,x)
    """
    return 'if((x)>0, atan((y)/(x)), if(((x)<0) and ((y)>=0), atan((y)/(x))+pi, if(((x)<0) and ((y)<0), atan((y)/(x))-pi, if(((x)==0) and ((y)>0), pi/2, if(((x)==0) and ((y)<0), -pi/2, 0)))))'.replace(
        'pi', str(math.pi)).replace('y', y).replace('x', x)


def v_cross(u, v):
    """muparser cross product function

    Compute the cross product of two 3x1 vectors

    Args:
        u (list or tuple of 3 strings): first vector
        v (list or tuple of 3 strings): second vector
    Returns:
        A list containing a muparser string of the cross product
    """
    """
    i = u[1]*v[2] - u[2]*v[1]
    j = u[2]*v[0] - u[0]*v[2]
    k = u[0]*v[1] - u[1]*v[0]
    """

    i = '(({u1})*({v2}) - ({u2})*({v1}))'.format(u1=u[1], u2=u[2], v1=v[1], v2=v[2])
    j = '(({u2})*({v0}) - ({u0})*({v2}))'.format(u0=u[0], u2=u[2], v0=v[0], v2=v[2])
    k = '(({u0})*({v1}) - ({u1})*({v0}))'.format(u0=u[0], u1=u[1], v0=v[0], v1=v[1])
    return [i, j, k]


def v_multiply(scalar, v1):
    """ Multiply vector by scalar"""
    vector = []
    for i, x in enumerate(v1):
        vector.append('(({})*({}))'.format(scalar, v1[i]))
    return vector

def v_multiply ( scalar , v1 ) : vector = [ ] for i , x in enumerate ( v1 ) : vector . append ( '(({})*({}))' . format ( scalar , v1 [ i ] ) ) return vector


def vert_attr(script, name='radius', function='x^2 + y^2'):
    """ Add a new Per-Vertex scalar attribute to current mesh and fill it with
        the defined function.

    The specified name can be used in other filter functions.

    It's possible to use parenthesis, per-vertex variables and boolean operator:
        (, ), and, or, <, >, =
    It's possible to use the following per-vertex variables in the expression:

    Variables:
        x, y, z (coordinates)
        nx, ny, nz (normal)
        r, g, b, a (color)
        q (quality)
        rad
        vi (vertex index)
        ?vtu, vtv (texture coordinates)
        ?ti (texture index)
        ?vsel (is the vertex selected? 1 yes, 0 no)
        and all custom vertex attributes already defined by user.

    Args:
        script: the FilterScript object or script filename to write
            the filter] to.
        name (str): the name of new attribute. You can access attribute in
            other filters through this name.
        function (str): function to calculate custom attribute value for each
            vertex

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = ''.join([
        '  <filter name="Define New Per Vertex Attribute">\n',
        '    <Param name="name" ',
        'value="{}" '.format(name),
        'description="Name" ',
        'type="RichString" ',
        '/>\n',
        '    <Param name="expr" ',
        'value="{}" '.format(str(function).replace('&', '&').replace('<', '<')),
        'description="Function" ',
        'type="RichString" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None

Add a new Per - Vertex scalar attribute to current mesh and fill it with the defined function .


def flip(script, force_flip=False, selected=False):
    """ Invert faces orientation, flipping the normals of the mesh.

    If requested, it tries to guess the right orientation; mainly it decides to
    flip all the faces if the minimum/maximum vertexes have not outward point
    normals for a few directions. Works well for single component watertight
    objects.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        force_flip (bool): If selected, the normals will always be flipped;
            otherwise, the filter tries to set them outside.
        selected (bool): If selected, only selected faces will be affected.

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = ''.join([
        '  <filter name="Invert Faces Orientation">\n',
        '    <Param name="forceFlip" ',
        'value="{}" '.format(str(force_flip).lower()),
        'description="Force Flip" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="onlySelected" ',
        'value="{}" '.format(str(selected).lower()),
        'description="Flip only selected faces" ',
        'type="RichBool" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None

Invert faces orientation flipping the normals of the mesh .


def point_sets(script, neighbors=10, smooth_iteration=0, flip=False,
               viewpoint_pos=(0.0, 0.0, 0.0)):
    """ Compute the normals of the vertices of a mesh without exploiting the
        triangle connectivity, useful for dataset with no faces.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        neighbors (int): The number of neighbors used to estimate normals.
        smooth_iteration (int): The number of smoothing iteration done on the
            p used to estimate and propagate normals.
        flip (bool): Flip normals w.r.t. viewpoint. If the 'viewpoint' (i.e.
            scanner position) is known, it can be used to disambiguate normals
            orientation, so that all the normals will be oriented in the same
            direction.
        viewpoint_pos (single xyz point, tuple or list): Set the x, y, z
            coordinates of the viewpoint position.

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = ''.join([
        '  <filter name="Compute normals for point sets">\n',
        '    <Param name="K" ',
        'value="{:d}" '.format(neighbors),
        'description="Neighbour num" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="smoothIter" ',
        'value="{:d}" '.format(smooth_iteration),
        'description="Smooth Iteration" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="flipFlag" ',
        'value="{}" '.format(str(flip).lower()),
        'description="Flip normals w.r.t. viewpoint" ',
        'type="RichBool" ',
        '/>\n',
        '    <Param name="viewPos" ',
        'x="{}" y="{}" z="{}" '.format(viewpoint_pos[0], viewpoint_pos[1],
                                       viewpoint_pos[2],),
        'description="Viewpoint Pos." ',
        'type="RichPoint3f" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None

Compute the normals of the vertices of a mesh without exploiting the triangle connectivity useful for dataset with no faces .


def taubin(script, iterations=10, t_lambda=0.5, t_mu=-0.53, selected=False):
    """ The lambda & mu Taubin smoothing, it make two steps of smoothing, forth
        and back, for each iteration.

    Based on:
    Gabriel Taubin
    "A signal processing approach to fair surface design"
    Siggraph 1995

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        iterations (int): The number of times that the taubin smoothing is
            iterated. Usually it requires a larger number of iteration than the
            classical laplacian.
        t_lambda (float): The lambda parameter of the Taubin Smoothing algorithm
        t_mu (float): The mu parameter of the Taubin Smoothing algorithm
        selected (bool): If selected the filter is performed only on the
            selected faces

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = ''.join([
        '  <filter name="Taubin Smooth">\n',
        '    <Param name="lambda" ',
        'value="{}" '.format(t_lambda),
        'description="Lambda" ',
        'type="RichFloat" ',
        '/>\n',
        '    <Param name="mu" ',
        'value="{}" '.format(t_mu),
        'description="mu" ',
        'type="RichFloat" ',
        '/>\n',
        '    <Param name="stepSmoothNum" ',
        'value="{:d}" '.format(iterations),
        'description="Smoothing steps" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="Selected" ',
        'value="{}" '.format(str(selected).lower()),
        'description="Affect only selected faces" ',
        'type="RichBool" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None

The lambda & mu Taubin smoothing it make two steps of smoothing forth and back for each iteration .


def depth(script, iterations=3, viewpoint=(0, 0, 0), selected=False):
    """ A laplacian smooth that is constrained to move vertices only along the
        view direction.

    Args:
        script: the FilterScript object or script filename to write
            the filter to.
        iterations (int): The number of times that the whole algorithm (normal
            smoothing + vertex fitting) is iterated.
        viewpoint (vector tuple or list): The position of the view point that
            is used to get the constraint direction.
        selected (bool): If selected the filter is performed only on the
            selected faces

    Layer stack:
        No impacts

    MeshLab versions:
        2016.12
        1.3.4BETA
    """
    filter_xml = ''.join([
        '  <filter name="Depth Smooth">\n',
        '    <Param name="stepSmoothNum" ',
        'value="{:d}" '.format(iterations),
        'description="Smoothing steps" ',
        'type="RichInt" ',
        '/>\n',
        '    <Param name="viewPoint" ',
        'x="{}" '.format(viewpoint[0]),
        'y="{}" '.format(viewpoint[1]),
        'z="{}" '.format(viewpoint[2]),
        'description="Smoothing steps" ',
        'type="RichPoint3f" ',
        '/>\n',
        '    <Param name="Selected" ',
        'value="{}" '.format(str(selected).lower()),
        'description="Affect only selected faces" ',
        'type="RichBool" ',
        '/>\n',
        '  </filter>\n'])
    util.write_filter(script, filter_xml)
    return None

A laplacian smooth that is constrained to move vertices only along the view direction .


def polylinesort(fbasename=None, log=None):
    """Sort separate line segments in obj format into a continuous polyline or polylines.
    NOT FINISHED; DO NOT USE

    Also measures the length of each polyline

    Return polyline and polylineMeta (lengths)

    """
    fext = os.path.splitext(fbasename)[1][1:].strip().lower()
    if fext != 'obj':
        print('Input file must be obj. Exiting ...')
        sys.exit(1)
    fread = open(fbasename, 'r')
    first = True
    polyline_vertices = []
    line_segments = []
    for line in fread:
        element, x_co, y_co, z_co = line.split()
        if element == 'v':
            polyline_vertices.append(
                [util.to_float(x_co), util.to_float(y_co), util.to_float(z_co)])
        elif element == 'l':
            p1 = x_co
            p2 = y_co
            line_segments.append([int(p1), int(p2)])

    fread.close()
    if log is not None:
        log_file = open(log, 'a')
        #log_file.write('***Axis Aligned Bounding Results for file "%s":\n' % fbasename)
        """log_file.write('min = %s\n' % aabb['min'])
        log_file.write('max = %s\n' % aabb['max'])
        log_file.write('center = %s\n' % aabb['center'])
        log_file.write('size = %s\n' % aabb['size'])
        log_file.write('diagonal = %s\n' % aabb['diagonal'])"""
        log_file.close()
    # print(aabb)
    return None

Sort separate line segments in obj format into a continuous polyline or polylines . NOT FINISHED ; DO NOT USE


def measure_topology(fbasename=None, log=None, ml_version=ml_version):
    """Measures mesh topology

    Args:
        fbasename (str): input filename.
        log (str): filename to log output

    Returns:
        dict: dictionary with the following keys:
            vert_num (int): number of vertices
            edge_num (int): number of edges
            face_num (int): number of faces
            unref_vert_num (int): number or unreferenced vertices
            boundry_edge_num (int): number of boundary edges
            part_num (int): number of parts (components) in the mesh.
            manifold (bool): True if mesh is two-manifold, otherwise false.
            non_manifold_edge (int): number of non_manifold edges.
            non_manifold_vert (int): number of non-manifold verices
            genus (int or str): genus of the mesh, either a number or
                'undefined' if the mesh is non-manifold.
            holes (int or str): number of holes in the mesh, either a number
                or 'undefined' if the mesh is non-manifold.

    """
    ml_script1_file = 'TEMP3D_measure_topology.mlx'
    ml_script1 = mlx.FilterScript(file_in=fbasename, ml_version=ml_version)
    compute.measure_topology(ml_script1)
    ml_script1.save_to_file(ml_script1_file)
    ml_script1.run_script(log=log, script_file=ml_script1_file)
    topology = ml_script1.topology
    return topology

def measure_topology ( fbasename = None , log = None , ml_version = ml_version ) : ml_script1_file = 'TEMP3D_measure_topology.mlx' ml_script1 = mlx . FilterScript ( file_in = fbasename , ml_version = ml_version ) compute . measure_topology ( ml_script1 ) ml_script1 . save_to_file ( ml_script1_file ) ml_script1 . run_script ( log = log , script_file = ml_script1_file ) topology = ml_script1 . topology return topology


def measure_all(fbasename=None, log=None, ml_version=ml_version):
    """Measures mesh geometry, aabb and topology."""
    ml_script1_file = 'TEMP3D_measure_gAndT.mlx'
    if ml_version == '1.3.4BETA':
        file_out = 'TEMP3D_aabb.xyz'
    else:
        file_out = None

    ml_script1 = mlx.FilterScript(file_in=fbasename, file_out=file_out, ml_version=ml_version)
    compute.measure_geometry(ml_script1)
    compute.measure_topology(ml_script1)
    ml_script1.save_to_file(ml_script1_file)
    ml_script1.run_script(log=log, script_file=ml_script1_file)
    geometry = ml_script1.geometry
    topology = ml_script1.topology

    if ml_version == '1.3.4BETA':
        if log is not None:
            log_file = open(log, 'a')
            log_file.write(
                '***Axis Aligned Bounding Results for file "%s":\n' %
                fbasename)
            log_file.close()
        aabb = measure_aabb(file_out, log)
    else:
        aabb = geometry['aabb']
    return aabb, geometry, topology

Measures mesh geometry aabb and topology .


def measure_dimension(fbasename=None, log=None, axis1=None, offset1=0.0,
                      axis2=None, offset2=0.0, ml_version=ml_version):
    """Measure a dimension of a mesh"""
    axis1 = axis1.lower()
    axis2 = axis2.lower()
    ml_script1_file = 'TEMP3D_measure_dimension.mlx'
    file_out = 'TEMP3D_measure_dimension.xyz'

    ml_script1 = mlx.FilterScript(file_in=fbasename, file_out=file_out, ml_version=ml_version)
    compute.section(ml_script1, axis1, offset1, surface=True)
    compute.section(ml_script1, axis2, offset2, surface=False)
    layers.delete_lower(ml_script1)
    ml_script1.save_to_file(ml_script1_file)
    ml_script1.run_script(log=log, script_file=ml_script1_file)

    for val in ('x', 'y', 'z'):
        if val not in (axis1, axis2):
            axis = val
    # ord: Get number that represents letter in ASCII
    # Here we find the offset from 'x' to determine the list reference
    # i.e. 0 for x, 1 for y, 2 for z
    axis_num = ord(axis) - ord('x')
    aabb = measure_aabb(file_out, log)
    dimension = {'min': aabb['min'][axis_num], 'max': aabb['max'][axis_num],
                 'length': aabb['size'][axis_num], 'axis': axis}
    if log is None:
        print('\nFor file "%s"' % fbasename)
        print('Dimension parallel to %s with %s=%s & %s=%s:' % (axis, axis1, offset1,
                                                                axis2, offset2))
        print('  Min = %s, Max = %s, Total length = %s' % (dimension['min'],
                                                           dimension['max'], dimension['length']))
    else:
        log_file = open(log, 'a')
        log_file.write('\nFor file "%s"\n' % fbasename)
        log_file.write('Dimension parallel to %s with %s=%s & %s=%s:\n' % (axis, axis1, offset1,
                                                                           axis2, offset2))
        log_file.write('min = %s\n' % dimension['min'])
        log_file.write('max = %s\n' % dimension['max'])
        log_file.write('Total length = %s\n' % dimension['length'])
        log_file.close()
    return dimension


def lowercase_ext(filename):
    """
    This is a helper used by UploadSet.save to provide lowercase extensions for
    all processed files, to compare with configured extensions in the same
    case.

    .. versionchanged:: 0.1.4
       Filenames without extensions are no longer lowercased, only the
       extension is returned in lowercase, if an extension exists.

    :param filename: The filename to ensure has a lowercase extension.
    """
    if '.' in filename:
        main, ext = os.path.splitext(filename)
        return main + ext.lower()
    # For consistency with os.path.splitext,
    # do not treat a filename without an extension as an extension.
    # That is, do not return filename.lower().
    return filename

This is a helper used by UploadSet . save to provide lowercase extensions for all processed files to compare with configured extensions in the same case .


def patch_request_class(app, size=64 * 1024 * 1024):
    """
    By default, Flask will accept uploads to an arbitrary size. While Werkzeug
    switches uploads from memory to a temporary file when they hit 500 KiB,
    it's still possible for someone to overload your disk space with a
    gigantic file.

    This patches the app's request class's
    `~werkzeug.BaseRequest.max_content_length` attribute so that any upload
    larger than the given size is rejected with an HTTP error.

    .. note::

       In Flask 0.6, you can do this by setting the `MAX_CONTENT_LENGTH`
       setting, without patching the request class. To emulate this behavior,
       you can pass `None` as the size (you must pass it explicitly). That is
       the best way to call this function, as it won't break the Flask 0.6
       functionality if it exists.

    .. versionchanged:: 0.1.1

    :param app: The app to patch the request class of.
    :param size: The maximum size to accept, in bytes. The default is 64 MiB.
                 If it is `None`, the app's `MAX_CONTENT_LENGTH` configuration
                 setting will be used to patch.
    """
    if size is None:
        if isinstance(app.request_class.__dict__['max_content_length'],
                      property):
            return
        size = app.config.get('MAX_CONTENT_LENGTH')
    reqclass = app.request_class
    patched = type(reqclass.__name__, (reqclass,),
                   {'max_content_length': size})
    app.request_class = patched

def patch_request_class ( app , size = 64 * 1024 * 1024 ) : if size is None : if isinstance ( app . request_class . __dict__ [ 'max_content_length' ] , property ) : return size = app . config . get ( 'MAX_CONTENT_LENGTH' ) reqclass = app . request_class patched = type ( reqclass . __name__ , ( reqclass , ) , { 'max_content_length' : size } ) app . request_class = patched

By default Flask will accept uploads to an arbitrary size . While Werkzeug switches uploads from memory to a temporary file when they hit 500 KiB it s still possible for someone to overload your disk space with a gigantic file .


def config_for_set(uset, app, defaults=None):
    """
    This is a helper function for `configure_uploads` that extracts the
    configuration for a single set.

    :param uset: The upload set.
    :param app: The app to load the configuration from.
    :param defaults: A dict with keys `url` and `dest` from the
                     `UPLOADS_DEFAULT_DEST` and `DEFAULT_UPLOADS_URL`
                     settings.
    """
    config = app.config
    prefix = 'UPLOADED_%s_' % uset.name.upper()
    using_defaults = False
    if defaults is None:
        defaults = dict(dest=None, url=None)

    allow_extns = tuple(config.get(prefix + 'ALLOW', ()))
    deny_extns = tuple(config.get(prefix + 'DENY', ()))
    destination = config.get(prefix + 'DEST')
    base_url = config.get(prefix + 'URL')

    if destination is None:
        # the upload set's destination wasn't given
        if uset.default_dest:
            # use the "default_dest" callable
            destination = uset.default_dest(app)
        if destination is None: # still
            # use the default dest from the config
            if defaults['dest'] is not None:
                using_defaults = True
                destination = os.path.join(defaults['dest'], uset.name)
            else:
                raise RuntimeError("no destination for set %s" % uset.name)

    if base_url is None and using_defaults and defaults['url']:
        base_url = addslash(defaults['url']) + uset.name + '/'

    return UploadConfiguration(destination, base_url, allow_extns, deny_extns)

This is a helper function for configure_uploads that extracts the configuration for a single set .


def configure_uploads(app, upload_sets):
    """
    Call this after the app has been configured. It will go through all the
    upload sets, get their configuration, and store the configuration on the
    app. It will also register the uploads module if it hasn't been set. This
    can be called multiple times with different upload sets.

    .. versionchanged:: 0.1.3
       The uploads module/blueprint will only be registered if it is needed
       to serve the upload sets.

    :param app: The `~flask.Flask` instance to get the configuration from.
    :param upload_sets: The `UploadSet` instances to configure.
    """
    if isinstance(upload_sets, UploadSet):
        upload_sets = (upload_sets,)

    if not hasattr(app, 'upload_set_config'):
        app.upload_set_config = {}
    set_config = app.upload_set_config
    defaults = dict(dest=app.config.get('UPLOADS_DEFAULT_DEST'),
                    url=app.config.get('UPLOADS_DEFAULT_URL'))

    for uset in upload_sets:
        config = config_for_set(uset, app, defaults)
        set_config[uset.name] = config

    should_serve = any(s.base_url is None for s in set_config.values())
    if '_uploads' not in app.blueprints and should_serve:
        app.register_blueprint(uploads_mod)

def configure_uploads ( app , upload_sets ) : if isinstance ( upload_sets , UploadSet ) : upload_sets = ( upload_sets , ) if not hasattr ( app , 'upload_set_config' ) : app . upload_set_config = { } set_config = app . upload_set_config defaults = dict ( dest = app . config . get ( 'UPLOADS_DEFAULT_DEST' ) , url = app . config . get ( 'UPLOADS_DEFAULT_URL' ) ) for uset in upload_sets : config = config_for_set ( uset , app , defaults ) set_config [ uset . name ] = config should_serve = any ( s . base_url is None for s in set_config . values ( ) ) if '_uploads' not in app . blueprints and should_serve : app . register_blueprint ( uploads_mod )

Call this after the app has been configured . It will go through all the upload sets get their configuration and store the configuration on the app . It will also register the uploads module if it hasn t been set . This can be called multiple times with different upload sets .


def config(self):
        """
        This gets the current configuration. By default, it looks up the
        current application and gets the configuration from there. But if you
        don't want to go to the full effort of setting an application, or it's
        otherwise outside of a request context, set the `_config` attribute to
        an `UploadConfiguration` instance, then set it back to `None` when
        you're done.
        """
        if self._config is not None:
            return self._config
        try:
            return current_app.upload_set_config[self.name]
        except AttributeError:
            raise RuntimeError("cannot access configuration outside request")

This gets the current configuration . By default it looks up the current application and gets the configuration from there . But if you don t want to go to the full effort of setting an application or it s otherwise outside of a request context set the _config attribute to an UploadConfiguration instance then set it back to None when you re done .


def url(self, filename):
        """
        This function gets the URL a file uploaded to this set would be
        accessed at. It doesn't check whether said file exists.

        :param filename: The filename to return the URL for.
        """
        base = self.config.base_url
        if base is None:
            return url_for('_uploads.uploaded_file', setname=self.name,
                           filename=filename, _external=True)
        else:
            return base + filename

def url ( self , filename ) : base = self . config . base_url if base is None : return url_for ( '_uploads.uploaded_file' , setname = self . name , filename = filename , _external = True ) else : return base + filename

This function gets the URL a file uploaded to this set would be accessed at . It doesn t check whether said file exists .


def path(self, filename, folder=None):
        """
        This returns the absolute path of a file uploaded to this set. It
        doesn't actually check whether said file exists.

        :param filename: The filename to return the path for.
        :param folder: The subfolder within the upload set previously used
                       to save to.
        """
        if folder is not None:
            target_folder = os.path.join(self.config.destination, folder)
        else:
            target_folder = self.config.destination
        return os.path.join(target_folder, filename)

def path ( self , filename , folder = None ) : if folder is not None : target_folder = os . path . join ( self . config . destination , folder ) else : target_folder = self . config . destination return os . path . join ( target_folder , filename )

This returns the absolute path of a file uploaded to this set . It doesn t actually check whether said file exists .


def extension_allowed(self, ext):
        """
        This determines whether a specific extension is allowed. It is called
        by `file_allowed`, so if you override that but still want to check
        extensions, call back into this.

        :param ext: The extension to check, without the dot.
        """
        return ((ext in self.config.allow) or
                (ext in self.extensions and ext not in self.config.deny))

def extension_allowed ( self , ext ) : return ( ( ext in self . config . allow ) or ( ext in self . extensions and ext not in self . config . deny ) )

This determines whether a specific extension is allowed . It is called by file_allowed so if you override that but still want to check extensions call back into this .


def resolve_conflict(self, target_folder, basename):
        """
        If a file with the selected name already exists in the target folder,
        this method is called to resolve the conflict. It should return a new
        basename for the file.

        The default implementation splits the name and extension and adds a
        suffix to the name consisting of an underscore and a number, and tries
        that until it finds one that doesn't exist.

        :param target_folder: The absolute path to the target.
        :param basename: The file's original basename.
        """
        name, ext = os.path.splitext(basename)
        count = 0
        while True:
            count = count + 1
            newname = '%s_%d%s' % (name, count, ext)
            if not os.path.exists(os.path.join(target_folder, newname)):
                return newname

def resolve_conflict ( self , target_folder , basename ) : name , ext = os . path . splitext ( basename ) count = 0 while True : count = count + 1 newname = '%s_%d%s' % ( name , count , ext ) if not os . path . exists ( os . path . join ( target_folder , newname ) ) : return newname

If a file with the selected name already exists in the target folder this method is called to resolve the conflict . It should return a new basename for the file .


def get_vprof_version(filename):
    """Returns actual version specified in filename."""
    with open(filename) as src_file:
        version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
                                  src_file.read(), re.M)
        if version_match:
            return version_match.group(1)
        raise RuntimeError('Unable to find version info.')

def
get_vprof_version
(
filename
)
:
with
open
(
filename
)
as
src_file
:
version_match
=
re
.
search
(
r"^__version__ = ['\"]([^'\"]*)['\"]"
,
src_file
.
read
(
)
,
re
.
M
)
if
version_match
:
return
version_match
.
group
(
1
)
raise
RuntimeError
(
'Unable to find version info.'
)

Returns actual version specified in filename .


def _remove_duplicates(objects):
    """Removes duplicate objects.

    http://www.peterbe.com/plog/uniqifiers-benchmark.
    """
    seen, uniq = set(), []
    for obj in objects:
        obj_id = id(obj)
        if obj_id in seen:
            continue
        seen.add(obj_id)
        uniq.append(obj)
    return uniq

def _remove_duplicates ( objects ) : seen , uniq = set ( ) , [ ] for obj in objects : obj_id = id ( obj ) if obj_id in seen : continue seen . add ( obj_id ) uniq . append ( obj ) return uniq


def _get_obj_count_difference(objs1, objs2):
    """Returns count difference in two collections of Python objects."""
    clean_obj_list1 = _process_in_memory_objects(objs1)
    clean_obj_list2 = _process_in_memory_objects(objs2)
    obj_count_1 = _get_object_count_by_type(clean_obj_list1)
    obj_count_2 = _get_object_count_by_type(clean_obj_list2)
    return obj_count_1 - obj_count_2

Returns count difference in two collections of Python objects .


def _format_obj_count(objects):
    """Formats object count."""
    result = []
    regex = re.compile(r'<(?P<type>\w+) \'(?P<name>\S+)\'>')
    for obj_type, obj_count in objects.items():
        if obj_count != 0:
            match = re.findall(regex, repr(obj_type))
            if match:
                obj_type, obj_name = match[0]
                result.append(("%s %s" % (obj_type, obj_name), obj_count))
    return sorted(result, key=operator.itemgetter(1), reverse=True)

def
_format_obj_count
(
objects
)
:
result
=
[
]
regex
=
re
.
compile
(
r'<(?P<type>\w+) \'(?P<name>\S+)\'>'
)
for
obj_type
,
obj_count
in
objects
.
items
(
)
:
if
obj_count
!=
0
:
match
=
re
.
findall
(
regex
,
repr
(
obj_type
)
)
if
match
:
obj_type
,
obj_name
=
match
[
0
]
result
.
append
(
(
"%s %s"
%
(
obj_type
,
obj_name
)
,
obj_count
)
)
return
sorted
(
result
,
key
=
operator
.
itemgetter
(
1
)
,
reverse
=
True
)


def _trace_memory_usage(self, frame, event, arg):  #pylint: disable=unused-argument
        """Checks memory usage when 'line' event occur."""
        if event == 'line' and frame.f_code.co_filename in self.target_modules:
            self._events_list.append(
                (frame.f_lineno, self._process.memory_info().rss,
                 frame.f_code.co_name, frame.f_code.co_filename))
        return self._trace_memory_usage

def
_trace_memory_usage
(
self
,
frame
,
event
,
arg
)
:
#pylint: disable=unused-argument
if
event
==
'line'
and
frame
.
f_code
.
co_filename
in
self
.
target_modules
:
self
.
_events_list
.
append
(
(
frame
.
f_lineno
,
self
.
_process
.
memory_info
(
)
.
rss
,
frame
.
f_code
.
co_name
,
frame
.
f_code
.
co_filename
)
)
return
self
.
_trace_memory_usage

Checks memory usage when line event occur .


def code_events(self):
        """Returns processed memory usage."""
        if self._resulting_events:
            return self._resulting_events
        for i, (lineno, mem, func, fname) in enumerate(self._events_list):
            mem_in_mb = float(mem - self.mem_overhead) / _BYTES_IN_MB
            if (self._resulting_events and
                    self._resulting_events[-1][0] == lineno and
                    self._resulting_events[-1][2] == func and
                    self._resulting_events[-1][3] == fname and
                    self._resulting_events[-1][1] < mem_in_mb):
                self._resulting_events[-1][1] = mem_in_mb
            else:
                self._resulting_events.append(
                    [i + 1, lineno, mem_in_mb, func, fname])
        return self._resulting_events

def code_events ( self ) : if self . _resulting_events : return self . _resulting_events for i , ( lineno , mem , func , fname ) in enumerate ( self . _events_list ) : mem_in_mb = float ( mem - self . mem_overhead ) / _BYTES_IN_MB if ( self . _resulting_events and self . _resulting_events [ - 1 ] [ 0 ] == lineno and self . _resulting_events [ - 1 ] [ 2 ] == func and self . _resulting_events [ - 1 ] [ 3 ] == fname and self . _resulting_events [ - 1 ] [ 1 ] < mem_in_mb ) : self . _resulting_events [ - 1 ] [ 1 ] = mem_in_mb else : self . _resulting_events . append ( [ i + 1 , lineno , mem_in_mb , func , fname ] ) return self . _resulting_events


def obj_overhead(self):
        """Returns all objects that are considered a profiler overhead.
        Objects are hardcoded for convenience.
        """
        overhead = [
            self,
            self._resulting_events,
            self._events_list,
            self._process
        ]
        overhead_count = _get_object_count_by_type(overhead)
        # One for reference to __dict__ and one for reference to
        # the current module.
        overhead_count[dict] += 2
        return overhead_count

Returns all objects that are considered a profiler overhead . Objects are hardcoded for convenience .


def compute_mem_overhead(self):
        """Returns memory overhead."""
        self.mem_overhead = (self._process.memory_info().rss -
                             builtins.initial_rss_size)

def compute_mem_overhead ( self ) : self . mem_overhead = ( self . _process . memory_info ( ) . rss - builtins . initial_rss_size )


def profile_package(self):
        """Returns memory stats for a package."""
        target_modules = base_profiler.get_pkg_module_names(self._run_object)
        try:
            with _CodeEventsTracker(target_modules) as prof:
                prof.compute_mem_overhead()
                runpy.run_path(self._run_object, run_name='__main__')
        except SystemExit:
            pass
        return prof, None

def profile_package ( self ) : target_modules = base_profiler . get_pkg_module_names ( self . _run_object ) try : with _CodeEventsTracker ( target_modules ) as prof : prof . compute_mem_overhead ( ) runpy . run_path ( self . _run_object , run_name = '__main__' ) except SystemExit : pass return prof , None


def profile_module(self):
        """Returns memory stats for a module."""
        target_modules = {self._run_object}
        try:
            with open(self._run_object, 'rb') as srcfile,\
                _CodeEventsTracker(target_modules) as prof:
                code = compile(srcfile.read(), self._run_object, 'exec')
                prof.compute_mem_overhead()
                exec(code, self._globs, None)
        except SystemExit:
            pass
        return prof, None

def profile_module ( self ) : target_modules = { self . _run_object } try : with open ( self . _run_object , 'rb' ) as srcfile , _CodeEventsTracker ( target_modules ) as prof : code = compile ( srcfile . read ( ) , self . _run_object , 'exec' ) prof . compute_mem_overhead ( ) exec ( code , self . _globs , None ) except SystemExit : pass return prof , None


def profile_function(self):
        """Returns memory stats for a function."""
        target_modules = {self._run_object.__code__.co_filename}
        with _CodeEventsTracker(target_modules) as prof:
            prof.compute_mem_overhead()
            result = self._run_object(*self._run_args, **self._run_kwargs)
        return prof, result

def profile_function ( self ) : target_modules = { self . _run_object . __code__ . co_filename } with _CodeEventsTracker ( target_modules ) as prof : prof . compute_mem_overhead ( ) result = self . _run_object ( * self . _run_args , * * self . _run_kwargs ) return prof , result


def run(self):
        """Collects memory stats for specified Python program."""
        existing_objects = _get_in_memory_objects()
        prof, result = self.profile()
        new_objects = _get_in_memory_objects()

        new_obj_count = _get_obj_count_difference(new_objects, existing_objects)
        result_obj_count = new_obj_count - prof.obj_overhead

        # existing_objects list is also profiler overhead
        result_obj_count[list] -= 1
        pretty_obj_count = _format_obj_count(result_obj_count)
        return {
            'objectName': self._object_name,
            'codeEvents': prof.code_events,
            'totalEvents': len(prof.code_events),
            'objectsCount': pretty_obj_count,
            'result': result,
            'timestamp': int(time.time())
        }

Collects memory stats for specified Python program .


def get_pkg_module_names(package_path):
    """Returns module filenames from package.

    Args:
        package_path: Path to Python package.
    Returns:
        A set of module filenames.
    """
    module_names = set()
    for fobj, modname, _ in pkgutil.iter_modules(path=[package_path]):
        filename = os.path.join(fobj.path, '%s.py' % modname)
        if os.path.exists(filename):
            module_names.add(os.path.abspath(filename))
    return module_names

def get_pkg_module_names ( package_path ) : module_names = set ( ) for fobj , modname , _ in pkgutil . iter_modules ( path = [ package_path ] ) : filename = os . path . join ( fobj . path , '%s.py' % modname ) if os . path . exists ( filename ) : module_names . add ( os . path . abspath ( filename ) ) return module_names


def run_in_separate_process(func, *args, **kwargs):
    """Runs function in separate process.

    This function is used instead of a decorator, since Python multiprocessing
    module can't serialize decorated function on all platforms.
    """
    manager = multiprocessing.Manager()
    manager_dict = manager.dict()
    process = ProcessWithException(
        manager_dict, target=func, args=args, kwargs=kwargs)
    process.start()
    process.join()
    exc = process.exception
    if exc:
        raise exc
    return process.output

def run_in_separate_process ( func , * args , * * kwargs ) : manager = multiprocessing . Manager ( ) manager_dict = manager . dict ( ) process = ProcessWithException ( manager_dict , target = func , args = args , kwargs = kwargs ) process . start ( ) process . join ( ) exc = process . exception if exc : raise exc return process . output


def get_run_object_type(run_object):
        """Determines run object type."""
        if isinstance(run_object, tuple):
            return 'function'
        run_object, _, _ = run_object.partition(' ')
        if os.path.isdir(run_object):
            return 'package'
        return 'module'

def
get_run_object_type
(
run_object
)
:
if
isinstance
(
run_object
,
tuple
)
:
return
'function'
run_object
,
_
,
_
=
run_object
.
partition
(
' '
)
if
os
.
path
.
isdir
(
run_object
)
:
return
'package'
return
'module'


def init_module(self, run_object):
        """Initializes profiler with a module."""
        self.profile = self.profile_module
        self._run_object, _, self._run_args = run_object.partition(' ')
        self._object_name = '%s (module)' % self._run_object
        self._globs = {
            '__file__': self._run_object,
            '__name__': '__main__',
            '__package__': None,
        }
        program_path = os.path.dirname(self._run_object)
        if sys.path[0] != program_path:
            sys.path.insert(0, program_path)
        self._replace_sysargs()

def
init_module
(
self
,
run_object
)
:
self
.
profile
=
self
.
profile_module
self
.
_run_object
,
_
,
self
.
_run_args
=
run_object
.
partition
(
' '
)
self
.
_object_name
=
'%s (module)'
%
self
.
_run_object
self
.
_globs
=
{
'__file__'
:
self
.
_run_object
,
'__name__'
:
'__main__'
,
'__package__'
:
,
}
program_path
=
os
.
path
.
dirname
(
self
.
_run_object
)
if
sys
.
path
[
0
]
!=
program_path
:
sys
.
path
.
insert
(
0
,
program_path
)
self
.
_replace_sysargs
(
)


def init_package(self, run_object):
        """Initializes profiler with a package."""
        self.profile = self.profile_package
        self._run_object, _, self._run_args = run_object.partition(' ')
        self._object_name = '%s (package)' % self._run_object
        self._replace_sysargs()

def
init_package
(
self
,
run_object
)
:
self
.
profile
=
self
.
profile_package
self
.
_run_object
,
_
,
self
.
_run_args
=
run_object
.
partition
(
' '
)
self
.
_object_name
=
'%s (package)'
%
self
.
_run_object
self
.
_replace_sysargs
(
)


def init_function(self, run_object):
        """Initializes profiler with a function."""
        self.profile = self.profile_function
        self._run_object, self._run_args, self._run_kwargs = run_object
        filename = inspect.getsourcefile(self._run_object)
        self._object_name = '%s @ %s (function)' % (
            self._run_object.__name__, filename)

def
init_function
(
self
,
run_object
)
:
self
.
profile
=
self
.
profile_function
self
.
_run_object
,
self
.
_run_args
,
self
.
_run_kwargs
=
run_object
filename
=
inspect
.
getsourcefile
(
self
.
_run_object
)
self
.
_object_name
=
'%s @ %s (function)'
%
(
self
.
_run_object
.
__name__
,
filename
)


def _replace_sysargs(self):
        """Replaces sys.argv with proper args to pass to script."""
        sys.argv[:] = [self._run_object]
        if self._run_args:
            sys.argv += self._run_args.split()

def _replace_sysargs ( self ) : sys . argv [ : ] = [ self . _run_object ] if self . _run_args : sys . argv += self . _run_args . split ( )

Replaces sys . argv with proper args to pass to script .


def sample(self, signum, frame):  #pylint: disable=unused-argument
        """Samples current stack and adds result in self._stats.

        Args:
            signum: Signal that activates handler.
            frame: Frame on top of the stack when signal is handled.
        """
        stack = []
        while frame and frame != self.base_frame:
            stack.append((
                frame.f_code.co_name,
                frame.f_code.co_filename,
                frame.f_code.co_firstlineno))
            frame = frame.f_back
        self._stats[tuple(stack)] += 1
        signal.setitimer(signal.ITIMER_PROF, _SAMPLE_INTERVAL)

def
sample
(
self
,
signum
,
frame
)
:
#pylint: disable=unused-argument
stack
=
[
]
while
frame
and
frame
!=
self
.
base_frame
:
stack
.
append
(
(
frame
.
f_code
.
co_name
,
frame
.
f_code
.
co_filename
,
frame
.
f_code
.
co_firstlineno
)
)
frame
=
frame
.
f_back
self
.
_stats
[
tuple
(
stack
)
]
+=
1
signal
.
setitimer
(
signal
.
ITIMER_PROF
,
_SAMPLE_INTERVAL
)

Samples current stack and adds result in self . _stats .


def _insert_stack(stack, sample_count, call_tree):
        """Inserts stack into the call tree.

        Args:
            stack: Call stack.
            sample_count: Sample count of call stack.
            call_tree: Call tree.
        """
        curr_level = call_tree
        for func in stack:
            next_level_index = {
                node['stack']: node for node in curr_level['children']}
            if func not in next_level_index:
                new_node = {'stack': func, 'children': [], 'sampleCount': 0}
                curr_level['children'].append(new_node)
                curr_level = new_node
            else:
                curr_level = next_level_index[func]
        curr_level['sampleCount'] = sample_count

def _insert_stack ( stack , sample_count , call_tree ) : curr_level = call_tree for func in stack : next_level_index = { node [ 'stack' ] : node for node in curr_level [ 'children' ] } if func not in next_level_index : new_node = { 'stack' : func , 'children' : [ ] , 'sampleCount' : 0 } curr_level [ 'children' ] . append ( new_node ) curr_level = new_node else : curr_level = next_level_index [ func ] curr_level [ 'sampleCount' ] = sample_count


def _fill_sample_count(self, node):
        """Counts and fills sample counts inside call tree."""
        node['sampleCount'] += sum(
            self._fill_sample_count(child) for child in node['children'])
        return node['sampleCount']

def _fill_sample_count ( self , node ) : node [ 'sampleCount' ] += sum ( self . _fill_sample_count ( child ) for child in node [ 'children' ] ) return node [ 'sampleCount' ]

Counts and fills sample counts inside call tree .


def _format_tree(self, node, total_samples):
        """Reformats call tree for the UI."""
        funcname, filename, _ = node['stack']
        sample_percent = self._get_percentage(
            node['sampleCount'], total_samples)
        color_hash = base_profiler.hash_name('%s @ %s' % (funcname, filename))
        return {
            'stack': node['stack'],
            'children': [self._format_tree(child, total_samples)
                         for child in node['children']],
            'sampleCount': node['sampleCount'],
            'samplePercentage': sample_percent,
            'colorHash': color_hash
        }

def
_format_tree
(
self
,
node
,
total_samples
)
:
funcname
,
filename
,
_
=
node
[
'stack'
]
sample_percent
=
self
.
_get_percentage
(
node
[
'sampleCount'
]
,
total_samples
)
color_hash
=
base_profiler
.
hash_name
(
'%s @ %s'
%
(
funcname
,
filename
)
)
return
{
'stack'
:
node
[
'stack'
]
,
'children'
:
[
self
.
_format_tree
(
child
,
total_samples
)
for
child
in
node
[
'children'
]
]
,
'sampleCount'
:
node
[
'sampleCount'
]
,
'samplePercentage'
:
sample_percent
,
'colorHash'
:
color_hash
}


def call_tree(self):
        """Returns call tree."""
        call_tree = {'stack': 'base', 'sampleCount': 0, 'children': []}
        for stack, sample_count in self._stats.items():
            self._insert_stack(reversed(stack), sample_count, call_tree)
        self._fill_sample_count(call_tree)
        if not call_tree['children']:
            return {}
        return self._format_tree(
            call_tree['children'][0], call_tree['sampleCount'])

def call_tree ( self ) : call_tree = { 'stack' : 'base' , 'sampleCount' : 0 , 'children' : [ ] } for stack , sample_count in self . _stats . items ( ) : self . _insert_stack ( reversed ( stack ) , sample_count , call_tree ) self . _fill_sample_count ( call_tree ) if not call_tree [ 'children' ] : return { } return self . _format_tree ( call_tree [ 'children' ] [ 0 ] , call_tree [ 'sampleCount' ] )


def _profile_package(self):
        """Runs statistical profiler on a package."""
        with _StatProfiler() as prof:
            prof.base_frame = inspect.currentframe()
            try:
                runpy.run_path(self._run_object, run_name='__main__')
            except SystemExit:
                pass

        call_tree = prof.call_tree
        return {
            'objectName': self._object_name,
            'sampleInterval': _SAMPLE_INTERVAL,
            'runTime': prof.run_time,
            'callStats': call_tree,
            'totalSamples': call_tree.get('sampleCount', 0),
            'timestamp': int(time.time())
        }

def _profile_package ( self ) : with _StatProfiler ( ) as prof : prof . base_frame = inspect . currentframe ( ) try : runpy . run_path ( self . _run_object , run_name = '__main__' ) except SystemExit : pass call_tree = prof . call_tree return { 'objectName' : self . _object_name , 'sampleInterval' : _SAMPLE_INTERVAL , 'runTime' : prof . run_time , 'callStats' : call_tree , 'totalSamples' : call_tree . get ( 'sampleCount' , 0 ) , 'timestamp' : int ( time . time ( ) ) }

Runs statistical profiler on a package .


def _profile_module(self):
        """Runs statistical profiler on a module."""
        with open(self._run_object, 'rb') as srcfile, _StatProfiler() as prof:
            code = compile(srcfile.read(), self._run_object, 'exec')
            prof.base_frame = inspect.currentframe()
            try:
                exec(code, self._globs, None)
            except SystemExit:
                pass

        call_tree = prof.call_tree
        return {
            'objectName': self._object_name,
            'sampleInterval': _SAMPLE_INTERVAL,
            'runTime': prof.run_time,
            'callStats': call_tree,
            'totalSamples': call_tree.get('sampleCount', 0),
            'timestamp': int(time.time())
        }

def _profile_module ( self ) : with open ( self . _run_object , 'rb' ) as srcfile , _StatProfiler ( ) as prof : code = compile ( srcfile . read ( ) , self . _run_object , 'exec' ) prof . base_frame = inspect . currentframe ( ) try : exec ( code , self . _globs , None ) except SystemExit : pass call_tree = prof . call_tree return { 'objectName' : self . _object_name , 'sampleInterval' : _SAMPLE_INTERVAL , 'runTime' : prof . run_time , 'callStats' : call_tree , 'totalSamples' : call_tree . get ( 'sampleCount' , 0 ) , 'timestamp' : int ( time . time ( ) ) }


def profile_function(self):
        """Runs statistical profiler on a function."""
        with _StatProfiler() as prof:
            result = self._run_object(*self._run_args, **self._run_kwargs)

        call_tree = prof.call_tree
        return {
            'objectName': self._object_name,
            'sampleInterval': _SAMPLE_INTERVAL,
            'runTime': prof.run_time,
            'callStats': call_tree,
            'totalSamples': call_tree.get('sampleCount', 0),
            'result': result,
            'timestamp': int(time.time())
        }

def profile_function ( self ) : with _StatProfiler ( ) as prof : result = self . _run_object ( * self . _run_args , * * self . _run_kwargs ) call_tree = prof . call_tree return { 'objectName' : self . _object_name , 'sampleInterval' : _SAMPLE_INTERVAL , 'runTime' : prof . run_time , 'callStats' : call_tree , 'totalSamples' : call_tree . get ( 'sampleCount' , 0 ) , 'result' : result , 'timestamp' : int ( time . time ( ) ) }

Runs statistical profiler on a function .


def _transform_stats(prof):
        """Processes collected stats for UI."""
        records = []
        for info, params in prof.stats.items():
            filename, lineno, funcname = info
            cum_calls, num_calls, time_per_call, cum_time, _ = params
            if prof.total_tt == 0:
                percentage = 0
            else:
                percentage = round(100 * (cum_time / prof.total_tt), 4)
            cum_time = round(cum_time, 4)
            func_name = '%s @ %s' % (funcname, filename)
            color_hash = base_profiler.hash_name(func_name)
            records.append(
                (filename, lineno, funcname, cum_time, percentage, num_calls,
                 cum_calls, time_per_call, filename, color_hash))
        return sorted(records, key=operator.itemgetter(4), reverse=True)

def
_transform_stats
(
prof
)
:
records
=
[
]
for
info
,
params
in
prof
.
stats
.
items
(
)
:
filename
,
lineno
,
funcname
=
info
cum_calls
,
num_calls
,
time_per_call
,
cum_time
,
_
=
params
if
prof
.
total_tt
==
0
:
percentage
=
0
else
:
percentage
=
round
(
100
*
(
cum_time
/
prof
.
total_tt
)
,
4
)
cum_time
=
round
(
cum_time
,
4
)
func_name
=
'%s @ %s'
%
(
funcname
,
filename
)
color_hash
=
base_profiler
.
hash_name
(
func_name
)
records
.
append
(
(
filename
,
lineno
,
funcname
,
cum_time
,
percentage
,
num_calls
,
cum_calls
,
time_per_call
,
filename
,
color_hash
)
)
return
sorted
(
records
,
key
=
operator
.
itemgetter
(
4
)
,
reverse
=
True
)


def _profile_package(self):
        """Runs cProfile on a package."""
        prof = cProfile.Profile()
        prof.enable()
        try:
            runpy.run_path(self._run_object, run_name='__main__')
        except SystemExit:
            pass
        prof.disable()
        prof_stats = pstats.Stats(prof)
        prof_stats.calc_callees()
        return {
            'objectName': self._object_name,
            'callStats': self._transform_stats(prof_stats),
            'totalTime': prof_stats.total_tt,
            'primitiveCalls': prof_stats.prim_calls,
            'totalCalls': prof_stats.total_calls,
            'timestamp': int(time.time())
        }

def _profile_package ( self ) : prof = cProfile . Profile ( ) prof . enable ( ) try : runpy . run_path ( self . _run_object , run_name = '__main__' ) except SystemExit : pass prof . disable ( ) prof_stats = pstats . Stats ( prof ) prof_stats . calc_callees ( ) return { 'objectName' : self . _object_name , 'callStats' : self . _transform_stats ( prof_stats ) , 'totalTime' : prof_stats . total_tt , 'primitiveCalls' : prof_stats . prim_calls , 'totalCalls' : prof_stats . total_calls , 'timestamp' : int ( time . time ( ) ) }


def _profile_module(self):
        """Runs cProfile on a module."""
        prof = cProfile.Profile()
        try:
            with open(self._run_object, 'rb') as srcfile:
                code = compile(srcfile.read(), self._run_object, 'exec')
            prof.runctx(code, self._globs, None)
        except SystemExit:
            pass
        prof_stats = pstats.Stats(prof)
        prof_stats.calc_callees()
        return {
            'objectName': self._object_name,
            'callStats': self._transform_stats(prof_stats),
            'totalTime': prof_stats.total_tt,
            'primitiveCalls': prof_stats.prim_calls,
            'totalCalls': prof_stats.total_calls,
            'timestamp': int(time.time())
        }

def _profile_module ( self ) : prof = cProfile . Profile ( ) try : with open ( self . _run_object , 'rb' ) as srcfile : code = compile ( srcfile . read ( ) , self . _run_object , 'exec' ) prof . runctx ( code , self . _globs , None ) except SystemExit : pass prof_stats = pstats . Stats ( prof ) prof_stats . calc_callees ( ) return { 'objectName' : self . _object_name , 'callStats' : self . _transform_stats ( prof_stats ) , 'totalTime' : prof_stats . total_tt , 'primitiveCalls' : prof_stats . prim_calls , 'totalCalls' : prof_stats . total_calls , 'timestamp' : int ( time . time ( ) ) }


def profile_function(self):
        """Runs cProfile on a function."""
        prof = cProfile.Profile()
        prof.enable()
        result = self._run_object(*self._run_args, **self._run_kwargs)
        prof.disable()
        prof_stats = pstats.Stats(prof)
        prof_stats.calc_callees()
        return {
            'objectName': self._object_name,
            'callStats': self._transform_stats(prof_stats),
            'totalTime': prof_stats.total_tt,
            'primitiveCalls': prof_stats.prim_calls,
            'totalCalls': prof_stats.total_calls,
            'result': result,
            'timestamp': int(time.time())
        }

def profile_function ( self ) : prof = cProfile . Profile ( ) prof . enable ( ) result = self . _run_object ( * self . _run_args , * * self . _run_kwargs ) prof . disable ( ) prof_stats = pstats . Stats ( prof ) prof_stats . calc_callees ( ) return { 'objectName' : self . _object_name , 'callStats' : self . _transform_stats ( prof_stats ) , 'totalTime' : prof_stats . total_tt , 'primitiveCalls' : prof_stats . prim_calls , 'totalCalls' : prof_stats . total_calls , 'result' : result , 'timestamp' : int ( time . time ( ) ) }


def init_db():
    """Initializes DB."""
    with contextlib.closing(connect_to_db()) as db:
        db.cursor().executescript(DB_SCHEMA)
        db.commit()

def init_db ( ) : with contextlib . closing ( connect_to_db ( ) ) as db : db . cursor ( ) . executescript ( DB_SCHEMA ) db . commit ( )


def show_guestbook():
    """Returns all existing guestbook records."""
    cursor = flask.g.db.execute(
        'SELECT name, message FROM entry ORDER BY id DESC;')
    entries = [{'name': row[0], 'message': row[1]} for row in cursor.fetchall()]
    return jinja2.Template(LAYOUT).render(entries=entries)

Returns all existing guestbook records .


def add_entry():
    """Adds single guestbook record."""
    name, msg = flask.request.form['name'], flask.request.form['message']
    flask.g.db.execute(
        'INSERT INTO entry (name, message) VALUES (?, ?)', (name, msg))
    flask.g.db.commit()
    return flask.redirect('/')


def profiler_handler(uri):
    """Profiler handler."""
    # HTTP method should be GET.
    if uri == 'main':
        runner.run(show_guestbook, 'cmhp')
    # In this case HTTP method should be POST singe add_entry uses POST
    elif uri == 'add':
        runner.run(add_entry, 'cmhp')
    return flask.redirect('/')


def start(host, port, profiler_stats, dont_start_browser, debug_mode):
    """Starts HTTP server with specified parameters.

    Args:
        host: Server host name.
        port: Server port.
        profiler_stats: A dict with collected program stats.
        dont_start_browser: Whether to open browser after profiling.
        debug_mode: Whether to redirect stderr to /dev/null.
    """
    stats_handler = functools.partial(StatsHandler, profiler_stats)
    if not debug_mode:
        sys.stderr = open(os.devnull, 'w')
    print('Starting HTTP server...')
    if not dont_start_browser:
        webbrowser.open('http://{}:{}/'.format(host, port))
    try:
        StatsServer((host, port), stats_handler).serve_forever()
    except KeyboardInterrupt:
        print('Stopping...')
        sys.exit(0)

def
start
(
host
,
port
,
profiler_stats
,
dont_start_browser
,
debug_mode
)
:
stats_handler
=
functools
.
partial
(
StatsHandler
,
profiler_stats
)
if
not
debug_mode
:
sys
.
stderr
=
open
(
os
.
devnull
,
'w'
)
print
(
'Starting HTTP server...'
)
if
not
dont_start_browser
:
webbrowser
.
open
(
'http://{}:{}/'
.
format
(
host
,
port
)
)
try
:
StatsServer
(
(
host
,
port
)
,
stats_handler
)
.
serve_forever
(
)
except
KeyboardInterrupt
:
print
(
'Stopping...'
)
sys
.
exit
(
0
)

Starts HTTP server with specified parameters .


def _handle_root():
        """Handles index.html requests."""
        res_filename = os.path.join(
            os.path.dirname(__file__), _PROFILE_HTML)
        with io.open(res_filename, 'rb') as res_file:
            content = res_file.read()
        return content, 'text/html'

def _handle_root ( ) : res_filename = os . path . join ( os . path . dirname ( __file__ ) , _PROFILE_HTML ) with io . open ( res_filename , 'rb' ) as res_file : content = res_file . read ( ) return content , 'text/html'


def _handle_other(self):
        """Handles static files requests."""
        res_filename = os.path.join(
            os.path.dirname(__file__), _STATIC_DIR, self.path[1:])
        with io.open(res_filename, 'rb') as res_file:
            content = res_file.read()
        _, extension = os.path.splitext(self.path)
        return content, 'text/%s' % extension[1:]

def _handle_other ( self ) : res_filename = os . path . join ( os . path . dirname ( __file__ ) , _STATIC_DIR , self . path [ 1 : ] ) with io . open ( res_filename , 'rb' ) as res_file : content = res_file . read ( ) _ , extension = os . path . splitext ( self . path ) return content , 'text/%s' % extension [ 1 : ]


def do_GET(self):
        """Handles HTTP GET requests."""
        handler = self.uri_map.get(self.path) or self._handle_other
        content, content_type = handler()
        compressed_content = gzip.compress(content)
        self._send_response(
            200, headers=(('Content-type', '%s; charset=utf-8' % content_type),
                          ('Content-Encoding', 'gzip'),
                          ('Content-Length', len(compressed_content))))
        self.wfile.write(compressed_content)

def
do_GET
(
self
)
:
handler
=
self
.
uri_map
.
get
(
self
.
path
)
or
self
.
_handle_other
content
,
content_type
=
handler
(
)
compressed_content
=
gzip
.
compress
(
content
)
self
.
_send_response
(
200
,
headers
=
(
(
'Content-type'
,
'%s; charset=utf-8'
%
content_type
)
,
(
'Content-Encoding'
,
'gzip'
)
,
(
'Content-Length'
,
len
(
compressed_content
)
)
)
)
self
.
wfile
.
write
(
compressed_content
)


def do_POST(self):
        """Handles HTTP POST requests."""
        post_data = self.rfile.read(int(self.headers['Content-Length']))
        json_data = gzip.decompress(post_data)
        self._profile_json.update(json.loads(json_data.decode('utf-8')))
        self._send_response(
            200, headers=(('Content-type', '%s; charset=utf-8' % 'text/json'),
                          ('Content-Encoding', 'gzip'),
                          ('Content-Length', len(post_data))))

def
do_POST
(
self
)
:
post_data
=
self
.
rfile
.
read
(
int
(
self
.
headers
[
'Content-Length'
]
)
)
json_data
=
gzip
.
decompress
(
post_data
)
self
.
_profile_json
.
update
(
json
.
loads
(
json_data
.
decode
(
'utf-8'
)
)
)
self
.
_send_response
(
200
,
headers
=
(
(
'Content-type'
,
'%s; charset=utf-8'
%
'text/json'
)
,
(
'Content-Encoding'
,
'gzip'
)
,
(
'Content-Length'
,
len
(
post_data
)
)
)
)


def _send_response(self, http_code, message=None, headers=None):
        """Sends HTTP response code, message and headers."""
        self.send_response(http_code, message)
        if headers:
            for header in headers:
                self.send_header(*header)
            self.end_headers()

def _send_response ( self , http_code , message = None , headers = None ) : self . send_response ( http_code , message ) if headers : for header in headers : self . send_header ( * header ) self . end_headers ( )

Sends HTTP response code message and headers .


def check_standard_dir(module_path):
    """Checks whether path belongs to standard library or installed modules."""
    if 'site-packages' in module_path:
        return True
    for stdlib_path in _STDLIB_PATHS:
        if fnmatch.fnmatchcase(module_path, stdlib_path + '*'):
            return True
    return False

def check_standard_dir ( module_path ) : if 'site-packages' in module_path : return True for stdlib_path in _STDLIB_PATHS : if fnmatch . fnmatchcase ( module_path , stdlib_path + '*' ) : return True return False

Checks whether path belongs to standard library or installed modules .


def record_line(self, frame, event, arg):  # pylint: disable=unused-argument
        """Records line execution time."""
        if event == 'line':
            if self.prev_timestamp:
                runtime = time.time() - self.prev_timestamp
                self.lines.append([self.prev_path, self.prev_lineno, runtime])
            self.prev_lineno = frame.f_lineno
            self.prev_path = frame.f_code.co_filename
            self.prev_timestamp = time.time()
        return self.record_line

def
record_line
(
self
,
frame
,
event
,
arg
)
:
# pylint: disable=unused-argument
if
event
==
'line'
:
if
self
.
prev_timestamp
:
runtime
=
time
.
time
(
)
self
.
prev_timestamp
self
.
lines
.
append
(
[
self
.
prev_path
,
self
.
prev_lineno
,
runtime
]
)
self
.
prev_lineno
=
frame
.
f_lineno
self
.
prev_path
=
frame
.
f_code
.
co_filename
self
.
prev_timestamp
=
time
.
time
(
)
return
self
.
record_line


def lines_without_stdlib(self):
        """Filters code from standard library from self.lines."""
        prev_line = None
        current_module_path = inspect.getabsfile(inspect.currentframe())
        for module_path, lineno, runtime in self.lines:
            module_abspath = os.path.abspath(module_path)
            if not prev_line:
                prev_line = [module_abspath, lineno, runtime]
            else:
                if (not check_standard_dir(module_path) and
                        module_abspath != current_module_path):
                    yield prev_line
                    prev_line = [module_abspath, lineno, runtime]
                else:
                    prev_line[2] += runtime
        yield prev_line

def lines_without_stdlib ( self ) : prev_line = None current_module_path = inspect . getabsfile ( inspect . currentframe ( ) ) for module_path , lineno , runtime in self . lines : module_abspath = os . path . abspath ( module_path ) if not prev_line : prev_line = [ module_abspath , lineno , runtime ] else : if ( not check_standard_dir ( module_path ) and module_abspath != current_module_path ) : yield prev_line prev_line = [ module_abspath , lineno , runtime ] else : prev_line [ 2 ] += runtime yield prev_line

Filters code from standard library from self . lines .


def fill_heatmap(self):
        """Fills code heatmap and execution count dictionaries."""
        for module_path, lineno, runtime in self.lines_without_stdlib:
            self._execution_count[module_path][lineno] += 1
            self._heatmap[module_path][lineno] += runtime

def fill_heatmap ( self ) : for module_path , lineno , runtime in self . lines_without_stdlib : self . _execution_count [ module_path ] [ lineno ] += 1 self . _heatmap [ module_path ] [ lineno ] += runtime

Fills code heatmap and execution count dictionaries .


def _skip_lines(src_code, skip_map):
        """Skips lines in src_code specified by skip map."""
        if not skip_map:
            return [['line', j + 1, l] for j, l in enumerate(src_code)]
        code_with_skips, i = [], 0
        for line, length in skip_map:
            code_with_skips.extend(
                ['line', i + j + 1, l] for j, l in enumerate(src_code[i:line]))
            if (code_with_skips
                    and code_with_skips[-1][0] == 'skip'):  # Merge skips.
                code_with_skips[-1][1] += length
            else:
                code_with_skips.append(['skip', length])
            i = line + length
        code_with_skips.extend(
            ['line', i + j + 1, l] for j, l in enumerate(src_code[i:]))
        return code_with_skips

def
_skip_lines
(
src_code
,
skip_map
)
:
if
not
skip_map
:
return
[
[
'line'
,
j
+
1
,
l
]
for
j
,
l
in
enumerate
(
src_code
)
]
code_with_skips
,
i
=
[
]
,
0
for
line
,
length
in
skip_map
:
code_with_skips
.
extend
(
[
'line'
,
i
+
j
+
1
,
l
]
for
j
,
l
in
enumerate
(
src_code
[
i
:
line
]
)
)
if
(
code_with_skips
and
code_with_skips
[
1
]
[
0
]
==
'skip'
)
:
# Merge skips.
code_with_skips
[
1
]
[
1
]
+=
length
else
:
code_with_skips
.
append
(
[
'skip'
,
length
]
)
i
=
line
+
length
code_with_skips
.
extend
(
[
'line'
,
i
+
j
+
1
,
l
]
for
j
,
l
in
enumerate
(
src_code
[
i
:
]
)
)
return
code_with_skips

Skips lines in src_code specified by skip map .


def _profile_package(self):
        """Calculates heatmap for package."""
        with _CodeHeatmapCalculator() as prof:
            try:
                runpy.run_path(self._run_object, run_name='__main__')
            except SystemExit:
                pass

        heatmaps = []
        for filename, heatmap in prof.heatmap.items():
            if os.path.isfile(filename):
                heatmaps.append(
                    self._format_heatmap(
                        filename, heatmap, prof.execution_count[filename]))

        run_time = sum(heatmap['runTime'] for heatmap in heatmaps)
        return {
            'objectName': self._run_object,
            'runTime': run_time,
            'heatmaps': heatmaps
        }

def _profile_package ( self ) : with _CodeHeatmapCalculator ( ) as prof : try : runpy . run_path ( self . _run_object , run_name = '__main__' ) except SystemExit : pass heatmaps = [ ] for filename , heatmap in prof . heatmap . items ( ) : if os . path . isfile ( filename ) : heatmaps . append ( self . _format_heatmap ( filename , heatmap , prof . execution_count [ filename ] ) ) run_time = sum ( heatmap [ 'runTime' ] for heatmap in heatmaps ) return { 'objectName' : self . _run_object , 'runTime' : run_time , 'heatmaps' : heatmaps }