Пример #1
0
def xls(request):
    """Serve xls output"""
    title = request.matchdict['title']
    config = get_config(title)
    with transaction.manager:
        models.populate_session(config.get('paths', 'database'))
        project = models.Project.fetch(title)
    from xlwt import Workbook, easyxf

    workbook = Workbook()
    heading_xf = easyxf('font: bold on; align: wrap on, '
                        'vert centre, horiz center')
    sheet = workbook.add_sheet('apartment')
    sheet.set_panes_frozen(True)
    sheet.set_horz_split_pos(1)
    sheet.set_remove_splits(True)
    attribs = config.get('project:data_renderer',
                         'apartment').split(', ')
    for attr_num, name in enumerate(attribs):
        sheet.col(attr_num).width = 256 * (len(name) + 3)
        sheet.write(0, attr_num, name, heading_xf)
    entity_class = import_from('art3dutils.models', 'Apartment')
    instances = entity_class.fetch_all(project.title)
    for num, instance in enumerate(instances):
        for attr_num, name in enumerate(attribs):
            sheet.write(num+1, attr_num, getattr(instance, name))
    response = Response(content_type='application/vnd.ms-excel')
    workbook.save(response.body_file)
    return response
Пример #2
0
def render(project_title, entity_name='project', shorthand=None, assets=None,
           limit=None, format_=None, available_only=False, **filters):
    """Render materials for an entity"""

    config = get_config(project_title)
    assets = assets or config.get(entity_name, 'assets')
    core_models.populate_session(config.get('paths', 'database'))
    entity_class = import_from('art3dutils.models', entity_name.title())
    instances = entity_class.fetch_all(project_title, shorthand=shorthand,
                                       limit=limit,
                                       available_only=available_only,
                                       **filters)
    for asset in assets.split(', '):
        print(cyan('Rendering `{0}`...'.format(asset)))
        logger = setup_logging(project_title, entity_name, asset)
        renderer_class = get_renderer_class(project_title, entity_name, asset)
        container = get_progress(instances)
        if len(instances) is 1:
            container = instances
        for instance in container:
            renderer = renderer_class(instance, config)
            try:
                renderer.render(format_)
            except core_models.ApartmentError as e:
                print(red(e))
                logger.error(e)
Пример #3
0
def projects(request):
    """Display project list"""
    config = get_config()
    with transaction.manager:
        models.populate_session(config.get('paths', 'database'))
        projects = models.Project.fetch_all()
    return {'projects': projects}
Пример #4
0
def project(request):
    """Display project data"""
    title = request.matchdict['title']
    config = get_config(title)
    with transaction.manager:
        models.populate_session(config.get('paths', 'database'))
        project = models.Project.fetch(title)
    return {'project': project}
Пример #5
0
def multi_render(project_title, entity_name='project', shorthand=None,
                 assets=None, limit=None, workers_count=2):
    """Multiprocessing version of `render`"""

    from multiprocessing import Queue, Process

    config = get_config(project_title)
    assets = assets or config.get(entity_name, 'assets').split(', ')

    def worker(work_queue, count):

        for key in get_progress(iter(work_queue.get, 'STOP'),
                                     length=count):
            for asset in assets:
                try:
                    renderer_class = import_from(
                        'hydra.renderers.{0}'.format(project_title),
                        '{0}{1}Renderer'.format(entity_name.title(),
                                                asset.title()))
                except (ImportError, AttributeError):
                    renderer_class = import_from(
                        'hydra.renderers.standard',
                        '{0}{1}Renderer'.format(entity_name.title(),
                                                asset.title()))
                instance_to_render = entity_class.fetch(shorthand_key=key)
                renderer = renderer_class(instance_to_render, config)
                try:
                    renderer.render()
                except core_models.ApartmentError as e:
                    print(red(e))

    core_models.populate_session(config.get('paths', 'database'))
    entity_class = import_from('art3dutils.models', entity_name.title())
    instances = entity_class.fetch_all(project_title, shorthand=shorthand,
                                       limit=limit)
    total = len(instances)
    queue = Queue()

    print(cyan('Forming queue...'))
    for instance in get_progress(instances):
        queue.put(instance.shorthand)

    workers_count = int(workers_count)
    processes = []

    print(cyan('Spawning {0} processes...'.format(workers_count)))
    for w in xrange(workers_count):
        p = Process(target=worker, args=(queue, total))
        p.start()
        processes.append(p)
        queue.put('STOP')

    for p in processes:
        p.join()
Пример #6
0
def delete(project_title):
    """Delete project files and directories"""
    config = get_config(project_title)
    session = core_models.populate_session(config.get('paths', 'database'))
    project = core_models.Project.fetch(project_title)
    if project:
        import shutil
        if confirm('Are you sure?'):
            try:
                shutil.rmtree('input/{title}'.format(title=project_title))
                shutil.rmtree('output/{title}'.format(title=project_title))
            except OSError:
                pass
            session.delete(project)
            session.commit()

            repo_dir = config.get('paths', 'repo')
            for root, dirs, files in os.walk(repo_dir):
                for filename in files:
                    name, ext = os.path.splitext(filename)
                    if name == project_title:
                        os.remove(os.path.join(root, filename))
                        print(green('Deleted {0}/{1}'.format(root, filename)))

            print(green('Project `{title}` '
                        'deleted!'.format(title=project_title)))
    else:
        print(yellow('No project named `{title}`. '
                     'Available projects:'.format(title=project_title)))
        show()
Пример #7
0
def mass_set_property(project_title, entity_name='apartment', **attributes):
    """Set property for all lots in project"""
    config = get_config(project_title)
    session = core_models.populate_session(config.get('paths', 'database'))
    entity_class = import_from('art3dutils.models', entity_name.title())
    instances = entity_class.fetch_all(project_title)
    container = get_progress(instances)
    for instance in container:
        for attribute_name in attributes:
            setattr(instance, attribute_name, attributes[attribute_name])
    session.commit()
Пример #8
0
def check(project_title):
    """Check if project is ready for production"""
    config = get_config(project_title)
    core_models.populate_session(config.get('paths', 'database'))
    project = core_models.Project.fetch(project_title)
    if config.has_section('input_data'):
        print(green(u'Project has config.'))
    else:
        print(yellow(u'Project has no config!'))
    try:
        print(green(u'Project is in database '
                    u'and has {1:d} '
                    u'lots.'.format(project_title,
                                    len(project.fetch_apartments()))))
    except AttributeError:
        print(yellow(u'Project is not in database!'.format(project_title)))
        raise SystemExit(0)

    print('Checking lot SVGs...')
    lots = core_models.Apartment.fetch_all(project_title)
    ok_count = 0
    fail_count = 0
    input_path = config.get('paths:input', 'project')
    for lot in get_progress(lots, 'lots'):
        try:
            lot.pick_file('{0}/apartment'.format(input_path))
            lot.pick_file('{0}/floor'.format(input_path))
            ok_count += 1
        except core_models.ApartmentError:
            fail_count += 1
        except OSError:
            print(red('No SVGs in project input directory!'))
            raise SystemExit(0)
    if not fail_count:
        print(green('All lots have SVGs or polygons.'))
    elif not ok_count:
        print(red('No lots have SVGs or polygons!'))
    else:
        print(yellow('{0} out of {1} '
                     'lots have no SVGs or polygons!'.format(fail_count,
                                                             len(lots))))
Пример #9
0
def show():
    """List all created projects"""
    config = get_config()
    core_models.populate_session(config.get('paths', 'database'))

    try:
        projects = core_models.Project.fetch_all()
        if len(projects):
            #title - 14 sym; # apts - 10
            print(cyan('============== =========='))
            print(cyan('TITLE          LOTS      '))
            print(cyan('============== =========='))
            project_row = '{title_str} {apt_no_str}'
            for project in projects:
                print(cyan(project_row.format(
                    title_str=project.title.ljust(14),
                    apt_no_str=len(project.fetch_apartments()))))
        else:
            print(yellow('No projects available.'))
    except sqlalchemy.exc.OperationalError:
        print(yellow('No database available.'))
Пример #10
0
def update(project_title, clean=False):
    """Add apartments to DB, canonize first"""
    config = get_config(project_title)
    if config.has_section('input_data'):
        execute(canonize, project_title)
    db = config.get('paths', 'database')
    session = core_models.populate_session(db, create_tables=True)

    if clean:
    #remove project
        project = core_models.Project.fetch(project_title)
        if project:
            session.delete(project)
            session.commit()

    #write new data
    print(cyan('Updating project data...'))
    canonic_json = config.get('paths:input', 'canonic_json')
    try:
        with codecs.open(canonic_json, 'r', 'utf-8') as f:
            json_data = json.load(f)
            for apt_obj in get_progress(json_data):
                if 'number' not in apt_obj:
                    apt_obj['number'] = 1
                if 'note' in apt_obj and type(apt_obj['note']) in (list, dict):
                    apt_obj['note'] = json.dumps(apt_obj['note'])
                core_models.Apartment.add(project_title, **apt_obj)
        session.commit()
    except IOError:
        print(red('No `{0}` file!'.format(canonic_json)))

    if config.has_option('database', 'post_update_filters'):
        print(cyan('Applying post-update filters...'))
        filters = []
        filter_names = config.get('database',
                                  'post_update_filters').split(', ')
        for filter_name in filter_names:
            filter_ = import_from('hydra.'
                                  'filters.{0}'.format(project_title),
                                  filter_name)
            filters.append(filter_)

        apartments = core_models.Apartment.fetch_all(project_title)
        for apartment in get_progress(apartments, 'apartments'):
            for filter_ in filters:
                filter_(apartment, config)
        session.commit()
Пример #11
0
def rename(project_title, new_title):
    """Rename project"""
    config = get_config(project_title)

    project_input_dir = config.get('paths:input', 'project')
    project_output_dir = config.get('paths:output', 'project')
    repo_dir = config.get('paths', 'repo')
    new_project_input_dir = project_input_dir.replace(project_title, new_title)
    new_project_output_dir = project_output_dir.replace(project_title,
                                                        new_title)

    for root, dirs, files in os.walk(repo_dir):
        for filename in files:
            name, ext = os.path.splitext(filename)
            if name == project_title:
                os.rename(os.path.join(root, filename),
                          os.path.join(root, '{0}{1}'.format(new_title, ext)))
                print(green('Renamed {0}/{1}'.format(root, filename)))

    with quiet():
        with lcd(project_input_dir):
            renamed_input = local('mv {0} {1}'.format(project_input_dir,
                                  new_project_input_dir))
            if renamed_input.succeeded:
                print(green('Renamed {0}'.format(project_input_dir)))
        with lcd(project_output_dir):
            renamed_output = local('mv {0} {1}'.format(project_output_dir,
                                   new_project_output_dir))
            if renamed_output.succeeded:
                print(green('Renamed {0}'.format(project_output_dir)))

    session = core_models.populate_session(config.get('paths', 'database'))
    project = core_models.Project.fetch(project_title)
    project.title = new_title
    session.add(project)
    session.commit()
    execute(update, new_title)
Пример #12
0
def create(project_title):
    """Initialize project with given title"""
    from mako.template import Template
    config = get_global_config(project_title)

    # initialize config
    config_path = config.get('paths:input', 'config')
    if os.path.exists(config_path):
        print(red('Project `{title}` already exists!'.format(
            title=project_title)))
        raise SystemExit(0)
    core_utils.create_dirs_in_path(config_path)
    with codecs.open(config_path, 'w', 'utf-8') as f:
        template = Template(filename='templates/config.ini.mako')
        contents = template.render(project_title=project_title)
        f.write(contents)

    session = core_models.populate_session(config.get('paths', 'database'),
                                          create_tables=True)
    project = core_models.Project(project_title)
    session.add(project)
    session.commit()

    print(green('Project `{title}` created!'.format(title=project_title)))
Пример #13
0
def deploy(project_title, entity_name='project', shorthand=None, assets=None,
           limit=None, file_format='json', available_only=False, **filters):

    current_host = env.hosts[0]
    config = get_config(project_title)

    core_models.populate_session(config.get('paths', 'database'))
    entity_class = import_from('art3dutils.models', entity_name.title())
    instances = entity_class.fetch_all(project_title, shorthand=shorthand,
                                       limit=limit,
                                       available_only=available_only,
                                       **filters)
    role = 'staging'
    if config.has_option('remote:production', 'host'):
        production_host = config.get('remote:production', 'host')
        if current_host == production_host:
            role = 'production'
    webroot = config.get('remote:{0}'.format(role), 'webroot')
    assets = assets or config.get(entity_name, 'assets')
    for asset in assets.split(', '):
        print(cyan('*** DEPLOYING {entity}{shorthand} {asset} TO `{role}` ***'.format(
            entity=entity_name, shorthand=" {}".format(shorthand) if shorthand else '',
            asset=asset, role=role)))
        remote_asset_path = config.get(
            'paths:deployment',
            '{entity}_{asset}'.format(entity=entity_name, asset=asset))
        remote_path = '{webroot}/' \
                      '{asset_path}'.format(webroot=webroot,
                                            asset_path=remote_asset_path)
        remote_dir = os.path.dirname(remote_path)
        if shorthand:
            renderer_class = get_renderer_class(project_title, entity_name, asset)
            def local_paths_gen():
                for instance in instances:
                    entity_dir = config.get('paths:input', 'entity').format(
                        entity=instance.fs_name)
                    local_path = renderer_class(instance, config).set_output_path()
                    if os.path.exists(local_path):
                        yield local_path
                    else:
                        print(yellow("No {} for {} {}").format(asset, instance.fs_name,
                                                               instance.shorthand))
            local_paths = local_paths_gen()
        elif entity_name == 'project' and\
            asset == 'data' and \
                config.has_option('paths:output', '{0}_{1}'.format(entity_name, asset)):
            local_path = (config.get('paths:output',
                                     '{0}_{1}'.format(entity_name, asset))) \
                .format(format=file_format, entity=entity_name, asset=asset, id='')
            local_paths = [local_path]
        else:
            local_path = config.get('paths:output',
                                    'entity_asset_dir').format(entity=entity_name,
                                                               asset=asset)
            local_paths = ['{0}/*'.format(local_path)]
        remote_dir_exists = True
        with cd(remote_dir):
            with quiet():
                if run('ls').failed:
                    remote_dir_exists = False
        dir_created = None
        if not remote_dir_exists:
            with quiet():
                dir_created = run('mkdir {0}'.format(remote_dir)).succeeded
        if dir_created:
            print(cyan('Directory `{0}` created...'.format(remote_dir)))
        for instance, local_path in izip(get_progress(instances, asset),
                                         local_paths):
            put(local_path, remote_path)
Пример #14
0
# -*- coding: utf-8 -*-

import __builtin__
import unittest

from art3dutils.models import populate_session, ATTR_TYPES
from art3d_hydra.filters.standard import data_filter
from art3d_hydra.iterators.standard import JSONIterator
from ConfigParser import SafeConfigParser as _SafeConfigParser

session = populate_session("sqlite:///", True)


class CommandTest(unittest.TestCase):
    def setUp(self):
        self.config = _SafeConfigParser()
        self.config.read("config.ini")

    def tearDown(self):
        pass

    def test_json_iterator(self):
        data_map = self.config.items("input_data:map")
        iterator = JSONIterator(data_map=data_map)
        path = self.config.get("input_data", "path")
        iterator.load_objects(path=path, root_container="JSONDataResult")
        for apt_dict in iterator:
            for attr_name, alias in data_map:
                self.assertIn(attr_name, apt_dict)

    def test_data_filter(self):