<commit_before>#! /usr/bin/env python
"""Create and dispatch separate simulations based on parameter sweep

This module will read in the accompanying configuration file
and create a folder with the base folder provided in the config file +
the current GMT time.
For example: of the base folder specified is '02-lens'
then a folder titled: 02-lens_batch_YYYY-MM-DD_HH-MM-SS
will be created.

In side this newly created folder, subfolders named by the
mutation, criterion, and run number will be created (d,c,r),
each will be a copy of the base folder (e.g., 02-lens).
These dcr represent a simulation, and will be run in parallel according
to the total number of cores availiable
"""

import configparser
import os
import numpy as np
import shutil
import subprocess
import multiprocessing as mp
from time import gmtime, strftime
import itertools

def _parse_config_fr_to_by(config_string):
    """Returns the value for the fr, to, and by, range in the config file.

    Args:
        config_string (string): a string of fr, to, by values
                                separated by \n character

    Returns:
        tuple: float of number to the right of the fr, to, and by values in the
               config file

    Examples: # TODO test this
        >>> print(_parse_config_fr_to_by("fr = 0\nto = 1\nby = .2")
        (0.0, 1.0, 0.2)
    """
    config_string = config_string.strip()
    fr_to_by_list = config_string.split('\n')

    # for each fr, to, by value, take the value to the right of the equal sign
    fr_to_by_str = tuple(e.split("=")[1].strip() for e in fr_to_by_list)
    fr_to_by_float = map(float, fr_to_by_str)
    return fr_to_by_float

def parse_config_list(config_string, sep=','):
    """Returns a python tuple of a delimited string from the config file

    Args:
        config_string (string): a delimited string separated by the sep param
        sep (string): delimited for config_string, default is ','

    Returns:
        tuple: of string split by the sep
    """
    return tuple(config_string.split(','))

    """Returns an ndarray values that will be used for the simulation run.

    Will include the 'to' value if the 'by' step will does not exceed the
    'to' value

    Args:
        fr (float): value of where the sweep will start
        to (float): value of where the sweep will end
        by (float): values between fr and to by specified step

    Returns:
        values (ndarray): values for parameter sweep

    Examples:
        >>> print(get_sweep_values(0, 10, 2))
        array([0, 2, 4, 6, 8, 10])

        >>> print(get_sweep_values(1, 10, 2))
        array([1, 3, 5, 7, 9])
    """
    values = np.arange(fr, to, by)
    # make the range inclusive on the right, since this is what
    # the usuer will most likely mean in the parameter file
    end_value = values[-1] + by
    if end_value == to:
        values = np.append(values, values[-1] + by)
    return values

def copy_directory(src, dest):
    try:
        shutil.copytree(src, dest)
    # Directories are the same
    except shutil.Error as e:
        print('Directory not copied. Error: %s' % e)
    # Any error saying that the directory doesn't exist
    except OSError as e:
        print('Directory not copied. Error: %s' % e)

def ftb_string_to_values(ftb_string):
    f, t, b = parse_config_fr_to_by(ftb_string)
    # print(f, t, b)

    sweep_values = np.arange(f, t, b)
    # print(str(sweep_values))

    # print(get_sweep_values(f, t, b))
    sweep_values = get_sweep_values(f, t, b)
    return sweep_values

def format_values(tuple_of_values):
    mutation, criterion, run_number = tuple_of_values

    mutation = float("{0:.2f}".format(mutation))
    criterion = int(criterion)
    run_number = int(run_number)

    assert isinstance(mutation, float)
    assert isinstance(criterion, int)
    assert isinstance(run_number, int)

    return mutation, criterion, run_number

def create_folder(base_directory, mutation_str, criterion_str,
                  run_number_str):
    # print('m: {}, c: {}, r: {}'.format(mutation_str, criterion_str,
    #                                    run_number_str))
    new_sim_folder_name = '_'.join(['d'+mutation_str,
                                    'c'+criterion_str,
                                    'r'+run_number_str])
    # print(new_sim_folder_name)

    batch_folder_name = '_'.join([base_directory, 'batch', current_gmt_time])
    # print('batch folder name: ', batch_folder_name)

    dir_to_copy_from = os.path.join(here, base_directory)
    # print('from: ', dir_to_copy_from)

    batch_folder_full_path = os.path.join(here, batch_folder_name)

    if not os.path.exists(batch_folder_full_path):
        # print('created: ', batch_folder_full_path)
        os.makedirs(batch_folder_full_path)

    dir_to_copy_to = os.path.join(batch_folder_full_path,
                                  new_sim_folder_name)
    # print('to : ', dir_to_copy_to)

    copy_directory(dir_to_copy_from, dir_to_copy_to)
    return dir_to_copy_to

def update_init_file(mutation, criterion, run, folder_name):
    """Updates the config file for a particular set of parameters for sweep

    Args:
        mutation (float): mutation value parameter for sweep
        ci (int): criterion value parameter for sweep
        run_number (int): run number for a set of value parameters for sweep
    """
    assert isinstance(mutation, float)
    assert isinstance(criterion, int)
    assert isinstance(run_number, int)

    sim_config = configparser.SafeConfigParser()
    sim_config_file_dir = os.path.join(folder_name, 'config.ini')
    sim_config.read(sim_config_file_dir)
    sim_config.set('LENSParameters', 'WeightTrainExampleMutationsProb',
                   str(mutation))
    sim_config.set('LENSParameters', 'Criterion', str(criterion))
    sim_config.set('General', 'RunNumber', str(run_number))
    with open(sim_config_file_dir, 'w') as update_config:
        sim_config.write(update_config)
        # print('config file updated: ', sim_config_file_dir)

def num_cores():
    cores = mp.cpu_count()
    print("Number of cores on this computer: ", cores)
    if cores <= 4:
        return cores
    else:
        return int(cores * (2/3.0))

def run_simulation(folder_name):
        ex_file = os.path.join(folder_name, 'main.py')
        subprocess.call(['python', ex_file])

###############################################################################
#
# BEGIN SCRIPT
#
###############################################################################
here = os.path.abspath(os.path.dirname(__file__))

# read in the parameter file
sweep_batch_config = configparser.ConfigParser()
sweep_batch_config_dir = os.path.join(here, 'batch_sweep.ini')
sweep_batch_config.read(sweep_batch_config_dir)

###############################################################################
#
# READ IN PARAMETER FILE VALUES
#
# TODO can reading in sweep values be generalized?
###############################################################################

num_sims_per_sweep_set = sweep_batch_config.getint(
    'Batch', 'NumberOfSimulationsPerSweepSet')
mutations_ftb_str = sweep_batch_config.get('Sweep',
                                           'WeightTrainExampleMutationsProb')
criterion_ftb_str = sweep_batch_config.get('Sweep', 'Criterion')

mutations_sweep_values = ftb_string_to_values(mutations_ftb_str)
criterions_sweep_values = ftb_string_to_values(criterion_ftb_str)

current_gmt_time = strftime("%Y-%m-%d_%H:%M:%S", gmtime())

###############################################################################
#
# CONVERT PARAMETER STRINGS TO PYTHON ARRAY VALUES (GET SWEEP VALUES)
#
###############################################################################

###############################################################################
#
# Cartesian product of parameters to create simulation folder with timestamp
#
###############################################################################
base_directory = sweep_batch_config.get('General', 'BaseDirectory')
base_directory_name = os.path.join(here, base_directory)

list_of_parameters = [mutations_sweep_values,
                      criterions_sweep_values,
                      range(num_sims_per_sweep_set)]
combination_of_parameters = itertools.product(*list_of_parameters)

list_of_sim_names = []

for combo in combination_of_parameters:
    mutation, criterion, run_number = format_values(combo)

    # print('m: {}, c: {}, r: {}'.format(mutation, criterion, run_number))
    mutation_str = "{0:03d}".format(int(mutation * 100))
    criterion_str = "{0:02d}".format(int(criterion))
    run_number_str = "{0:02d}".format(int(run_number))
    folder_created = create_folder(base_directory, mutation_str,
                                   criterion_str, run_number_str)
    list_of_sim_names.append(folder_created)
    update_init_file(mutation, criterion, run_number, folder_created)

###############################################################################
#
# RUN PARALLEL SIMULATIONS, FTW!
#
###############################################################################

num_cores = num_cores()
print("Number of cores for batch sweep simulation: ", num_cores)
pool = mp.Pool(processes=num_cores)

pool.map(run_simulation, list_of_sim_names)
<commit_msg>new interface and function get_sweep_values_range (formerly get_sweep_values)<commit_after>#! /usr/bin/env python
"""Create and dispatch separate simulations based on parameter sweep

This module will read in the accompanying configuration file
and create a folder with the base folder provided in the config file +
the current GMT time.
For example: of the base folder specified is '02-lens'
then a folder titled: 02-lens_batch_YYYY-MM-DD_HH-MM-SS
will be created.

In side this newly created folder, subfolders named by the
mutation, criterion, and run number will be created (d,c,r),
each will be a copy of the base folder (e.g., 02-lens).
These dcr represent a simulation, and will be run in parallel according
to the total number of cores availiable
"""

import configparser
import os
import numpy as np
import shutil
import subprocess
import multiprocessing as mp
from time import gmtime, strftime
import itertools

def _parse_config_fr_to_by(config_string):
    """Returns the value for the fr, to, and by, range in the config file.

    Args:
        config_string (string): a string of fr, to, by values
                                separated by \n character

    Returns:
        tuple: float of number to the right of the fr, to, and by values in the
               config file

    Examples: # TODO test this
        >>> print(_parse_config_fr_to_by("fr = 0\nto = 1\nby = .2")
        (0.0, 1.0, 0.2)
    """
    config_string = config_string.strip()
    fr_to_by_list = config_string.split('\n')

    # for each fr, to, by value, take the value to the right of the equal sign
    fr_to_by_str = tuple(e.split("=")[1].strip() for e in fr_to_by_list)
    fr_to_by_float = map(float, fr_to_by_str)
    return fr_to_by_float

def parse_config_list(config_string, sep=','):
    """Returns a python tuple of a delimited string from the config file

    Args:
        config_string (string): a delimited string separated by the sep param
        sep (string): delimited for config_string, default is ','

    Returns:
        tuple: of string split by the sep
    """
    return tuple(config_string.split(','))

def _get_sweep_values_range(fr, to, by):
    """Returns an ndarray values that will be used for the simulation run.

    Will include the 'to' value if the 'by' step will does not exceed the
    'to' value

    Args:
        fr (float): value of where the sweep will start
        to (float): value of where the sweep will end
        by (float): values between fr and to by specified step

    Returns:
        values (ndarray): values for parameter sweep

    Examples:
        >>> print(get_sweep_values(0, 10, 2))
        array([0, 2, 4, 6, 8, 10])

        >>> print(get_sweep_values(1, 10, 2))
        array([1, 3, 5, 7, 9])
    """
    assert(isinstance(fr, float))
    assert(isinstance(to, float))
    assert(isinstance(by, float))

    values = np.arange(fr, to, by)
    # print('values in _get_sweep_values_range(): ', str(values))
    # make the range inclusive on the right, since this is what
    # the usuer will most likely mean in the parameter file
    end_value = values[-1] + by
    if end_value == to:
        values = np.append(values, values[-1] + by)

    # print('return values in _get_sweep_values_range(): ', str(values))
    return values

def copy_directory(src, dest):
    try:
        shutil.copytree(src, dest)
    # Directories are the same
    except shutil.Error as e:
        print('Directory not copied. Error: %s' % e)
    # Any error saying that the directory doesn't exist
    except OSError as e:
        print('Directory not copied. Error: %s' % e)

def ftb_string_to_values(ftb_string):
    f, t, b = parse_config_fr_to_by(ftb_string)
    # print(f, t, b)

    sweep_values = np.arange(f, t, b)
    # print(str(sweep_values))

    # print(get_sweep_values(f, t, b))
    sweep_values = get_sweep_values(f, t, b)
    return sweep_values

def format_values(tuple_of_values):
    mutation, criterion, run_number = tuple_of_values

    mutation = float("{0:.2f}".format(mutation))
    criterion = int(criterion)
    run_number = int(run_number)

    assert isinstance(mutation, float)
    assert isinstance(criterion, int)
    assert isinstance(run_number, int)

    return mutation, criterion, run_number

def create_folder(base_directory, mutation_str, criterion_str,
                  run_number_str):
    # print('m: {}, c: {}, r: {}'.format(mutation_str, criterion_str,
    #                                    run_number_str))
    new_sim_folder_name = '_'.join(['d'+mutation_str,
                                    'c'+criterion_str,
                                    'r'+run_number_str])
    # print(new_sim_folder_name)

    batch_folder_name = '_'.join([base_directory, 'batch', current_gmt_time])
    # print('batch folder name: ', batch_folder_name)

    dir_to_copy_from = os.path.join(here, base_directory)
    # print('from: ', dir_to_copy_from)

    batch_folder_full_path = os.path.join(here, batch_folder_name)

    if not os.path.exists(batch_folder_full_path):
        # print('created: ', batch_folder_full_path)
        os.makedirs(batch_folder_full_path)

    dir_to_copy_to = os.path.join(batch_folder_full_path,
                                  new_sim_folder_name)
    # print('to : ', dir_to_copy_to)

    copy_directory(dir_to_copy_from, dir_to_copy_to)
    return dir_to_copy_to

def update_init_file(mutation, criterion, run, folder_name):
    """Updates the config file for a particular set of parameters for sweep

    Args:
        mutation (float): mutation value parameter for sweep
        ci (int): criterion value parameter for sweep
        run_number (int): run number for a set of value parameters for sweep
    """
    assert isinstance(mutation, float)
    assert isinstance(criterion, int)
    assert isinstance(run_number, int)

    sim_config = configparser.SafeConfigParser()
    sim_config_file_dir = os.path.join(folder_name, 'config.ini')
    sim_config.read(sim_config_file_dir)
    sim_config.set('LENSParameters', 'WeightTrainExampleMutationsProb',
                   str(mutation))
    sim_config.set('LENSParameters', 'Criterion', str(criterion))
    sim_config.set('General', 'RunNumber', str(run_number))
    with open(sim_config_file_dir, 'w') as update_config:
        sim_config.write(update_config)
        # print('config file updated: ', sim_config_file_dir)

def num_cores():
    cores = mp.cpu_count()
    print("Number of cores on this computer: ", cores)
    if cores <= 4:
        return cores
    else:
        return int(cores * (2/3.0))

def run_simulation(folder_name):
        ex_file = os.path.join(folder_name, 'main.py')
        subprocess.call(['python', ex_file])

###############################################################################
#
# BEGIN SCRIPT
#
###############################################################################
here = os.path.abspath(os.path.dirname(__file__))

# read in the parameter file
sweep_batch_config = configparser.ConfigParser()
sweep_batch_config_dir = os.path.join(here, 'batch_sweep.ini')
sweep_batch_config.read(sweep_batch_config_dir)

###############################################################################
#
# READ IN PARAMETER FILE VALUES
#
# TODO can reading in sweep values be generalized?
###############################################################################

num_sims_per_sweep_set = sweep_batch_config.getint(
    'Batch', 'NumberOfSimulationsPerSweepSet')
mutations_ftb_str = sweep_batch_config.get('Sweep',
                                           'WeightTrainExampleMutationsProb')
criterion_ftb_str = sweep_batch_config.get('Sweep', 'Criterion')

mutations_sweep_values = ftb_string_to_values(mutations_ftb_str)
criterions_sweep_values = ftb_string_to_values(criterion_ftb_str)

current_gmt_time = strftime("%Y-%m-%d_%H:%M:%S", gmtime())

###############################################################################
#
# CONVERT PARAMETER STRINGS TO PYTHON ARRAY VALUES (GET SWEEP VALUES)
#
###############################################################################

###############################################################################
#
# Cartesian product of parameters to create simulation folder with timestamp
#
###############################################################################
base_directory = sweep_batch_config.get('General', 'BaseDirectory')
base_directory_name = os.path.join(here, base_directory)

list_of_parameters = [mutations_sweep_values,
                      criterions_sweep_values,
                      range(num_sims_per_sweep_set)]
combination_of_parameters = itertools.product(*list_of_parameters)

list_of_sim_names = []

for combo in combination_of_parameters:
    mutation, criterion, run_number = format_values(combo)

    # print('m: {}, c: {}, r: {}'.format(mutation, criterion, run_number))
    mutation_str = "{0:03d}".format(int(mutation * 100))
    criterion_str = "{0:02d}".format(int(criterion))
    run_number_str = "{0:02d}".format(int(run_number))
    folder_created = create_folder(base_directory, mutation_str,
                                   criterion_str, run_number_str)
    list_of_sim_names.append(folder_created)
    update_init_file(mutation, criterion, run_number, folder_created)

###############################################################################
#
# RUN PARALLEL SIMULATIONS, FTW!
#
###############################################################################

num_cores = num_cores()
print("Number of cores for batch sweep simulation: ", num_cores)
pool = mp.Pool(processes=num_cores)

pool.map(run_simulation, list_of_sim_names)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from html import unescape
from collections import namedtuple

EntryBase = namedtuple('Entry',
                       ['id', 'title'])

class Entry(EntryBase):
    def __new__(cls, d):
        return super().__new__(cls,
                               str(d['_id']),
                               d.get('title'))

EntryDayBase = namedtuple('EntryDay',
                          ['id',
                           'title',
                           'category',
                           'source',
                           'tag',
                           'spider',
                           'domain',
                           'link'])

class EntryDay(EntryDayBase):
    def __new__(cls, d):
        return super().__new__(cls,
                               str(d['_id']),
                               d.get('title'),
                               d.get('category'),
                               d.get('source'),
                               d.get('tag'),
                               d.get('spider'),
                               d.get('domain'),
                               d.get('link'))

ArticleBase = namedtuple('Article',
                         ['id',
                          'title',
                          'domain',
                          'link',
                          'content',
                          'lang',
                          'source',
                          'spider'])

class Article(ArticleBase):
    def __new__(cls, d):
        content = d.get('content')
        if isinstance(content,
                      bytes):
            content = content.decode('UTF-8')
        return super().__new__(cls,
                               str(d['_id']),
                               unescape(d.get('title')),
                               d.get('domain'),
                               d.get('link'),
                               content,
                               d.get('lang'),
                               d.get('source'),
                               d.get('spider'))

AID = namedtuple('AID', ['id'])
<commit_msg>clean<commit_after># -*- coding: utf-8 -*-

from html import unescape
from collections import namedtuple

EntryBase = namedtuple('Entry',
                       ['id', 'title'])

class Entry(EntryBase):
    def __new__(cls, d):
        return super().__new__(cls,
                               str(d['_id']),
                               d.get('title'))

EntryDayBase = namedtuple('EntryDay',
                          ['id',
                           'title',
                           'category',
                           'source',
                           'tag',
                           'spider',
                           'domain',
                           'link'])

class EntryDay(EntryDayBase):
    def __new__(cls, d):
        return super().__new__(cls,
                               str(d['_id']),
                               d.get('title'),
                               d.get('category'),
                               d.get('source'),
                               d.get('tag'),
                               d.get('spider'),
                               d.get('domain'),
                               d.get('link'))

ArticleBase = namedtuple('Article',
                         ['id',
                          'title',
                          'domain',
                          'link',
                          'content',
                          'lang',
                          'source',
                          'spider'])

class Article(ArticleBase):
    def __new__(cls, d):
        content = d.get('content')
        if isinstance(content,
                      bytes):
            content = content.decode('UTF-8')
        title = unescape(d.get('title'))
        return super().__new__(cls,
                               str(d['_id']),
                               title,
                               d.get('domain'),
                               d.get('link'),
                               content,
                               d.get('lang'),
                               d.get('source'),
                               d.get('spider'))

AID = namedtuple('AID', ['id'])
<|endoftext|>


<commit_before>__author__ = 'ayost'

import os
import re
import sys
import json
from collections import OrderedDict

parts = OrderedDict()

def verify_input(value, obj):
    if obj['Type'] == "Number":
        try:
            x = int(value)
        except:
            print("Expecting number!")
            return None
    elif obj['Type'] == "List<Number>":
        num_list = re.split(r'\s*,\s*', value)
        for num in num_list:
            try:
                x = int(num)
            except:
                print("Must be a list of numbers!")
                return None
    typed_value = value
    if "MinLength" in obj:
        if len(str(typed_value)) < int(obj['MinLength']):
            return None
    if "MaxLength" in obj:
        if len(str(typed_value)) > int(obj['MaxLength']):
            return None
    if "MinValue" in obj:
        if int(typed_value) < int(obj['MinValue']):
            return None
    if "MaxValue" in obj:
        if int(typed_value) > int(obj['MaxValue']):
            return None
    if "AllowedValues" in obj:
        matched = False
        for v in obj['AllowedValues']:
            if re.match(r'(?i)' + re.escape(v), typed_value):
                typed_value = v
                matched = True
                break
        if not matched:
            print("Allowed values: " + json.dumps(obj['AllowedValues']))
            return None
    if "AllowedPattern" in obj:
        if not re.match(obj['AllowedPattern'], str(typed_value)):
            print('Does not match allowed pattern')
            return None
    return typed_value

def prompt(params):
    options = OrderedDict()
    for key in params:
        input_message = key + " "
        if "Default" in params[key]:
            input_message += "[" + params[key]['Default'] + "]"
        input_message += ":"
        accepted = False
        while not accepted:
            value = input("\t" + input_message)
            if len(value) < 1:
                if "Default" in params[key]:
                    if "Reference" in params[key]:
                        options[key] = params[key]['Default']
                    accepted = True
                else:
                    print("No default value specified, please enter a value")
            else:
                verified_value = verify_input(value, params[key])
                if verified_value is not None:
                    options[key] = verified_value
                    accepted = True
    return options

def makesub(subpart):
    partf = open(os.path.abspath('../Parts/' + subpart + '.subpart'))
    part = json.load(partf, object_pairs_hook=OrderedDict)
    partf.close()
    subobj = OrderedDict()
    variables = prompt(part['Variables'])
    for key in part['Object']:
        if key in variables:
            subobj[key] = variables[key]
        else:
            subobj[key] = part['Object'][key]
    return subobj

def map_part(part, template):
    if 'Conditions' in part:
        for condition in part['Conditions']:
            template['Conditions'][condition] = part['Conditions'][condition]
    if 'Mappings' in part:
        for mapping in part['Mappings']:
            template['Mappings'][mapping] = part['Mappings'][mapping]
    if 'Resources' in part:
        for res in part['Resources']:
            template['Resources'][res] = part['Resources'][res]
    if 'Outputs' in part:
        for output in part['Outputs']:
            template['Outputs'][output] = part['Outputs'][output]
    if 'Connections' in part:
        if 'SubParts' in part['Connections']:
            for subpart in part['Connections']['SubParts']:
                subpartName = re.sub(r'^[Ll]ist::', "", part['Connections']['SubParts'][subpart]['Type'])
                answer = ""
                addPart = False
                while len(answer.strip()) < 1:
                    answer = input("Add a " + subpartName + "? (y/n): ")
                    addPart = re.match(r'[yY]', answer)
                subs = []
                isList = re.match(r'^[Ll]ist::', part['Connections']['SubParts'][subpart]['Type'])
                while addPart:
                    subs.append(makesub(subpartName))
                    if isList:
                        answer = ""
                        while len(answer.strip()) < 1:
                            answer = input("Add another " + subpartName + "? (y/n): ")
                            addPart = re.match(r'[yY]', answer)
                    else:
                        addPart = False
                for res in part['Resources']:
                    if subpart in part['Resources'][res]['Properties']:
                        if isList:
                            part['Resources'][res]['Properties'][subpart] = subs
                        else:
                            part['Resources'][res]['Properties'][subpart] = subs[0]

def replace_ref(part, key, value):
    typed_value = json.dumps(value)
    part_string = json.dumps(part)
    clean_string = re.sub(r'\{\s*"\s*Ref\s*"\s*:\s*"\s*' + re.escape(key) + r'\s*"\s*\}', typed_value, part_string)
    clean_part = json.loads(clean_string, object_pairs_hook=OrderedDict)
    return clean_part

def changeNames(part, mod):
    resources = OrderedDict()
    for res in part['Resources']:
        resources[res + str(mod['Count'])] = part['Resources'][res]
    if 'Conditions' in part:
        resstring = json.dumps(resources)
        conditions = OrderedDict()
        for cond in part['Conditions']:
            conditions[cond + str(mod['Count'])] = part['Conditions'][cond]
            resstring = re.sub(r'"' + re.escape(cond) + r'"', '"' + (cond + str(mod['Count'])) + '"', resstring)
        part['Conditions'] = conditions
        part['Resources'] = json.loads(resstring, object_pairs_hook=OrderedDict)
    else:
        part['Resources'] = resources
    if 'Outputs' in part:
        outs = OrderedDict()
        for out in part['Outputs']:
            outs[out+str(mod['Count'])] = part['Outputs'][out]
        part['Outputs'] = outs

def build_objects(part_list, template):
    added = []
    for part in part_list:
        max_count = 0
        for module in added:
            if module['Type'] == part['Type']:
                if module['Count'] > max_count:
                    max_count = module['Count']
        numAppend = max_count + 1
        mod = {
            'LogicalName': part['Type'] + str(numAppend),
            'Type': part['Type'],
            'Count': numAppend
        }
        changeNames(part, mod)
        part = replace_ref(part, mod['Type'], {"Ref": mod['LogicalName']})
        params = part['Parameters']
        if ('Connections' in part) and ('Substitutes' in part['Connections']):
            for sub in part['Connections']['Substitutes']:
                typestring = re.sub(r'^[Ll]ist::', "", sub['Type'])
                if typestring in (module['Type'] for module in added):
                    for module in added:
                        if module['Type'] == typestring:
                            part = replace_ref(part, sub['Parameter'], {"Ref": module['LogicalName']})
                            try:
                                params.pop(sub['Parameter'])
                            except KeyError:
                                pass
                            break
        print("Parameters for " + mod['LogicalName'])
        filled_params = prompt(params)
        for fp in filled_params:
            part = replace_ref(part, fp, filled_params[fp])
        map_part(part, template)
        added.append(mod)
        if mod['Type'] == "ACL" or mod['Type'] == "ACLEntry":
            answer = ""
            addRule = False
            while len(answer) < 1:
                if mod['Type'] == "ACL":
                    answer = (input("Add an ACL Rule? (y/n): ")).strip()
                else:
                    answer = (input("Add another ACL Rule? (y/n): ")).strip()
                if answer[0].upper() == 'Y':
                    addRule = True
                elif answer[0].upper() == 'N':
                    addRule = False
                else:
                    answer = ""
            if addRule:
                part_list.insert(len(added), parts['ACLEntry'].copy())

def build_template():
    template = OrderedDict()
    template['Description'] = input("Describe this stack: ")
    template['Parameters'] = OrderedDict()
    template['Mappings'] = OrderedDict()
    template['Conditions'] = OrderedDict()
    template['Resources'] = OrderedDict()
    template['Outputs'] = OrderedDict()
    return template

def order_parts(parts_list):
    num_parts = len(parts_list)
    order = []
    temp_list = []
    while len(order) < num_parts:
        for p in parts_list:
            part = parts[p.upper()].copy()
            deps = []
            count = 0
            if ('Connections' in part) and ('Substitutes' in part['Connections']):
                for sub in part['Connections']['Substitutes']:
                    deps.append(re.sub(r'^[Ll]ist::', "", sub['Type']))
            for dep in deps:
                if dep.upper() in (partname.upper() for partname in parts_list):
                    count += 1
            if count < 1:
                order.append(part)
            else:
                temp_list.append(p)
        parts_list.clear()
        for t in temp_list:
            parts_list.append(t)
        temp_list.clear()
    return order

def load_parts():
    for root, dirs, files in os.walk('Parts'):
        for file in files:
#            print(file)
            f = open(os.path.abspath(os.path.join(root, file)))
            obj = json.load(f, object_pairs_hook=OrderedDict)
            f.close()
            parts[obj['Type'].upper()] = obj

def generate(layers):
    load_parts()
    name = input("Stack Name: ")
    temp = build_template()
    ordered_parts = order_parts(layers)
    build_objects(ordered_parts, temp)
    # print(json.dumps(temp, indent=2))
    outfile = open('Stacks/' + name + '.stack', 'w')
    json.dump(temp, outfile, indent=2)
    outfile.close()

if __name__ == '__main__':
    generate(sys.argv[1:])<commit_msg>Paths relative to script location, not absolute<commit_after>__author__ = 'ayost'

import os
import re
import sys
import json
from collections import OrderedDict

parts = OrderedDict()
SCRIPT_LOCATION = os.path.abspath(os.path.dirname(sys.argv[0]))

def verify_input(value, obj):
    if obj['Type'] == "Number":
        try:
            x = int(value)
        except:
            print("Expecting number!")
            return None
    elif obj['Type'] == "List<Number>":
        num_list = re.split(r'\s*,\s*', value)
        for num in num_list:
            try:
                x = int(num)
            except:
                print("Must be a list of numbers!")
                return None
    typed_value = value
    if "MinLength" in obj:
        if len(str(typed_value)) < int(obj['MinLength']):
            return None
    if "MaxLength" in obj:
        if len(str(typed_value)) > int(obj['MaxLength']):
            return None
    if "MinValue" in obj:
        if int(typed_value) < int(obj['MinValue']):
            return None
    if "MaxValue" in obj:
        if int(typed_value) > int(obj['MaxValue']):
            return None
    if "AllowedValues" in obj:
        matched = False
        for v in obj['AllowedValues']:
            if re.match(r'(?i)' + re.escape(v), typed_value):
                typed_value = v
                matched = True
                break
        if not matched:
            print("Allowed values: " + json.dumps(obj['AllowedValues']))
            return None
    if "AllowedPattern" in obj:
        if not re.match(obj['AllowedPattern'], str(typed_value)):
            print('Does not match allowed pattern')
            return None
    return typed_value

def prompt(params):
    options = OrderedDict()
    for key in params:
        input_message = key + " "
        if "Default" in params[key]:
            input_message += "[" + params[key]['Default'] + "]"
        input_message += ":"
        accepted = False
        while not accepted:
            value = input("\t" + input_message)
            if len(value) < 1:
                if "Default" in params[key]:
                    if "Reference" in params[key]:
                        options[key] = params[key]['Default']
                    accepted = True
                else:
                    print("No default value specified, please enter a value")
            else:
                verified_value = verify_input(value, params[key])
                if verified_value is not None:
                    options[key] = verified_value
                    accepted = True
    return options

def makesub(subpart):
    partf = open(os.path.join(SCRIPT_LOCATION, 'Parts', subpart + '.subpart'))
    part = json.load(partf, object_pairs_hook=OrderedDict)
    partf.close()
    subobj = OrderedDict()
    variables = prompt(part['Variables'])
    for key in part['Object']:
        if key in variables:
            subobj[key] = variables[key]
        else:
            subobj[key] = part['Object'][key]
    return subobj

def map_part(part, template):
    if 'Conditions' in part:
        for condition in part['Conditions']:
            template['Conditions'][condition] = part['Conditions'][condition]
    if 'Mappings' in part:
        for mapping in part['Mappings']:
            template['Mappings'][mapping] = part['Mappings'][mapping]
    if 'Resources' in part:
        for res in part['Resources']:
            template['Resources'][res] = part['Resources'][res]
    if 'Outputs' in part:
        for output in part['Outputs']:
            template['Outputs'][output] = part['Outputs'][output]
    if 'Connections' in part:
        if 'SubParts' in part['Connections']:
            for subpart in part['Connections']['SubParts']:
                subpartName = re.sub(r'^[Ll]ist::', "", part['Connections']['SubParts'][subpart]['Type'])
                answer = ""
                addPart = False
                while len(answer.strip()) < 1:
                    answer = input("Add a " + subpartName + "? (y/n): ")
                    addPart = re.match(r'[yY]', answer)
                subs = []
                isList = re.match(r'^[Ll]ist::', part['Connections']['SubParts'][subpart]['Type'])
                while addPart:
                    subs.append(makesub(subpartName))
                    if isList:
                        answer = ""
                        while len(answer.strip()) < 1:
                            answer = input("Add another " + subpartName + "? (y/n): ")
                            addPart = re.match(r'[yY]', answer)
                    else:
                        addPart = False
                for res in part['Resources']:
                    if subpart in part['Resources'][res]['Properties']:
                        if isList:
                            part['Resources'][res]['Properties'][subpart] = subs
                        else:
                            part['Resources'][res]['Properties'][subpart] = subs[0]

def replace_ref(part, key, value):
    typed_value = json.dumps(value)
    part_string = json.dumps(part)
    clean_string = re.sub(r'\{\s*"\s*Ref\s*"\s*:\s*"\s*' + re.escape(key) + r'\s*"\s*\}', typed_value, part_string)
    clean_part = json.loads(clean_string, object_pairs_hook=OrderedDict)
    return clean_part

def changeNames(part, mod):
    resources = OrderedDict()
    for res in part['Resources']:
        resources[res + str(mod['Count'])] = part['Resources'][res]
    if 'Conditions' in part:
        resstring = json.dumps(resources)
        conditions = OrderedDict()
        for cond in part['Conditions']:
            conditions[cond + str(mod['Count'])] = part['Conditions'][cond]
            resstring = re.sub(r'"' + re.escape(cond) + r'"', '"' + (cond + str(mod['Count'])) + '"', resstring)
        part['Conditions'] = conditions
        part['Resources'] = json.loads(resstring, object_pairs_hook=OrderedDict)
    else:
        part['Resources'] = resources
    if 'Outputs' in part:
        outs = OrderedDict()
        for out in part['Outputs']:
            outs[out+str(mod['Count'])] = part['Outputs'][out]
        part['Outputs'] = outs

def build_objects(part_list, template):
    added = []
    for part in part_list:
        max_count = 0
        for module in added:
            if module['Type'] == part['Type']:
                if module['Count'] > max_count:
                    max_count = module['Count']
        numAppend = max_count + 1
        mod = {
            'LogicalName': part['Type'] + str(numAppend),
            'Type': part['Type'],
            'Count': numAppend
        }
        changeNames(part, mod)
        part = replace_ref(part, mod['Type'], {"Ref": mod['LogicalName']})
        params = part['Parameters']
        if ('Connections' in part) and ('Substitutes' in part['Connections']):
            for sub in part['Connections']['Substitutes']:
                typestring = re.sub(r'^[Ll]ist::', "", sub['Type'])
                if typestring in (module['Type'] for module in added):
                    for module in added:
                        if module['Type'] == typestring:
                            part = replace_ref(part, sub['Parameter'], {"Ref": module['LogicalName']})
                            try:
                                params.pop(sub['Parameter'])
                            except KeyError:
                                pass
                            break
        print("Parameters for " + mod['LogicalName'])
        filled_params = prompt(params)
        for fp in filled_params:
            part = replace_ref(part, fp, filled_params[fp])
        map_part(part, template)
        added.append(mod)
        if mod['Type'] == "ACL" or mod['Type'] == "ACLEntry":
            answer = ""
            addRule = False
            while len(answer) < 1:
                if mod['Type'] == "ACL":
                    answer = (input("Add an ACL Rule? (y/n): ")).strip()
                else:
                    answer = (input("Add another ACL Rule? (y/n): ")).strip()
                if answer[0].upper() == 'Y':
                    addRule = True
                elif answer[0].upper() == 'N':
                    addRule = False
                else:
                    answer = ""
            if addRule:
                part_list.insert(len(added), parts['ACLEntry'].copy())

def build_template():
    template = OrderedDict()
    template['Description'] = input("Describe this stack: ")
    template['Parameters'] = OrderedDict()
    template['Mappings'] = OrderedDict()
    template['Conditions'] = OrderedDict()
    template['Resources'] = OrderedDict()
    template['Outputs'] = OrderedDict()
    return template

def order_parts(parts_list):
    num_parts = len(parts_list)
    order = []
    temp_list = []
    while len(order) < num_parts:
        for p in parts_list:
            part = parts[p.upper()].copy()
            deps = []
            count = 0
            if ('Connections' in part) and ('Substitutes' in part['Connections']):
                for sub in part['Connections']['Substitutes']:
                    deps.append(re.sub(r'^[Ll]ist::', "", sub['Type']))
            for dep in deps:
                if dep.upper() in [partname.upper() for partname in parts_list]:
                    count += 1
            if count < 1:
                order.append(part)
            else:
                temp_list.append(p)
        parts_list.clear()
        for t in temp_list:
            parts_list.append(t)
        temp_list.clear()
    return order

def load_parts():
    for root, dirs, files in os.walk('Parts'):
        for file in files:
#            print(file)
            f = open(os.path.abspath(os.path.join(root, file)))
            obj = json.load(f, object_pairs_hook=OrderedDict)
            f.close()
            parts[obj['Type'].upper()] = obj

def generate(layers):
    load_parts()
    name = input("Stack Name: ")
    temp = build_template()
    ordered_parts = order_parts(layers)
    build_objects(ordered_parts, temp)
    # print(json.dumps(temp, indent=2))
    outfile = open('Stacks/' + name + '.stack', 'w')
    json.dump(temp, outfile, indent=2)
    outfile.close()
    print("Stack File " + name + " Saved!")

if __name__ == '__main__':
    generate(sys.argv[1:])<|endoftext|>


<commit_before>#!/usr/bin/python

import smbus
import math
import sys
import time
import ProBotConstantsFile
import StartFile
import SocketAngleFile

# Initialization of classes from local files
Pconst = ProBotConstantsFile.Constants()
InitProgram=StartFile.StartFileClass()
Pub_Sub3=SocketAngleFile.SocketClass()

class mpu6050Class():
	# Power management registers
	power_mgmt_1 = 0x6b
	power_mgmt_2 = 0x6c
	bus = smbus.SMBus(1) # or bus = smbus.SMBus(1) for Revision 2 boards
	# Scale Modifiers

    	ACCEL_SCALE_MODIFIER_2G = 16384.0
    	ACCEL_SCALE_MODIFIER_4G = 8192.0
    	ACCEL_SCALE_MODIFIER_8G = 4096.0
    	ACCEL_SCALE_MODIFIER_16G = 2048.0

    	GYRO_SCALE_MODIFIER_250DEG = 131.0
    	GYRO_SCALE_MODIFIER_500DEG = 65.5
    	GYRO_SCALE_MODIFIER_1000DEG = 32.8
    	GYRO_SCALE_MODIFIER_2000DEG = 16.4

	accel_scale_modifier=ACCEL_SCALE_MODIFIER_2G
	gyro_scale_modifier=GYRO_SCALE_MODIFIER_250DEG

    	def __init__(self, address=0x68, lastAccelerometerAngleX=0):
		self.lastAccelerometerAngleX=lastAccelerometerAngleX
		self.address = address
		# Now wake up the MPU6050 as it starts in sleep mode
		self.bus.write_byte(self.address, 0)
		self.bus.write_byte_data(self.address, self.power_mgmt_1, 0)
		time.sleep(0.5)

	def read_byte(self, adr):
		return self.bus.read_byte_data(self.address, adr)

	def read_word(self,adr):
    		high = self.bus.read_byte_data(self.address, adr)
    		low = self.bus.read_byte_data(self.address, adr+1)
    		val = (high << 8) + low
    		return val

	def read_word_2c(self,adr):
    		val = self.read_word(adr)
    		if (val >= 0x8000):
        		return -((65535 - val) + 1)
    		else:
        		return val

	def dist(self,a,b):
    		return math.sqrt((a*a)+(b*b))

	def get_y_rotation(self,x,y,z):
    		radians = math.atan2(x, self.dist(y,z))
    		return -math.degrees(radians)

	def get_x_rotation(self,x,y,z):
    		radians = math.atan2(y, self.dist(x,z))
    		return math.degrees(radians)

	def RollPitch(self):
		while True:
                	try:
				#gyro_xout = self.read_word_2c(0x43)
				#gyro_yout = self.read_word_2c(0x45)
                		#gyro_zout = self.read_word_2c(0x47)

                		#gyro_xout_scaled = gyro_xout/self.gyro_scale_modifier
                		#gyro_yout_scaled = gyro_yout/self.gyro_scale_modifier
                		#gyro_zout_scaled = gyro_zout/self.gyro_scale_modifier

                		accel_xout = self.read_word_2c(0x3b)
                		accel_yout = self.read_word_2c(0x3d)
                		accel_zout = self.read_word_2c(0x3f)

                		accel_xout_scaled = accel_xout /self.accel_scale_modifier
                		accel_yout_scaled = accel_yout /self.accel_scale_modifier
                		accel_zout_scaled = accel_zout /self.accel_scale_modifier

                		Pitch = self.get_y_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)
				Pitch+=Pconst.Angle_offset
				print Pitch
				publisher=Pub_Sub3.publisher(Pitch)

    			except IOError, err:
        			continue

			except:
                        	print("Unexpected error:\n", sys.exc_info()[0])
                        	sys.exit('\n\nAngle Readings STOPPED!!!\n')
                        	raise

if __name__ == "__main__":
    mpu6050Class = mpu6050Class()
    mpu6050Class.RollPitch()
<commit_msg>Update AngleFile.py<commit_after>#!/usr/bin/python

import smbus
import math
import sys
import time
import ProBotConstantsFile
import StartFile
import SocketAngleFile

# Initialization of classes from local files
Pconst = ProBotConstantsFile.Constants()
InitProgram=StartFile.StartFileClass()
Pub_Sub3=SocketAngleFile.SocketClass()

class mpu6050Class():
	# Power management registers
	power_mgmt_1 = 0x6b
	power_mgmt_2 = 0x6c
	bus = smbus.SMBus(1) # or bus = smbus.SMBus(1) for Revision 2 boards
	# Scale Modifiers

    	ACCEL_SCALE_MODIFIER_2G = 16384.0
    	ACCEL_SCALE_MODIFIER_4G = 8192.0
    	ACCEL_SCALE_MODIFIER_8G = 4096.0
    	ACCEL_SCALE_MODIFIER_16G = 2048.0

    	GYRO_SCALE_MODIFIER_250DEG = 131.0
    	GYRO_SCALE_MODIFIER_500DEG = 65.5
    	GYRO_SCALE_MODIFIER_1000DEG = 32.8
    	GYRO_SCALE_MODIFIER_2000DEG = 16.4

	accel_scale_modifier=ACCEL_SCALE_MODIFIER_2G
	gyro_scale_modifier=GYRO_SCALE_MODIFIER_250DEG

    	def __init__(self, address=0x68, lastAccelerometerAngleX=0):
		self.lastAccelerometerAngleX=lastAccelerometerAngleX
		self.address = address
		# Now wake up the MPU6050 as it starts in sleep mode
		self.bus.write_byte(self.address, 0)
		self.bus.write_byte_data(self.address, self.power_mgmt_1, 0)
		time.sleep(0.5)

	def read_byte(self, adr):
		return self.bus.read_byte_data(self.address, adr)

	def read_word(self,adr):
    		high = self.bus.read_byte_data(self.address, adr)
    		low = self.bus.read_byte_data(self.address, adr+1)
    		val = (high << 8) + low
    		return val

	def read_word_2c(self,adr):
    		val = self.read_word(adr)
    		if (val >= 0x8000):
        		return -((65535 - val) + 1)
    		else:
        		return val

	def dist(self,a,b):
    		return math.sqrt((a*a)+(b*b))

	def get_y_rotation(self,x,y,z):
    		radians = math.atan2(x, self.dist(y,z))
    		return -math.degrees(radians)

	def get_x_rotation(self,x,y,z):
    		radians = math.atan2(y, self.dist(x,z))
    		return math.degrees(radians)

	def RollPitch(self):
		while True:
                	try:
				gyro_xout = self.read_word_2c(0x43)
				gyro_yout = self.read_word_2c(0x45)
                		gyro_zout = self.read_word_2c(0x47)

                		gyro_xout_scaled = gyro_xout/self.gyro_scale_modifier
                		gyro_yout_scaled = gyro_yout/self.gyro_scale_modifier
                		gyro_zout_scaled = gyro_zout/self.gyro_scale_modifier

                		accel_xout = self.read_word_2c(0x3b)
                		accel_yout = self.read_word_2c(0x3d)
                		accel_zout = self.read_word_2c(0x3f)

                		accel_xout_scaled = accel_xout /self.accel_scale_modifier
                		accel_yout_scaled = accel_yout /self.accel_scale_modifier
                		accel_zout_scaled = accel_zout /self.accel_scale_modifier

                		Pitch = self.get_y_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled)
				Pitch+=Pconst.Angle_offset
				print Pitch
				publisher=Pub_Sub3.publisher(Pitch)

    			except IOError, err:
        			continue

			except:
                        	print("Unexpected error:\n", sys.exc_info()[0])
                        	sys.exit('\n\nAngle Readings STOPPED!!!\n')
                        	raise

if __name__ == "__main__":
    mpu6050Class = mpu6050Class()
    mpu6050Class.RollPitch()
<|endoftext|>


<commit_before>from simulator import parameters
from simulator.transactions_unimaus import UniMausTransactionModel
import time
from simulator.customer_unimaus import GenuineCustomer, FraudulentCustomer
from experiments import result_handling

def run_single():

    start_time = time.time()

    # initialise the model with some parameters
    params = parameters.get_default_parameters()
    model = UniMausTransactionModel(params, GenuineCustomer, FraudulentCustomer)

    # run the simulation until termination
    while not model.terminated:
        model.step()

    # get the collected data
    agent_vars = model.log_collector.get_agent_vars_dataframe()
    agent_vars.index = agent_vars.index.droplevel(1)

    print('customers left:', len(model.customers))
    print('fraudsters left:', len(model.fraudsters))
    print('simulation took ', round((time.time() - start_time)/60., 2), ' minutes')

    result_handling.save_results(model)

if __name__ == '__main__':

    run_single()
<commit_msg>check if params dont change<commit_after>from simulator import parameters
from simulator.transactions_unimaus import UniMausTransactionModel
import time
from simulator.customer_unimaus import GenuineCustomer, FraudulentCustomer
from experiments import result_handling
import numpy as np
import datetime
import pandas as pd

def check_parameter_consistency(params1):

    params2 = parameters.get_default_parameters()

    # make sure we didn't accidentally change the input parameters
    for key in params1.keys():
        try:
            if isinstance(params1[key], np.ndarray):
                assert np.sum(params1[key] - params2[key]) == 0
            elif isinstance(params1[key], float) or isinstance(params1[key], int):
                assert params1[key] - params2[key] == 0
            elif isinstance(params1[key], datetime.date):
                pass
            elif isinstance(params1[key], pd.DataFrame):
                assert np.sum(params1[key].values - params2[key].values) == 0
            elif isinstance(params1[key], list):
                for i in range(len(params1[key])):
                    assert np.sum(params1[key][i].values - params2[key][i].values) == 0
            else:
                print("unknown type", key, type(params1[key]))
        except AssertionError:
            print("!! params changed:", key)

def run_single():

    start_time = time.time()

    # initialise the model with some parameters
    params = parameters.get_default_parameters().copy()
    model = UniMausTransactionModel(params, GenuineCustomer, FraudulentCustomer)

    # run the simulation until termination
    while not model.terminated:
        model.step()

    # get the collected data
    agent_vars = model.log_collector.get_agent_vars_dataframe()
    agent_vars.index = agent_vars.index.droplevel(1)

    print('customers left:', len(model.customers))
    print('fraudsters left:', len(model.fraudsters))
    print('simulation took ', round((time.time() - start_time)/60., 2), ' minutes')

    # make sure we didn't accidentally changed the default parameters
    check_parameter_consistency(params)

    # save the results
    result_handling.save_results(model)

if __name__ == '__main__':

    run_single()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Andre Anjos <andre.anjos@idiap.ch>
# Fri 20 Sep 14:45:01 2013

"""Blitz++ Array bindings for Python"""

import pkg_resources

from ._library import array, as_blitz
from . import version
from .version import module as __version__
from .version import api as __api_version__

def get_include():
  """Returns the directory containing the C/C++ API include directives"""

  return pkg_resources.resource_filename(__name__, 'include')

def get_config():
  """Returns a string containing the configuration information.
  """

  from .version import externals

  packages = pkg_resources.require(__name__)
  this = packages[0]
  deps = packages[1:]

  retval =  "%s: %s (%s)\n" % (this.key, this.version, this.location)
  retval += "  - c/c++ dependencies:\n"
  for k in sorted(externals): retval += "    - %s: %s\n" % (k, externals[k])
  retval += "  - python dependencies:\n"
  for d in deps: retval += "    - %s: %s (%s)\n" % (d.key, d.version, d.location)

  return retval.strip()

# gets sphinx autodoc done right - don't remove it
__all__ = [_ for _ in dir() if not _.startswith('_')]
<commit_msg>Add API number in get_config()<commit_after>#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Andre Anjos <andre.anjos@idiap.ch>
# Fri 20 Sep 14:45:01 2013

"""Blitz++ Array bindings for Python"""

import pkg_resources

from ._library import array, as_blitz
from . import version
from .version import module as __version__
from .version import api as __api_version__

def get_include():
  """Returns the directory containing the C/C++ API include directives"""

  return pkg_resources.resource_filename(__name__, 'include')

def get_config():
  """Returns a string containing the configuration information.
  """

  from .version import externals

  packages = pkg_resources.require(__name__)
  this = packages[0]
  deps = packages[1:]

  retval =  "%s: %s [api=0x%04x] (%s)\n" % (this.key, this.version,
      version.api, this.location)
  retval += "  - c/c++ dependencies:\n"
  for k in sorted(externals): retval += "    - %s: %s\n" % (k, externals[k])
  retval += "  - python dependencies:\n"
  for d in deps: retval += "    - %s: %s (%s)\n" % (d.key, d.version, d.location)

  return retval.strip()

# gets sphinx autodoc done right - don't remove it
__all__ = [_ for _ in dir() if not _.startswith('_')]
<|endoftext|>


<commit_before># vim: tabstop=4 shiftwidth=4
"""
This module contains FileEntry class which is used to retrieve entries
from a file system.  Since pulling data from the file system and parsing
it is expensive (especially when you have 100s of entries) we delay
fetching data until it's demanded.

We know some metadata at the beginning.  This is the data that's
populated via the __populateBasicMetadata(...) method.  We keep
track of the metadata keys that it has populated and when we're
asked for something that we don't have, then we get the file from
the filesystem, parse it, and populate the rest of the metadata
and the contents of the file.

The FileEntry calls EntryBase methods addToCache and getFromCache
to handle caching.
"""
import time, os, re
from Pyblosxom import tools
import base

class FileEntry(base.EntryBase):
    """
    This class gets it's data and metadata from the file specified
    by the filename argument.

    """
    def __init__(self, request, filename, root):
        """
        @param request: the Request object
        @type  request: Request

        @param filename: the complete filename for the file in question
            including path
        @type  filename: string

        @param root: i have no clue what this is
        @type  root: string
        """
        base.EntryBase.__init__(self, request)
        self._config = request.getConfiguration()
        self._filename = filename
        self._root = root
        if self._root.endswith(os.sep): self._root = self._root[:-1]

        self._original_metadata_keys = []
        self._populated_data = 0
        self.__populateBasicMetadata()

    def __repr__(self):
        return "<fileentry f'%s' r'%s'>" % (self._filename, self._root)

    def getId(self):
        """
        Returns the id for this content item--in this case, it's the
        filename.
        """
        return self._filename

    def getData(self):
        """
        Returns the data for this file entry.  The data is the parsed
        (via the entryparser) content of the entry.  We do this on-demand
        by checking to see if we've gotten it and if we haven't then
        we get it at that point.

        @returns: the content for this entry
        @rtype: string
        """
        if self._populated_data == 0:
            self.__populateData()
        return self._data

    def getMetadata(self, key, default=None):
        """
        Some of our metadata comes from os.stats--and the rest
        comes from running the entry parser on the file.  so
        we try to fulfill as many things from os.stats as we
        can before retrieving and parsing the file.
        """
        if self._populated_data == 1 or key in self._original_metadata_keys:
            return self._metadata.get(key, default)

        self.__populateData()
        return self._metadata.get(key, default)

    def __populateBasicMetadata(self):
        """
        Fills the metadata dict with metadata about the given file.  This
        metadata consists of things we pick up from an os.stat call as
        well as knowledge of the filename and the root directory.
        The rest of the metadata comes from parsing the file itself which
        is done with __populateData.
        """
        file_basename = os.path.basename(self._filename)

        path = self._filename.replace(self._root, '')
        path = path.replace(os.path.basename(self._filename), '')
        path = path[:-1]

        absolute_path = self._filename.replace(self._root, '')
        absolute_path = absolute_path.replace(file_basename, '')
        absolute_path = absolute_path[1:][:-1]

        fn, ext = os.path.splitext(file_basename)
        if absolute_path == '':
            file_path = fn
        else:
            file_path = os.path.join(absolute_path, fn)

        tb_id = '%s/%s' % (absolute_path, fn)
        tb_id = re.sub(r'[^A-Za-z0-9]', '_', tb_id)

        self['path'] = path
        self['tb_id'] = tb_id
        self['absolute_path'] = absolute_path
        self['file_path'] = file_path
        self['fn'] = fn
        self['filename'] = self._filename

        # handle the time portions
        timeTuple = tools.filestat(self._request, self._filename)
        self.setTime(timeTuple)

        # when someone does a getMetadata and they're looking for
        # a key not in this list, then we'll have to parse the
        # file and complete the list of keys.
        self._original_metadata_keys = self.keys()
        self._original_metadata_keys.remove(base.CONTENT_KEY)

    def __populateData(self):
        """
        Populates the rest of the data for this entry from a given
        file.  This could be just the contents of the file, but the
        file could also contain metadata that overrides the metadata
        we normally pull.
        """
        data = self._request.getData()

        entrydict = self.getFromCache(self._filename)
        if not entrydict:
            fileExt = re.search(r'\.([\w]+)$', self._filename)
            try:
                eparser = data['extensions'][fileExt.groups()[0]]
                entrydict = eparser(self._filename, self._request)
                self.addToCache(self._filename, entrydict)
            except IOError:
                return None

        self.update(entrydict)
        self._populated_data = 1
<commit_msg>Oops--I still don't fully understand what self._root is.  I added another "root" which is the datadir.  Silliness....<commit_after># vim: tabstop=4 shiftwidth=4
"""
This module contains FileEntry class which is used to retrieve entries
from a file system.  Since pulling data from the file system and parsing
it is expensive (especially when you have 100s of entries) we delay
fetching data until it's demanded.

We know some metadata at the beginning.  This is the data that's
populated via the __populateBasicMetadata(...) method.  We keep
track of the metadata keys that it has populated and when we're
asked for something that we don't have, then we get the file from
the filesystem, parse it, and populate the rest of the metadata
and the contents of the file.

The FileEntry calls EntryBase methods addToCache and getFromCache
to handle caching.
"""
import time, os, re
from Pyblosxom import tools
import base

class FileEntry(base.EntryBase):
    """
    This class gets it's data and metadata from the file specified
    by the filename argument.

    """
    def __init__(self, request, filename, root, datadir=""):
        """
        @param request: the Request object
        @type  request: Request

        @param filename: the complete filename for the file in question
            including path
        @type  filename: string

        @param root: i have no clue what this is
        @type  root: string

        @param datadir: the datadir
        @type  datadir: string
        """
        base.EntryBase.__init__(self, request)
        self._config = request.getConfiguration()
        self._filename = filename
        self._root = root

        self._datadir = datadir or self._config["datadir"]
        if self._datadir.endswith(os.sep):
            self._datadir = self._datadir[:-1]

        self._original_metadata_keys = []
        self._populated_data = 0
        self.__populateBasicMetadata()

    def __repr__(self):
        return "<fileentry f'%s' r'%s'>" % (self._filename, self._root)

    def getId(self):
        """
        Returns the id for this content item--in this case, it's the
        filename.
        """
        return self._filename

    def getData(self):
        """
        Returns the data for this file entry.  The data is the parsed
        (via the entryparser) content of the entry.  We do this on-demand
        by checking to see if we've gotten it and if we haven't then
        we get it at that point.

        @returns: the content for this entry
        @rtype: string
        """
        if self._populated_data == 0:
            self.__populateData()
        return self._data

    def getMetadata(self, key, default=None):
        """
        Some of our metadata comes from os.stats--and the rest
        comes from running the entry parser on the file.  so
        we try to fulfill as many things from os.stats as we
        can before retrieving and parsing the file.
        """
        if self._populated_data == 1 or key in self._original_metadata_keys:
            return self._metadata.get(key, default)

        self.__populateData()
        return self._metadata.get(key, default)

    def __populateBasicMetadata(self):
        """
        Fills the metadata dict with metadata about the given file.  This
        metadata consists of things we pick up from an os.stat call as
        well as knowledge of the filename and the root directory.
        The rest of the metadata comes from parsing the file itself which
        is done with __populateData.
        """
        file_basename = os.path.basename(self._filename)

        path = self._filename.replace(self._root, '')
        path = path.replace(os.path.basename(self._filename), '')
        path = path[:-1]

        absolute_path = self._filename.replace(self._datadir, '')
        absolute_path = absolute_path.replace(file_basename, '')
        absolute_path = absolute_path[1:][:-1]

        fn, ext = os.path.splitext(file_basename)
        if absolute_path == '':
            file_path = fn
        else:
            file_path = os.path.join(absolute_path, fn)

        tb_id = '%s/%s' % (absolute_path, fn)
        tb_id = re.sub(r'[^A-Za-z0-9]', '_', tb_id)

        self['path'] = path
        self['tb_id'] = tb_id
        self['absolute_path'] = absolute_path
        self['file_path'] = file_path
        self['fn'] = fn
        self['filename'] = self._filename

        # handle the time portions
        timeTuple = tools.filestat(self._request, self._filename)
        self.setTime(timeTuple)

        # when someone does a getMetadata and they're looking for
        # a key not in this list, then we'll have to parse the
        # file and complete the list of keys.
        self._original_metadata_keys = self.keys()
        self._original_metadata_keys.remove(base.CONTENT_KEY)

    def __populateData(self):
        """
        Populates the rest of the data for this entry from a given
        file.  This could be just the contents of the file, but the
        file could also contain metadata that overrides the metadata
        we normally pull.
        """
        data = self._request.getData()

        entrydict = self.getFromCache(self._filename)
        if not entrydict:
            fileExt = re.search(r'\.([\w]+)$', self._filename)
            try:
                eparser = data['extensions'][fileExt.groups()[0]]
                entrydict = eparser(self._filename, self._request)
                self.addToCache(self._filename, entrydict)
            except IOError:
                return None

        self.update(entrydict)
        self._populated_data = 1
<|endoftext|>


<commit_before># Using OpenCV to
# Hough Circle Transform
# https://docs.opencv.org/3.4/d4/d70/tutorial_hough_circle.html

#%% Detect Circles in Source Image

import dataclasses
from typing import List

from cv2 import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

IMAGE_LEVEL_NAME = "level_153.png"
original_image = cv.imread(f"./images/{IMAGE_LEVEL_NAME}")

# Trimming factors to remove irrelevant portions of the image which might contain circles.
header_trim = 150
footer_trim = 150

working_image = cv.cvtColor(original_image, cv.COLOR_BGR2GRAY)
working_image = cv.medianBlur(working_image, 5)
working_image = working_image[header_trim:-footer_trim, :]

# TODO: What do these params mean?
circles = cv.HoughCircles(working_image, cv.HOUGH_GRADIENT, 1, 50,
                            param1=100, param2=30,
                            minRadius=30, maxRadius=50)

assert circles is not None, "Could not detect any circles"

# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")

# Convert the circle coordinates to the 2D space of the original image
@dataclasses.dataclass
class Circle:
    column: int
    row: int
    radius: int
    # TODO: Better datatype for color
    color: int

circles: List[Circle] = [
    Circle(
        column=x,
        row=y+header_trim,
        radius=r,
        # TODO: Determine color of dot in image. Either color of center point pixel
        # or average color of all pixels within a slightly smaller circle, to avoid
        # antialiased colors.
        color=1
    )
    for (x, y, r) in circles
]

#%% Detect Containers in Source Image

import os

# Converts working_image to a black/white image which makes the countours algorithm
# work better. WHITE_THRESHOLD sets the lower/upper bounds on what brightnesses
# should be considered "white". These values were selected through trial and error,
# visually inspecting the resulting `thresh` with `plt.imshow`
WHITE_THRESHOLD = (200, 255)
_, thresh = cv.threshold(working_image, *WHITE_THRESHOLD, cv.THRESH_BINARY)

# Uses cv.findContours to sketch out the boundaries of all objects that passed the
# threshold filter.
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

# TODO: What is hierarchy for?

def draw_contour(*, contour_index=-1, show, save):
    output = cv.drawContours(
        image=cv.cvtColor(working_image.copy(), cv.COLOR_GRAY2BGR),
        contours=contours,
        contourIdx=contour_index,
        color=(0,0,255), # "Red" in BGR colorspace
        thickness=2,
    )

    if show:
        plt.imshow(output)
        plt.show()

    if save:
        os.makedirs(f"./images/contours/{IMAGE_LEVEL_NAME}", exist_ok=True)
        cv.imwrite(f"./images/contours/{IMAGE_LEVEL_NAME}/contour_{contour_index}.png", output)

    return output

# Saves all contours to storage so they can be easily viewed in series.
for i, contour in enumerate(contours):
    draw_contour(contour_index=i, show=False, save=True)

@dataclasses.dataclass
class Rectangle:
    """
    Names the properties of the rectangle, where col/row refer
    to the location of the upper left corner of the rectangle.
    """
    column: int
    row: int
    width: int
    height: int

# Generates bounding rectangles for all
bounding_rectangles: List[Rectangle] = []
for contour in contours:
    bounds = cv.boundingRect(contour)
    rectangle = Rectangle(
        column=bounds[0],
        row=bounds[1] + header_trim,
        width=bounds[2],
        height=bounds[3],
    )
    bounding_rectangles.append(rectangle)

# Determine which rectangles are not bounded by any of the other bounding rectangles.
# That should result in a list that we can consider the "containers".
containers: List[Rectangle] = []

def r1_contains_r2(r1: Rectangle, r2: Rectangle):
    return (
        r2.row >= r1.row and
        r2.row <= (r1.row + r1.height) and
        r2.column >= r1.column and
        r2.column <= (r1.column + r1.width)
    )

# Casual N^2 Alg
for current in bounding_rectangles:
    contained_by_one = any(filter(lambda other: other != current and r1_contains_r2(other, current), bounding_rectangles))
    if not contained_by_one:
        containers.append(current)

#%% Highlight Objects and Show

# loop over the (x, y) coordinates and radius of the circles
display_image = original_image.copy()
for circle in circles:
    # draw the circle in the output image
    cv.circle(display_image, (circle.column, circle.row), circle.radius, (0, 0, 0), 2)
    cv.circle(display_image, (circle.column, circle.row), 1, (0, 0, 0), 4)

for rectangle in containers:
    cv.rectangle(
        display_image,
        (rectangle.column, rectangle.row),
        (rectangle.column + rectangle.width, rectangle.row + rectangle.height),
        (0,0,0),
        2,
    )

# Show the original image side-by-side with circles circled
cv.imwrite(f"./images/objects_identified_{IMAGE_LEVEL_NAME}", display_image)
plt.imshow(cv.cvtColor(cv.hconcat([original_image, display_image]), cv.COLOR_BGR2RGB))
plt.show()

#%% Group Circles into Containers

# TODO:
<commit_msg>Code comment improvement<commit_after># Using OpenCV to
# Hough Circle Transform
# https://docs.opencv.org/3.4/d4/d70/tutorial_hough_circle.html

#%% Detect Circles in Source Image

import dataclasses
from typing import List

from cv2 import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

IMAGE_LEVEL_NAME = "level_153.png"
original_image = cv.imread(f"./images/{IMAGE_LEVEL_NAME}")

# Trimming factors to remove irrelevant portions of the image which might contain circles.
header_trim = 150
footer_trim = 150

working_image = cv.cvtColor(original_image, cv.COLOR_BGR2GRAY)
working_image = cv.medianBlur(working_image, 5)
working_image = working_image[header_trim:-footer_trim, :]

# TODO: What do these params mean?
circles = cv.HoughCircles(working_image, cv.HOUGH_GRADIENT, 1, 50,
                            param1=100, param2=30,
                            minRadius=30, maxRadius=50)

assert circles is not None, "Could not detect any circles"

# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")

# Convert the circle coordinates to the 2D space of the original image
@dataclasses.dataclass
class Circle:
    column: int
    row: int
    radius: int
    # TODO: Better datatype for color
    color: int

circles: List[Circle] = [
    Circle(
        column=x,
        row=y+header_trim,
        radius=r,
        # TODO: Determine color of dot in image. Either color of center point pixel
        # or average color of all pixels within a slightly smaller circle, to avoid
        # antialiased colors.
        color=1
    )
    for (x, y, r) in circles
]

#%% Detect Containers in Source Image

import os

# Converts working_image to a black/white image which makes the countours algorithm
# work better. WHITE_THRESHOLD sets the lower/upper bounds on what brightnesses
# should be considered "white". These values were selected through trial and error,
# visually inspecting the resulting `thresh` with `plt.imshow`
WHITE_THRESHOLD = (200, 255)
_, thresh = cv.threshold(working_image, *WHITE_THRESHOLD, cv.THRESH_BINARY)

# Uses cv.findContours to sketch out the boundaries of all objects that passed the
# threshold filter.
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

# TODO: What is hierarchy for?

def draw_contour(*, contour_index=-1, show, save):
    output = cv.drawContours(
        image=cv.cvtColor(working_image.copy(), cv.COLOR_GRAY2BGR),
        contours=contours,
        contourIdx=contour_index,
        color=(0,0,255), # "Red" in BGR colorspace
        thickness=2,
    )

    if show:
        plt.imshow(output)
        plt.show()

    if save:
        os.makedirs(f"./images/contours/{IMAGE_LEVEL_NAME}", exist_ok=True)
        cv.imwrite(f"./images/contours/{IMAGE_LEVEL_NAME}/contour_{contour_index}.png", output)

    return output

# Saves all contours to storage so they can be easily viewed in series.
for i, contour in enumerate(contours):
    draw_contour(contour_index=i, show=False, save=True)

@dataclasses.dataclass
class Rectangle:
    """
    Names the properties of the rectangle, where col/row refer
    to the location of the upper left corner of the rectangle.
    """
    column: int
    row: int
    width: int
    height: int

# Generates bounding rectangles for all
bounding_rectangles: List[Rectangle] = []
for contour in contours:
    bounds = cv.boundingRect(contour)
    rectangle = Rectangle(
        column=bounds[0],
        row=bounds[1] + header_trim,
        width=bounds[2],
        height=bounds[3],
    )
    bounding_rectangles.append(rectangle)

# Determine which rectangles are not bounded by any of the other bounding rectangles.
# That should result in a list that we can consider the "containers".
containers: List[Rectangle] = []

def r1_contains_r2(r1: Rectangle, r2: Rectangle):
    return (
        r2.row >= r1.row and
        r2.row <= (r1.row + r1.height) and
        r2.column >= r1.column and
        r2.column <= (r1.column + r1.width)
    )

# Casual N^2 Alg to make sure that each bounding rectangle is contained by no other bounding rectangles
for current in bounding_rectangles:
    contained_by_one = any(filter(lambda other: other != current and r1_contains_r2(other, current), bounding_rectangles))
    if not contained_by_one:
        containers.append(current)

#%% Highlight Objects and Show

# loop over the (x, y) coordinates and radius of the circles
display_image = original_image.copy()
for circle in circles:
    # draw the circle in the output image
    cv.circle(display_image, (circle.column, circle.row), circle.radius, (0, 0, 0), 2)
    cv.circle(display_image, (circle.column, circle.row), 1, (0, 0, 0), 4)

for rectangle in containers:
    cv.rectangle(
        display_image,
        (rectangle.column, rectangle.row),
        (rectangle.column + rectangle.width, rectangle.row + rectangle.height),
        (0,0,0),
        2,
    )

# Show the original image side-by-side with circles circled
cv.imwrite(f"./images/objects_identified_{IMAGE_LEVEL_NAME}", display_image)
plt.imshow(cv.cvtColor(cv.hconcat([original_image, display_image]), cv.COLOR_BGR2RGB))
plt.show()

#%% Group Circles into Containers

# TODO:
<|endoftext|>


<commit_before>from .shape import Drawing
from .shape import Shape
from .shape import Pane

from .stroke_info import StrokeInfoFactory

class Character(Shape):
	def __init__(self, strokes=[], name=""):
		self.name = name
		self.strokes = strokes

	def setName(self, name):
		self.name = name

	def setStrokes(self, strokes):
		self.strokes = strokes

	def getStrokes(self):
		return self.strokes

	def draw(self, drawingSystem):
		strokes=self.getStrokes()
		for stroke in strokes:
			stroke.draw(drawingSystem)

strokeInfoFactory=StrokeInfoFactory()

class Stroke(Drawing, Shape):
	def __init__(self, startPoint, strokeInfo=None, strokePath=None, infoPane=Pane.BBOX, statePane=Pane.BBOX):
		super().__init__(infoPane, statePane)
		self.startPoint=startPoint

		if strokeInfo:
			self.strokeInfo=strokeInfo
			self.strokePath=strokeInfo.getStrokePath()
			self.name=strokeInfo.getName()
		else:
			self.strokeInfo=None
			self.strokePath=strokePath
			self.name=""

	def clone(self):
		stroke=Stroke(self.startPoint, strokeInfo=self.strokeInfo, strokePath=self.strokePath,
			infoPane=self.getInfoPane(), statePane=self.getStatePane())
		return stroke

	def getName(self):
		return self.name

	def getStartPoint(self):
		return self.startPoint

	def getStrokePath(self):
		return self.strokePath

	def draw(self, drawingSystem):
		startPoint = self.getStartPoint()

		stroke=self
		drawingSystem.onPreDrawStroke(stroke)
		drawingSystem.setPane(stroke.getInfoPane(), stroke.getStatePane())

		drawingSystem.startDrawing(startPoint)

		strokePath = stroke.getStrokePath()
		strokePath.draw(drawingSystem)

		drawingSystem.endDrawing()
		drawingSystem.onPostDrawStroke(stroke)

	def computeBoundary(self):
		startPoint=self.getStartPoint()
		strokePath=self.getStrokePath()
		return strokePath.computeBoundaryWithStartPoint(startPoint)

def generateStroke(name, startPoint, parameterList):
	strokeInfo = strokeInfoFactory.generateStrokeInfo(name, parameterList)
	strokePath=strokeInfo.getStrokePath()
	boundary=strokePath.computeBoundaryWithStartPoint(startPoint)

	pane = Pane(*boundary)
	infoPane = pane
	statePane = pane
	return Stroke(startPoint, strokeInfo=strokeInfo, infoPane=infoPane, statePane=statePane)

class StrokeGroupInfo:
	def __init__(self, strokeList, bBoxPane):
		self.strokeList=strokeList
		self.bBoxPane=bBoxPane

	def getStrokeList(self):
		return self.strokeList

	def getBBoxPane(self):
		return self.bBoxPane

	@classmethod
	def generateInstanceByStrokeList(cls, strokeList):
		def mergeBoundaryList(boundaryList):
			from xie.graphics.shape import mergeBoundary
			r = boundaryList[0]
			for b in boundaryList[1:]:
				r = mergeBoundary(r, b)
			return r

		boundaryList=[stroke.computeBoundary() for stroke in strokeList]
		bBox=mergeBoundaryList(boundaryList)

		return StrokeGroupInfo(strokeList, Pane(*bBox))

	@staticmethod
	def generateInstanceFromComposition(strokeList, bBoxPane):
		return StrokeGroupInfo(strokeList, bBoxPane)

class StrokeGroup(Drawing):
	def __init__(self, strokeGroupInfo):
		pane=strokeGroupInfo.getBBoxPane()
		super().__init__(pane, pane)
		self.strokeGroupInfo=strokeGroupInfo

	def clone(self):
		strokeList=[s.clone() for s in self.getStrokeList()]
		strokeGroupInfo=StrokeGroupInfo.generateInstanceFromComposition(strokeList, self.getInfoPane())
		strokeGroup=StrokeGroup(strokeGroupInfo)
		strokeGroup.setStatePane(self.getStatePane())
		return strokeGroup

	def getDrawingList(self):
		return self.getStrokeList()

	def getStrokeList(self):
		return self.strokeGroupInfo.getStrokeList()

	def getCount(self):
		return len(self.getStrokeList())

	@classmethod
	def generateInstanceByInfo(cls, strokeGroupInfo):
		return StrokeGroup(strokeGroupInfo)

	@staticmethod
	def generateStrokeGroup(sg, pane):
		strokeGroup=sg.clone()

		newSgTargetPane=pane
		sgTargetPane=strokeGroup.getStatePane()
		sgInfoPane=strokeGroup.getInfoPane()
		for drawing in strokeGroup.getDrawingList():
			sTargetPane=drawing.getStatePane()
			sInfoPane=drawing.getInfoPane()
			drawing.transformBy(sgInfoPane, newSgTargetPane)

		strokeGroup.setStatePane(newSgTargetPane)
		strokeGroup.setInfoPane(newSgTargetPane)

		return strokeGroup

	@staticmethod
	def generateStrokeGroupInfo(strokeGroupPanePair):
		def computeBBox(paneList):
			left=min(map(lambda pane: pane.getLeft(), paneList))
			top=min(map(lambda pane: pane.getTop(), paneList))
			right=max(map(lambda pane: pane.getRight(), paneList))
			bottom=max(map(lambda pane: pane.getBottom(), paneList))
			return Pane(left, top, right, bottom)

		resultStrokeList=[]
		paneList=[]
		for strokeGroup, pane in strokeGroupPanePair:
			strokeGroup=StrokeGroup.generateStrokeGroup(strokeGroup, pane)
			resultStrokeList.extend(strokeGroup.getStrokeList())
			paneList.append(strokeGroup.getInfoPane())

		pane=computeBBox(paneList)
		strokeGroupInfo=StrokeGroupInfo.generateInstanceFromComposition(resultStrokeList, pane)

		return strokeGroupInfo

<commit_msg>Refactoring. Refine StrokeGroup.generateInstance*().<commit_after>from .shape import Drawing
from .shape import Shape
from .shape import Pane

from .stroke_info import StrokeInfoFactory

class Character(Shape):
	def __init__(self, strokes=[], name=""):
		self.name = name
		self.strokes = strokes

	def setName(self, name):
		self.name = name

	def setStrokes(self, strokes):
		self.strokes = strokes

	def getStrokes(self):
		return self.strokes

	def draw(self, drawingSystem):
		strokes=self.getStrokes()
		for stroke in strokes:
			stroke.draw(drawingSystem)

strokeInfoFactory=StrokeInfoFactory()

class Stroke(Drawing, Shape):
	def __init__(self, startPoint, strokeInfo=None, strokePath=None, infoPane=Pane.BBOX, statePane=Pane.BBOX):
		super().__init__(infoPane, statePane)
		self.startPoint=startPoint

		if strokeInfo:
			self.strokeInfo=strokeInfo
			self.strokePath=strokeInfo.getStrokePath()
			self.name=strokeInfo.getName()
		else:
			self.strokeInfo=None
			self.strokePath=strokePath
			self.name=""

	def clone(self):
		stroke=Stroke(self.startPoint, strokeInfo=self.strokeInfo, strokePath=self.strokePath,
			infoPane=self.getInfoPane(), statePane=self.getStatePane())
		return stroke

	def getName(self):
		return self.name

	def getStartPoint(self):
		return self.startPoint

	def getStrokePath(self):
		return self.strokePath

	def draw(self, drawingSystem):
		startPoint = self.getStartPoint()

		stroke=self
		drawingSystem.onPreDrawStroke(stroke)
		drawingSystem.setPane(stroke.getInfoPane(), stroke.getStatePane())

		drawingSystem.startDrawing(startPoint)

		strokePath = stroke.getStrokePath()
		strokePath.draw(drawingSystem)

		drawingSystem.endDrawing()
		drawingSystem.onPostDrawStroke(stroke)

	def computeBoundary(self):
		startPoint=self.getStartPoint()
		strokePath=self.getStrokePath()
		return strokePath.computeBoundaryWithStartPoint(startPoint)

def generateStroke(name, startPoint, parameterList):
	strokeInfo = strokeInfoFactory.generateStrokeInfo(name, parameterList)
	strokePath=strokeInfo.getStrokePath()
	boundary=strokePath.computeBoundaryWithStartPoint(startPoint)

	pane = Pane(*boundary)
	infoPane = pane
	statePane = pane
	return Stroke(startPoint, strokeInfo=strokeInfo, infoPane=infoPane, statePane=statePane)

class StrokeGroupInfo:
	def __init__(self, strokeList, bBoxPane):
		self.strokeList=strokeList
		self.bBoxPane=bBoxPane

	def getStrokeList(self):
		return self.strokeList

	def getBBoxPane(self):
		return self.bBoxPane

	@classmethod
	def generateInstanceByStrokeList(cls, strokeList):
		def mergeBoundaryList(boundaryList):
			from xie.graphics.shape import mergeBoundary
			r = boundaryList[0]
			for b in boundaryList[1:]:
				r = mergeBoundary(r, b)
			return r

		boundaryList=[stroke.computeBoundary() for stroke in strokeList]
		bBox=mergeBoundaryList(boundaryList)

		return StrokeGroupInfo(strokeList, Pane(*bBox))

	@staticmethod
	def generateInstanceFromComposition(strokeList, bBoxPane):
		return StrokeGroupInfo(strokeList, bBoxPane)

class StrokeGroup(Drawing):
	def __init__(self, strokeGroupInfo):
		pane=strokeGroupInfo.getBBoxPane()
		super().__init__(pane, pane)
		self.strokeGroupInfo=strokeGroupInfo

	def clone(self):
		strokeList=[s.clone() for s in self.getStrokeList()]
		strokeGroupInfo=StrokeGroupInfo.generateInstanceFromComposition(strokeList, self.getInfoPane())
		strokeGroup=StrokeGroup(strokeGroupInfo)
		strokeGroup.setStatePane(self.getStatePane())
		return strokeGroup

	def getDrawingList(self):
		return self.getStrokeList()

	def getStrokeList(self):
		return self.strokeGroupInfo.getStrokeList()

	def getCount(self):
		return len(self.getStrokeList())

	@classmethod
	def generateInstanceByInfo(cls, strokeGroupInfo):
		return StrokeGroup(strokeGroupInfo)

	@classmethod
	def generateInstanceByStrokeGroupPane(cls, sg, pane):
		strokeGroup=sg.clone()

		newSgTargetPane=pane
		sgTargetPane=strokeGroup.getStatePane()
		sgInfoPane=strokeGroup.getInfoPane()
		for drawing in strokeGroup.getDrawingList():
			sTargetPane=drawing.getStatePane()
			sInfoPane=drawing.getInfoPane()
			drawing.transformBy(sgInfoPane, newSgTargetPane)

		strokeGroup.setStatePane(newSgTargetPane)
		strokeGroup.setInfoPane(newSgTargetPane)

		return strokeGroup

	@classmethod
	def generateInstanceByStrokeGroupPanePairList(cls, strokeGroupPanePairList):
		def computeBBox(paneList):
			left=min(map(lambda pane: pane.getLeft(), paneList))
			top=min(map(lambda pane: pane.getTop(), paneList))
			right=max(map(lambda pane: pane.getRight(), paneList))
			bottom=max(map(lambda pane: pane.getBottom(), paneList))
			return Pane(left, top, right, bottom)

		resultStrokeList=[]
		paneList=[]
		for strokeGroup, pane in strokeGroupPanePairList:
			strokeGroup=StrokeGroup.generateInstanceByStrokeGroupPane(strokeGroup, pane)
			resultStrokeList.extend(strokeGroup.getStrokeList())
			paneList.append(strokeGroup.getInfoPane())

		pane=computeBBox(paneList)
		strokeGroupInfo=StrokeGroupInfo.generateInstanceFromComposition(resultStrokeList, pane)
		strokeGroup=StrokeGroup.generateInstanceByInfo(strokeGroupInfo)

		return strokeGroup

<|endoftext|>