<commit_before># coding=utf-8
"""Configurations file for User Map.

..note: By design, you can override these settings from your project's
    settings.py with prefix 'USER_MAP' on the variable e.g
    'USER_MAP_USER_ICONS'.
"""
from django.conf import settings

# USER_MODEL: The auth user model is set in project's settings
USER_MODEL = settings.AUTH_USER_MODEL

# USER MAP Settings
default_setting = {
    'project_name': 'Django User Map',
    'favicon_file': 'user_map/img/user-icon.png',
    'login_view': 'django.contrib.auth.views.login',
    'marker': {
        'icon': 'user_map/img/user-icon.png',
        'shadow': 'user_map/img/shadow-icon.png'  # or 'shadow': None
    },
    'leaflet_config': {
        'TILES': [(
            # The title
            'MapQuest',
            # Tile's URL
            'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png',
            # More valid leaflet option is passed here
            {
                'attribution':
                    '© OpenStreetMap'
                    ' and contributors, under an open license. Tiles Courtesy of '
                    'MapQuest <img '
                    'src="http://developer.mapquest.com/content/osm/mq_logo'
                    '.png"',
                'subdomains': '1234'

            }
        )]
    },
    'roles': [
        {
            'id': 1,
            'name': 'Django User',
            'badge': 'user_map/img/inasafe-badge-user.png'
        },
        {
            'id': 2,
            'name': 'Django Trainer',
            'badge': 'user_map/img/inasafe-badge-trainer.png'
        },
        {
            'id': 3,
            'name': 'Django Developer',
            'badge': 'user_map/img/inasafe-badge-developer.png'
        }
    ],
    'api_user_fields': [
        'username', 'first_name', 'last_name'
    ],
}

user_map_settings = getattr(settings, 'USER_MAP', default_setting)

# PROJECT_NAME: The project name for this apps e.g InaSAFE
PROJECT_NAME = user_map_settings.get(
    'project_name', default_setting['project_name'])

# FAVICON_FILE: Favicon for this apps
FAVICON_FILE = user_map_settings.get(
    'favicon_file', default_setting['favicon_file'])

# LOGIN_VIEW: The view to the login page
LOGIN_VIEW = user_map_settings.get(
    'login_view', default_setting['login_view'])

# MARKER
MARKER = user_map_settings.get(
    'marker', default_setting['marker'])

LEAFLET_CONFIG = user_map_settings.get(
    'leaflet_config', default_setting['leaflet_config'])
LEAFLET_TILES = LEAFLET_CONFIG['TILES']

#  ROLES: All user roles and their badges
ROLES = user_map_settings.get('roles', default_setting['roles'])

#  API_USER_FIELDS
API_USER_FIELDS = user_map_settings.get(
    'api_user_fields', default_setting['api_user_fields'])
<commit_msg>Just mention the leaflet reference for valid options.<commit_after># coding=utf-8
"""Configurations file for User Map.

..note: By design, you can override these settings from your project's
    settings.py with prefix 'USER_MAP' on the variable e.g
    'USER_MAP_USER_ICONS'.
"""
from django.conf import settings

# USER_MODEL: The auth user model is set in project's settings
USER_MODEL = settings.AUTH_USER_MODEL

# USER MAP Settings
default_setting = {
    'project_name': 'Django User Map',
    'favicon_file': 'user_map/img/user-icon.png',
    'login_view': 'django.contrib.auth.views.login',
    'marker': {
        'icon': 'user_map/img/user-icon.png',
        'shadow': 'user_map/img/shadow-icon.png'  # or 'shadow': None
    },
    'leaflet_config': {
        'TILES': [(
            # The title
            'MapQuest',
            # Tile's URL
            'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png',
            # More valid leaflet option are passed here
            # See here: http://leafletjs.com/reference.html#tilelayer
            {
                'attribution':
                    '© OpenStreetMap'
                    ' and contributors, under an open license. Tiles Courtesy of '
                    'MapQuest <img '
                    'src="http://developer.mapquest.com/content/osm/mq_logo'
                    '.png"',
                'subdomains': '1234'

            }
        )]
    },
    'roles': [
        {
            'id': 1,
            'name': 'Django User',
            'badge': 'user_map/img/inasafe-badge-user.png'
        },
        {
            'id': 2,
            'name': 'Django Trainer',
            'badge': 'user_map/img/inasafe-badge-trainer.png'
        },
        {
            'id': 3,
            'name': 'Django Developer',
            'badge': 'user_map/img/inasafe-badge-developer.png'
        }
    ],
    'api_user_fields': [
        'username', 'first_name', 'last_name'
    ],
}

user_map_settings = getattr(settings, 'USER_MAP', default_setting)

# PROJECT_NAME: The project name for this apps e.g InaSAFE
PROJECT_NAME = user_map_settings.get(
    'project_name', default_setting['project_name'])

# FAVICON_FILE: Favicon for this apps
FAVICON_FILE = user_map_settings.get(
    'favicon_file', default_setting['favicon_file'])

# LOGIN_VIEW: The view to the login page
LOGIN_VIEW = user_map_settings.get(
    'login_view', default_setting['login_view'])

# MARKER
MARKER = user_map_settings.get(
    'marker', default_setting['marker'])

LEAFLET_CONFIG = user_map_settings.get(
    'leaflet_config', default_setting['leaflet_config'])
LEAFLET_TILES = LEAFLET_CONFIG['TILES']

#  ROLES: All user roles and their badges
ROLES = user_map_settings.get('roles', default_setting['roles'])

#  API_USER_FIELDS
API_USER_FIELDS = user_map_settings.get(
    'api_user_fields', default_setting['api_user_fields'])
<|endoftext|>


<commit_before>from .parse_defines import parse_defines
from .parse_selectors import parse_selectors
from .parse_properties import parse_properties
from .strip_comments import strip_comments
from .ParseFile import *
import pgmapcss.mapnik
import copy

def parse_file(stat, filename=None, base_style=None, content=None):
    if not 'max_prop_id' in stat:
        stat['max_prop_id'] = 0

    if base_style:
        parse_file(stat, content=pgmapcss.mapnik.get_base_style(base_style))

    if not 'statements' in stat:
        stat['statements'] = []
        stat['defines'] = {}

    f = ParseFile(filename=filename, content=content)

    f.set_content(strip_comments(f))

# read statements until there's only whitespace left
    while True:
        while True:
            r = parse_defines(stat, f)
            if not r:
                break;
            elif r and r[0] == 'import':
                parse_file(stat, r[1])

        if f.match('\s*$'):
            return True

        selectors = []
        parse_selectors(selectors, f)

        properties = []
        parse_properties(properties, f)

        for i in selectors:
            statement = i.copy()
            statement['properties'] = copy.deepcopy(properties)
            stat['statements'].append(statement)

            for prop in statement['properties']:
                prop['statement'] = statement
                prop['id'] = stat['max_prop_id']
                stat['max_prop_id'] = stat['max_prop_id'] + 1
<commit_msg>Parse File: assign each statement an id<commit_after>from .parse_defines import parse_defines
from .parse_selectors import parse_selectors
from .parse_properties import parse_properties
from .strip_comments import strip_comments
from .ParseFile import *
import pgmapcss.mapnik
import copy

def parse_file(stat, filename=None, base_style=None, content=None):
    if not 'max_prop_id' in stat:
        stat['max_prop_id'] = 0

    if base_style:
        parse_file(stat, content=pgmapcss.mapnik.get_base_style(base_style))

    if not 'statements' in stat:
        stat['statements'] = []
        stat['defines'] = {}

    f = ParseFile(filename=filename, content=content)

    f.set_content(strip_comments(f))

# read statements until there's only whitespace left
    while True:
        while True:
            r = parse_defines(stat, f)
            if not r:
                break;
            elif r and r[0] == 'import':
                parse_file(stat, r[1])

        if f.match('\s*$'):
            return True

        selectors = []
        parse_selectors(selectors, f)

        properties = []
        parse_properties(properties, f)

        for i in selectors:
            statement = i.copy()
            statement['properties'] = copy.deepcopy(properties)
            stat['statements'].append(statement)
            statement['id'] = stat['max_prop_id']
            stat['max_prop_id'] = stat['max_prop_id'] + 1

            for prop in statement['properties']:
                prop['statement'] = statement
                prop['id'] = stat['max_prop_id']
                stat['max_prop_id'] = stat['max_prop_id'] + 1
<|endoftext|>


<commit_before>import logging
from collections import defaultdict

import six

from user_sync import error, identity_type
from user_sync.config.common import DictConfig
from user_sync.connector.connector_sign import SignConnector
from user_sync.engine.umapi import AdobeGroup
from user_sync.error import AssertionException
from user_sync.helper import normalize_string

class SignSyncEngine:
    default_options = {
        'admin_roles': None,
        'create_users': False,
        'directory_group_filter': None,
        'entitlement_groups': [],
        'identity_types': [],
        'sign_only_limit': 200,
        'sign_orgs': [],
        'test_mode': False,
        'user_groups': []
    }
    name = 'sign_sync'
    DEFAULT_GROUP_NAME = 'default group'

    def __init__(self, caller_options):
        super().__init__()
        options = dict(self.default_options)
        options.update(caller_options)
        self.options = options
        self.logger = logging.getLogger(self.name)
        self.test_mode = options.get('test_mode')
        sync_config = DictConfig('<%s configuration>' % self.name, caller_options)
        self.user_groups = options['user_groups'] = sync_config.get_list('user_groups', True)
        if self.user_groups is None:
            self.user_groups = []
        self.user_groups = self._groupify(self.user_groups)
        self.entitlement_groups = self._groupify(sync_config.get_list('entitlement_groups'))
        self.identity_types = sync_config.get_list('identity_types', True)
        if self.identity_types is None:
            self.identity_types = ['adobeID', 'enterpriseID', 'federatedID']
        self.directory_user_by_user_key = {}
        # dict w/ structure - umapi_name -> adobe_group -> [set of roles]
        self.admin_roles = self._admin_role_mapping(sync_config)

        # builder = user_sync.config.common.OptionsBuilder(sync_config)
        # builder.set_string_value('logger_name', self.name)
        # builder.set_bool_value('test_mode', False)
        # options = builder.get_options()

        sign_orgs = sync_config.get_list('sign_orgs')
        self.connectors = {cfg.get('console_org'): SignConnector(cfg) for cfg in sign_orgs}
        self.create_new_users = sync_config.get_bool("create_new_users")
        self.deactivate_sign_only_users = sync_config.get_bool("deactivate_sign_only_users")

    def run(self, directory_groups, directory_connector):
        """
        Run the Sign sync
        :param directory_groups:
        :param directory_connector:
        :return:
        """
        if self.test_mode:
            self.logger.info("Sign Sync disabled in test mode")
            return
        # directory_users = self.read_desired_user_groups(directory_groups, directory_connector)
        self.read_desired_user_groups(directory_groups, directory_connector)
        # if directory_users is None:
        #     raise AssertionException("Error retrieving users from directory")
        for org_name, sign_connector in self.connectors.items():
            # create any new Sign groups
            for new_group in set(self.user_groups[org_name]) - set(sign_connector.sign_groups()):
                self.logger.info("Creating new Sign group: {}".format(new_group))
                sign_connector.create_group(new_group)
            self.update_sign_users(self.directory_user_by_user_key, sign_connector, org_name)
            if self.deactivate_sign_only_users:
                self.deactivate_sign_users(self.directory_user_by_user_key, sign_connector)

    def update_sign_users(self, directory_users, sign_connector, org_name):
        sign_users = sign_connector.get_users()
        for _, directory_user in directory_users.items():
            sign_user = sign_users.get(directory_user['email'])
            if not self.should_sync(directory_user, org_name):
                continue

            assignment_group = None

            for group in self.user_groups[org_name]:
                if group in directory_user['groups']:
                    assignment_group = group
                    break

            if assignment_group is None:
                assignment_group = self.DEFAULT_GROUP_NAME

            group_id = sign_connector.get_group(assignment_group)
            admin_roles = self.admin_roles.get(org_name, {})
            user_roles = self.resolve_new_roles(directory_user, admin_roles)
            if self.create_new_users is True and sign_user is None:
                self.insert_new_users(sign_connector, directory_user, user_roles, group_id, assignment_group)
            if sign_user is None: # sign_user may still be None here is flag 'create_new_users' is False and user does not exist
                continue
            else:
                self.update_existing_users(sign_connector, sign_user, directory_user, group_id, user_roles, assignment_group)

    @staticmethod
    def roles_match(resolved_roles, sign_roles):
        if isinstance(sign_roles, str):
            sign_roles = [sign_roles]
        return sorted(resolved_roles) == sorted(sign_roles)

    @staticmethod
    def resolve_new_roles(umapi_user, role_mapping):
        roles = set()
        for group in umapi_user['groups']:
            sign_roles = role_mapping.get(group.lower())
            if sign_roles is None:
                continue
            roles.update(sign_roles)
        return list(roles) if roles else ['NORMAL_USER']

    def should_sync(self, umapi_user, org_name):
        """
        Initial gatekeeping to determine if user is candidate for Sign sync
        Any checks that don't depend on the Sign record go here
        Sign record must be defined for user, and user must belong to at least one entitlement group
        and user must be accepted identity type
        :param umapi_user:
        :param org_name:
        :return:
        """
        return set(umapi_user['groups']) & set(self.entitlement_groups[org_name]) and \
               umapi_user['type'] in self.identity_types

    @staticmethod
    def _groupify(groups):
        processed_groups = defaultdict(list)
        for g in groups:
            processed_group = AdobeGroup.create(g)
            processed_groups[processed_group.umapi_name].append(processed_group.group_name.lower())
        return processed_groups

    @staticmethod
    def _admin_role_mapping(sync_config):
        admin_roles = sync_config.get_list('admin_roles', True)
        if admin_roles is None:
            return {}

        mapped_admin_roles = {}
        for mapping in admin_roles:
            sign_role = mapping.get('sign_role')
            if sign_role is None:
                raise AssertionException("must define a Sign role in admin role mapping")
            adobe_groups = mapping.get('adobe_groups')
            if adobe_groups is None or not len(adobe_groups):
                continue
            for g in adobe_groups:
                group = AdobeGroup.create(g)
                group_name = group.group_name.lower()
                if group.umapi_name not in mapped_admin_roles:
                    mapped_admin_roles[group.umapi_name] = {}
                if group_name not in mapped_admin_roles[group.umapi_name]:
                    mapped_admin_roles[group.umapi_name][group_name] = set()
                mapped_admin_roles[group.umapi_name][group_name].add(sign_role)
        return mapped_admin_roles

    def read_desired_user_groups(self, mappings, directory_connector):
        self.logger.debug('Building work list...')

        options = self.options
        directory_group_filter = options['directory_group_filter']
        if directory_group_filter is not None:
            directory_group_filter = set(directory_group_filter)
        extended_attributes = options.get('extended_attributes')

        directory_user_by_user_key = self.directory_user_by_user_key

        directory_groups = set(six.iterkeys(mappings))
        if directory_group_filter is not None:
            directory_groups.update(directory_group_filter)
        directory_users = directory_connector.load_users_and_groups(groups=directory_groups,
                                                                    extended_attributes=extended_attributes,
                                                                    all_users=directory_group_filter is None)

        for directory_user in directory_users:
            user_key = self.get_directory_user_key(directory_user)
            if not user_key:
                self.logger.warning("Ignoring directory user with empty user key: %s", directory_user)
                continue
            directory_user_by_user_key[user_key] = directory_user

    def get_directory_user_key(self, directory_user):
        """
        :type directory_user: dict
        """
        email = directory_user.get('email')
        if email:
            return six.text_type(email)
        return None

    def get_user_key(self, id_type, username, domain, email=None):
        """
        Construct the user key for a directory or adobe user.
        The user key is the stringification of the tuple (id_type, username, domain)
        but the domain part is left empty if the username is an email address.
        If the parameters are invalid, None is returned.
        :param username: (required) username of the user, can be his email
        :param domain: (optional) domain of the user
        :param email: (optional) email of the user
        :param id_type: (required) id_type of the user
        :return: string "id_type,username,domain" (or None)
        :rtype: str
        """
        id_type = identity_type.parse_identity_type(id_type)
        email = normalize_string(email) if email else None
        username = normalize_string(username) or email
        domain = normalize_string(domain)

        if not id_type:
            return None
        if not username:
            return None
        if username.find('@') >= 0:
            domain = ""
        elif not domain:
            return None
        return six.text_type(id_type) + u',' + six.text_type(username) + u',' + six.text_type(domain)

    def get_identity_type_from_directory_user(self, directory_user):
        identity_type = directory_user.get('identity_type')
        if identity_type is None:
            identity_type = self.options['new_account_type']
            self.logger.warning('Found user with no identity type, using %s: %s', identity_type, directory_user)
        return identity_type

    def update_existing_users(self, sign_connector, sign_user, directory_user, group_id, user_roles, assignment_group):
            update_data = {
                "email": sign_user['email'],
                "firstName": sign_user['firstName'],
                "groupId": group_id,
                "lastName": sign_user['lastName'],
                "roles": user_roles,
            }
            if sign_user['group'].lower() == assignment_group and self.roles_match(user_roles, sign_user['roles']):
                self.logger.debug("skipping Sign update for '{}' -- no updates needed".format(directory_user['email']))
                return
            try:
                sign_connector.update_user(sign_user['userId'], update_data)
                self.logger.info("Updated Sign user '{}', Group: '{}', Roles: {}".format(
                    directory_user['email'], assignment_group, update_data['roles']))
            except AssertionError as e:
                self.logger.error("Error updating user {}".format(e))

    def insert_new_users(self, sign_connector, directory_user, user_roles, group_id, assignment_group):
        """
        Inserts new user in the Sign Console
        :param sign_connector:
        :param directory_user:
        :param user_roles:
        :param group_id:
        :param assignment_group:
        :return:
        """
        insert_data = {
            "email": directory_user['email'],
            "firstName": directory_user['firstname'],
            "groupId": group_id,
            "lastName": directory_user['lastname'],
            "roles": user_roles,
        }
        try:
            sign_connector.insert_user(insert_data)
            self.logger.info("Inserted Sign user '{}', Group: '{}', Roles: {}".format(
            directory_user['email'], assignment_group, insert_data['roles']))
        except AssertionException as e:
            self.logger.error(format(e))
        return

    def deactivate_sign_users(self, directory_users, sign_connector):
        """
        Searches users to deactivate in the Sign Netpune console
        :param sign_connector:
        :param sign_user:
        :return:
        """
        sign_users = sign_connector.get_users()
        director_users_emails = []
        director_users_emails = list(map(lambda directory_user:directory_user['email'].lower(), directory_users.values()))
        for _, sign_user in sign_users.items():
            if sign_user['email'].lower() not in director_users_emails:
                sign_connector.deactivate_user(sign_user['userId'])

<commit_msg>Added keys to default options<commit_after>import logging
from collections import defaultdict

import six

from user_sync import error, identity_type
from user_sync.config.common import DictConfig
from user_sync.connector.connector_sign import SignConnector
from user_sync.engine.umapi import AdobeGroup
from user_sync.error import AssertionException
from user_sync.helper import normalize_string

class SignSyncEngine:
    default_options = {
        'admin_roles': None,
        'create_users': False,
        'directory_group_filter': None,
        'entitlement_groups': [],
        'identity_types': [],
        'sign_only_limit': 200,
        'sign_orgs': [],
        'test_mode': False,
        'user_groups': [],
        'create_new_users': False,
        'deactivate_sign_only_users': False
    }
    name = 'sign_sync'
    DEFAULT_GROUP_NAME = 'default group'

    def __init__(self, caller_options):
        super().__init__()
        options = dict(self.default_options)
        options.update(caller_options)
        self.options = options
        self.logger = logging.getLogger(self.name)
        self.test_mode = options.get('test_mode')
        sync_config = DictConfig('<%s configuration>' % self.name, caller_options)
        self.user_groups = options['user_groups'] = sync_config.get_list('user_groups', True)
        if self.user_groups is None:
            self.user_groups = []
        self.user_groups = self._groupify(self.user_groups)
        self.entitlement_groups = self._groupify(sync_config.get_list('entitlement_groups'))
        self.identity_types = sync_config.get_list('identity_types', True)
        if self.identity_types is None:
            self.identity_types = ['adobeID', 'enterpriseID', 'federatedID']
        self.directory_user_by_user_key = {}
        # dict w/ structure - umapi_name -> adobe_group -> [set of roles]
        self.admin_roles = self._admin_role_mapping(sync_config)

        # builder = user_sync.config.common.OptionsBuilder(sync_config)
        # builder.set_string_value('logger_name', self.name)
        # builder.set_bool_value('test_mode', False)
        # options = builder.get_options()

        sign_orgs = sync_config.get_list('sign_orgs')
        self.connectors = {cfg.get('console_org'): SignConnector(cfg) for cfg in sign_orgs}
        self.create_new_users = sync_config.get_bool("create_new_users")
        self.deactivate_sign_only_users = sync_config.get_bool("deactivate_sign_only_users")

    def run(self, directory_groups, directory_connector):
        """
        Run the Sign sync
        :param directory_groups:
        :param directory_connector:
        :return:
        """
        if self.test_mode:
            self.logger.info("Sign Sync disabled in test mode")
            return
        # directory_users = self.read_desired_user_groups(directory_groups, directory_connector)
        self.read_desired_user_groups(directory_groups, directory_connector)
        # if directory_users is None:
        #     raise AssertionException("Error retrieving users from directory")
        for org_name, sign_connector in self.connectors.items():
            # create any new Sign groups
            for new_group in set(self.user_groups[org_name]) - set(sign_connector.sign_groups()):
                self.logger.info("Creating new Sign group: {}".format(new_group))
                sign_connector.create_group(new_group)
            self.update_sign_users(self.directory_user_by_user_key, sign_connector, org_name)
            if self.deactivate_sign_only_users:
                self.deactivate_sign_users(self.directory_user_by_user_key, sign_connector)

    def update_sign_users(self, directory_users, sign_connector, org_name):
        sign_users = sign_connector.get_users()
        for _, directory_user in directory_users.items():
            sign_user = sign_users.get(directory_user['email'])
            if not self.should_sync(directory_user, org_name):
                continue

            assignment_group = None

            for group in self.user_groups[org_name]:
                if group in directory_user['groups']:
                    assignment_group = group
                    break

            if assignment_group is None:
                assignment_group = self.DEFAULT_GROUP_NAME

            group_id = sign_connector.get_group(assignment_group)
            admin_roles = self.admin_roles.get(org_name, {})
            user_roles = self.resolve_new_roles(directory_user, admin_roles)
            if self.create_new_users is True and sign_user is None:
                self.insert_new_users(sign_connector, directory_user, user_roles, group_id, assignment_group)
            if sign_user is None: # sign_user may still be None here is flag 'create_new_users' is False and user does not exist
                continue
            else:
                self.update_existing_users(sign_connector, sign_user, directory_user, group_id, user_roles, assignment_group)

    @staticmethod
    def roles_match(resolved_roles, sign_roles):
        if isinstance(sign_roles, str):
            sign_roles = [sign_roles]
        return sorted(resolved_roles) == sorted(sign_roles)

    @staticmethod
    def resolve_new_roles(umapi_user, role_mapping):
        roles = set()
        for group in umapi_user['groups']:
            sign_roles = role_mapping.get(group.lower())
            if sign_roles is None:
                continue
            roles.update(sign_roles)
        return list(roles) if roles else ['NORMAL_USER']

    def should_sync(self, umapi_user, org_name):
        """
        Initial gatekeeping to determine if user is candidate for Sign sync
        Any checks that don't depend on the Sign record go here
        Sign record must be defined for user, and user must belong to at least one entitlement group
        and user must be accepted identity type
        :param umapi_user:
        :param org_name:
        :return:
        """
        return set(umapi_user['groups']) & set(self.entitlement_groups[org_name]) and \
               umapi_user['type'] in self.identity_types

    @staticmethod
    def _groupify(groups):
        processed_groups = defaultdict(list)
        for g in groups:
            processed_group = AdobeGroup.create(g)
            processed_groups[processed_group.umapi_name].append(processed_group.group_name.lower())
        return processed_groups

    @staticmethod
    def _admin_role_mapping(sync_config):
        admin_roles = sync_config.get_list('admin_roles', True)
        if admin_roles is None:
            return {}

        mapped_admin_roles = {}
        for mapping in admin_roles:
            sign_role = mapping.get('sign_role')
            if sign_role is None:
                raise AssertionException("must define a Sign role in admin role mapping")
            adobe_groups = mapping.get('adobe_groups')
            if adobe_groups is None or not len(adobe_groups):
                continue
            for g in adobe_groups:
                group = AdobeGroup.create(g)
                group_name = group.group_name.lower()
                if group.umapi_name not in mapped_admin_roles:
                    mapped_admin_roles[group.umapi_name] = {}
                if group_name not in mapped_admin_roles[group.umapi_name]:
                    mapped_admin_roles[group.umapi_name][group_name] = set()
                mapped_admin_roles[group.umapi_name][group_name].add(sign_role)
        return mapped_admin_roles

    def read_desired_user_groups(self, mappings, directory_connector):
        self.logger.debug('Building work list...')

        options = self.options
        directory_group_filter = options['directory_group_filter']
        if directory_group_filter is not None:
            directory_group_filter = set(directory_group_filter)
        extended_attributes = options.get('extended_attributes')

        directory_user_by_user_key = self.directory_user_by_user_key

        directory_groups = set(six.iterkeys(mappings))
        if directory_group_filter is not None:
            directory_groups.update(directory_group_filter)
        directory_users = directory_connector.load_users_and_groups(groups=directory_groups,
                                                                    extended_attributes=extended_attributes,
                                                                    all_users=directory_group_filter is None)

        for directory_user in directory_users:
            user_key = self.get_directory_user_key(directory_user)
            if not user_key:
                self.logger.warning("Ignoring directory user with empty user key: %s", directory_user)
                continue
            directory_user_by_user_key[user_key] = directory_user

    def get_directory_user_key(self, directory_user):
        """
        :type directory_user: dict
        """
        email = directory_user.get('email')
        if email:
            return six.text_type(email)
        return None

    def get_user_key(self, id_type, username, domain, email=None):
        """
        Construct the user key for a directory or adobe user.
        The user key is the stringification of the tuple (id_type, username, domain)
        but the domain part is left empty if the username is an email address.
        If the parameters are invalid, None is returned.
        :param username: (required) username of the user, can be his email
        :param domain: (optional) domain of the user
        :param email: (optional) email of the user
        :param id_type: (required) id_type of the user
        :return: string "id_type,username,domain" (or None)
        :rtype: str
        """
        id_type = identity_type.parse_identity_type(id_type)
        email = normalize_string(email) if email else None
        username = normalize_string(username) or email
        domain = normalize_string(domain)

        if not id_type:
            return None
        if not username:
            return None
        if username.find('@') >= 0:
            domain = ""
        elif not domain:
            return None
        return six.text_type(id_type) + u',' + six.text_type(username) + u',' + six.text_type(domain)

    def get_identity_type_from_directory_user(self, directory_user):
        identity_type = directory_user.get('identity_type')
        if identity_type is None:
            identity_type = self.options['new_account_type']
            self.logger.warning('Found user with no identity type, using %s: %s', identity_type, directory_user)
        return identity_type

    def update_existing_users(self, sign_connector, sign_user, directory_user, group_id, user_roles, assignment_group):
            update_data = {
                "email": sign_user['email'],
                "firstName": sign_user['firstName'],
                "groupId": group_id,
                "lastName": sign_user['lastName'],
                "roles": user_roles,
            }
            if sign_user['group'].lower() == assignment_group and self.roles_match(user_roles, sign_user['roles']):
                self.logger.debug("skipping Sign update for '{}' -- no updates needed".format(directory_user['email']))
                return
            try:
                sign_connector.update_user(sign_user['userId'], update_data)
                self.logger.info("Updated Sign user '{}', Group: '{}', Roles: {}".format(
                    directory_user['email'], assignment_group, update_data['roles']))
            except AssertionError as e:
                self.logger.error("Error updating user {}".format(e))

    def insert_new_users(self, sign_connector, directory_user, user_roles, group_id, assignment_group):
        """
        Inserts new user in the Sign Console
        :param sign_connector:
        :param directory_user:
        :param user_roles:
        :param group_id:
        :param assignment_group:
        :return:
        """
        insert_data = {
            "email": directory_user['email'],
            "firstName": directory_user['firstname'],
            "groupId": group_id,
            "lastName": directory_user['lastname'],
            "roles": user_roles,
        }
        try:
            sign_connector.insert_user(insert_data)
            self.logger.info("Inserted Sign user '{}', Group: '{}', Roles: {}".format(
            directory_user['email'], assignment_group, insert_data['roles']))
        except AssertionException as e:
            self.logger.error(format(e))
        return

    def deactivate_sign_users(self, directory_users, sign_connector):
        """
        Searches users to deactivate in the Sign Netpune console
        :param sign_connector:
        :param sign_user:
        :return:
        """
        sign_users = sign_connector.get_users()
        director_users_emails = []
        director_users_emails = list(map(lambda directory_user:directory_user['email'].lower(), directory_users.values()))
        for _, sign_user in sign_users.items():
            if sign_user['email'].lower() not in director_users_emails:
                sign_connector.deactivate_user(sign_user['userId'])

<|endoftext|>


<commit_before>import matplotlib.pyplot as plt
import numpy as np

def horizontal_bar(sorted_streaks, sort):
    """
    Render a horizontal bar chart of streaks.

    Values have already been sorted by sort.
    """
    # Only extract those users & streaks for streaks that are non-zero:
    users, streaks = zip(*[(user, streak.get(sort)) for user, streak
                           in sorted_streaks if streak.get(sort) > 0][::-1])

    title = 'Top Contributors by {} Streak'.format(sort.title())

    figure = plt.figure(num=None, figsize=(6, 15))
    y_pos = np.arange(len(users))  # y-location of bars
    print('y_pos', y_pos)
    plt.barh(y_pos, streaks, facecolor='#5555EE', edgecolor='grey', align='center')
    plt.yticks(y_pos, users)
    plt.xlim([0, max(streaks) + 10])  # x-limits a bit wider at right
    plt.ylim([-1, len(users)])  # tighten y-limits
    plt.subplots_adjust(left=0.25)  # Wider left margin for long usernames
    plt.title(title)
    ax = plt.gca()
    ax.yaxis.set_ticks_position('none')
    ax.xaxis.set_ticks_position('bottom')

    for format in ('png', 'svg'):
        figure.savefig('temp/top_{}.{}'.format(sort, format), format=format)

<commit_msg>Edit edge colour<commit_after>import matplotlib.pyplot as plt
import numpy as np

def horizontal_bar(sorted_streaks, sort):
    """
    Render a horizontal bar chart of streaks.

    Values have already been sorted by sort.
    """
    # Only extract those users & streaks for streaks that are non-zero:
    users, streaks = zip(*[(user, streak.get(sort)) for user, streak
                           in sorted_streaks if streak.get(sort) > 0][::-1])

    title = 'Top Contributors by {} Streak'.format(sort.title())

    figure = plt.figure(num=None, figsize=(6, 15))
    y_pos = np.arange(len(users))  # y-location of bars
    print('y_pos', y_pos)
    plt.barh(y_pos, streaks, facecolor='#7AE2FF', edgecolor='#6699FF',
             align='center')
    plt.yticks(y_pos, users)
    plt.xlim([0, max(streaks) + 10])  # x-limits a bit wider at right
    plt.ylim([-1, len(users)])  # tighten y-limits
    plt.subplots_adjust(left=0.25)  # Wider left margin for long usernames
    plt.title(title)
    ax = plt.gca()
    ax.yaxis.set_ticks_position('none')
    ax.xaxis.set_ticks_position('bottom')

    for format in ('png', 'svg'):
        figure.savefig('temp/top_{}.{}'.format(sort, format), format=format)

<|endoftext|>


<commit_before># Copyright (C) 2011 Atsushi Togo
# All rights reserved.
#
# This file is part of phonopy.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in
#   the documentation and/or other materials provided with the
#   distribution.
#
# * Neither the name of the phonopy project nor the names of its
#   contributors may be used to endorse or promote products derived
#   from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import sys
import numpy as np
import phonopy.structure.spglib as spg
from phonopy.structure.atoms import Atoms

class Symmetry:
    def __init__(self, cell, symprec=1e-5, is_symmetry=True):
        self._cell = cell
        self._symprec = symprec

        self._symmetry_operations = None
        self._international_table = None
        self._dataset = None
        self._wyckoff_letters = None
        self._map_atoms = None
        if not is_symmetry:
            self._set_nosym()
        elif cell.get_magnetic_moments() is None:
            self._set_symmetry_dataset()
        else:
            self._set_symmetry_operations()

        self._pointgroup_operations = None
        self._pointgroup = None
        self._set_pointgroup_operations()

        self._independent_atoms = None
        self._map_operations = None
        self._set_map_operations()

    def get_symmetry_operations(self):
        return self._symmetry_operations

    def get_symmetry_operation(self, operation_number):
        operation = self._symmetry_operations
        return {'rotations': operation['rotations'][operation_number],
                'translations': operation['translations'][operation_number]}

    def get_pointgroup_operations(self):
        return self._pointgroup_operations

    def get_pointgroup(self):
        return self._pointgroup

    def get_international_table(self):
        return self._international_table

    def get_Wyckoff_letters(self):
        return self._wyckoff_letters

    def get_dataset(self):
        """Detail of dataset is found in spglib.get_symmetry_dataset.
        """
        return self._dataset

    def get_independent_atoms(self):
        return self._independent_atoms

    def get_map_atoms(self):
        return self._map_atoms

    def get_map_operations(self):
        return self._map_operations

    def get_site_symmetry(self, atom_number):
        pos = self._cell.get_scaled_positions()[atom_number]
        symprec = self._symprec
        rot = self._symmetry_operations['rotations']
        trans = self._symmetry_operations['translations']
        site_symmetries = []

        for r, t in zip(rot, trans):
            rot_pos = np.dot(pos, r.T) + t
            diff = pos - rot_pos
            if (abs(diff - np.rint(diff)) < symprec).all():
                site_symmetries.append(r)

        return np.array(site_symmetries, dtype='intc')

    def get_symmetry_tolerance(self):
        return self._symprec

    def get_reciprocal_operations(self):
        """
        Definition of operation:
        q' = Rq

        This is transpose of that shown in ITA (q' = qR).
        """
        return self._reciprocal_operations

    def _set_map_atoms(self):
        rotations = self._symmetry_operations['rotations']
        translations = self._symmetry_operations['translations']
        positions = self._cell.get_scaled_positions()
        lattice = self._cell.get_cell()
        map_atoms = range(self._cell.get_number_of_atoms())
        for i, p in enumerate(positions):
            is_found = False
            for j in range(i):
                for r, t in zip(rotations, translations):
                    diff = np.dot(p, r.T) + t - positions[j]
                    diff -= np.rint(diff)
                    dist = np.linalg.norm(np.dot(diff, lattice))
                    if dist < self._symprec:
                        map_atoms[i] = j
                        is_found = True
                        break
                if is_found:
                    break
        self._map_atoms = np.array(map_atoms, dtype=int)

    def _set_symmetry_dataset(self):
        self._dataset = spg.get_symmetry_dataset(self._cell, self._symprec)
        self._symmetry_operations = {
            'rotations': self._dataset['rotations'],
            'translations': self._dataset['translations']}
        self._international_table = "%s (%d)" % (self._dataset['international'],
                                                 self._dataset['number'])
        self._wyckoff_letters = self._dataset['wyckoffs']
        self._map_atoms = self._dataset['equivalent_atoms']

    def _set_symmetry_operations(self):
        self._symmetry_operations = spg.get_symmetry(self._cell, self._symprec)
        self._set_map_atoms()

    def _set_pointgroup_operations(self):
        rotations = []
        for rot in self._symmetry_operations['rotations']:
            is_same = False
            for tmp_rot in rotations:
                if (tmp_rot==rot).all():
                    is_same = True
                    break
            if not is_same:
                rotations.append(rot)

        reciprocal_rotations = [rot.T for rot in rotations]
        exist_r_inv = False
        for rot in rotations:
            if (rot + np.eye(3, dtype='intc') == 0).all():
                exist_r_inv = True
                break
        if not exist_r_inv:
            reciprocal_rotations += [-rot.T for rot in rotations]

        self._pointgroup_operations = np.array(rotations, dtype='intc')
        self._pointgroup = get_pointgroup(self._pointgroup_operations)[0]
        self._reciprocal_operations = np.array(reciprocal_rotations,
                                               dtype='intc')

    def _set_map_operations(self):
        ops = self._symmetry_operations
        pos = self._cell.get_scaled_positions()
        map_operations = np.zeros(len(pos), dtype=int)
        independent_atoms = []

        for i, eq_atom in enumerate(self._map_atoms):
            if i == eq_atom:
                independent_atoms.append(i)
            for j, (r, t) in enumerate(
                zip(ops['rotations'], ops['translations'])):

                diff = np.dot(pos[i], r.T) + t - pos[eq_atom]
                if (abs(diff - np.rint(diff)) < self._symprec).all():
                    map_operations[i] = j
                    break

        self._independent_atoms = np.array(independent_atoms)
        self._map_operations = map_operations

    def _set_nosym(self):
        translations = []
        rotations = []

        if 'get_supercell_to_unitcell_map' in dir(self._cell):
            s2u_map = self._cell.get_supercell_to_unitcell_map()
            positions = self._cell.get_scaled_positions()

            for i, j in enumerate(s2u_map):
                if j==0:
                    ipos0 = i
                    break

            for i, p in zip(s2u_map, positions):
                if i==0:
                    trans = p - positions[ipos0]
                    trans -= np.floor(trans)
                    translations.append(trans)
                    rotations.append(np.eye(3, dtype='intc'))

            self._map_atoms = s2u_map
        else:
            rotations.append(np.eye(3, dtype=int))
            translations.append(np.zeros(3, dtype='double'))
            self._map_atoms = range(self._cell.get_number_of_atoms())

        self._symmetry_operations = {
            'rotations': np.array(rotations, dtype='intc'),
            'translations': np.array(translations, dtype='double')}
        self._international_table = 'P1 (1)'
        self._wyckoff_letters = ['a'] * self._cell.get_number_of_atoms()

def find_primitive(cell, symprec=1e-5):
    """
    A primitive cell is searched in the input cell. When a primitive
    cell is found, an object of Atoms class of the primitive cell is
    returned. When not, None is returned.
    """
    lattice, positions, numbers = spg.find_primitive(cell, symprec)
    if lattice == None:
        return None
    else:
        return Atoms(numbers=numbers,
                     scaled_positions=positions,
                     cell=lattice,
                     pbc=True)

def get_pointgroup(rotations):
    ptg = spg.get_pointgroup(rotations)
    return ptg[0].strip(), ptg[2]

def get_lattice_vector_equivalence(point_symmetry):
    """Return (b==c, c==a, a==b)"""
    # primitive_vectors: column vectors

    equivalence = [False, False, False]
    for r in point_symmetry:
        if (np.abs(r[:, 0]) == [0, 1, 0]).all():
            equivalence[2] = True
        if (np.abs(r[:, 0]) == [0, 0, 1]).all():
            equivalence[1] = True
        if (np.abs(r[:, 1]) == [1, 0, 0]).all():
            equivalence[2] = True
        if (np.abs(r[:, 1]) == [0, 0, 1]).all():
            equivalence[0] = True
        if (np.abs(r[:, 2]) == [1, 0, 0]).all():
            equivalence[1] = True
        if (np.abs(r[:, 2]) == [0, 1, 0]).all():
            equivalence[0] = True

    return equivalence

if __name__ == '__main__':
    from phonopy.structure.symmetry import Symmetry
    from phonopy.interface.vasp import read_vasp

    def get_magmom(text):
        magmom = []
        for numxmag in text.split():
            if '*' in numxmag:
                num, mag = numxmag.split('*')
                magmom += [float(mag)] * int(num)
            else:
                magmom.append(float(numxmag))
        return magmom

    def parse_incar(filename):
        for line in open(filename):
            for conf in line.split(';'):
                if 'MAGMOM' in conf:
                    return get_magmom(conf.split('=')[1])

    cell = read_vasp("POSCAR")
    symmetry = Symmetry(cell, symprec=1e-3)
    map_nonspin = symmetry.get_map_atoms()
    print "Number of operations w/o spin", len(symmetry.get_symmetry_operations()['rotations'])
    magmoms = parse_incar("INCAR")
    cell.set_magnetic_moments(magmoms)
    symmetry = Symmetry(cell, symprec=1e-3)
    print "Number of operations w spin", len(symmetry.get_symmetry_operations()['rotations'])
    map_withspin = symmetry.get_map_atoms()
    if ((map_nonspin - map_withspin) == 0).all():
        print True
    else:
        print False
        print map_nonspin
        print map_withspin
<commit_msg>Follow spglib change on treating magmom<commit_after># Copyright (C) 2011 Atsushi Togo
# All rights reserved.
#
# This file is part of phonopy.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in
#   the documentation and/or other materials provided with the
#   distribution.
#
# * Neither the name of the phonopy project nor the names of its
#   contributors may be used to endorse or promote products derived
#   from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import sys
import numpy as np
import phonopy.structure.spglib as spg
from phonopy.structure.atoms import Atoms

class Symmetry:
    def __init__(self, cell, symprec=1e-5, is_symmetry=True):
        self._cell = cell
        self._symprec = symprec

        self._symmetry_operations = None
        self._international_table = None
        self._dataset = None
        self._wyckoff_letters = None
        self._map_atoms = None
        if not is_symmetry:
            self._set_nosym()
        elif cell.get_magnetic_moments() is None:
            self._set_symmetry_dataset()
        else:
            self._set_symmetry_operations()

        self._pointgroup_operations = None
        self._pointgroup = None
        self._set_pointgroup_operations()

        self._independent_atoms = None
        self._map_operations = None
        self._set_map_operations()

    def get_symmetry_operations(self):
        return self._symmetry_operations

    def get_symmetry_operation(self, operation_number):
        operation = self._symmetry_operations
        return {'rotations': operation['rotations'][operation_number],
                'translations': operation['translations'][operation_number]}

    def get_pointgroup_operations(self):
        return self._pointgroup_operations

    def get_pointgroup(self):
        return self._pointgroup

    def get_international_table(self):
        return self._international_table

    def get_Wyckoff_letters(self):
        return self._wyckoff_letters

    def get_dataset(self):
        """Detail of dataset is found in spglib.get_symmetry_dataset.
        """
        return self._dataset

    def get_independent_atoms(self):
        return self._independent_atoms

    def get_map_atoms(self):
        return self._map_atoms

    def get_map_operations(self):
        return self._map_operations

    def get_site_symmetry(self, atom_number):
        pos = self._cell.get_scaled_positions()[atom_number]
        symprec = self._symprec
        rot = self._symmetry_operations['rotations']
        trans = self._symmetry_operations['translations']
        site_symmetries = []

        for r, t in zip(rot, trans):
            rot_pos = np.dot(pos, r.T) + t
            diff = pos - rot_pos
            if (abs(diff - np.rint(diff)) < symprec).all():
                site_symmetries.append(r)

        return np.array(site_symmetries, dtype='intc')

    def get_symmetry_tolerance(self):
        return self._symprec

    def get_reciprocal_operations(self):
        """
        Definition of operation:
        q' = Rq

        This is transpose of that shown in ITA (q' = qR).
        """
        return self._reciprocal_operations

    def _set_map_atoms(self):
        rotations = self._symmetry_operations['rotations']
        translations = self._symmetry_operations['translations']
        positions = self._cell.get_scaled_positions()
        lattice = self._cell.get_cell()
        map_atoms = range(self._cell.get_number_of_atoms())
        for i, p in enumerate(positions):
            is_found = False
            for j in range(i):
                for r, t in zip(rotations, translations):
                    diff = np.dot(p, r.T) + t - positions[j]
                    diff -= np.rint(diff)
                    dist = np.linalg.norm(np.dot(diff, lattice))
                    if dist < self._symprec:
                        map_atoms[i] = j
                        is_found = True
                        break
                if is_found:
                    break
        self._map_atoms = np.array(map_atoms, dtype=int)

    def _set_symmetry_dataset(self):
        self._dataset = spg.get_symmetry_dataset(self._cell, self._symprec)
        self._symmetry_operations = {
            'rotations': self._dataset['rotations'],
            'translations': self._dataset['translations']}
        self._international_table = "%s (%d)" % (self._dataset['international'],
                                                 self._dataset['number'])
        self._wyckoff_letters = self._dataset['wyckoffs']
        self._map_atoms = self._dataset['equivalent_atoms']

    def _set_symmetry_operations(self):
        self._symmetry_operations = spg.get_symmetry(self._cell,
                                                     self._symprec,
                                                     use_magmoms=True)
        self._set_map_atoms()

    def _set_pointgroup_operations(self):
        rotations = []
        for rot in self._symmetry_operations['rotations']:
            is_same = False
            for tmp_rot in rotations:
                if (tmp_rot==rot).all():
                    is_same = True
                    break
            if not is_same:
                rotations.append(rot)

        reciprocal_rotations = [rot.T for rot in rotations]
        exist_r_inv = False
        for rot in rotations:
            if (rot + np.eye(3, dtype='intc') == 0).all():
                exist_r_inv = True
                break
        if not exist_r_inv:
            reciprocal_rotations += [-rot.T for rot in rotations]

        self._pointgroup_operations = np.array(rotations, dtype='intc')
        self._pointgroup = get_pointgroup(self._pointgroup_operations)[0]
        self._reciprocal_operations = np.array(reciprocal_rotations,
                                               dtype='intc')

    def _set_map_operations(self):
        ops = self._symmetry_operations
        pos = self._cell.get_scaled_positions()
        map_operations = np.zeros(len(pos), dtype=int)
        independent_atoms = []

        for i, eq_atom in enumerate(self._map_atoms):
            if i == eq_atom:
                independent_atoms.append(i)
            for j, (r, t) in enumerate(
                zip(ops['rotations'], ops['translations'])):

                diff = np.dot(pos[i], r.T) + t - pos[eq_atom]
                if (abs(diff - np.rint(diff)) < self._symprec).all():
                    map_operations[i] = j
                    break

        self._independent_atoms = np.array(independent_atoms)
        self._map_operations = map_operations

    def _set_nosym(self):
        translations = []
        rotations = []

        if 'get_supercell_to_unitcell_map' in dir(self._cell):
            s2u_map = self._cell.get_supercell_to_unitcell_map()
            positions = self._cell.get_scaled_positions()

            for i, j in enumerate(s2u_map):
                if j==0:
                    ipos0 = i
                    break

            for i, p in zip(s2u_map, positions):
                if i==0:
                    trans = p - positions[ipos0]
                    trans -= np.floor(trans)
                    translations.append(trans)
                    rotations.append(np.eye(3, dtype='intc'))

            self._map_atoms = s2u_map
        else:
            rotations.append(np.eye(3, dtype=int))
            translations.append(np.zeros(3, dtype='double'))
            self._map_atoms = range(self._cell.get_number_of_atoms())

        self._symmetry_operations = {
            'rotations': np.array(rotations, dtype='intc'),
            'translations': np.array(translations, dtype='double')}
        self._international_table = 'P1 (1)'
        self._wyckoff_letters = ['a'] * self._cell.get_number_of_atoms()

def find_primitive(cell, symprec=1e-5):
    """
    A primitive cell is searched in the input cell. When a primitive
    cell is found, an object of Atoms class of the primitive cell is
    returned. When not, None is returned.
    """
    lattice, positions, numbers = spg.find_primitive(cell, symprec)
    if lattice == None:
        return None
    else:
        return Atoms(numbers=numbers,
                     scaled_positions=positions,
                     cell=lattice,
                     pbc=True)

def get_pointgroup(rotations):
    ptg = spg.get_pointgroup(rotations)
    return ptg[0].strip(), ptg[2]

def get_lattice_vector_equivalence(point_symmetry):
    """Return (b==c, c==a, a==b)"""
    # primitive_vectors: column vectors

    equivalence = [False, False, False]
    for r in point_symmetry:
        if (np.abs(r[:, 0]) == [0, 1, 0]).all():
            equivalence[2] = True
        if (np.abs(r[:, 0]) == [0, 0, 1]).all():
            equivalence[1] = True
        if (np.abs(r[:, 1]) == [1, 0, 0]).all():
            equivalence[2] = True
        if (np.abs(r[:, 1]) == [0, 0, 1]).all():
            equivalence[0] = True
        if (np.abs(r[:, 2]) == [1, 0, 0]).all():
            equivalence[1] = True
        if (np.abs(r[:, 2]) == [0, 1, 0]).all():
            equivalence[0] = True

    return equivalence

if __name__ == '__main__':
    from phonopy.structure.symmetry import Symmetry
    from phonopy.interface.vasp import read_vasp

    def get_magmom(text):
        magmom = []
        for numxmag in text.split():
            if '*' in numxmag:
                num, mag = numxmag.split('*')
                magmom += [float(mag)] * int(num)
            else:
                magmom.append(float(numxmag))
        return magmom

    def parse_incar(filename):
        for line in open(filename):
            for conf in line.split(';'):
                if 'MAGMOM' in conf:
                    return get_magmom(conf.split('=')[1])

    cell = read_vasp("POSCAR")
    symmetry = Symmetry(cell, symprec=1e-3)
    map_nonspin = symmetry.get_map_atoms()
    print "Number of operations w/o spin", len(symmetry.get_symmetry_operations()['rotations'])
    magmoms = parse_incar("INCAR")
    cell.set_magnetic_moments(magmoms)
    symmetry = Symmetry(cell, symprec=1e-3)
    print "Number of operations w spin", len(symmetry.get_symmetry_operations()['rotations'])
    map_withspin = symmetry.get_map_atoms()
    if ((map_nonspin - map_withspin) == 0).all():
        print True
    else:
        print False
        print map_nonspin
        print map_withspin
<|endoftext|>


<commit_before>###############################################################################
# Caleydo - Visualization for Molecular Biology - http://caleydo.org
# Copyright (c) The Caleydo Team. All rights reserved.
# Licensed under the new BSD license, available at http://caleydo.org/license
###############################################################################

from builtins import range
from builtins import object
import numpy as np
import numpy.ma as ma
import datetime as dt

class NumpyTablesEncoder(object):
  def __contains__(self, obj):
    if isinstance(obj, np.ndarray):
      return True
    if isinstance(obj, np.generic):
      return True
    if isinstance(obj, dt.datetime):
      return True
    return False

  def __call__(self, obj, base_encoder):
    if isinstance(obj, np.ndarray):
      if obj.ndim == 1:
        return [base_encoder.default(x) for x in obj]
      else:
        return [base_encoder.default(obj[i]) for i in range(obj.shape[0])]
    if isinstance(obj, np.generic):
      a = np.asscalar(obj)
      if (isinstance(a, float) and np.isnan(a)) or ma.is_masked(a):
        return None
      return a
    if isinstance(obj, dt.datetime):
      return obj.isoformat()
    return None

n = NumpyTablesEncoder()

def create():
  return n
<commit_msg>use `obj.strftime("%s")` to get timestamp<commit_after>###############################################################################
# Caleydo - Visualization for Molecular Biology - http://caleydo.org
# Copyright (c) The Caleydo Team. All rights reserved.
# Licensed under the new BSD license, available at http://caleydo.org/license
###############################################################################

from builtins import range
from builtins import object
import numpy as np
import numpy.ma as ma
import datetime as dt

class NumpyTablesEncoder(object):
  def __contains__(self, obj):
    if isinstance(obj, np.ndarray):
      return True
    if isinstance(obj, np.generic):
      return True
    if isinstance(obj, dt.datetime):
      return True
    return False

  def __call__(self, obj, base_encoder):
    if isinstance(obj, np.ndarray):
      if obj.ndim == 1:
        return [base_encoder.default(x) for x in obj]
      else:
        return [base_encoder.default(obj[i]) for i in range(obj.shape[0])]
    if isinstance(obj, np.generic):
      a = np.asscalar(obj)
      if (isinstance(a, float) and np.isnan(a)) or ma.is_masked(a):
        return None
      return a
    if isinstance(obj, dt.datetime):
      return obj.strftime("%s")
    return None

n = NumpyTablesEncoder()

def create():
  return n
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# USAGE: geturl.py FILE_OR_DIR1 FILE_OR_DIR2 ...
#
# prints out the URL associated with each item
#

import os
import sys

import svn.wc
import svn.core

def main(pool, files):
  for f in files:
    dirpath = fullpath = os.path.abspath(f)
    if not os.path.isdir(dirpath):
      dirpath = os.path.dirname(dirpath)
    adm_baton = svn.wc.adm_open(None, dirpath, 1, 1, pool)
    try:
      entry = svn.wc.entry(fullpath, adm_baton, 0, pool)
      print entry.url
    finally:
      svn.wc.adm_close(adm_baton)

if __name__ == '__main__':
  svn.core.run_app(main, sys.argv[1:])
<commit_msg>* tools/examples/geturl.py   (main): Use automatic pool management.<commit_after>#!/usr/bin/env python
#
# USAGE: geturl.py FILE_OR_DIR1 FILE_OR_DIR2 ...
#
# prints out the URL associated with each item
#

import os
import sys

import svn.wc
import svn.core

def main(files):
  for f in files:
    dirpath = fullpath = os.path.abspath(f)
    if not os.path.isdir(dirpath):
      dirpath = os.path.dirname(dirpath)
    adm_baton = svn.wc.adm_open(None, dirpath, 1, 1)
    try:
      entry = svn.wc.entry(fullpath, adm_baton, 0)
      print entry.url
    finally:
      svn.wc.adm_close(adm_baton)

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


<commit_before>"""The generic interface for all exporters.
"""
# mbed SDK
# Copyright (c) 2011-2016 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function, division, absolute_import

import sys
from os.path import join, abspath, dirname, exists, isfile
from os.path import basename, relpath, normpath, splitext
from os import makedirs, walk
import copy
from shutil import rmtree, copyfile
import zipfile

from ..resources import Resources, FileType, FileRef
from ..config import ALLOWED_FEATURES
from ..build_api import prepare_toolchain
from ..targets import TARGET_NAMES
from . import (lpcxpresso, iar, makefile, embitz, coide, kds, simplicity,
               atmelstudio, mcuxpresso, sw4stm32, e2studio, zip, cmsis, uvision,
               cdt, vscode, gnuarmeclipse, qtcreator, cmake, nb, cces, codeblocks)

EXPORTERS = {
    u'uvision6': uvision.UvisionArmc6,
    u'uvision5': uvision.UvisionArmc5,
    u'make_gcc_arm': makefile.GccArm,
    u'make_armc5': makefile.Armc5,
    u'make_armc6': makefile.Armc6,
    u'make_iar': makefile.IAR,
    u'iar': iar.IAR,
    u'embitz' : embitz.EmBitz,
    u'sw4stm32'    : sw4stm32.Sw4STM32,
    u'e2studio' : e2studio.E2Studio,
    u'eclipse_gcc_arm'  : cdt.EclipseGcc,
    u'eclipse_iar'      : cdt.EclipseIAR,
    u'eclipse_armc5'    : cdt.EclipseArmc5,
    u'gnuarmeclipse': gnuarmeclipse.GNUARMEclipse,
    u'mcuxpresso': mcuxpresso.MCUXpresso,
    u'netbeans':     nb.GNUARMNetbeans,
    u'qtcreator': qtcreator.QtCreator,
    u'vscode_gcc_arm' : vscode.VSCodeGcc,
    u'vscode_iar' : vscode.VSCodeIAR,
    u'vscode_armc5' : vscode.VSCodeArmc5,
    u'cmake_gcc_arm': cmake.GccArm,
    u'cces' : cces.CCES,
    u'codeblocks': codeblocks.CodeBlocks
}

ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN = """
Sorry, the target %s is not currently supported on the %s toolchain.
Please refer to Exporting to offline toolchains for more information.
"""

ERROR_MESSAGE_NOT_EXPORT_LIBS = """
To export this project please import the export version of the mbed library.
"""

def mcu_ide_list():
    """Shows list of exportable ides

    """
    supported_ides = sorted(EXPORTERS.keys())
    return "\n".join(supported_ides)

def mcu_ide_matrix(verbose_html=False):
    """Shows target map using prettytable

    Keyword argumets:
    verbose_html - print the matrix in html format
    """
    supported_ides = sorted(EXPORTERS.keys())
    # Only use it in this function so building works without extra modules
    from prettytable import PrettyTable, HEADER

    # All tests status table print
    table_printer = PrettyTable(["Platform"] + supported_ides, junction_char="|", hrules=HEADER)
    # Align table
    for col in supported_ides:
        table_printer.align[col] = "c"
    table_printer.align["Platform"] = "l"

    perm_counter = 0
    for target in sorted(TARGET_NAMES):
        row = [target]  # First column is platform name
        for ide in supported_ides:
            text = "-"
            if EXPORTERS[ide].is_target_supported(target):
                if verbose_html:
                    text = "✓"
                else:
                    text = "x"
                perm_counter += 1
            row.append(text)
        table_printer.add_row(row)

    # creates a html page in a shorter format suitable for readme.md
    if verbose_html:
        result = table_printer.get_html_string()
    else:
        result = table_printer.get_string()
    result += "\n\n"
    result += "Total IDEs: %d\n"% (len(supported_ides))
    if verbose_html:
        result += "
"
    result += "Total platforms: %d\n"% (len(TARGET_NAMES))
    if verbose_html:
        result += "
"
    result += "Total permutations: %d"% (perm_counter)
    if verbose_html:
        result = result.replace("&", "&")
    return result

def get_exporter_toolchain(ide):
    """ Return the exporter class and the toolchain string as a tuple

    Positional arguments:
    ide - the ide name of an exporter
    """
    return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN

def generate_project_files(resources, export_path, target, name, toolchain, ide,
                           macros=None):
    """Generate the project files for a project

    Positional arguments:
    resources - a Resources object containing all of the files needed to build
      this project
    export_path - location to place project files
    name - name of the project
    toolchain - a toolchain class that corresponds to the toolchain used by the
      IDE or makefile
    ide - IDE name to export to

    Optional arguments:
    macros - additional macros that should be defined within the exported
      project
    """
    exporter_cls, _ = get_exporter_toolchain(ide)
    exporter = exporter_cls(target, export_path, name, toolchain,
                            extra_symbols=macros, resources=resources)
    exporter.generate()
    files = exporter.generated_files
    return files, exporter

def _inner_zip_export(resources, prj_files, inc_repos):
    to_zip = sum((resources.get_file_refs(ftype) for ftype
                  in Resources.ALL_FILE_TYPES),
                 [])
    to_zip.extend(FileRef(basename(pfile), pfile) for pfile in prj_files)
    for dest, source in resources.get_file_refs(FileType.BLD_REF):
        target_dir, _ = splitext(dest)
        dest = join(target_dir, ".bld", "bldrc")
        to_zip.append(FileRef(dest, source))
    if inc_repos:
        for dest, source in resources.get_file_refs(FileType.REPO_DIRS):
            for root, _, files in walk(source):
                for repo_file in files:
                    file_source = join(root, repo_file)
                    file_dest = join(dest, relpath(file_source, source))
                    to_zip.append(FileRef(file_dest, file_source))
    return to_zip

def zip_export(file_name, prefix, resources, project_files, inc_repos, notify):
    """Create a zip file from an exported project.

    Positional Parameters:
    file_name - the file name of the resulting zip file
    prefix - a directory name that will prefix the entire zip file's contents
    resources - a resources object with files that must be included in the zip
    project_files - a list of extra files to be added to the root of the prefix
      directory
    """
    to_zip_list = sorted(set(_inner_zip_export(
        resources, project_files, inc_repos)))
    total_files = len(to_zip_list)
    zipped = 0
    with zipfile.ZipFile(file_name, "w") as zip_file:
        for dest, source in to_zip_list:
            if source and isfile(source):
                zip_file.write(source, join(prefix, dest))
                zipped += 1
                notify.progress("Zipping", source,
                                100 * (zipped / total_files))
            else:
                zipped += 1

def export_project(src_paths, export_path, target, ide, libraries_paths=None,
                   linker_script=None, notify=None, name=None, inc_dirs=None,
                   jobs=1, config=None, macros=None, zip_proj=None,
                   inc_repos=False, build_profile=None, app_config=None,
                   ignore=None):
    """Generates a project file and creates a zip archive if specified

    Positional Arguments:
    src_paths - a list of paths from which to find source files
    export_path - a path specifying the location of generated project files
    target - the mbed board/mcu for which to generate the executable
    ide - the ide for which to generate the project fields

    Keyword Arguments:
    libraries_paths - paths to additional libraries
    linker_script - path to the linker script for the specified target
    notify - function is passed all events, and expected to handle notification
      of the user, emit the events to a log, etc.
    name - project name
    inc_dirs - additional include directories
    jobs - number of threads
    config - toolchain's config object
    macros - User-defined macros
    zip_proj - string name of the zip archive you wish to creat (exclude arg
     if you do not wish to create an archive
    ignore - list of paths to add to mbedignore
    """

    # Convert src_path to a list if needed
    if isinstance(src_paths, dict):
        paths = sum(src_paths.values(), [])
    elif isinstance(src_paths, list):
        paths = src_paths[:]
    else:
        paths = [src_paths]

    # Extend src_paths wit libraries_paths
    if libraries_paths is not None:
        paths.extend(libraries_paths)

    if not isinstance(src_paths, dict):
        src_paths = {"": paths}

    # Export Directory
    if not exists(export_path):
        makedirs(export_path)

    _, toolchain_name = get_exporter_toolchain(ide)

    # Pass all params to the unified prepare_resources()
    toolchain = prepare_toolchain(
        paths, "", target, toolchain_name, macros=macros, jobs=jobs,
        notify=notify, config=config, build_profile=build_profile,
        app_config=app_config, ignore=ignore)

    toolchain.RESPONSE_FILES = False
    if name is None:
        name = basename(normpath(abspath(src_paths[0])))

    resources = Resources(notify, collect_ignores=True)
    resources.add_toolchain_labels(toolchain)
    for loc, path in src_paths.items():
        for p in path:
            resources.add_directory(p, into_path=loc)
    toolchain.build_dir = export_path
    toolchain.config.load_resources(resources)
    toolchain.set_config_data(toolchain.config.get_config_data())
    config_header = toolchain.get_config_header()
    resources.add_file_ref(FileType.HEADER, basename(config_header), config_header)

    # Change linker script if specified
    if linker_script is not None:
        resources.linker_script = linker_script

    if toolchain.config.name is not None:
        name = toolchain.config.app_config_data['artifact_name']

    files, exporter = generate_project_files(resources, export_path,
                                             target, name, toolchain, ide,
                                             macros=macros)
    if zip_proj:
        resources.add_features(ALLOWED_FEATURES)
        if isinstance(zip_proj, basestring):
            zip_export(join(export_path, zip_proj), name, resources,
                       files + list(exporter.static_files), inc_repos, notify)
        else:
            zip_export(zip_proj, name, resources,
                       files + list(exporter.static_files), inc_repos, notify)
    else:
        for static_file in exporter.static_files:
            if not exists(join(export_path, basename(static_file))):
                copyfile(static_file, join(export_path, basename(static_file)))

    return exporter
<commit_msg>Update tools/export/__init__.py<commit_after>"""The generic interface for all exporters.
"""
# mbed SDK
# Copyright (c) 2011-2016 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function, division, absolute_import

import sys
from os.path import join, abspath, dirname, exists, isfile
from os.path import basename, relpath, normpath, splitext
from os import makedirs, walk
import copy
from shutil import rmtree, copyfile
import zipfile

from ..resources import Resources, FileType, FileRef
from ..config import ALLOWED_FEATURES
from ..build_api import prepare_toolchain
from ..targets import TARGET_NAMES
from . import (lpcxpresso, iar, makefile, embitz, coide, kds, simplicity,
               atmelstudio, mcuxpresso, sw4stm32, e2studio, zip, cmsis, uvision,
               cdt, vscode, gnuarmeclipse, qtcreator, cmake, nb, cces, codeblocks)

EXPORTERS = {
    u'uvision6': uvision.UvisionArmc6,
    u'uvision5': uvision.UvisionArmc5,
    u'make_gcc_arm': makefile.GccArm,
    u'make_armc5': makefile.Armc5,
    u'make_armc6': makefile.Armc6,
    u'make_iar': makefile.IAR,
    u'iar': iar.IAR,
    u'embitz' : embitz.EmBitz,
    u'sw4stm32'    : sw4stm32.Sw4STM32,
    u'e2studio' : e2studio.E2Studio,
    u'eclipse_gcc_arm'  : cdt.EclipseGcc,
    u'eclipse_iar'      : cdt.EclipseIAR,
    u'eclipse_armc5'    : cdt.EclipseArmc5,
    u'gnuarmeclipse': gnuarmeclipse.GNUARMEclipse,
    u'mcuxpresso': mcuxpresso.MCUXpresso,
    u'netbeans':     nb.GNUARMNetbeans,
    u'qtcreator': qtcreator.QtCreator,
    u'vscode_gcc_arm' : vscode.VSCodeGcc,
    u'vscode_iar' : vscode.VSCodeIAR,
    u'vscode_armc5' : vscode.VSCodeArmc5,
    u'cmake_gcc_arm': cmake.GccArm,
    u'cces' : cces.CCES,
    u'codeblocks': codeblocks.CodeBlocks
}

ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN = """
Sorry, the target %s is not currently supported on the %s toolchain.
Please refer to Exporting to offline toolchains for more information.
"""

ERROR_MESSAGE_NOT_EXPORT_LIBS = """
To export this project please import the export version of the mbed library.
"""

def mcu_ide_list():
    """Shows list of exportable ides

    """
    supported_ides = sorted(EXPORTERS.keys())
    return "\n".join(supported_ides)

def mcu_ide_matrix(verbose_html=False):
    """Shows target map using prettytable

    Keyword argumets:
    verbose_html - print the matrix in html format
    """
    supported_ides = sorted(EXPORTERS.keys())
    # Only use it in this function so building works without extra modules
    from prettytable import PrettyTable, HEADER

    # All tests status table print
    table_printer = PrettyTable(["Platform"] + supported_ides, junction_char="|", hrules=HEADER)
    # Align table
    for col in supported_ides:
        table_printer.align[col] = "c"
    table_printer.align["Platform"] = "l"

    perm_counter = 0
    for target in sorted(TARGET_NAMES):
        row = [target]  # First column is platform name
        for ide in supported_ides:
            text = "-"
            if EXPORTERS[ide].is_target_supported(target):
                if verbose_html:
                    text = "✓"
                else:
                    text = "x"
                perm_counter += 1
            row.append(text)
        table_printer.add_row(row)

    # creates a html page in a shorter format suitable for readme.md
    if verbose_html:
        result = table_printer.get_html_string()
    else:
        result = table_printer.get_string()
    result += "\n\n"
    result += "Total IDEs: %d\n"% (len(supported_ides))
    if verbose_html:
        result += "
"
    result += "Total platforms: %d\n"% (len(TARGET_NAMES))
    if verbose_html:
        result += "
"
    result += "Total permutations: %d"% (perm_counter)
    if verbose_html:
        result = result.replace("&", "&")
    return result

def get_exporter_toolchain(ide):
    """ Return the exporter class and the toolchain string as a tuple

    Positional arguments:
    ide - the ide name of an exporter
    """
    return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN

def generate_project_files(resources, export_path, target, name, toolchain, ide,
                           macros=None):
    """Generate the project files for a project

    Positional arguments:
    resources - a Resources object containing all of the files needed to build
      this project
    export_path - location to place project files
    name - name of the project
    toolchain - a toolchain class that corresponds to the toolchain used by the
      IDE or makefile
    ide - IDE name to export to

    Optional arguments:
    macros - additional macros that should be defined within the exported
      project
    """
    exporter_cls, _ = get_exporter_toolchain(ide)
    exporter = exporter_cls(target, export_path, name, toolchain,
                            extra_symbols=macros, resources=resources)
    exporter.generate()
    files = exporter.generated_files
    return files, exporter

def _inner_zip_export(resources, prj_files, inc_repos):
    to_zip = sum((resources.get_file_refs(ftype) for ftype
                  in Resources.ALL_FILE_TYPES),
                 [])
    to_zip.extend(FileRef(basename(pfile), pfile) for pfile in prj_files)
    for dest, source in resources.get_file_refs(FileType.BLD_REF):
        target_dir, _ = splitext(dest)
        dest = join(target_dir, ".bld", "bldrc")
        to_zip.append(FileRef(dest, source))
    if inc_repos:
        for dest, source in resources.get_file_refs(FileType.REPO_DIRS):
            for root, _, files in walk(source):
                for repo_file in files:
                    file_source = join(root, repo_file)
                    file_dest = join(dest, relpath(file_source, source))
                    to_zip.append(FileRef(file_dest, file_source))
    return to_zip

def zip_export(file_name, prefix, resources, project_files, inc_repos, notify):
    """Create a zip file from an exported project.

    Positional Parameters:
    file_name - the file name of the resulting zip file
    prefix - a directory name that will prefix the entire zip file's contents
    resources - a resources object with files that must be included in the zip
    project_files - a list of extra files to be added to the root of the prefix
      directory
    """
    to_zip_list = sorted(set(_inner_zip_export(
        resources, project_files, inc_repos)))
    total_files = len(to_zip_list)
    zipped = 0
    with zipfile.ZipFile(file_name, "w") as zip_file:
        for dest, source in to_zip_list:
            if source and isfile(source):
                zip_file.write(source, join(prefix, dest))
                zipped += 1
                notify.progress("Zipping", source,
                                100 * (zipped / total_files))
            else:
                zipped += 1

def export_project(src_paths, export_path, target, ide, libraries_paths=None,
                   linker_script=None, notify=None, name=None, inc_dirs=None,
                   jobs=1, config=None, macros=None, zip_proj=None,
                   inc_repos=False, build_profile=None, app_config=None,
                   ignore=None):
    """Generates a project file and creates a zip archive if specified

    Positional Arguments:
    src_paths - a list of paths from which to find source files
    export_path - a path specifying the location of generated project files
    target - the mbed board/mcu for which to generate the executable
    ide - the ide for which to generate the project fields

    Keyword Arguments:
    libraries_paths - paths to additional libraries
    linker_script - path to the linker script for the specified target
    notify - function is passed all events, and expected to handle notification
      of the user, emit the events to a log, etc.
    name - project name
    inc_dirs - additional include directories
    jobs - number of threads
    config - toolchain's config object
    macros - User-defined macros
    zip_proj - string name of the zip archive you wish to creat (exclude arg
     if you do not wish to create an archive
    ignore - list of paths to add to mbedignore
    """

    # Convert src_path to a list if needed
    if isinstance(src_paths, dict):
        paths = sum(src_paths.values(), [])
    elif isinstance(src_paths, list):
        paths = src_paths[:]
    else:
        paths = [src_paths]

    # Extend src_paths wit libraries_paths
    if libraries_paths is not None:
        paths.extend(libraries_paths)

    if not isinstance(src_paths, dict):
        src_paths = {"": paths}

    # Export Directory
    if not exists(export_path):
        makedirs(export_path)

    _, toolchain_name = get_exporter_toolchain(ide)

    # Pass all params to the unified prepare_resources()
    toolchain = prepare_toolchain(
        paths, "", target, toolchain_name, macros=macros, jobs=jobs,
        notify=notify, config=config, build_profile=build_profile,
        app_config=app_config, ignore=ignore)

    toolchain.RESPONSE_FILES = False
    if name is None:
        name = basename(normpath(abspath(src_paths[0])))

    resources = Resources(notify, collect_ignores=True)
    resources.add_toolchain_labels(toolchain)
    for loc, path in src_paths.items():
        for p in path:
            resources.add_directory(p, into_path=loc)
    toolchain.build_dir = export_path
    toolchain.config.load_resources(resources)
    toolchain.set_config_data(toolchain.config.get_config_data())
    config_header = toolchain.get_config_header()
    resources.add_file_ref(FileType.HEADER, basename(config_header), config_header)

    # Change linker script if specified
    if linker_script is not None:
        resources.linker_script = linker_script

    if toolchain.config.name is not None:
        name = toolchain.config.name

    files, exporter = generate_project_files(resources, export_path,
                                             target, name, toolchain, ide,
                                             macros=macros)
    if zip_proj:
        resources.add_features(ALLOWED_FEATURES)
        if isinstance(zip_proj, basestring):
            zip_export(join(export_path, zip_proj), name, resources,
                       files + list(exporter.static_files), inc_repos, notify)
        else:
            zip_export(zip_proj, name, resources,
                       files + list(exporter.static_files), inc_repos, notify)
    else:
        for static_file in exporter.static_files:
            if not exists(join(export_path, basename(static_file))):
                copyfile(static_file, join(export_path, basename(static_file)))

    return exporter
<|endoftext|>