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

from flask import Blueprint, url_for, request, abort
from views import DashboardView, ObjectListView, ObjectFormView
from views import ObjectDeleteView
from dashboard import default_dashboard

def recursive_getattr(obj, attr):
    """Returns object related attributes, as it's a template filter None
    is return when attribute doesn't exists.

    eg::

        a = object()
        a.b = object()
        a.b.c = 1
        recursive_getattr(a, 'b.c') => 1
        recursive_getattr(a, 'b.d') => None
    """
    try:
        if "." not in attr:
                return getattr(obj, attr)
        else:
            l = attr.split('.')
            return recursive_getattr(getattr(obj, l[0]), '.'.join(l[1:]))
    except AttributeError:
        return None

class AdminNode(object):
    """An AdminNode just act as navigation container, it doesn't provide any
    rules.

    :param admin: the parent admin object
    :param short_title: the short module title use on navigation
        & breadcrumbs
    :param title: the long title
    :param parent: the parent navigation path
    """
    def __init__(self, admin, endpoint, short_title, title=None, parent=None):
        self.admin = admin
        self.endpoint = endpoint
        self.short_title = short_title
        self.title = title
        self.parent = parent

class Admin(object):
    """Class that provides a way to add admin interface to Flask applications.

    :param app: the Flask application
    :param url_prefix: the url prefix
    :param main_dashboard: the main dashboard object
    :param endpoint: the endpoint
    """
    def __init__(self, app, url_prefix="/admin",
            main_dashboard=default_dashboard, endpoint='admin'):
        self.blueprint = Blueprint(endpoint, __name__,
            static_folder='static', template_folder='templates')
        self.register_main_dashboard(main_dashboard)
        self.app = app
        self.url_prefix = url_prefix
        self.endpoint = endpoint
        self.secure_functions = {}

        @self.blueprint.before_request
        def before_request():
            """Checks security for current endpoint."""
            endpoint = request.url_rule.endpoint\
                .lstrip("%s" % self.endpoint)
            self.check_endpoint_security(endpoint)

        self.blueprint.add_url_rule('/', view_func=DashboardView.as_view(
            'dashboard', dashboard=self.main_dashboard))
        self.app.register_blueprint(self.blueprint, url_prefix=url_prefix)
        self.registered_nodes = odict.odict()
        # Registers recursive_getattr filter
        self.app.jinja_env.filters['recursive_getattr'] = recursive_getattr

    def register_node(self, endpoint,  short_title, title=None, parent=None,
            node_class=AdminNode):
        title = short_title if not title else title
        new_node = node_class(self, endpoint, short_title, title=None)
        self._add_node(new_node, endpoint, parent=parent)
        return new_node

    def register_module(self, module_class, rule, endpoint, short_title,
            title=None, parent=None):
        """Registers new module to current admin.
        """
        title = short_title if not title else title
        new_module = module_class(self, rule, endpoint, short_title, title,
            parent=parent)
        self._add_node(new_module, endpoint, parent=parent)
        return new_module

    def _add_node(self, node_object, endpoint, parent=None):
        if parent and not parent in self.registered_nodes:
            raise Exception('parent admin node doesn\'t exist')
        path = "%s.%s" % (parent, endpoint) if parent else endpoint
        self.registered_nodes[path] = node_object

    def register_main_dashboard(self, main_dashboard):
        self.main_dashboard = main_dashboard
        self.main_dashboard.admin = self

    @property
    def navigation(self):
        """Returns main navigation elements as nested dict.
        """
        depth = {}
        depth[0] = {
            'class': 'main-dashboard',
            'short_title': 'dashboard',
            'title': 'Go to main dashboard',
            'url': url_for('%s.dashboard' % self.blueprint.name),
            'children': [],
        }
        navigation = [depth[0]]
        for path in self.registered_nodes:
            module = self.registered_nodes[path]
            level = path.count('.')
            if hasattr(module, 'rules') and len(module.rules) > 0:
                url = url_for(module.rules[0])
            else:
                url = None
            depth[level] = {
                'class': path,
                'short_title': module.short_title,
                'title': 'Go to %s' % module.short_title,
                'url': url,
                'children': [],
            }
            if level == 0:
                navigation.append(depth[level])
            else:
                parent = depth[level - 1]
                parent['children'].append(depth[level])
        return navigation

    def secure_endpoint(self, endpoint, http_code=403):
        """Gives a way to secure specific path.

        :param endpoint: the endpoint to protect
        :param http_code: the response http code
        """
        def decorator(f):
            self.add_endpoint_security(endpoint, f, http_code)
            return f
        return decorator

    def add_endpoint_security(self, endpoint, function, http_code=403):
        """Registers security function for given path.

        :param endpoint: the endpoint to secure
        :function: the security function
        :param http_code: the response http code
        """
        if endpoint in self.secure_functions:
            self.secure_functions[endpoint].append((function, http_code,))
        else:
            self.secure_functions[endpoint] = [(function, http_code,)]

    def check_endpoint_security(self, endpoint):
        """Checks security for specific and point.

        :param endpoint: the endpoint to check
        """
        for path in self.secure_functions:
            if endpoint.startswith(path):
                for function, http_code in self.secure_functions[path]:
                    if not function():
                        return abort(http_code)

class AdminModule(AdminNode):
    """Class that provides a way to create simple admin module.

    :param admin: the parent admin object
    :param url_prefix: the url prefix
    :param short_title: the short module title use un navigation
        & breadcrumbs
    :param title: the long title
    """
    def __init__(self, admin, url_prefix, endpoint, short_title, title,
            parent=None):
        self.admin = admin
        self.endpoint = endpoint
        self.short_title = short_title
        self.title = title
        self.url_prefix = url_prefix
        self.rules = []
        self.parent = parent
        self.register_rules()

    def add_url_rule(self, rule, endpoint, view_func=None, **options):
        """Adds a routing rule to the application from relative endpoint.

        :param rule: the rule
        :param endpoint: the endpoint
        :param view_func: the view
        """
        full_endpoint = "%s.%s_%s" % (self.admin.endpoint,
            self.endpoint, endpoint)
        self.admin.app.add_url_rule("%s%s%s" % (self.admin.url_prefix,
            self.url_prefix, rule), full_endpoint, view_func, **options)
        self.rules.append(full_endpoint)

    def register_rules(self):
        """Registers all module rules after initialization.
        """
        raise NotImplementedError('Admin module class must provide'
            + ' register_rules()')

    def secure_endpoint(self, endpoint, http_code=403):
        """Gives a way to secure endpoints.

        :param endpoint: the endpoint to protect
        :param http_code: the response http code
        """
        def decorator(f):
            self.admin.add_endpoint_security(".%s_%s" % (self.endpoint,
                endpoint.lstrip('.')), f, http_code)
            return f
        return decorator

class ObjectAdminModule(AdminModule):
    """Base class for object admin modules backends.
    Provides all required methods to retrieve, create, update and delete
    objects.
    """
    # List relateds
    list_view = ObjectListView
    list_template = 'list.html'
    list_fields = None
    list_title = 'list'
    list_per_page = 10
    searchable_fields = None
    order_by = None
    # Edit relateds
    edit_template = 'edit.html'
    form_view = ObjectFormView
    form_class = None
    edit_title = 'edit object'
    # New relateds
    new_title = 'new object'
    # Delete relateds
    delete_view = ObjectDeleteView

    def __new__(cls, *args, **kwargs):
        if not cls.list_fields:
            raise NotImplementedError()
        return super(ObjectAdminModule, cls).__new__(cls, *args, **kwargs)

    def register_rules(self):
        """Adds object list rule to current app.
        """
        self.add_url_rule('/', 'list',
            view_func=self.list_view.as_view('short_title', self))
        self.add_url_rule('/page/<page>', 'list',
            view_func=self.list_view.as_view('short_title', self))
        self.add_url_rule('/new', 'new',
            view_func=self.form_view.as_view('short_title', self))
        self.add_url_rule('/<pk>/edit', 'edit',
            view_func=self.form_view.as_view('short_title', self))
        self.add_url_rule('/<pk>/delete', 'delete',
            view_func=self.delete_view.as_view('short_title', self))

    def get_object_list(self, search=None, order_by_field=None,
            order_by_direction=None, offset=None, limit=None):
        """Returns objects list ordered and filtered.

        :param search: the search string for quick filtering
        :param order_by_field: the ordering field
        :param order_by_direction: the ordering direction
        :param offset: the pagintation offset
        :param limit: the pagination limit
        """
        raise NotImplementedError()

    def count_list(self, search=None):
        """Counts filtered object list.

        :param search: the search string for quick filtering.
        """
        raise NotImplementedError()

    def get_actions_for_object(self, object):
        """Returns action available for each object.

        :param object: the raw object
        """
        raise NotImplementedError()

    def get_form(self, object):
        """Returns form initialy populate from object instance.

        :param object: the edited object
        """
        return self.form_class(obj=object)

    def get_object(self, pk=None):
        """Returns object retrieve by primary key.

        :param pk: the object primary key
        """
        raise NotImplementedError()

    def create_object(self):
        """Returns new object instance."""
        raise NotImplementedError()

    def save_object(self, object):
        """Persits object.

        :param object: the object to persist
        """
        raise NotImplementedError()

    def delete_object(self, object):
        """Deletes object.

        :param object: the object to delete
        """
        raise NotImplementedError()
<commit_msg>AdminNode.parent now return parent object, not parent path<commit_after># -*- coding: utf-8 -*-
import odict

from flask import Blueprint, url_for, request, abort
from views import DashboardView, ObjectListView, ObjectFormView
from views import ObjectDeleteView
from dashboard import default_dashboard

def recursive_getattr(obj, attr):
    """Returns object related attributes, as it's a template filter None
    is return when attribute doesn't exists.

    eg::

        a = object()
        a.b = object()
        a.b.c = 1
        recursive_getattr(a, 'b.c') => 1
        recursive_getattr(a, 'b.d') => None
    """
    try:
        if "." not in attr:
                return getattr(obj, attr)
        else:
            l = attr.split('.')
            return recursive_getattr(getattr(obj, l[0]), '.'.join(l[1:]))
    except AttributeError:
        return None

class AdminNode(object):
    """An AdminNode just act as navigation container, it doesn't provide any
    rules.

    :param admin: the parent admin object
    :param short_title: the short module title use on navigation
        & breadcrumbs
    :param title: the long title
    :param parent: the parent navigation path
    """
    def __init__(self, admin, endpoint, short_title, title=None, parent=None):
        self.admin = admin
        self.endpoint = endpoint
        self.short_title = short_title
        self.title = title
        self._parent = parent

    @property
    def parent(self):
        parent = self._parent
        return self.admin.registered_nodes[parent] if parent else None

class Admin(object):
    """Class that provides a way to add admin interface to Flask applications.

    :param app: the Flask application
    :param url_prefix: the url prefix
    :param main_dashboard: the main dashboard object
    :param endpoint: the endpoint
    """
    def __init__(self, app, url_prefix="/admin",
            main_dashboard=default_dashboard, endpoint='admin'):
        self.blueprint = Blueprint(endpoint, __name__,
            static_folder='static', template_folder='templates')
        self.register_main_dashboard(main_dashboard)
        self.app = app
        self.url_prefix = url_prefix
        self.endpoint = endpoint
        self.secure_functions = {}

        @self.blueprint.before_request
        def before_request():
            """Checks security for current endpoint."""
            endpoint = request.url_rule.endpoint\
                .lstrip("%s" % self.endpoint)
            self.check_endpoint_security(endpoint)

        self.blueprint.add_url_rule('/', view_func=DashboardView.as_view(
            'dashboard', dashboard=self.main_dashboard))
        self.app.register_blueprint(self.blueprint, url_prefix=url_prefix)
        self.registered_nodes = odict.odict()
        # Registers recursive_getattr filter
        self.app.jinja_env.filters['recursive_getattr'] = recursive_getattr

    def register_node(self, endpoint,  short_title, title=None, parent=None,
            node_class=AdminNode):
        title = short_title if not title else title
        new_node = node_class(self, endpoint, short_title, title=None)
        self._add_node(new_node, endpoint, parent=parent)
        return new_node

    def register_module(self, module_class, rule, endpoint, short_title,
            title=None, parent=None):
        """Registers new module to current admin.
        """
        title = short_title if not title else title
        new_module = module_class(self, rule, endpoint, short_title, title,
            parent=parent)
        self._add_node(new_module, endpoint, parent=parent)
        return new_module

    def _add_node(self, node_object, endpoint, parent=None):
        if parent and not parent in self.registered_nodes:
            raise Exception('Parent admin node not registered')
        path = "%s.%s" % (parent, endpoint) if parent else endpoint
        self.registered_nodes[path] = node_object

    def register_main_dashboard(self, main_dashboard):
        self.main_dashboard = main_dashboard
        self.main_dashboard.admin = self

    @property
    def navigation(self):
        """Returns main navigation elements as nested dict.
        """
        depth = {}
        depth[0] = {
            'class': 'main-dashboard',
            'short_title': 'dashboard',
            'title': 'Go to main dashboard',
            'url': url_for('%s.dashboard' % self.blueprint.name),
            'children': [],
        }
        navigation = [depth[0]]
        for path in self.registered_nodes:
            module = self.registered_nodes[path]
            level = path.count('.')
            if hasattr(module, 'rules') and len(module.rules) > 0:
                url = url_for(module.rules[0])
            else:
                url = None
            depth[level] = {
                'class': path,
                'short_title': module.short_title,
                'title': 'Go to %s' % module.short_title,
                'url': url,
                'children': [],
            }
            if level == 0:
                navigation.append(depth[level])
            else:
                parent = depth[level - 1]
                parent['children'].append(depth[level])
        return navigation

    def secure_endpoint(self, endpoint, http_code=403):
        """Gives a way to secure specific path.

        :param endpoint: the endpoint to protect
        :param http_code: the response http code
        """
        def decorator(f):
            self.add_endpoint_security(endpoint, f, http_code)
            return f
        return decorator

    def add_endpoint_security(self, endpoint, function, http_code=403):
        """Registers security function for given path.

        :param endpoint: the endpoint to secure
        :function: the security function
        :param http_code: the response http code
        """
        if endpoint in self.secure_functions:
            self.secure_functions[endpoint].append((function, http_code,))
        else:
            self.secure_functions[endpoint] = [(function, http_code,)]

    def check_endpoint_security(self, endpoint):
        """Checks security for specific and point.

        :param endpoint: the endpoint to check
        """
        for path in self.secure_functions:
            if endpoint.startswith(path):
                for function, http_code in self.secure_functions[path]:
                    if not function():
                        return abort(http_code)

class AdminModule(AdminNode):
    """Class that provides a way to create simple admin module.

    :param admin: the parent admin object
    :param url_prefix: the url prefix
    :param short_title: the short module title use un navigation
        & breadcrumbs
    :param title: the long title
    """
    def __init__(self, admin, url_prefix, endpoint, short_title, title,
            parent=None):
        self.admin = admin
        self.endpoint = endpoint
        self.short_title = short_title
        self.title = title
        self.url_prefix = url_prefix
        self.rules = []
        self._parent = parent
        self.register_rules()

    def add_url_rule(self, rule, endpoint, view_func=None, **options):
        """Adds a routing rule to the application from relative endpoint.

        :param rule: the rule
        :param endpoint: the endpoint
        :param view_func: the view
        """
        full_endpoint = "%s.%s_%s" % (self.admin.endpoint,
            self.endpoint, endpoint)
        self.admin.app.add_url_rule("%s%s%s" % (self.admin.url_prefix,
            self.url_prefix, rule), full_endpoint, view_func, **options)
        self.rules.append(full_endpoint)

    def register_rules(self):
        """Registers all module rules after initialization.
        """
        raise NotImplementedError('Admin module class must provide'
            + ' register_rules()')

    def secure_endpoint(self, endpoint, http_code=403):
        """Gives a way to secure endpoints.

        :param endpoint: the endpoint to protect
        :param http_code: the response http code
        """
        def decorator(f):
            self.admin.add_endpoint_security(".%s_%s" % (self.endpoint,
                endpoint.lstrip('.')), f, http_code)
            return f
        return decorator

class ObjectAdminModule(AdminModule):
    """Base class for object admin modules backends.
    Provides all required methods to retrieve, create, update and delete
    objects.
    """
    # List relateds
    list_view = ObjectListView
    list_template = 'list.html'
    list_fields = None
    list_title = 'list'
    list_per_page = 10
    searchable_fields = None
    order_by = None
    # Edit relateds
    edit_template = 'edit.html'
    form_view = ObjectFormView
    form_class = None
    edit_title = 'edit object'
    # New relateds
    new_title = 'new object'
    # Delete relateds
    delete_view = ObjectDeleteView

    def __new__(cls, *args, **kwargs):
        if not cls.list_fields:
            raise NotImplementedError()
        return super(ObjectAdminModule, cls).__new__(cls, *args, **kwargs)

    def register_rules(self):
        """Adds object list rule to current app.
        """
        self.add_url_rule('/', 'list',
            view_func=self.list_view.as_view('short_title', self))
        self.add_url_rule('/page/<page>', 'list',
            view_func=self.list_view.as_view('short_title', self))
        self.add_url_rule('/new', 'new',
            view_func=self.form_view.as_view('short_title', self))
        self.add_url_rule('/<pk>/edit', 'edit',
            view_func=self.form_view.as_view('short_title', self))
        self.add_url_rule('/<pk>/delete', 'delete',
            view_func=self.delete_view.as_view('short_title', self))

    def get_object_list(self, search=None, order_by_field=None,
            order_by_direction=None, offset=None, limit=None):
        """Returns objects list ordered and filtered.

        :param search: the search string for quick filtering
        :param order_by_field: the ordering field
        :param order_by_direction: the ordering direction
        :param offset: the pagintation offset
        :param limit: the pagination limit
        """
        raise NotImplementedError()

    def count_list(self, search=None):
        """Counts filtered object list.

        :param search: the search string for quick filtering.
        """
        raise NotImplementedError()

    def get_actions_for_object(self, object):
        """Returns action available for each object.

        :param object: the raw object
        """
        raise NotImplementedError()

    def get_form(self, object):
        """Returns form initialy populate from object instance.

        :param object: the edited object
        """
        return self.form_class(obj=object)

    def get_object(self, pk=None):
        """Returns object retrieve by primary key.

        :param pk: the object primary key
        """
        raise NotImplementedError()

    def create_object(self):
        """Returns new object instance."""
        raise NotImplementedError()

    def save_object(self, object):
        """Persits object.

        :param object: the object to persist
        """
        raise NotImplementedError()

    def delete_object(self, object):
        """Deletes object.

        :param object: the object to delete
        """
        raise NotImplementedError()
<|endoftext|>


<commit_before>from collections import namedtuple

from soap.datatype import int_type, float_type, ArrayType
from soap.context import context
from soap.expression import operators

DEVICE_LATENCY_TABLE = {
    ('Virtex7', 333): {
        int_type: {
            'comparison': 1,
            operators.UNARY_SUBTRACT_OP: 0,
            operators.ADD_OP: 1,
            operators.SUBTRACT_OP: 1,
            operators.MULTIPLY_OP: 7,
            operators.DIVIDE_OP: 36,
            operators.INDEX_ACCESS_OP: 2,
        },
        float_type: {
            'comparison': 3,
            'conversion': 8,
            operators.UNARY_SUBTRACT_OP: 0,
            operators.ADD_OP: 11,
            operators.SUBTRACT_OP: 11,
            operators.MULTIPLY_OP: 7,
            operators.DIVIDE_OP: 30,
            operators.EXPONENTIATE_OP: 20,
            operators.INDEX_ACCESS_OP: 2,
        },
        ArrayType: {
            operators.INDEX_UPDATE_OP: 1,
            operators.SUBSCRIPT_OP: 0,
        },
    },
}

NONPIPELINED_OPERATORS = {
    operators.FIXPOINT_OP,
}
PIPELINED_OPERATORS = set(operators.OPERATORS) - NONPIPELINED_OPERATORS
MAX_SHARE_COUNT = 8
SHARED_DATATYPE_OPERATORS = {
    (float_type, 'conversion'),
    (float_type, 'comparison'),
    (float_type, operators.ADD_OP),
    (float_type, operators.SUBTRACT_OP),
    (float_type, operators.MULTIPLY_OP),
    (float_type, operators.DIVIDE_OP),
}

class OperatorResourceTuple(namedtuple('Statistics', ['dsp', 'ff', 'lut'])):
    def __add__(self, other):
        dsp, ff, lut = [a + b for a, b in zip(self, other)]
        return self.__class__(dsp, ff, lut)
    __radd__ = __add__

    def __mul__(self, other):
        if not isinstance(other, (int, float)):
            raise TypeError(
                '{} can only be multiplied with a number.'
                .format(self.__class__.__name__))
        return self.__class__(
            other * self.dsp, other * self.ff, other * self.lut)
    __rmul__ = __mul__

s = OperatorResourceTuple

DEVICE_RESOURCE_TABLE = {
    'Virtex7': {
        int_type: {
            'comparison': s(0, 0, 39),
            operators.ADD_OP: s(0, 32, 32),
            operators.SUBTRACT_OP: s(0, 32, 32),
            operators.MULTIPLY_OP: s(4, 32, 32),
            operators.DIVIDE_OP: s(0, 2016, 2016),
            operators.UNARY_SUBTRACT_OP: s(0, 0, 1),
            operators.TERNARY_SELECT_OP: s(0, 32, 71),
            operators.FIXPOINT_OP: s(0, 0, 71),
            operators.BARRIER_OP: s(0, 0, 0),
            operators.INDEX_ACCESS_OP: s(0, 0, 0),
        },
        float_type: {
            'conversion': s(0, 128, 341),
            'comparison': s(0, 66, 72),
            operators.ADD_OP: s(2, 368, 236),  # full dsp
            operators.SUBTRACT_OP: s(2, 368, 236),  # full dsp
            operators.MULTIPLY_OP: s(3, 197, 123),  # max dsp
            operators.DIVIDE_OP: s(0, 1410, 867),
            operators.UNARY_SUBTRACT_OP: s(0, 0, 1),
            operators.EXPONENTIATE_OP: s(7, 483, 1053),  # full dsp
            operators.TERNARY_SELECT_OP: s(0, 0, 71),
            operators.FIXPOINT_OP: s(0, 0, 0),
            operators.BARRIER_OP: s(0, 0, 0),
            operators.INDEX_ACCESS_OP: s(0, 0, 0),
        },
        ArrayType: {
            operators.INDEX_UPDATE_OP: s(0, 0, 0),
            operators.SUBSCRIPT_OP: s(0, 0, 0),
        }
    },
}

try:
    LATENCY_TABLE = DEVICE_LATENCY_TABLE[context.device, context.frequency]
    RESOURCE_TABLE = DEVICE_RESOURCE_TABLE[context.device]
except KeyError:
    raise KeyError(
        'Statistics for device {} and frequency {} MHz combination not found.'
        .format(context.device, context.frequency))
<commit_msg>Update statistics<commit_after>from collections import namedtuple

from soap.datatype import int_type, float_type, ArrayType
from soap.context import context
from soap.expression import operators

DEVICE_LATENCY_TABLE = {
    ('Virtex7', 333): {
        int_type: {
            'comparison': 1,
            operators.UNARY_SUBTRACT_OP: 0,
            operators.ADD_OP: 1,
            operators.SUBTRACT_OP: 1,
            operators.MULTIPLY_OP: 7,
            operators.DIVIDE_OP: 36,
            operators.INDEX_ACCESS_OP: 2,
        },
        float_type: {
            'comparison': 3,
            'conversion': 8,
            operators.UNARY_SUBTRACT_OP: 0,
            operators.ADD_OP: 10,
            operators.SUBTRACT_OP: 10,
            operators.MULTIPLY_OP: 7,
            operators.DIVIDE_OP: 30,
            operators.EXPONENTIATE_OP: 20,
            operators.INDEX_ACCESS_OP: 2,
        },
        ArrayType: {
            operators.INDEX_UPDATE_OP: 1,
            operators.SUBSCRIPT_OP: 0,
        },
    },
}

NONPIPELINED_OPERATORS = {
    operators.FIXPOINT_OP,
}
PIPELINED_OPERATORS = set(operators.OPERATORS) - NONPIPELINED_OPERATORS
MAX_SHARE_COUNT = 8
SHARED_DATATYPE_OPERATORS = {
    (float_type, 'conversion'),
    (float_type, 'comparison'),
    (float_type, operators.ADD_OP),
    (float_type, operators.SUBTRACT_OP),
    (float_type, operators.MULTIPLY_OP),
    (float_type, operators.DIVIDE_OP),
}

class OperatorResourceTuple(namedtuple('Statistics', ['dsp', 'ff', 'lut'])):
    def __add__(self, other):
        dsp, ff, lut = [a + b for a, b in zip(self, other)]
        return self.__class__(dsp, ff, lut)
    __radd__ = __add__

    def __mul__(self, other):
        if not isinstance(other, (int, float)):
            raise TypeError(
                '{} can only be multiplied with a number.'
                .format(self.__class__.__name__))
        return self.__class__(
            other * self.dsp, other * self.ff, other * self.lut)
    __rmul__ = __mul__

s = OperatorResourceTuple

DEVICE_RESOURCE_TABLE = {
    'Virtex7': {
        int_type: {
            'comparison': s(0, 0, 39),
            operators.ADD_OP: s(0, 32, 32),
            operators.SUBTRACT_OP: s(0, 32, 32),
            operators.MULTIPLY_OP: s(4, 32, 32),
            operators.DIVIDE_OP: s(0, 2016, 2016),
            operators.UNARY_SUBTRACT_OP: s(0, 0, 1),
            operators.TERNARY_SELECT_OP: s(0, 32, 71),
            operators.FIXPOINT_OP: s(0, 0, 71),
            operators.BARRIER_OP: s(0, 0, 0),
            operators.INDEX_ACCESS_OP: s(0, 0, 0),
        },
        float_type: {
            'conversion': s(0, 128, 341),
            'comparison': s(0, 66, 72),
            operators.ADD_OP: s(2, 364, 238),  # full dsp
            operators.SUBTRACT_OP: s(2, 364, 238),  # full dsp
            operators.MULTIPLY_OP: s(3, 197, 123),  # max dsp
            operators.DIVIDE_OP: s(0, 1410, 867),
            operators.UNARY_SUBTRACT_OP: s(0, 0, 1),
            operators.EXPONENTIATE_OP: s(7, 483, 1053),  # full dsp
            operators.TERNARY_SELECT_OP: s(0, 0, 71),
            operators.FIXPOINT_OP: s(0, 0, 0),
            operators.BARRIER_OP: s(0, 0, 0),
            operators.INDEX_ACCESS_OP: s(0, 0, 0),
        },
        ArrayType: {
            operators.INDEX_UPDATE_OP: s(0, 0, 0),
            operators.SUBSCRIPT_OP: s(0, 0, 0),
        }
    },
}

try:
    LATENCY_TABLE = DEVICE_LATENCY_TABLE[context.device, context.frequency]
    RESOURCE_TABLE = DEVICE_RESOURCE_TABLE[context.device]
except KeyError:
    raise KeyError(
        'Statistics for device {} and frequency {} MHz combination not found.'
        .format(context.device, context.frequency))
<|endoftext|>


<commit_before>from django.db import models
from django_countries.fields import CountryField
import datetime

class SuperClass(models.Model):
    # This class is the base of everything
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class MembershipCommon(models.Model):
    # This is for all things that have a membership, for relations.

    begin_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)

    class Meta:
        abstract = True

class Members(SuperClass):
    GENDER_CHOICES = (("MA", "Man"),("WO", "Woman"), ("UN","Unknown"))

    given_names = models.CharField(max_length=64, blank=False, null=False, default="UNKNOWN")
    preferred_name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    surname = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    maiden_name = models.CharField(max_length=32, blank=True, null=False, default="")
    nickname = models.CharField(max_length=32, blank=True, null=False, default="")
    birth_date = models.DateField(blank=True, null=True)
    student_id = models.CharField(max_length=10, blank=True, null=False, default="")
    gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default="UN")
    graduated = models.BooleanField(default=False)
    graduated_year = models.IntegerField(max_length=4, blank=True, null=True)
    dead = models.BooleanField(default=False)
    mobile_phone = models.CharField(max_length=20, blank=True, null=False, default="")
    phone = models.CharField(max_length=20, blank=True, null=False, default="")
    street_address = models.CharField(max_length=64, blank=True, null=False, default="")
    postal_code = models.CharField(max_length=64, blank=True, null=False, default="")
    city = models.CharField(max_length=64, blank=True, null=False, default="")
    country = CountryField(blank_label="Välj land", blank=True, null=False, default="") # https://pypi.python.org/pypi/django-countries/1.0.1
    url = models.CharField(max_length=64, blank=True, null=False, default="")
    email = models.CharField(max_length=64, blank=True, null=False, default="")

    subscribed_to_modulen = models.BooleanField(default=False)
    allow_publish_info = models.BooleanField(default=True)

    username = models.CharField(max_length=32, blank=True, null=False, default="")
    crm_id = models.CharField(max_length=32, blank=True, null=False, default="")

    def _get_full_name(self):
        return "%s %s" % (self.given_names, self.surname)

    def _get_full_preferred_name(self):
        return "%s %s" % (self.preferred_name, self.surname)

    full_name = property(_get_full_name)
    full_preferred_name = property(_get_full_preferred_name)

    def __str__(self):
        return self.full_name

class CommitteeTypes(models.Model):
    # Committees are like groups, but they exist multiple years.
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    abbrevation = models.CharField(max_length=32, blank=True, null=False, default="")
    description = models.TextField(blank=True, null=False, default="")

class Committees(SuperClass):
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    abbrevation = models.CharField(max_length=32, blank=True, null=False, default="")
    begin_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)

    committee_type = models.ForeignKey("CommitteeTypes")
    members = models.ManyToManyField("Members", through="MembersCommitteesRelation")

class MembersCommitteesRelation(MembershipCommon):
    post_type = models.ForeignKey("PostTypes")
    member = models.ForeignKey("Members")
    committee = models.ForeignKey("Committees")

class DepartmentTypes(models.Model):
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    abbrevation = models.CharField(max_length=32, blank=True, null=False, default="")
    description = models.TextField(blank=True, null=False, default="")

class Departments(SuperClass):
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    abbrevation = models.CharField(max_length=32, blank=True, null=False, default="")

    members = models.ManyToManyField("Members", through="MembersDepartmentsRelation")

class MembersDepartmentsRelation(MembershipCommon):
    member = models.ForeignKey("Members")
    department = models.ForeignKey("Departments")

class PostTypes(models.Model):
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    description = models.TextField(blank=True, null=False, default="")

class Posts(SuperClass):
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    post_type = models.ForeignKey("PostTypes")
    members = models.ManyToManyField("Members", through="MembersPostsRelation")

class MembersPostsRelation(MembershipCommon):
    member = models.ForeignKey("Members")
    post = models.ForeignKey("Posts")

class Groups(SuperClass):
    # A group is a one time thing.
    name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    year = models.IntegerField(max_length=4, blank=True, null=True)
    description = models.TextField(blank=True, null=False, default="")

    begin_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)

    members = models.ManyToManyField(Members, through="MembersGroupsRelation")

class MembersGroupsRelation(MembershipCommon):
    member = models.ForeignKey("Members")
    group = models.ForeignKey("Groups")
<commit_msg>Updated models<commit_after>from django.db import models
from django_countries.fields import CountryField
import datetime

def getEpoch():
	return datetime.date(1872, 1, 1)

class SuperClass(models.Model):
    # This class is the base of everything
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class Member(SuperClass):
    GENDER_CHOICES = (("MA", "Man"),("WO", "Woman"), ("UN","Unknown"))

    given_names = models.CharField(max_length=64, blank=False, null=False, default="UNKNOWN")
    preferred_name = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    surname = models.CharField(max_length=32, blank=False, null=False, default="UNKNOWN")
    maiden_name = models.CharField(max_length=32, blank=True, null=False, default="")
    nickname = models.CharField(max_length=32, blank=True, null=False, default="")
    birth_date = models.DateField(blank=True, null=True)
    student_id = models.CharField(max_length=10, blank=True, null=False, default="")
    gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default="UN")
    graduated = models.BooleanField(default=False)
    graduated_year = models.IntegerField(max_length=4, blank=True, null=True)
    dead = models.BooleanField(default=False)
    mobile_phone = models.CharField(max_length=20, blank=True, null=False, default="")
    phone = models.CharField(max_length=20, blank=True, null=False, default="")
    street_address = models.CharField(max_length=64, blank=True, null=False, default="")
    postal_code = models.CharField(max_length=64, blank=True, null=False, default="")
    city = models.CharField(max_length=64, blank=True, null=False, default="")
    country = CountryField(blank_label="Välj land", blank=True, null=False, default="") # https://pypi.python.org/pypi/django-countries/1.0.1
    url = models.CharField(max_length=64, blank=True, null=False, default="")
    email = models.CharField(max_length=64, blank=True, null=False, default="")

    subscribed_to_modulen = models.BooleanField(default=False)
    allow_publish_info = models.BooleanField(default=True)

    username = models.CharField(max_length=32, blank=True, null=False, default="")
    crm_id = models.CharField(max_length=32, blank=True, null=False, default="")

    def _get_full_name(self):
        return "%s %s" % (self.given_names, self.surname)

    def _get_full_preferred_name(self):
        return "%s %s" % (self.preferred_name, self.surname)

    full_name = property(_get_full_name)
    full_preferred_name = property(_get_full_preferred_name)

    def __str__(self):
        return self.full_name

class DecorationOwnership(SuperClass):
	member = models.ForeignKey("Member")
	decoration = models.ForeignKey("Decoration")
	acquired = models.DateField(default=getEpoch())

class Decoration(SuperClass):
	name = models.CharField(max_length=64, blank=False, null=False, unique=True)

class GroupMembership(SuperClass):
	member = models.ForeignKey("Member")
	group = models.ForeignKey("Group")
	begin_date = models.DateField(default=getEpoch())
	end_date = models.DateField(default=getEpoch())

class Group(SuperClass):
	name = models.CharField(max_length=64, blank=False, null=False, unique=True)
	grouptype = models.ForeignKey("GroupType")
	begin_date = models.DateField(default=getEpoch())
	end_date = models.DateField(default=getEpoch())

class GroupType(SuperClass):
	name = models.CharField(max_length=64, blank=False, null=False, unique=True)

class Functionary(SuperClass):
	name = models.CharField(max_length=64, blank=False, null=False, unique=True)
	member = ForeignKey("Member")
	functionarytype = ForeignKey("FunctionaryType")
	begin_date = models.DateField(default=getEpoch())
	end_date = models.DateField(default=getEpoch())

class FunctionaryType(SuperClass):
	name = models.CharField(max_length=64, blank=False, null=False, unique=True)

<|endoftext|>


<commit_before># modified from https://www.raspberrypi.org/learning/sense-hat-data-debug_logger/code/Sense_Logger_v4.py

# package imports
import os
from time import sleep, time
import logging
import numpy

# Raspberry Pi hardware imports
import picamera
import picamera.array
from sense_hat import SenseHat

sensehat = SenseHat()

# define interval in seconds between each image capture
picamera_capture_interval = 3

start_time = time()
timeout = 30

# define path to log directory
log_dir = os.path.join('/home/pi/Desktop', 'virde_log', 'log_' + str(int(start_time)))

# create path to log directory if it doesn't exist
if not os.path.exists(log_dir):
    os.mkdir(log_dir)

# define formatter that adds header to first line
class FormatterWithHeader(logging.Formatter):
    def __init__(self, header, fmt=None, datefmt=None, style='%'):
        super().__init__(fmt, datefmt, style)
        self.header = header  # This is hard coded but you could make dynamic
        # Override the normal format method
        self.format = self.first_line_format

    def first_line_format(self, record):
        # First time in, switch back to the normal format function
        self.format = super().format
        return self.header + "\n" + self.format(record)

# add headers to log files
with open(os.path.join(log_dir, 'events.log'), 'w') as events_log:
    events_log.write('DateTime,Message' + '\n')
with open(os.path.join(log_dir, 'sensor.log'), 'w') as sensor_log:
    sensor_log.write('DateTime,Temp_h,Temp_p,Humidity,Pressure,Pitch,Roll,Yaw,Mag_x,Mag_y,Mag_z,Accel_x,Accel_y,Accel_z,Gyro_x,Gyro_y,Gyro_z' + '\n')
with open(os.path.join(log_dir, 'images.log'), 'w') as images_log:
    images_log.write('DateTime,ImagePath' + '\n')

# create loggers
events_logger = logging.getLogger('events')
sensor_logger = logging.getLogger('sensor')
images_logger = logging.getLogger('images')

# set logging levels
events_logger.setLevel(logging.DEBUG)
sensor_logger.setLevel(logging.DEBUG)
images_logger.setLevel(logging.DEBUG)

# create file handlers
events_file_handler = logging.FileHandler(os.path.join(log_dir, 'events.log'))
sensor_file_handler = logging.FileHandler(os.path.join(log_dir, 'sensor.log'))
images_file_handler = logging.FileHandler(os.path.join(log_dir, 'images.log'))

# set file handler logging levels
events_file_handler.setLevel(logging.DEBUG)
sensor_file_handler.setLevel(logging.INFO)
images_file_handler.setLevel(logging.INFO)

# add formatters to the file handlers
events_file_handler.setFormatter(logging.Formatter('%(asctime)s,%(message)s'))
sensor_file_handler.setFormatter(logging.Formatter('%(asctime)s,%(message)s'))
images_file_handler.setFormatter(logging.Formatter('%(asctime)s,%(message)s'))

# add file handlers to the loggers
events_logger.addHandler(events_file_handler)
sensor_logger.addHandler(sensor_file_handler)
images_logger.addHandler(images_file_handler)

# define function to return a csv line of all sensehat data
def get_sensehat_data():
    output_data = []

    output_data.append(sensehat.get_temperature_from_humidity())
    output_data.append(sensehat.get_temperature_from_pressure())
    output_data.append(sensehat.get_humidity())
    output_data.append(sensehat.get_pressure())

    orientation = sensehat.get_orientation()
    output_data.extend([orientation['yaw'], orientation['pitch'], orientation['roll']])

    magnetometer = sensehat.get_compass_raw()
    output_data.extend([magnetometer['x'], magnetometer['y'], magnetometer['z']])

    accelerometer = sensehat.get_accelerometer_raw()
    output_data.extend([accelerometer['x'], accelerometer['y'], accelerometer['z']])

    gyroscope = sensehat.get_gyroscope_raw()
    output_data.extend([gyroscope['x'], gyroscope['y'], gyroscope['z']])

    # return output data
    return output_data

# define starting time for thread completion
start_time = time()

# log script start
events_logger.info('Started logging')

while time() < start_time + timeout:
    # take sensor measurements every second within the picamera logging interval
    for second in range(1, picamera_capture_interval):
        sleep(1)
        sensor_logger.info(','.join(str(value) for value in get_sensehat_data()))

    with picamera.PiCamera() as camera:
        # set to maximum v2 resolution
        camera.resolution = (3280, 2464)

        # let automatic exposure settle for 2 seconds
        sleep(1)
        sensor_logger.info(','.join(str(value) for value in get_sensehat_data()))
        sleep(1)

        # capture PNG image after processing
        image_name = os.path.join(log_dir, 'image_' + str(int(time())) + '.png')
        camera.capture(image_name)
        images_logger.info(image_name)

        # capture unencoded RGB directly to binary file
        #image_name = os.path.join(log_dir, 'rgb_' + str(int(time())) + '.data')
        #with open(image_name, 'wb') as binary_file:
        #    camera.capture(binary_file, 'rgb')

        # log image save
        #images_logger.info(image_name)

        # capture Bayer data to binary file after demosaicing
        image_name = os.path.join(log_dir, 'rgb_bayer_' + str(int(time())) + '.data')
        with picamera.array.PiBayerArray(camera) as stream:
            # capture to stream as bayer data
            camera.capture(stream, 'jpeg', bayer=True)

            # Demosaic data and write to output (just use stream.array if you want to skip the demosaic step)
            output = (stream.demosaic() >> 2).astype(numpy.uint8)

            # save to file
            with open(image_name, 'wb') as binary_file:
                output.tofile(binary_file)

            # log image save
            images_logger.info(image_name)

# log script completion
events_logger.info('Finished logging')
<commit_msg>reenabled unencoded image capture<commit_after># modified from https://www.raspberrypi.org/learning/sense-hat-data-debug_logger/code/Sense_Logger_v4.py

# package imports
import os
from time import sleep, time
import logging
import numpy

# Raspberry Pi hardware imports
import picamera
import picamera.array
from sense_hat import SenseHat

sensehat = SenseHat()

# define interval in seconds between each image capture
picamera_capture_interval = 3

start_time = time()
timeout = 30

# define path to log directory
log_dir = os.path.join('/home/pi/Desktop', 'virde_log', 'log_' + str(int(start_time)))

# create path to log directory if it doesn't exist
if not os.path.exists(log_dir):
    os.mkdir(log_dir)

# define formatter that adds header to first line
class FormatterWithHeader(logging.Formatter):
    def __init__(self, header, fmt=None, datefmt=None, style='%'):
        super().__init__(fmt, datefmt, style)
        self.header = header  # This is hard coded but you could make dynamic
        # Override the normal format method
        self.format = self.first_line_format

    def first_line_format(self, record):
        # First time in, switch back to the normal format function
        self.format = super().format
        return self.header + "\n" + self.format(record)

# add headers to log files
with open(os.path.join(log_dir, 'events.log'), 'w') as events_log:
    events_log.write('DateTime,Message' + '\n')
with open(os.path.join(log_dir, 'sensor.log'), 'w') as sensor_log:
    sensor_log.write('DateTime,Temp_h,Temp_p,Humidity,Pressure,Pitch,Roll,Yaw,Mag_x,Mag_y,Mag_z,Accel_x,Accel_y,Accel_z,Gyro_x,Gyro_y,Gyro_z' + '\n')
with open(os.path.join(log_dir, 'images.log'), 'w') as images_log:
    images_log.write('DateTime,ImagePath' + '\n')

# create loggers
events_logger = logging.getLogger('events')
sensor_logger = logging.getLogger('sensor')
images_logger = logging.getLogger('images')

# set logging levels
events_logger.setLevel(logging.DEBUG)
sensor_logger.setLevel(logging.DEBUG)
images_logger.setLevel(logging.DEBUG)

# create file handlers
events_file_handler = logging.FileHandler(os.path.join(log_dir, 'events.log'))
sensor_file_handler = logging.FileHandler(os.path.join(log_dir, 'sensor.log'))
images_file_handler = logging.FileHandler(os.path.join(log_dir, 'images.log'))

# set file handler logging levels
events_file_handler.setLevel(logging.DEBUG)
sensor_file_handler.setLevel(logging.INFO)
images_file_handler.setLevel(logging.INFO)

# add formatters to the file handlers
events_file_handler.setFormatter(logging.Formatter('%(asctime)s,%(message)s'))
sensor_file_handler.setFormatter(logging.Formatter('%(asctime)s,%(message)s'))
images_file_handler.setFormatter(logging.Formatter('%(asctime)s,%(message)s'))

# add file handlers to the loggers
events_logger.addHandler(events_file_handler)
sensor_logger.addHandler(sensor_file_handler)
images_logger.addHandler(images_file_handler)

# define function to return a csv line of all sensehat data
def get_sensehat_data():
    output_data = []

    output_data.append(sensehat.get_temperature_from_humidity())
    output_data.append(sensehat.get_temperature_from_pressure())
    output_data.append(sensehat.get_humidity())
    output_data.append(sensehat.get_pressure())

    orientation = sensehat.get_orientation()
    output_data.extend([orientation['yaw'], orientation['pitch'], orientation['roll']])

    magnetometer = sensehat.get_compass_raw()
    output_data.extend([magnetometer['x'], magnetometer['y'], magnetometer['z']])

    accelerometer = sensehat.get_accelerometer_raw()
    output_data.extend([accelerometer['x'], accelerometer['y'], accelerometer['z']])

    gyroscope = sensehat.get_gyroscope_raw()
    output_data.extend([gyroscope['x'], gyroscope['y'], gyroscope['z']])

    # return output data
    return output_data

# define starting time for thread completion
start_time = time()

# log script start
events_logger.info('Started logging')

while time() < start_time + timeout:
    # take sensor measurements every second within the picamera logging interval
    for second in range(1, picamera_capture_interval):
        sleep(1)
        sensor_logger.info(','.join(str(value) for value in get_sensehat_data()))

    with picamera.PiCamera() as camera:
        # set to maximum v2 resolution
        camera.resolution = (3280, 2464)

        # let automatic exposure settle for 2 seconds
        sleep(1)
        sensor_logger.info(','.join(str(value) for value in get_sensehat_data()))
        sleep(1)

        # capture PNG image after processing
        image_name = os.path.join(log_dir, 'image_' + str(int(time())) + '.png')
        camera.capture(image_name)
        images_logger.info(image_name)

        # capture unencoded RGB directly to binary file
        image_name = os.path.join(log_dir, 'rgb_' + str(int(time())) + '.data')
        with open(image_name, 'wb') as binary_file:
            camera.capture(binary_file, 'rgb')

        # log image save
        images_logger.info(image_name)

        # capture Bayer data to binary file after demosaicing
        image_name = os.path.join(log_dir, 'rgb_bayer_' + str(int(time())) + '.data')
        with picamera.array.PiBayerArray(camera) as stream:
            # capture to stream as bayer data
            camera.capture(stream, 'jpeg', bayer=True)

            # Demosaic data and write to output (just use stream.array if you want to skip the demosaic step)
            output = (stream.demosaic() >> 2).astype(numpy.uint8)

            # save to file
            with open(image_name, 'wb') as binary_file:
                output.tofile(binary_file)

            # log image save
            images_logger.info(image_name)

# log script completion
events_logger.info('Finished logging')
<|endoftext|>


<commit_before>#!/usr/bin/env python

"""Flask-GCM wrapper for python-gcm."""

from gcm.gcm import (
    GCM as _GCM,
    GCM_URL,
)

# Import exception classes into the flask_gcm package
from gcm.gcm import (  # NOQA
    GCMException,
    GCMMalformedJsonException,
    GCMConnectionException,
    GCMAuthenticationException,
    GCMTooManyRegIdsException,
    GCMInvalidTtlException,
    GCMMissingRegistrationException,
    GCMMismatchSenderIdException,
    GCMNotRegisteredException,
    GCMMessageTooBigException,
    GCMInvalidRegistrationException,
    GCMUnavailableException,
)

# import other functions into flask_gcm package
from gcm.gcm import group_response, urlencode_utf8  # NOQA

# Version info
__project__ = 'Flask-GCM'
__MAJOR__ = 0
__MINOR__ = 0
__PATCH__ = 0
__version__ = '{}.{}.{}'.format(__MAJOR__, __MINOR__, __PATCH__)
VERSION = __project__ + '-' + __version__

# Define what gets imported when using `from flask_gcm import *`
__all__ = ('GCM',
           'GCMException',
           'GCMMalformedJsonException',
           'GCMConnectionException',
           'GCMAuthenticationException',
           'GCMTooManyRegIdsException',
           'GCMInvalidTtlException',
           'GCMMissingRegistrationException',
           'GCMMismatchSenderIdException',
           'GCMNotRegisteredException',
           'GCMMessageTooBigException',
           'GCMInvalidRegistrationException',
           'GCMUnavailableException',)

class GCM(_GCM):

    """Convenience wrapper class for GCM library."""

    def __init__(self, app=None, api_key=None, url=GCM_URL):
        """Initialize the GCM object with flask app settings."""
        self.app = app
        if self.app:
            self.init_app(app)

    def init_app(self, app):
        """Initialize the GCM object with flask app settings."""
        # Configure default GCM settings
        app.config.setdefault('GCM_URL', GCM_URL)
        app.config.setdefault('GCM_KEY', None)
        app.config.setdefault('GCM_PROXY', None)
        # The following is a limit hard coded into the python-gcm library:
        app.config.setdefault('GCM_MAX_DEVICES_PER_REQUEST', 1000)

        # Configure GCM from app settings
        self.url = app.config.get('GCM_URL')
        self.api_key = app.config.get('GCM_KEY')
        self.proxy = app.config.get('GCM_PROXY')

        # Register GCM on app extensions
        if not hasattr(app, 'extensions'):  # pragma: no cover
            # For older versions of Flask before 0.7
            app.extensions = {}
        app.extensions['gcm'] = self

        # init python-gcm object
        super(self.__class__, self).__init__(self.api_key, url=self.url,
                                             proxy=self.proxy)
<commit_msg>fix for python2.6<commit_after>#!/usr/bin/env python

"""Flask-GCM wrapper for python-gcm."""

from gcm.gcm import (
    GCM as _GCM,
    GCM_URL,
)

# Import exception classes into the flask_gcm package
from gcm.gcm import (  # NOQA
    GCMException,
    GCMMalformedJsonException,
    GCMConnectionException,
    GCMAuthenticationException,
    GCMTooManyRegIdsException,
    GCMInvalidTtlException,
    GCMMissingRegistrationException,
    GCMMismatchSenderIdException,
    GCMNotRegisteredException,
    GCMMessageTooBigException,
    GCMInvalidRegistrationException,
    GCMUnavailableException,
)

# import other functions into flask_gcm package
from gcm.gcm import group_response, urlencode_utf8  # NOQA

# Version info
__project__ = 'Flask-GCM'
__MAJOR__ = 0
__MINOR__ = 0
__PATCH__ = 0
__version__ = '{0}.{1}.{2}'.format(__MAJOR__, __MINOR__, __PATCH__)
VERSION = __project__ + '-' + __version__

# Define what gets imported when using `from flask_gcm import *`
__all__ = ('GCM',
           'GCMException',
           'GCMMalformedJsonException',
           'GCMConnectionException',
           'GCMAuthenticationException',
           'GCMTooManyRegIdsException',
           'GCMInvalidTtlException',
           'GCMMissingRegistrationException',
           'GCMMismatchSenderIdException',
           'GCMNotRegisteredException',
           'GCMMessageTooBigException',
           'GCMInvalidRegistrationException',
           'GCMUnavailableException',)

class GCM(_GCM):

    """Convenience wrapper class for GCM library."""

    def __init__(self, app=None, api_key=None, url=GCM_URL):
        """Initialize the GCM object with flask app settings."""
        self.app = app
        if self.app:
            self.init_app(app)

    def init_app(self, app):
        """Initialize the GCM object with flask app settings."""
        # Configure default GCM settings
        app.config.setdefault('GCM_URL', GCM_URL)
        app.config.setdefault('GCM_KEY', None)
        app.config.setdefault('GCM_PROXY', None)
        # The following is a limit hard coded into the python-gcm library:
        app.config.setdefault('GCM_MAX_DEVICES_PER_REQUEST', 1000)

        # Configure GCM from app settings
        self.url = app.config.get('GCM_URL')
        self.api_key = app.config.get('GCM_KEY')
        self.proxy = app.config.get('GCM_PROXY')

        # Register GCM on app extensions
        if not hasattr(app, 'extensions'):  # pragma: no cover
            # For older versions of Flask before 0.7
            app.extensions = {}
        app.extensions['gcm'] = self

        # init python-gcm object
        super(self.__class__, self).__init__(self.api_key, url=self.url,
                                             proxy=self.proxy)
<|endoftext|>


<commit_before>from flask import Flask, Response

from .resolver import Pushrod, pushrod_view
from .formatters.base import formatter, UnformattedResponse
from .formatters.json import json_formatter

from unittest import TestCase
import json

test_response = {
    "spam": "eggs",
    "yes": [
        "maybe",
        "no",
    ],
    "nonsense": (
        True,
        False,
        "FILE_NOT_FOUND",
        -5.4,
    ),
}

@formatter('repr')
def repr_formatter(unformatted):
    return unformatted.formatted(repr(unformatted.response), "text/plain")

class PushrodTestCase(TestCase):
    def setUp(self):
        app = Flask(__name__)
        pushrod = Pushrod(app)

        pushrod.register_formatter(repr_formatter)
        pushrod.default_formatter = repr_formatter

        self.app = app
        self.client = app.test_client()

class PushrodResolverTestCase(PushrodTestCase):
    def test_raw_dict_response_data(self):
        @self.app.route("/raw_dict")
        @pushrod_view()
        def test_view_raw_dict():
            return test_response

        test_view_raw_dict_response = self.client.get("/raw_dict")
        assert test_view_raw_dict_response.status_code == 200, \
            "Invalid status code returned from dict-returning view"
        assert test_view_raw_dict_response.data == repr(test_response), \
            "Invalid data returned from dict-returning view"

    def test_response_data(self):
        @self.app.route("/200_response")
        @pushrod_view()
        def test_view_200_view():
            return UnformattedResponse(test_response)

        @self.app.route("/404_response")
        @pushrod_view()
        def test_view_404_view():
            return UnformattedResponse(test_response, 404)

        test_view_200_response = self.client.get("/200_response")
        assert test_view_200_response.status_code == 200, \
            "Invalid status code returned from 200-returning view"
        assert test_view_200_response.data == repr(test_response), \
            "Invalid data returned from 200-returning view"

        test_view_404_response = self.client.get("/404_response")
        assert test_view_404_response.status_code == 404, \
            "Invalid status code returned from 404-returning view"
        assert test_view_404_response.data == repr(test_response), \
            "Invalid data returned from 404-returning view"

    def test_response_bypass(self):
        @self.app.route("/raw_string")
        @pushrod_view()
        def test_raw_string_view():
            return "test"

        @self.app.route("/regular_response")
        @pushrod_view()
        def test_regular_response_view():
            return Response("test")

        test_raw_string_response = self.client.get("/raw_string")
        assert test_raw_string_response.status_code == 200, \
            "Invalid status code returned from raw string view"
        assert test_raw_string_response.data == "test", \
            "Invalid data returned from raw string view"

        test_regular_response_response = self.client.get("/regular_response")
        assert test_regular_response_response.status_code == 200, \
            "Invalid status code returned from regular response view"
        assert test_regular_response_response.data == "test", \
            "Invalid data returned from regular response view"

class PushrodFormatterTestCase(PushrodTestCase):
    def test_json_formatter(self):
        regular = json.dumps(test_response)
        formatted = self.app.pushrod.format_response(
            test_response, json_formatter)

        assert regular == formatted.data
<commit_msg>Try to parse the json output in the test<commit_after>from flask import Flask, Response

from .resolver import Pushrod, pushrod_view
from .formatters.base import formatter, UnformattedResponse
from .formatters.json import json_formatter

from unittest import TestCase
import json

test_response = {
    "spam": "eggs",
    "yes": [
        "maybe",
        "no",
    ],
    "nonsense": (
        True,
        False,
        "FILE_NOT_FOUND",
        -5.4,
    ),
}

@formatter('repr')
def repr_formatter(unformatted):
    return unformatted.formatted(repr(unformatted.response), "text/plain")

class PushrodTestCase(TestCase):
    def setUp(self):
        app = Flask(__name__)
        pushrod = Pushrod(app)

        pushrod.register_formatter(repr_formatter)
        pushrod.default_formatter = repr_formatter

        self.app = app
        self.client = app.test_client()

class PushrodResolverTestCase(PushrodTestCase):
    def test_raw_dict_response_data(self):
        @self.app.route("/raw_dict")
        @pushrod_view()
        def test_view_raw_dict():
            return test_response

        test_view_raw_dict_response = self.client.get("/raw_dict")
        assert test_view_raw_dict_response.status_code == 200, \
            "Invalid status code returned from dict-returning view"
        assert test_view_raw_dict_response.data == repr(test_response), \
            "Invalid data returned from dict-returning view"

    def test_response_data(self):
        @self.app.route("/200_response")
        @pushrod_view()
        def test_view_200_view():
            return UnformattedResponse(test_response)

        @self.app.route("/404_response")
        @pushrod_view()
        def test_view_404_view():
            return UnformattedResponse(test_response, 404)

        test_view_200_response = self.client.get("/200_response")
        assert test_view_200_response.status_code == 200, \
            "Invalid status code returned from 200-returning view"
        assert test_view_200_response.data == repr(test_response), \
            "Invalid data returned from 200-returning view"

        test_view_404_response = self.client.get("/404_response")
        assert test_view_404_response.status_code == 404, \
            "Invalid status code returned from 404-returning view"
        assert test_view_404_response.data == repr(test_response), \
            "Invalid data returned from 404-returning view"

    def test_response_bypass(self):
        @self.app.route("/raw_string")
        @pushrod_view()
        def test_raw_string_view():
            return "test"

        @self.app.route("/regular_response")
        @pushrod_view()
        def test_regular_response_view():
            return Response("test")

        test_raw_string_response = self.client.get("/raw_string")
        assert test_raw_string_response.status_code == 200, \
            "Invalid status code returned from raw string view"
        assert test_raw_string_response.data == "test", \
            "Invalid data returned from raw string view"

        test_regular_response_response = self.client.get("/regular_response")
        assert test_regular_response_response.status_code == 200, \
            "Invalid status code returned from regular response view"
        assert test_regular_response_response.data == "test", \
            "Invalid data returned from regular response view"

class PushrodFormatterTestCase(PushrodTestCase):
    def test_json_formatter(self):
        regular = json.dumps(test_response)
        formatted = self.app.pushrod.format_response(
            test_response, json_formatter)

        assert regular == formatted.data

        json.loads(formatted.data)
<|endoftext|>


<commit_before>import os

import requests
from threading import Thread
import vk_api
from datetime import datetime
import time
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords
import matplotlib
matplotlib.use('Agg')
from wordcloud import WordCloud
import random
import pymorphy2
from pymongo import MongoClient
import config

print('Connecting to VK...', end=' ')
vk_group = vk_api.VkApi(token=config.vk_community_token).get_api()
vk_session = vk_api.VkApi(token=config.vk_user_token)
tools = vk_api.VkTools(vk_session)
vk = vk_session.get_api()
print('Done')

print('Connecting to MongoDB...', end=' ')
collection = MongoClient(config.mongo_host)[config.mongo_db]['photos']
print('Done')

remove_words = ['год']
DIR = os.path.dirname(__file__)

processing = []

def cloud(user_id):
    wall = tools.get_all('wall.get', 100, {'owner_id': user_id})['items']
    wall = list(filter(lambda x: datetime.fromtimestamp(x['date']).year == 2017, wall))

    tokenizer = RegexpTokenizer('[а-яА-ЯёЁ]+')
    morph = pymorphy2.MorphAnalyzer()

    def transform(sentence):
        return map(lambda x: morph.parse(x)[0].normal_form.replace('ё', 'е'),
                   filter(
                       lambda x: len(x) > 2 and 'NOUN' in morph.parse(x)[0].tag,
                       tokenizer.tokenize(sentence.replace('\xa0', ' '))
                   )
                   )

    top_words = []
    for post in wall:
        if 'text' in post:
            top_words.extend(transform(post['text']))
        if 'copy_history' in post:
            for copy in post['copy_history']:
                if 'text' in copy:
                    top_words.extend(transform(copy['text']))
    top_words = list(filter(lambda x: x.lower() not in remove_words, top_words))
    if not top_words:
        return

    def color_func(word, font_size, position, orientation, random_state=None, **kwargs):
        return "hsl(%d, 100%%, %d%%)" % (random.randint(0, 360), random.randint(20, 50))

    sw = (stopwords.words('russian') + stopwords.words('english') + remove_words)
    wordcloud = WordCloud(
        max_words=200,
        max_font_size=500,
        background_color='white',
        margin=5,
        width=1000,
        height=1000,
        stopwords=sw,
        prefer_horizontal=0.95
    ).generate(' '.join(top_words))
    wordcloud = wordcloud.recolor(color_func=color_func, random_state=3)
    wordcloud.to_file(os.path.join(DIR, 'clouds/{}.jpg'.format(user_id)))
    return open(os.path.join(DIR, 'clouds/{}.jpg'.format(user_id)), 'rb'), wall

def send_cloud(user_id, message):
    processing.append(user_id)

    print(processing)

    if message.lower() != 'облако':
        vk_group.messages.send(user_id=user_id, message='Если ты хочешь получить свое облако тегов за 2018 '
                                                        'год, отправь мне слово "облако" без кавычек 🙃')
        return

    print('Generating cloud for', user_id)
    try:
        if not vk.groups.isMember(group_id=config.group_id, user_id=user_id):
            vk_group.messages.send(user_id=user_id,
                                   message='Чтобы составить облако тегов, '
                                           'подпишись на меня https://vk.com/wwcloud 🙄')
            time.sleep(1)
            vk_group.messages.send(user_id=user_id,
                                   message='Когда будешь готов, снова отправь кодовое слово "облако" 😊')
            processing.remove(user_id)
            time.sleep(5)
            return
        if len(vk.wall.get(owner_id=user_id, count=1)['items']) == 0:
            vk_group.messages.send(user_id=user_id,
                                   message='Похоже, у тебя недостаточно записей на стене '
                                           'для составления облака тегов☹')
            processing.remove(user_id)
            time.sleep(5)
            return
        vk_group.messages.send(user_id=user_id, message='Посмотрим, что тебя интересвало в 2018 году больше всего 😋')
        user = vk.users.get(user_ids=user_id)[0]
        user_id = user['id']
        name = user['first_name'] + ' ' + user['last_name']
        data = vk.photos.getUploadServer(album_id=config.album_id, group_id=config.group_id)
        DATA_UPLOAD_URL = data['upload_url']
        clouded = cloud(user_id)
        if not clouded:
            vk_group.messages.send(user_id=user_id,
                                   message='Похоже, у тебя недостаточно записей на стене '
                                           'для составления облака тегов ☹')
            time.sleep(5)
            return
        clouded, wall = clouded
        r = requests.post(DATA_UPLOAD_URL, files={'photo': clouded}).json()
        photo = vk.photos.save(server=r['server'], photos_list=r['photos_list'], group_id=r['gid'], album_id=r['aid'],
                               hash=r['hash'])[0]
        vk_group.messages.send(user_id=user_id, message='А вот и твое облако тегов! 🌍',
                               attachment='photo{}_{}'.format(photo['owner_id'], photo['id']))
        vk_group.messages.send(user_id=user_id, message='Не забудь рассказать друзьям 😉')
        post_id = None
        if not collection.find_one({'user_id': user_id, 'timestamp': {'$gt': time.time() - 86400}}):
            try:
                post_id = vk.wall.post(owner_id=-config.group_id, from_group=1,
                                       message='Облако тегов для *id{}({})'.format(user_id, name),
                                       attachments='photo{}_{}'.format(photo['owner_id'], photo['id']))['post_id']
            except Exception:
                vk_group.messages.send(user_id=user_id,
                                       message='Похоже, я превысил лимит количества постов на сегодня 😭')
                vk_group.messages.send(user_id=user_id,
                                       message='Создай новое облако завтра, и я выложу его на стену группы 😎')
        if post_id:
            collection.insert(
                {'user_id': user_id, 'owner_id': photo['owner_id'], 'id': photo['id'], 'wall': wall, 'post': post_id,
                 'timestamp': time.time()})
            vk_group.messages.send(user_id=user_id, attachment='wall{}_{}'.format(photo['owner_id'], post_id))
        else:
            collection.insert({'user_id': user_id, 'owner_id': photo['owner_id'], 'id': photo['id'], 'wall': wall})
        processing.remove(user_id)
        print('Finished cloud for', user_id)
    except Exception as e:
        processing.remove(user_id)
        print('Finished cloud for', user_id, 'with error')
        raise e

def process_updates(updates):
    for update in updates:
        if update[0] == 4 and update[3] not in processing:
            Thread(target=send_cloud, args=(update[3], update[6])).start()

if __name__ == '__main__':
    print('Initializing longpoll connection...', end=' ')
    longpoll = vk_group.messages.getLongPollServer()
    print('Done')
    while True:
        try:
            response = requests.get('https://{}?act=a_check&key={}&ts={}&wait=25%mode=128'.format(
                longpoll['server'],
                longpoll['key'],
                longpoll['ts']
            ), timeout=25).json()
            longpoll['ts'] = response['ts'] if 'ts' in response else longpoll['ts']
            Thread(target=process_updates, args=(response['updates'],)).start()
        except Exception as e:
            while True:
                try:
                    longpoll = vk_group.messages.getLongPollServer()
                    break
                except Exception:
                    continue
            print(e)
            continue
<commit_msg>Change the way we saving the result<commit_after>import os

import requests
from threading import Thread
import vk_api
from datetime import datetime
import time
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords
import matplotlib
matplotlib.use('Agg')
from wordcloud import WordCloud
import random
import pymorphy2
from pymongo import MongoClient
import config
import io

print('Connecting to VK...', end=' ')
vk_group = vk_api.VkApi(token=config.vk_community_token).get_api()
vk_session = vk_api.VkApi(token=config.vk_user_token)
tools = vk_api.VkTools(vk_session)
vk = vk_session.get_api()
print('Done')

print('Connecting to MongoDB...', end=' ')
collection = MongoClient(config.mongo_host)[config.mongo_db]['photos']
print('Done')

remove_words = ['год']
DIR = os.path.dirname(__file__)

processing = []

def cloud(user_id):
    wall = tools.get_all('wall.get', 100, {'owner_id': user_id})['items']
    wall = list(filter(lambda x: datetime.fromtimestamp(x['date']).year == 2017, wall))

    tokenizer = RegexpTokenizer('[а-яА-ЯёЁ]+')
    morph = pymorphy2.MorphAnalyzer()

    def transform(sentence):
        return map(lambda x: morph.parse(x)[0].normal_form.replace('ё', 'е'),
                   filter(
                       lambda x: len(x) > 2 and 'NOUN' in morph.parse(x)[0].tag,
                       tokenizer.tokenize(sentence.replace('\xa0', ' '))
                   )
                   )

    top_words = []
    for post in wall:
        if 'text' in post:
            top_words.extend(transform(post['text']))
        if 'copy_history' in post:
            for copy in post['copy_history']:
                if 'text' in copy:
                    top_words.extend(transform(copy['text']))
    top_words = list(filter(lambda x: x.lower() not in remove_words, top_words))
    if not top_words:
        return

    def color_func(word, font_size, position, orientation, random_state=None, **kwargs):
        return "hsl(%d, 100%%, %d%%)" % (random.randint(0, 360), random.randint(20, 50))

    sw = (stopwords.words('russian') + stopwords.words('english') + remove_words)
    wordcloud = WordCloud(
        max_words=200,
        max_font_size=500,
        background_color='white',
        margin=5,
        width=1000,
        height=1000,
        stopwords=sw,
        prefer_horizontal=0.95
    ).generate(' '.join(top_words))
    wordcloud = wordcloud.recolor(color_func=color_func, random_state=3).to_image()
    img_arr = io.BytesIO()
    wordcloud.save(img_arr, format='PNG')
    return img_arr.getvalue(), wall

def send_cloud(user_id, message):
    processing.append(user_id)

    print(processing)

    if message.lower() != 'облако':
        vk_group.messages.send(user_id=user_id, message='Если ты хочешь получить свое облако тегов за 2018 '
                                                        'год, отправь мне слово "облако" без кавычек 🙃')
        return

    print('Generating cloud for', user_id)
    try:
        if not vk.groups.isMember(group_id=config.group_id, user_id=user_id):
            vk_group.messages.send(user_id=user_id,
                                   message='Чтобы составить облако тегов, '
                                           'подпишись на меня https://vk.com/wwcloud 🙄')
            time.sleep(1)
            vk_group.messages.send(user_id=user_id,
                                   message='Когда будешь готов, снова отправь кодовое слово "облако" 😊')
            processing.remove(user_id)
            time.sleep(5)
            return
        if len(vk.wall.get(owner_id=user_id, count=1)['items']) == 0:
            vk_group.messages.send(user_id=user_id,
                                   message='Похоже, у тебя недостаточно записей на стене '
                                           'для составления облака тегов☹')
            processing.remove(user_id)
            time.sleep(5)
            return
        vk_group.messages.send(user_id=user_id, message='Посмотрим, что тебя интересовало в 2018 году больше всего 😋')
        user = vk.users.get(user_ids=user_id)[0]
        user_id = user['id']
        name = user['first_name'] + ' ' + user['last_name']
        data = vk.photos.getUploadServer(album_id=config.album_id, group_id=config.group_id)
        DATA_UPLOAD_URL = data['upload_url']
        clouded = cloud(user_id)
        if not clouded:
            vk_group.messages.send(user_id=user_id,
                                   message='Похоже, у тебя недостаточно записей на стене '
                                           'для составления облака тегов ☹')
            time.sleep(5)
            return
        clouded, wall = clouded
        r = requests.post(DATA_UPLOAD_URL, files={'photo': clouded}).json()
        photo = vk.photos.save(server=r['server'], photos_list=r['photos_list'], group_id=r['gid'], album_id=r['aid'],
                               hash=r['hash'])[0]
        vk_group.messages.send(user_id=user_id, message='А вот и твое облако тегов! 🌍',
                               attachment='photo{}_{}'.format(photo['owner_id'], photo['id']))
        vk_group.messages.send(user_id=user_id, message='Не забудь рассказать друзьям 😉')
        post_id = None
        if not collection.find_one({'user_id': user_id, 'timestamp': {'$gt': time.time() - 86400}}):
            try:
                post_id = vk.wall.post(owner_id=-config.group_id, from_group=1,
                                       message='Облако тегов для *id{}({})'.format(user_id, name),
                                       attachments='photo{}_{}'.format(photo['owner_id'], photo['id']))['post_id']
            except Exception:
                vk_group.messages.send(user_id=user_id,
                                       message='Похоже, я превысил лимит количества постов на сегодня 😭')
                vk_group.messages.send(user_id=user_id,
                                       message='Создай новое облако завтра, и я выложу его на стену группы 😎')
        if post_id:
            collection.insert(
                {'user_id': user_id, 'owner_id': photo['owner_id'], 'id': photo['id'], 'wall': wall, 'post': post_id,
                 'timestamp': time.time()})
            vk_group.messages.send(user_id=user_id, attachment='wall{}_{}'.format(photo['owner_id'], post_id))
        else:
            collection.insert({'user_id': user_id, 'owner_id': photo['owner_id'], 'id': photo['id'], 'wall': wall})
        processing.remove(user_id)
        print('Finished cloud for', user_id)
    except Exception as e:
        processing.remove(user_id)
        print('Finished cloud for', user_id, 'with error')
        raise e

def process_updates(updates):
    for update in updates:
        if update[0] == 4 and update[3] not in processing:
            Thread(target=send_cloud, args=(update[3], update[6])).start()

if __name__ == '__main__':
    print('Initializing longpoll connection...', end=' ')
    longpoll = vk_group.messages.getLongPollServer()
    print('Done')
    while True:
        try:
            response = requests.get('https://{}?act=a_check&key={}&ts={}&wait=25%mode=128'.format(
                longpoll['server'],
                longpoll['key'],
                longpoll['ts']
            ), timeout=25).json()
            longpoll['ts'] = response['ts'] if 'ts' in response else longpoll['ts']
            Thread(target=process_updates, args=(response['updates'],)).start()
        except Exception as e:
            while True:
                try:
                    longpoll = vk_group.messages.getLongPollServer()
                    break
                except Exception:
                    continue
            print(e)
            continue
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Default libs
import json
import logging

# Library modules
from process import check_output

# Project modules
from .settings import SKETCHTOOL
from .utils import unicode_or_none

logger = logging.getLogger(__name__)

class SketchObject(object):
  def __unicode__(self):
    return u'<SketchObject>'

  def __str__(self):
    return unicode(self).encode('ascii', 'replace')

  def __repr__(self):
    return unicode(self)

class Bounds(SketchObject):
  def __init__(self, bounds_str):
    bounds_list = [float(num) for num in bounds_str.split(',')]

    self.x, self.y = bounds_list[0], bounds_list[1]
    self.width, self.height = bounds_list[2], bounds_list[3]

  def __unicode__(self):
    return u'<Bounds (x=%s, y=%s, width=%s, height=%s)>' % (self.x, self.y, self.width, self.height)

class Rect(SketchObject):
  def __init__(self, rect_dict):
    print 'Rect_dict: %s' % rect_dict
    self.x, self.y = float(rect_dict['x']), float(rect_dict['y'])
    self.width, self.height = float(rect_dict['height']), float(rect_dict['width'])

  def __unicode__(self):
    return u'<Rect (x=%s, y=%s, width=%s, height=%s)>' % (self.x, self.y, self.width, self.height)

class Page(SketchObject):
  def __init__(self, page_dict):
    self.id = unicode_or_none(page_dict, 'id')
    self.name = unicode_or_none(page_dict, 'name')
    self.bounds = Bounds(unicode_or_none(page_dict, 'bounds'))
    self.slices = self.parse_slices(page_dict)

  def __unicode__(self):
    return u'<Page (id=\'%s\', name=\'%s\', bounds=%s, slices=%s)>' % \
           (self.id, self.name, self.bounds, self.slices)

  def parse_slices(self, page_dict):
    if 'slices' not in page_dict:
      return []

    slices = []
    for slice_dict in page_dict['slices']:
      slices.append(Slice(slice_dict))
    return slices

class Slice(SketchObject):
  def __init__(self, slice_dict):
    self.id = unicode_or_none(slice_dict, 'id')
    self.name = unicode_or_none(slice_dict, 'name')
    self.rect = Rect(slice_dict['rect'])

  def __unicode__(self):
    return u'<Slice (id=\'%s\', name=\'%s\', rect=%s)>' % (self.id, self.name, self.rect)

def execute(cmd):
  ''' Call cmd and return None if any exception occurs '''
  try:
    return check_output(cmd)
  except Exception as e:
    print u'Couldnt execute cmd: %s.\nReason: %s' % (cmd, e)
    return None

def exec_list_cmd(cmd):
  ''' Execute a `sketchtool list` command and parse the output '''
  result = execute(cmd)
  if not result:
    return None

  list_dict = json.loads(result)
  for page_dict in list_dict['pages']:
    page = Page(page_dict)
    print 'Page: %s' % page

def list_slices(src_path):
  cmd = [SKETCHTOOL, 'list', 'slices', src_path]
  return exec_list_cmd(cmd)

def list_artboards(src_path):
  cmd = [SKETCHTOOL, 'list', 'artboards', src_path]
  return exec_list_cmd(cmd)

def list_pages(src_path):
  cmd = [SKETCHTOOL, 'list', 'pages', src_path]
  return exec_list_cmd(cmd)

# def pages_preview(src_path):
#   try:
#     check_call()
#   except Exception as e:
#     print u'Unable to extract pages: %s' % e
#     return None
<commit_msg>Parse Artboards, define SketchExportable class<commit_after># -*- coding: utf-8 -*-
# Default libs
import json
import logging

# Library modules
from process import check_output

# Project modules
from .settings import SKETCHTOOL
from .utils import unicode_or_none

logger = logging.getLogger(__name__)

class SketchObject(object):
  ''' Base class for any generic Sketch object '''
  def __unicode__(self):
    return u'<SketchObject>'

  def __str__(self):
    return unicode(self).encode('ascii', 'replace')

  def __repr__(self):
    return unicode(self)

class SketchExportable(SketchObject):
  ''' Base class for any exportable Sketch item, i.e. Pages, Artboards, Slices '''
  def __init__(self, exportable_dict):
    self.id = unicode_or_none(exportable_dict, 'id')
    self.name = unicode_or_none(exportable_dict, 'name')

  def __unicode__(self):
    return u'<SketchExportable (id=\'%s\', name=\'%s\')>' % (self.id, self.name)

class Bounds(SketchObject):
  def __init__(self, bounds_str):
    bounds_list = [float(num) for num in bounds_str.split(',')]

    self.x, self.y = bounds_list[0], bounds_list[1]
    self.width, self.height = bounds_list[2], bounds_list[3]

  def __unicode__(self):
    return u'<Bounds (x=%s, y=%s, width=%s, height=%s)>' % (self.x, self.y, self.width, self.height)

class Rect(SketchObject):
  def __init__(self, rect_dict):
    print 'Rect_dict: %s' % rect_dict
    self.x, self.y = float(rect_dict['x']), float(rect_dict['y'])
    self.width, self.height = float(rect_dict['height']), float(rect_dict['width'])

  def __unicode__(self):
    return u'<Rect (x=%s, y=%s, width=%s, height=%s)>' % (self.x, self.y, self.width, self.height)

class Page(SketchExportable):
  def __init__(self, page_dict):
    self.bounds = Bounds(unicode_or_none(page_dict, 'bounds'))
    self.slices = self.parse_slices(page_dict)
    self.artboards = self.parse_artboards(page_dict)
    super(Page, self).__init__(page_dict)

  def __unicode__(self):
    return u'<Page (id=\'%s\', name=\'%s\', bounds=%s, slices=%s)>' % \
           (self.id, self.name, self.bounds, self.slices)

  def parse_slices(self, page_dict):
    slices = []
    if 'slices' in page_dict:
      for slice_dict in page_dict['slices']:
        slices.append(Slice(slice_dict))
    return slices

  def parse_artboards(self, page_dict):
    artboards = []
    if 'artboards' in page_dict:
      for artboard_dict in page_dict['artboards']:
        artboards.append(Artboard(artboard_dict))
    return artboards

class Slice(SketchExportable):
  def __init__(self, slice_dict):
    self.rect = Rect(slice_dict['rect'])
    super(Slice, self).__init__(slice_dict)

  def __unicode__(self):
    return u'<Slice (id=\'%s\', name=\'%s\', rect=%s)>' % (self.id, self.name, self.rect)

class Artboard(SketchExportable):
  def __init__(self, artboard_dict):
    self.rect = Rect(artboard_dict['rect'])
    super(Artboard, self).__init__(artboard_dict)

  def __unicode__(self):
    return u'<Artboard (id=\'%s\', name=\'%s\', rect=%s)>' % (self.id, self.name, self.rect)

def execute(cmd):
  ''' Call cmd and return None if any exception occurs '''
  try:
    return check_output(cmd)
  except Exception as e:
    print u'Couldnt execute cmd: %s.\nReason: %s' % (cmd, e)
    return None

def exec_list_cmd(cmd):
  ''' Execute a `sketchtool list` command and parse the output '''
  result = execute(cmd)
  if not result:
    return None

  print u'Raw result: %s' % result
  list_dict = json.loads(result)
  for page_dict in list_dict['pages']:
    page = Page(page_dict)
    print 'Page: %s' % page

def list_slices(src_path):
  cmd = [SKETCHTOOL, 'list', 'slices', src_path]
  return exec_list_cmd(cmd)

def list_artboards(src_path):
  cmd = [SKETCHTOOL, 'list', 'artboards', src_path]
  return exec_list_cmd(cmd)

def list_pages(src_path):
  cmd = [SKETCHTOOL, 'list', 'pages', src_path]
  return exec_list_cmd(cmd)

# def pages_preview(src_path):
#   try:
#     check_call()
#   except Exception as e:
#     print u'Unable to extract pages: %s' % e
#     return None
<|endoftext|>