<commit_before># Copyright 2020 The StackStorm Authors.
# Copyright 2019 Extreme Networks, Inc.
#
# 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.

import os
import os.path
import stat
import errno

from mongoengine import ValidationError
import six

# TODO: Encapsulate mongoengine errors in our persistence layer. Exceptions
#       that bubble up to this layer should be core Python exceptions or
#       StackStorm defined exceptions.

from st2api.controllers import resource
from st2api.controllers.v1.action_views import ActionViewsController
from st2common import log as logging
from st2common.constants.triggers import ACTION_FILE_WRITTEN_TRIGGER
from st2common.exceptions.action import InvalidActionParameterException
from st2common.exceptions.apivalidation import ValueValidationException
from st2common.persistence.action import Action
from st2common.models.api.action import ActionAPI
from st2common.persistence.pack import Pack
from st2common.rbac.types import PermissionType
from st2common.rbac.backends import get_rbac_backend
from st2common.router import abort
from st2common.router import Response
from st2common.validators.api.misc import validate_not_part_of_system_pack
from st2common.content.utils import get_pack_base_path
from st2common.content.utils import get_pack_resource_file_abs_path
from st2common.content.utils import get_relative_path_to_pack_file
from st2common.services.packs import delete_action_files_from_pack
from st2common.transport.reactor import TriggerDispatcher
from st2common.util.system_info import get_host_info
import st2common.validators.api.action as action_validator

http_client = six.moves.http_client

LOG = logging.getLogger(__name__)

class ActionsController(resource.ContentPackResourceController):
    """
    Implements the RESTful web endpoint that handles
    the lifecycle of Actions in the system.
    """

    views = ActionViewsController()

    model = ActionAPI
    access = Action
    supported_filters = {"name": "name", "pack": "pack", "tags": "tags.name"}

    query_options = {"sort": ["pack", "name"]}

    valid_exclude_attributes = ["parameters", "notify"]

    def __init__(self, *args, **kwargs):
        super(ActionsController, self).__init__(*args, **kwargs)
        self._trigger_dispatcher = TriggerDispatcher(LOG)

    def get_all(
        self,
        exclude_attributes=None,
        include_attributes=None,
        sort=None,
        offset=0,
        limit=None,
        requester_user=None,
        **raw_filters,
    ):
        return super(ActionsController, self)._get_all(
            exclude_fields=exclude_attributes,
            include_fields=include_attributes,
            sort=sort,
            offset=offset,
            limit=limit,
            raw_filters=raw_filters,
            requester_user=requester_user,
        )

    def get_one(self, ref_or_id, requester_user):
        return super(ActionsController, self)._get_one(
            ref_or_id,
            requester_user=requester_user,
            permission_type=PermissionType.ACTION_VIEW,
        )

    def post(self, action, requester_user):
        """
        Create a new action.

        Handles requests:
            POST /actions/
        """

        permission_type = PermissionType.ACTION_CREATE
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_api_permission(
            user_db=requester_user, resource_api=action, permission_type=permission_type
        )

        try:
            # Perform validation
            validate_not_part_of_system_pack(action)
            action_validator.validate_action(action)
        except (
            ValidationError,
            ValueError,
            ValueValidationException,
            InvalidActionParameterException,
        ) as e:
            LOG.exception("Unable to create action data=%s", action)
            abort(http_client.BAD_REQUEST, six.text_type(e))
            return

        # Write pack data files to disk (if any are provided)
        data_files = getattr(action, "data_files", [])
        written_data_files = []
        if data_files:
            written_data_files = self._handle_data_files(
                pack_ref=action.pack, data_files=data_files
            )

        action_model = ActionAPI.to_model(action)

        LOG.debug("/actions/ POST verified ActionAPI object=%s", action)
        action_db = Action.add_or_update(action_model)
        LOG.debug("/actions/ POST saved ActionDB object=%s", action_db)

        # Dispatch an internal trigger for each written data file. This way user
        # automate comitting this files to git using StackStorm rule
        if written_data_files:
            self._dispatch_trigger_for_written_data_files(
                action_db=action_db, written_data_files=written_data_files
            )

        extra = {"acion_db": action_db}
        LOG.audit("Action created. Action.id=%s" % (action_db.id), extra=extra)
        action_api = ActionAPI.from_model(action_db)

        return Response(json=action_api, status=http_client.CREATED)

    def put(self, action, ref_or_id, requester_user):
        action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id)

        # Assert permissions
        permission_type = PermissionType.ACTION_MODIFY
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_db_permission(
            user_db=requester_user,
            resource_db=action_db,
            permission_type=permission_type,
        )

        action_id = action_db.id

        if not getattr(action, "pack", None):
            action.pack = action_db.pack

        # Perform validation
        validate_not_part_of_system_pack(action)
        action_validator.validate_action(action)

        # Write pack data files to disk (if any are provided)
        data_files = getattr(action, "data_files", [])
        written_data_files = []
        if data_files:
            written_data_files = self._handle_data_files(
                pack_ref=action.pack, data_files=data_files
            )

        try:
            action_db = ActionAPI.to_model(action)
            LOG.debug("/actions/ PUT incoming action: %s", action_db)
            action_db.id = action_id
            action_db = Action.add_or_update(action_db)
            LOG.debug("/actions/ PUT after add_or_update: %s", action_db)
        except (ValidationError, ValueError) as e:
            LOG.exception("Unable to update action data=%s", action)
            abort(http_client.BAD_REQUEST, six.text_type(e))
            return

        # Dispatch an internal trigger for each written data file. This way user
        # automate committing this files to git using StackStorm rule
        if written_data_files:
            self._dispatch_trigger_for_written_data_files(
                action_db=action_db, written_data_files=written_data_files
            )

        action_api = ActionAPI.from_model(action_db)
        LOG.debug("PUT /actions/ client_result=%s", action_api)

        return action_api

    def delete(self, ref_or_id, requester_user):
        """
        Delete an action.

        Handles requests:
            POST /actions/1?_method=delete
            DELETE /actions/1
            DELETE /actions/mypack.myaction
        """
        action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id)
        action_id = action_db.id

        permission_type = PermissionType.ACTION_DELETE
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_db_permission(
            user_db=requester_user,
            resource_db=action_db,
            permission_type=permission_type,
        )

        try:
            validate_not_part_of_system_pack(action_db)
        except ValueValidationException as e:
            abort(http_client.BAD_REQUEST, six.text_type(e))

        LOG.debug(
            "DELETE /actions/ lookup with ref_or_id=%s found object: %s",
            ref_or_id,
            action_db,
        )

        pack_name = action_db["pack"]
        entry_point = action_db["entry_point"]
        metadata_file = action_db["metadata_file"]

        try:
            Action.delete(action_db)
            delete_action_files_from_pack(
                pack_name=pack_name,
                entry_point=entry_point,
                metadata_file=metadata_file,
            )
        except Exception as e:
            LOG.error(
                'Database delete encountered exception during delete of id="%s". '
                "Exception was %s",
                action_id,
                e,
            )
            abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e))
            return

        extra = {"action_db": action_db}
        LOG.audit("Action deleted. Action.id=%s" % (action_db.id), extra=extra)
        return Response(status=http_client.NO_CONTENT)

    def _handle_data_files(self, pack_ref, data_files):
        """
        Method for handling action data files.

        This method performs two tasks:

        1. Writes files to disk
        2. Updates affected PackDB model
        """
        # Write files to disk
        written_file_paths = self._write_data_files_to_disk(
            pack_ref=pack_ref, data_files=data_files
        )

        # Update affected PackDB model (update a list of files)
        # Update PackDB
        self._update_pack_model(
            pack_ref=pack_ref,
            data_files=data_files,
            written_file_paths=written_file_paths,
        )

        return written_file_paths

    def _write_data_files_to_disk(self, pack_ref, data_files):
        """
        Write files to disk.
        """
        written_file_paths = []

        for data_file in data_files:
            file_path = data_file["file_path"]
            content = data_file["content"]

            file_path = get_pack_resource_file_abs_path(
                pack_ref=pack_ref, resource_type="action", file_path=file_path
            )

            LOG.debug('Writing data file "%s" to "%s"' % (str(data_file), file_path))

            try:
                self._write_data_file(
                    pack_ref=pack_ref, file_path=file_path, content=content
                )
            except (OSError, IOError) as e:
                # Throw a more user-friendly exception on Permission denied error
                if e.errno == errno.EACCES:
                    msg = (
                        'Unable to write data to "%s" (permission denied). Make sure '
                        "permissions for that pack directory are configured correctly so "
                        "st2api can write to it." % (file_path)
                    )
                    raise ValueError(msg)
                raise e

            written_file_paths.append(file_path)

        return written_file_paths

    def _update_pack_model(self, pack_ref, data_files, written_file_paths):
        """
        Update PackDB models (update files list).
        """
        file_paths = []  # A list of paths relative to the pack directory for new files
        for file_path in written_file_paths:
            file_path = get_relative_path_to_pack_file(
                pack_ref=pack_ref, file_path=file_path
            )
            file_paths.append(file_path)

        pack_db = Pack.get_by_ref(pack_ref)
        pack_db.files = set(pack_db.files)
        pack_db.files.update(set(file_paths))
        pack_db.files = list(pack_db.files)
        pack_db = Pack.add_or_update(pack_db)

        return pack_db

    def _write_data_file(self, pack_ref, file_path, content):
        """
        Write data file on disk.
        """
        # Throw if pack directory doesn't exist
        pack_base_path = get_pack_base_path(pack_name=pack_ref)
        if not os.path.isdir(pack_base_path):
            raise ValueError('Directory for pack "%s" doesn\'t exist' % (pack_ref))

        # Create pack sub-directory tree if it doesn't exist
        directory = os.path.dirname(file_path)

        if not os.path.isdir(directory):
            # NOTE: We apply same permission bits as we do on pack install. If we don't do that,
            # st2api won't be able to write to pack sub-directory
            mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH
            os.makedirs(directory, mode)

        with open(file_path, "w") as fp:
            fp.write(content)

    def _dispatch_trigger_for_written_data_files(self, action_db, written_data_files):
        trigger = ACTION_FILE_WRITTEN_TRIGGER["name"]
        host_info = get_host_info()

        for file_path in written_data_files:
            payload = {
                "ref": action_db.ref,
                "file_path": file_path,
                "host_info": host_info,
            }
            self._trigger_dispatcher.dispatch(trigger=trigger, payload=payload)

actions_controller = ActionsController()
<commit_msg>Adding extra try/except block for disk file delete<commit_after># Copyright 2020 The StackStorm Authors.
# Copyright 2019 Extreme Networks, Inc.
#
# 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.

import os
import os.path
import stat
import errno

from mongoengine import ValidationError
import six

# TODO: Encapsulate mongoengine errors in our persistence layer. Exceptions
#       that bubble up to this layer should be core Python exceptions or
#       StackStorm defined exceptions.

from st2api.controllers import resource
from st2api.controllers.v1.action_views import ActionViewsController
from st2common import log as logging
from st2common.constants.triggers import ACTION_FILE_WRITTEN_TRIGGER
from st2common.exceptions.action import InvalidActionParameterException
from st2common.exceptions.apivalidation import ValueValidationException
from st2common.persistence.action import Action
from st2common.models.api.action import ActionAPI
from st2common.persistence.pack import Pack
from st2common.rbac.types import PermissionType
from st2common.rbac.backends import get_rbac_backend
from st2common.router import abort
from st2common.router import Response
from st2common.validators.api.misc import validate_not_part_of_system_pack
from st2common.content.utils import get_pack_base_path
from st2common.content.utils import get_pack_resource_file_abs_path
from st2common.content.utils import get_relative_path_to_pack_file
from st2common.services.packs import delete_action_files_from_pack
from st2common.transport.reactor import TriggerDispatcher
from st2common.util.system_info import get_host_info
import st2common.validators.api.action as action_validator

http_client = six.moves.http_client

LOG = logging.getLogger(__name__)

class ActionsController(resource.ContentPackResourceController):
    """
    Implements the RESTful web endpoint that handles
    the lifecycle of Actions in the system.
    """

    views = ActionViewsController()

    model = ActionAPI
    access = Action
    supported_filters = {"name": "name", "pack": "pack", "tags": "tags.name"}

    query_options = {"sort": ["pack", "name"]}

    valid_exclude_attributes = ["parameters", "notify"]

    def __init__(self, *args, **kwargs):
        super(ActionsController, self).__init__(*args, **kwargs)
        self._trigger_dispatcher = TriggerDispatcher(LOG)

    def get_all(
        self,
        exclude_attributes=None,
        include_attributes=None,
        sort=None,
        offset=0,
        limit=None,
        requester_user=None,
        **raw_filters,
    ):
        return super(ActionsController, self)._get_all(
            exclude_fields=exclude_attributes,
            include_fields=include_attributes,
            sort=sort,
            offset=offset,
            limit=limit,
            raw_filters=raw_filters,
            requester_user=requester_user,
        )

    def get_one(self, ref_or_id, requester_user):
        return super(ActionsController, self)._get_one(
            ref_or_id,
            requester_user=requester_user,
            permission_type=PermissionType.ACTION_VIEW,
        )

    def post(self, action, requester_user):
        """
        Create a new action.

        Handles requests:
            POST /actions/
        """

        permission_type = PermissionType.ACTION_CREATE
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_api_permission(
            user_db=requester_user, resource_api=action, permission_type=permission_type
        )

        try:
            # Perform validation
            validate_not_part_of_system_pack(action)
            action_validator.validate_action(action)
        except (
            ValidationError,
            ValueError,
            ValueValidationException,
            InvalidActionParameterException,
        ) as e:
            LOG.exception("Unable to create action data=%s", action)
            abort(http_client.BAD_REQUEST, six.text_type(e))
            return

        # Write pack data files to disk (if any are provided)
        data_files = getattr(action, "data_files", [])
        written_data_files = []
        if data_files:
            written_data_files = self._handle_data_files(
                pack_ref=action.pack, data_files=data_files
            )

        action_model = ActionAPI.to_model(action)

        LOG.debug("/actions/ POST verified ActionAPI object=%s", action)
        action_db = Action.add_or_update(action_model)
        LOG.debug("/actions/ POST saved ActionDB object=%s", action_db)

        # Dispatch an internal trigger for each written data file. This way user
        # automate comitting this files to git using StackStorm rule
        if written_data_files:
            self._dispatch_trigger_for_written_data_files(
                action_db=action_db, written_data_files=written_data_files
            )

        extra = {"acion_db": action_db}
        LOG.audit("Action created. Action.id=%s" % (action_db.id), extra=extra)
        action_api = ActionAPI.from_model(action_db)

        return Response(json=action_api, status=http_client.CREATED)

    def put(self, action, ref_or_id, requester_user):
        action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id)

        # Assert permissions
        permission_type = PermissionType.ACTION_MODIFY
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_db_permission(
            user_db=requester_user,
            resource_db=action_db,
            permission_type=permission_type,
        )

        action_id = action_db.id

        if not getattr(action, "pack", None):
            action.pack = action_db.pack

        # Perform validation
        validate_not_part_of_system_pack(action)
        action_validator.validate_action(action)

        # Write pack data files to disk (if any are provided)
        data_files = getattr(action, "data_files", [])
        written_data_files = []
        if data_files:
            written_data_files = self._handle_data_files(
                pack_ref=action.pack, data_files=data_files
            )

        try:
            action_db = ActionAPI.to_model(action)
            LOG.debug("/actions/ PUT incoming action: %s", action_db)
            action_db.id = action_id
            action_db = Action.add_or_update(action_db)
            LOG.debug("/actions/ PUT after add_or_update: %s", action_db)
        except (ValidationError, ValueError) as e:
            LOG.exception("Unable to update action data=%s", action)
            abort(http_client.BAD_REQUEST, six.text_type(e))
            return

        # Dispatch an internal trigger for each written data file. This way user
        # automate committing this files to git using StackStorm rule
        if written_data_files:
            self._dispatch_trigger_for_written_data_files(
                action_db=action_db, written_data_files=written_data_files
            )

        action_api = ActionAPI.from_model(action_db)
        LOG.debug("PUT /actions/ client_result=%s", action_api)

        return action_api

    def delete(self, ref_or_id, requester_user):
        """
        Delete an action.

        Handles requests:
            POST /actions/1?_method=delete
            DELETE /actions/1
            DELETE /actions/mypack.myaction
        """
        action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id)
        action_id = action_db.id

        permission_type = PermissionType.ACTION_DELETE
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_db_permission(
            user_db=requester_user,
            resource_db=action_db,
            permission_type=permission_type,
        )

        try:
            validate_not_part_of_system_pack(action_db)
        except ValueValidationException as e:
            abort(http_client.BAD_REQUEST, six.text_type(e))

        LOG.debug(
            "DELETE /actions/ lookup with ref_or_id=%s found object: %s",
            ref_or_id,
            action_db,
        )

        pack_name = action_db["pack"]
        entry_point = action_db["entry_point"]
        metadata_file = action_db["metadata_file"]

        try:
            Action.delete(action_db)
            try:
                delete_action_files_from_pack(
                    pack_name=pack_name,
                    entry_point=entry_point,
                    metadata_file=metadata_file,
                )
            except Exception as e:
                LOG.error(
                    "Exception encountered during deleting resource files from disk."
                    "Exception was %s",
                    e,
                )
                abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e))
                return
        except Exception as e:
            LOG.error(
                'Database delete encountered exception during delete of id="%s". '
                "Exception was %s",
                action_id,
                e,
            )
            abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e))
            return

        extra = {"action_db": action_db}
        LOG.audit("Action deleted. Action.id=%s" % (action_db.id), extra=extra)
        return Response(status=http_client.NO_CONTENT)

    def _handle_data_files(self, pack_ref, data_files):
        """
        Method for handling action data files.

        This method performs two tasks:

        1. Writes files to disk
        2. Updates affected PackDB model
        """
        # Write files to disk
        written_file_paths = self._write_data_files_to_disk(
            pack_ref=pack_ref, data_files=data_files
        )

        # Update affected PackDB model (update a list of files)
        # Update PackDB
        self._update_pack_model(
            pack_ref=pack_ref,
            data_files=data_files,
            written_file_paths=written_file_paths,
        )

        return written_file_paths

    def _write_data_files_to_disk(self, pack_ref, data_files):
        """
        Write files to disk.
        """
        written_file_paths = []

        for data_file in data_files:
            file_path = data_file["file_path"]
            content = data_file["content"]

            file_path = get_pack_resource_file_abs_path(
                pack_ref=pack_ref, resource_type="action", file_path=file_path
            )

            LOG.debug('Writing data file "%s" to "%s"' % (str(data_file), file_path))

            try:
                self._write_data_file(
                    pack_ref=pack_ref, file_path=file_path, content=content
                )
            except (OSError, IOError) as e:
                # Throw a more user-friendly exception on Permission denied error
                if e.errno == errno.EACCES:
                    msg = (
                        'Unable to write data to "%s" (permission denied). Make sure '
                        "permissions for that pack directory are configured correctly so "
                        "st2api can write to it." % (file_path)
                    )
                    raise ValueError(msg)
                raise e

            written_file_paths.append(file_path)

        return written_file_paths

    def _update_pack_model(self, pack_ref, data_files, written_file_paths):
        """
        Update PackDB models (update files list).
        """
        file_paths = []  # A list of paths relative to the pack directory for new files
        for file_path in written_file_paths:
            file_path = get_relative_path_to_pack_file(
                pack_ref=pack_ref, file_path=file_path
            )
            file_paths.append(file_path)

        pack_db = Pack.get_by_ref(pack_ref)
        pack_db.files = set(pack_db.files)
        pack_db.files.update(set(file_paths))
        pack_db.files = list(pack_db.files)
        pack_db = Pack.add_or_update(pack_db)

        return pack_db

    def _write_data_file(self, pack_ref, file_path, content):
        """
        Write data file on disk.
        """
        # Throw if pack directory doesn't exist
        pack_base_path = get_pack_base_path(pack_name=pack_ref)
        if not os.path.isdir(pack_base_path):
            raise ValueError('Directory for pack "%s" doesn\'t exist' % (pack_ref))

        # Create pack sub-directory tree if it doesn't exist
        directory = os.path.dirname(file_path)

        if not os.path.isdir(directory):
            # NOTE: We apply same permission bits as we do on pack install. If we don't do that,
            # st2api won't be able to write to pack sub-directory
            mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH
            os.makedirs(directory, mode)

        with open(file_path, "w") as fp:
            fp.write(content)

    def _dispatch_trigger_for_written_data_files(self, action_db, written_data_files):
        trigger = ACTION_FILE_WRITTEN_TRIGGER["name"]
        host_info = get_host_info()

        for file_path in written_data_files:
            payload = {
                "ref": action_db.ref,
                "file_path": file_path,
                "host_info": host_info,
            }
            self._trigger_dispatcher.dispatch(trigger=trigger, payload=payload)

actions_controller = ActionsController()
<|endoftext|>


<commit_before># encoding: utf-8
from __future__ import division, print_function, unicode_literals

###########################################################################################################
#
#
#	Reporter Plugin
#
#	Read the docs:
#	https://github.com/schriftgestalt/GlyphsSDK/tree/master/Python%20Templates/Reporter
#
#
###########################################################################################################

from GlyphsApp import *
from GlyphsApp.plugins import *
from AppKit import NSRoundLineJoinStyle

class ShowComponentOrder(ReporterPlugin):

	@objc.python_method
	def settings(self):
		self.menuName = Glyphs.localize({
			'en': 'Component Order',
			'de': 'Reihenfolge der Komponenten',
			'fr': 'ordre des composants',
			'es': 'orden de componentes',
			'nl': 'volgorde van componenten',
		})

	@objc.python_method
	def foreground(self, layer):
		self.colorComponents( layer )

	@objc.python_method
	def inactiveLayerBackground(self, layer):
		self.colorComponents( layer, colorfactor=0.6, selectionCounts=False )

	@objc.python_method
	def colorComponents(self, Layer, colorfactor=1.0, selectionCounts=True):
		if Layer.components:
			factor = 1.0 / len(Layer.components)

			try:
				# GLYPHS 3
				layerObjects = Layer.shapes
			except:
				# GLYPHS 2
				layerObjects = Layer.components

			for i, thisShape in enumerate( layerObjects ):
				if type(thisShape) is GSComponent:
					difference = factor * float( i )
					componentArea = thisShape.bezierPath

					# colored fill
					componentColor = NSColor.colorWithCalibratedRed_green_blue_alpha_(
						colorfactor * (difference ** 2.0), # red
						colorfactor * (1.0 - difference),  # green
						colorfactor * difference,          # blue
						0.7, # alpha
						)

					if selectionCounts and thisShape in Layer.selection:
						componentColor.highlightWithLevel_(0.5).set()
					else:
						componentColor.set()
					componentArea.fill()

					if not thisShape.automaticAlignment:
						componentColor.colorWithAlphaComponent_(0.8).set()
						componentArea.setLineWidth_(2.0/self.getScale())
						componentArea.setLineDash_count_phase_((4/self.getScale()**0.9,3/self.getScale()**0.9),2,0.0)
						componentArea.stroke()
				else:
					# GLYPHS 3
					NSColor.textColor.colorWithAlphaComponent_(0.4).set()
					thisShape.bezierPath.fill()

			if Glyphs.versionNumber < 3.0:
				NSColor.textColor.colorWithAlphaComponent_(0.4).set()
				Layer.bezierPath.fill()

	def needsExtraMainOutlineDrawingForInactiveLayer_(self, layer):
		if layer.components:
			return False
		else:
			return True

	@objc.python_method
	def __file__(self):
		"""Please leave this method unchanged"""
		return __file__
<commit_msg>better highlighting<commit_after># encoding: utf-8
from __future__ import division, print_function, unicode_literals

###########################################################################################################
#
#
#	Reporter Plugin
#
#	Read the docs:
#	https://github.com/schriftgestalt/GlyphsSDK/tree/master/Python%20Templates/Reporter
#
#
###########################################################################################################

from GlyphsApp import *
from GlyphsApp.plugins import *
from AppKit import NSRoundLineJoinStyle

class ShowComponentOrder(ReporterPlugin):

	@objc.python_method
	def settings(self):
		self.menuName = Glyphs.localize({
			'en': 'Component Order',
			'de': 'Reihenfolge der Komponenten',
			'fr': 'ordre des composants',
			'es': 'orden de componentes',
			'nl': 'volgorde van componenten',
		})

	@objc.python_method
	def foreground(self, layer):
		self.colorComponents( layer )

	@objc.python_method
	def inactiveLayerBackground(self, layer):
		self.colorComponents( layer, colorfactor=0.6, selectionCounts=False )

	@objc.python_method
	def colorComponents(self, Layer, colorfactor=1.0, selectionCounts=True):
		if Layer.components:
			factor = 1.0 / len(Layer.components)

			try:
				# GLYPHS 3
				layerObjects = Layer.shapes
			except:
				# GLYPHS 2
				layerObjects = Layer.components

			for i, thisShape in enumerate( layerObjects ):
				if type(thisShape) is GSComponent:
					difference = factor * float( i )
					componentArea = thisShape.bezierPath

					# colored fill
					componentColor = NSColor.colorWithCalibratedRed_green_blue_alpha_(
						colorfactor * (difference ** 2.0), # red
						colorfactor * (1.0 - difference),  # green
						colorfactor * difference,          # blue
						0.67, # alpha
						)

					if selectionCounts and thisShape in Layer.selection:
						componentColor.highlightWithLevel_(0.33).set()
					else:
						componentColor.set()
					componentArea.fill()

					if not thisShape.doesAlign():
						componentColor.colorWithAlphaComponent_(0.8).set()
						componentArea.setLineWidth_(2.0/self.getScale())
						componentArea.setLineDash_count_phase_((4/self.getScale()**0.9,3/self.getScale()**0.9),2,0.0)
						componentArea.stroke()
				else:
					# GLYPHS 3
					NSColor.textColor().colorWithAlphaComponent_(0.4).set()
					thisShape.bezierPath.fill()

			if Glyphs.versionNumber < 3.0:
				NSColor.textColor().colorWithAlphaComponent_(0.4).set()
				for thisPath in Layer.paths:
					thisPath.bezierPath.fill()

	def needsExtraMainOutlineDrawingForInactiveLayer_(self, layer):
		if layer.components:
			return False
		else:
			return True

	@objc.python_method
	def __file__(self):
		"""Please leave this method unchanged"""
		return __file__
<|endoftext|>


<commit_before># Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt

def execute(filters=None):
	if not filters: filters = {}

	columns = get_columns(filters)
	item_map = get_item_details()
	pl = get_price_list()
	last_purchase_rate = get_last_purchase_rate()
	bom_rate = get_item_bom_rate()
	val_rate_map = get_valuation_rate()

	precision = get_currency_precision or 2

	data = []
	for item in sorted(item_map):
		data.append([item, item_map[item]["item_name"],
			item_map[item]["description"], item_map[item]["stock_uom"],
			flt(last_purchase_rate.get(item, 0), precision),
			flt(val_rate_map.get(item, 0), precision),
			pl.get(item, {}).get("Selling"),
			pl.get(item, {}).get("Buying"),
			flt(bom_rate.get(item, 0), precision),
			flt(item_map[item]["standard_rate"], precision)
		])

	return columns, data

def get_currency_precision():
	company_currency = webnotes.conn.get_value("Company",
		webnotes.conn.get_default("company"), "default_currency")
	currency_format = webnotes.conn.get_value("Currency", company_currency, "number_format")

	from webnotes.utils import get_number_format_info
	return get_number_format_info(currency_format)[2]

def get_columns(filters):
	"""return columns based on filters"""

	columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", "UOM:Link/UOM:80",
		"Last Purchase Rate:Currency:90", "Valuation Rate:Currency:80",	"Sales Price List::80",
		"Purchase Price List::80", "BOM Rate:Currency:90", "Standard Rate:Currency:100"]

	return columns

def get_item_details():
	"""returns all items details"""

	item_map = {}

	for i in webnotes.conn.sql("select name, item_name, description, \
		stock_uom, standard_rate from tabItem \
		order by item_code", as_dict=1):
			item_map.setdefault(i.name, i)

	return item_map

def get_price_list():
	"""Get selling & buying price list of every item"""

	rate = {}

	price_list = webnotes.conn.sql("""select item_code, buying, selling,
		concat(price_list, " - ", currency, " ", ref_rate) as price
		from `tabItem Price`""", as_dict=1)

	for j in price_list:
		if j.price:
			rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price)
	item_rate_map = {}

	for item in rate:
		for buying_or_selling in rate[item]:
			item_rate_map.setdefault(item, {}).setdefault(buying_or_selling,
				", ".join(rate[item].get(buying_or_selling, [])))

	return item_rate_map

def get_last_purchase_rate():

	item_last_purchase_rate_map = {}

	query = """select * from (select
					result.item_code,
					result.purchase_rate
					from (
						(select
							po_item.item_code,
							po_item.item_name,
							po.transaction_date as posting_date,
							po_item.purchase_ref_rate,
							po_item.discount_rate,
							po_item.purchase_rate
						from `tabPurchase Order` po, `tabPurchase Order Item` po_item
						where po.name = po_item.parent and po.docstatus = 1)
						union
						(select
							pr_item.item_code,
							pr_item.item_name,
							pr.posting_date,
							pr_item.purchase_ref_rate,
							pr_item.discount_rate,
							pr_item.purchase_rate
						from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
						where pr.name = pr_item.parent and pr.docstatus = 1)
				) result
				order by result.item_code asc, result.posting_date desc) result_wrapper
				group by item_code"""

	for d in webnotes.conn.sql(query, as_dict=1):
		item_last_purchase_rate_map.setdefault(d.item_code, d.purchase_rate)

	return item_last_purchase_rate_map

def get_item_bom_rate():
	"""Get BOM rate of an item from BOM"""

	item_bom_map = {}

	for b in webnotes.conn.sql("""select item, (total_cost/quantity) as bom_rate
		from `tabBOM` where is_active=1 and is_default=1""", as_dict=1):
			item_bom_map.setdefault(b.item, flt(b.bom_rate))

	return item_bom_map

def get_valuation_rate():
	"""Get an average valuation rate of an item from all warehouses"""

	item_val_rate_map = {}

	for d in webnotes.conn.sql("""select item_code,
		sum(actual_qty*valuation_rate)/sum(actual_qty) as val_rate
		from tabBin where actual_qty > 0 group by item_code""", as_dict=1):
			item_val_rate_map.setdefault(d.item_code, d.val_rate)

	return item_val_rate_map
<commit_msg>decimal places fixed in item prices report<commit_after># Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt

def execute(filters=None):
	if not filters: filters = {}

	columns = get_columns(filters)
	item_map = get_item_details()
	pl = get_price_list()
	last_purchase_rate = get_last_purchase_rate()
	bom_rate = get_item_bom_rate()
	val_rate_map = get_valuation_rate()

	precision = get_currency_precision() or 2

	data = []
	for item in sorted(item_map):
		data.append([item, item_map[item]["item_name"],
			item_map[item]["description"], item_map[item]["stock_uom"],
			flt(last_purchase_rate.get(item, 0), precision),
			flt(val_rate_map.get(item, 0), precision),
			pl.get(item, {}).get("Selling"),
			pl.get(item, {}).get("Buying"),
			flt(bom_rate.get(item, 0), precision),
			flt(item_map[item]["standard_rate"], precision)
		])

	return columns, data

def get_currency_precision():
	company_currency = webnotes.conn.get_value("Company",
		webnotes.conn.get_default("company"), "default_currency")
	currency_format = webnotes.conn.get_value("Currency", company_currency, "number_format")

	from webnotes.utils import get_number_format_info
	return get_number_format_info(currency_format)[2]

def get_columns(filters):
	"""return columns based on filters"""

	columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", "UOM:Link/UOM:80",
		"Last Purchase Rate:Currency:90", "Valuation Rate:Currency:80",	"Sales Price List::80",
		"Purchase Price List::80", "BOM Rate:Currency:90", "Standard Rate:Currency:100"]

	return columns

def get_item_details():
	"""returns all items details"""

	item_map = {}

	for i in webnotes.conn.sql("select name, item_name, description, \
		stock_uom, standard_rate from tabItem \
		order by item_code", as_dict=1):
			item_map.setdefault(i.name, i)

	return item_map

def get_price_list():
	"""Get selling & buying price list of every item"""

	rate = {}

	price_list = webnotes.conn.sql("""select item_code, buying, selling,
		concat(price_list, " - ", currency, " ", ref_rate) as price
		from `tabItem Price`""", as_dict=1)

	for j in price_list:
		if j.price:
			rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price)
	item_rate_map = {}

	for item in rate:
		for buying_or_selling in rate[item]:
			item_rate_map.setdefault(item, {}).setdefault(buying_or_selling,
				", ".join(rate[item].get(buying_or_selling, [])))

	return item_rate_map

def get_last_purchase_rate():

	item_last_purchase_rate_map = {}

	query = """select * from (select
					result.item_code,
					result.purchase_rate
					from (
						(select
							po_item.item_code,
							po_item.item_name,
							po.transaction_date as posting_date,
							po_item.purchase_ref_rate,
							po_item.discount_rate,
							po_item.purchase_rate
						from `tabPurchase Order` po, `tabPurchase Order Item` po_item
						where po.name = po_item.parent and po.docstatus = 1)
						union
						(select
							pr_item.item_code,
							pr_item.item_name,
							pr.posting_date,
							pr_item.purchase_ref_rate,
							pr_item.discount_rate,
							pr_item.purchase_rate
						from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
						where pr.name = pr_item.parent and pr.docstatus = 1)
				) result
				order by result.item_code asc, result.posting_date desc) result_wrapper
				group by item_code"""

	for d in webnotes.conn.sql(query, as_dict=1):
		item_last_purchase_rate_map.setdefault(d.item_code, d.purchase_rate)

	return item_last_purchase_rate_map

def get_item_bom_rate():
	"""Get BOM rate of an item from BOM"""

	item_bom_map = {}

	for b in webnotes.conn.sql("""select item, (total_cost/quantity) as bom_rate
		from `tabBOM` where is_active=1 and is_default=1""", as_dict=1):
			item_bom_map.setdefault(b.item, flt(b.bom_rate))

	return item_bom_map

def get_valuation_rate():
	"""Get an average valuation rate of an item from all warehouses"""

	item_val_rate_map = {}

	for d in webnotes.conn.sql("""select item_code,
		sum(actual_qty*valuation_rate)/sum(actual_qty) as val_rate
		from tabBin where actual_qty > 0 group by item_code""", as_dict=1):
			item_val_rate_map.setdefault(d.item_code, d.val_rate)

	return item_val_rate_map
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
###############################################################################
#
# ODOO (ex OpenERP)
# Open Source Management Solution
# Copyright (C) 2001-2015 Micronaet S.r.l. (<https://micronaet.com>)
# Developer: Nicola Riolini @thebrush (<https://it.linkedin.com/in/thebrush>)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

import os
import sys
import logging
import openerp
import openerp.netsvc as netsvc
import openerp.addons.decimal_precision as dp
from openerp.osv import fields, osv, expression
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from openerp import SUPERUSER_ID#, api
from openerp import tools
from openerp.tools.translate import _
from openerp.tools.float_utils import float_round as round
from openerp.tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    float_compare)

_logger = logging.getLogger(__name__)

class SaleOrderLine(osv.osv):
    """ Model name: Sale order line
    """

    _inherit = 'sale.order.line'

    _columns = {
        'ready_deadline': fields.boolean('Ready deadline',
        help='This product has no deadline was order and keep as ready'),
        }

class ResCompany(osv.osv):
    """ Model name: Res company
    """

    _inherit = 'res.company'

    # TODO Parameters:
    _columns = {
        }

class ProductProduct(osv.osv):
    """ Model name: ProductProduct
    """

    _inherit = 'product.product'

    def round_interger_order(self, number, approx=1, mode='over'):
        ''' Approx function for order quantity:
            Approx number to value approx (integer > 1)
            Mode =
                'normal' (nothing is done)
                'over' (to the next approx level  exceeded)
                'under' (to the next approx level  exceeded)
        '''
        if approx <= 1:
            return number

        if mode == 'over':
            extra = (approx if number % approx > 0.001 else 0)
        #elif mode == 'under':
        #    extra = (approx if number % approx > 0.001 else 0)
        else:
            extra = 0.0
        return round(number / approx , 0) * approx + extra

    _columns = {
        'manual_stock_level': fields.boolean('Manual stock level',
            help='Manual has fixed q., not manual will be updated automatic'),

        # ---------------------------------------------------------------------
        # Period day for range:
        # ---------------------------------------------------------------------
        'day_leadtime': fields.integer('Lead time',
            help='Lead time period in days for receive purchase in stock '),
        'day_min_level': fields.integer('Min day time',
            help='Secure min time period in days for receive purchase in stock'
            ),
        'day_max_level': fields.integer('Max day time',
            help='Secure max time period in days for purchase'),
        'day_max_ready_level': fields.integer('Ready day time',
            help='Secure extra order for ready purchase product '
                '(for long leadtime)'),

        # ---------------------------------------------------------------------
        # Quantity fields:
        # ---------------------------------------------------------------------
        'approx_integer': fields.integer(
            'Approx (int)', help='Approx integer value, ex. 50'),
        'approx_mode': fields.selection([
            ('normal', 'Normal (nothing)'),
            ('under', 'Under approximate'),
            ('over', 'Over approximate'),
            ], 'Approx mode',
            help='Normal nothing, Under: 145 approx 50 = 100 (not 150)'
                '105 approx 50 = 150 (not 100)',),

        'medium_stock_qty': fields.float('Calculated medium', digits=(16, 4),
            help='Min q. level for trigger the purchase order'),
        'min_stock_level': fields.float('Min stock level', digits=(16, 4),
            help='Min q. level for trigger the purchase order'),
        'max_stock_level': fields.float('Max stock level', digits=(16, 4),
            help='Max q. for stock level when trigger the purchase order'),
        'ready_stock_level': fields.float('Max stock level ready',
            digits=(16, 4),
            help='Max q. for stock level when trigger the purchase order'),
        }

    _defaults = {
        'approx_integer': lambda *x: 50,
        'approx_mode': lambda *x: 'over',

        'day_leadtime': lambda *x: 7,
        'day_min_level': lambda *x: 10,
        'day_max_level': lambda *x: 37,
        }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>generic bugfix (fast message)<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
###############################################################################
#
# ODOO (ex OpenERP)
# Open Source Management Solution
# Copyright (C) 2001-2015 Micronaet S.r.l. (<https://micronaet.com>)
# Developer: Nicola Riolini @thebrush (<https://it.linkedin.com/in/thebrush>)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

import os
import sys
import logging
import openerp
import openerp.netsvc as netsvc
import openerp.addons.decimal_precision as dp
from openerp.osv import fields, osv, expression
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from openerp import SUPERUSER_ID#, api
from openerp import tools
from openerp.tools.translate import _
from openerp.tools.float_utils import float_round as round
from openerp.tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    float_compare)

_logger = logging.getLogger(__name__)

class SaleOrderLine(osv.osv):
    """ Model name: Sale order line
    """

    _inherit = 'sale.order.line'

    _columns = {
        'ready_deadline': fields.boolean('Ready deadline',
        help='This product has no deadline was order and keep as ready'),
        }

class ResCompany(osv.osv):
    """ Model name: Res company
    """

    _inherit = 'res.company'

    # TODO Parameters:
    _columns = {
        }

class ProductProduct(osv.osv):
    """ Model name: ProductProduct
    """

    _inherit = 'product.product'

    def round_interger_order(self, number, approx=1, mode='over'):
        ''' Approx function for order quantity:
            Approx number to value approx (integer > 1)
            Mode =
                'normal' (nothing is done)
                'over' (to the next approx level  exceeded)
                'under' (to the next approx level  exceeded)
        '''
        if approx <= 1:
            return number

        if mode == 'over':
            extra = (approx if number % approx > 0.001 else 0)
            return number // approx + extra

        elif mode == 'under':
            return number // approx

        elif mode == 'normal':
            return round(number / approx , 0) * approx
        else:
             return number

    _columns = {
        'manual_stock_level': fields.boolean('Manual stock level',
            help='Manual has fixed q., not manual will be updated automatic'),

        # ---------------------------------------------------------------------
        # Period day for range:
        # ---------------------------------------------------------------------
        'day_leadtime': fields.integer('Lead time',
            help='Lead time period in days for receive purchase in stock '),
        'day_min_level': fields.integer('Min day time',
            help='Secure min time period in days for receive purchase in stock'
            ),
        'day_max_level': fields.integer('Max day time',
            help='Secure max time period in days for purchase'),
        'day_max_ready_level': fields.integer('Ready day time',
            help='Secure extra order for ready purchase product '
                '(for long leadtime)'),

        # ---------------------------------------------------------------------
        # Quantity fields:
        # ---------------------------------------------------------------------
        'approx_integer': fields.integer(
            'Approx (int)', help='Approx integer value, ex. 50'),
        'approx_mode': fields.selection([
            ('normal', 'Normal (nothing)'),
            ('under', 'Under approximate'),
            ('over', 'Over approximate'),
            ], 'Approx mode',
            help='Normal nothing, Under: 145 approx 50 = 100 (not 150)'
                '105 approx 50 = 150 (not 100)',),

        'medium_stock_qty': fields.float('Calculated medium', digits=(16, 4),
            help='Min q. level for trigger the purchase order'),
        'min_stock_level': fields.float('Min stock level', digits=(16, 4),
            help='Min q. level for trigger the purchase order'),
        'max_stock_level': fields.float('Max stock level', digits=(16, 4),
            help='Max q. for stock level when trigger the purchase order'),
        'ready_stock_level': fields.float('Max stock level ready',
            digits=(16, 4),
            help='Max q. for stock level when trigger the purchase order'),
        }

    _defaults = {
        'approx_integer': lambda *x: 50,
        'approx_mode': lambda *x: 'over',

        'day_leadtime': lambda *x: 7,
        'day_min_level': lambda *x: 10,
        'day_max_level': lambda *x: 37,
        }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


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

from typing import Union, Tuple, Optional
from copy import deepcopy

from sklearn.ensemble.forest import ExtraTreesClassifier \
    as ExtraTreesClassifierClass

from sklearn_porter.estimator.EstimatorApiABC import EstimatorApiABC
from sklearn_porter.estimator.EstimatorBase import EstimatorBase
from sklearn_porter.enums import Method, Language, Template
from sklearn_porter.utils import get_logger

L = get_logger(__name__)

class ExtraTreesClassifier(EstimatorBase, EstimatorApiABC):
    """Extract model data and port an ExtraTreesClassifier classifier."""

    estimator = None  # type: ExtraTreesClassifierClass

    def __init__(self, estimator: ExtraTreesClassifierClass):
        super().__init__(estimator)
        L.info('Create specific estimator `%s`.', self.estimator_name)
        est = self.estimator  # alias

        self.meta_info = dict()
        self.model_data = dict()

    def port(
            self,
            method: Optional[Method] = None,
            language: Optional[Language] = None,
            template: Optional[Template] = None,
            **kwargs
    ) -> Union[str, Tuple[str, str]]:
        """
        Port an estimator.

        Parameters
        ----------
        method : Method
            The required method.
        language : Language
            The required language.
        template : Template
            The required template.
        kwargs

        Returns
        -------
        The ported estimator.
        """
        method, language, template = self.check(
            method=method, language=language, template=template)

        # Arguments:
        kwargs.setdefault('method_name', method.value)
        converter = kwargs.get('converter')

        # Placeholders:
        plas = deepcopy(self.placeholders)  # alias
        plas.update(dict(
            class_name=kwargs.get('class_name'),
            method_name=kwargs.get('method_name'),
        ))
        plas.update(self.meta_info)

        # Templates:
        temps = self._load_templates(language.value.KEY)

        return str(self.estimator)
<commit_msg>feature/oop-api-refactoring: Adapt the ExtraTreesClassifier estimator<commit_after># -*- coding: utf-8 -*-

from sklearn.ensemble import ExtraTreesClassifier as ExtraTreesClassifierClass

from sklearn_porter.estimator.EstimatorBase import EstimatorBase
from sklearn_porter.estimator.RandomForestClassifier import \
    RandomForestClassifier
from sklearn_porter.utils import get_logger

L = get_logger(__name__)

class ExtraTreesClassifier(RandomForestClassifier, EstimatorBase):
    """Extract model data and port an ExtraTreesClassifier classifier."""

    estimator = None  # type: ExtraTreesClassifierClass

    def __init__(self, estimator: ExtraTreesClassifierClass):
        super().__init__(estimator)
<|endoftext|>


<commit_before>from django.http.response import JsonResponse
from rest_framework import permissions
from rest_framework.generics import CreateAPIView

from agir.donations.serializers import (
    CreateDonationSerializer,
    SendDonationSerializer,
    TYPE_MONTHLY,
)
from agir.people.models import Person
from django.db import transaction
from agir.payments.actions.payments import create_payment
from agir.donations.allocations import create_monthly_donation
import json
from agir.donations.apps import DonsConfig
from agir.payments import payment_modes
from agir.payments.models import Subscription
from django.urls import reverse
from agir.donations.views import DONATION_SESSION_NAMESPACE
from agir.donations.tasks import send_monthly_donation_confirmation_email

class CreateDonationAPIView(CreateAPIView):
    permission_classes = (permissions.AllowAny,)
    serializer_class = CreateDonationSerializer
    queryset = Person.objects.none()

class SendDonationAPIView(CreateAPIView):
    permission_classes = (permissions.AllowAny,)
    serializer_class = SendDonationSerializer
    queryset = Person.objects.none()

    def clear_session(self):
        del self.request.session[DONATION_SESSION_NAMESPACE]

    # Create person with only its model fields in validated_data
    def create_person(self, validated_data):
        clean_data = {}
        for attr, value in validated_data.items():
            if getattr(Person, attr, False):
                clean_data[attr] = value

        person = Person.objects.create(**clean_data)
        person.save()
        return person

    def update_person(self, instance, validated_data):
        for attr, value in validated_data.items():
            # Add newsletters
            if attr == "subscribed_lfi":
                if Person.NEWSLETTER_LFI not in instance.newsletters:
                    instance.newsletters.append(Person.NEWSLETTER_LFI)
                continue
            if attr == "subscribed_2022":
                if Person.NEWSLETTER_2022 not in instance.newsletters:
                    instance.newsletters.append(Person.NEWSLETTER_2022)
                if Person.NEWSLETTER_2022_EXCEPTIONNEL not in instance.newsletters:
                    instance.newsletters.append(Person.NEWSLETTER_2022_EXCEPTIONNEL)
                continue
            setattr(instance, attr, value)
        instance.save()
        return instance

    def post(self, request, *args, **kwargs):

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data
        amount = validated_data["amount"]
        payment_mode = validated_data["payment_mode"]
        connected_user = False
        person = None

        # Check user connected
        if request.user.is_authenticated and request.user.person is not None:
            if validated_data["email"] == request.user.person.email:
                connected_user = True
                del validated_data["email"]

        # User exist and connected : update user informations
        if connected_user:
            person = Person.objects.get(pk=request.user.person.id)
            # Update newsletters only if checked
            if not validated_data["subscribed_lfi"]:
                del validated_data["subscribed_lfi"]

            if not validated_data["subscribed_2022"]:
                del validated_data["subscribed_2022"]

            self.update_person(person, validated_data)

        allocations = {
            str(allocation["group"].id): allocation["amount"]
            for allocation in validated_data.get("allocations", [])
        }

        if "allocations" in validated_data:
            validated_data["allocations"] = json.dumps(allocations)

        payment_type = DonsConfig.PAYMENT_TYPE

        # Monthly payments
        if validated_data["type"] == TYPE_MONTHLY:
            payment_type = DonsConfig.SUBSCRIPTION_TYPE

            # Confirm email if the user is unknown
            if not connected_user:
                email = validated_data["email"]
                del validated_data["email"]
                send_monthly_donation_confirmation_email.delay(
                    confirmation_view_name="monthly_donation_confirm",
                    email=email,
                    subscription_total=amount,
                    **validated_data,
                )
                self.clear_session()
                return JsonResponse(
                    {"next": reverse("monthly_donation_confirmation_email_sent")}
                )

            # Check user already monthly donator
            if Subscription.objects.filter(
                person=person, status=Subscription.STATUS_ACTIVE, mode=payment_mode,
            ):
                # stocker toutes les infos en session
                # attention à ne pas juste modifier le dictionnaire existant,
                # parce que la session ne se "rendrait pas compte" qu'elle a changé
                # et cela ne serait donc pas persisté
                self.request.session[DONATION_SESSION_NAMESPACE] = {
                    "new_subscription": {
                        "type": payment_type,
                        "mode": payment_mode,
                        "subscription_total": amount,
                        "meta": validated_data,
                    },
                    **self.request.session.get(DONATION_SESSION_NAMESPACE, {}),
                }
                return JsonResponse({"next": reverse("already_has_subscription")})

            with transaction.atomic():
                subscription = create_monthly_donation(
                    person=person,
                    mode=payment_mode,
                    subscription_total=amount,
                    allocations=allocations,
                    meta=validated_data,
                    type=payment_type,
                )

            self.clear_session()
            return JsonResponse(
                {"next": reverse("subscription_page", args=[subscription.pk])}
            )

        # Direct payments
        with transaction.atomic():
            payment = create_payment(
                person=person,
                type=payment_type,
                mode=payment_mode,
                price=amount,
                meta=validated_data,
                **kwargs,
            )

        self.clear_session()
        return JsonResponse({"next": payment.get_payment_url()})
<commit_msg>try to solve black<commit_after>from django.http.response import JsonResponse
from rest_framework import permissions
from rest_framework.generics import CreateAPIView

from agir.donations.serializers import (
    CreateDonationSerializer,
    SendDonationSerializer,
    TYPE_MONTHLY,
)
from agir.people.models import Person
from django.db import transaction
from agir.payments.actions.payments import create_payment
from agir.donations.allocations import create_monthly_donation
import json
from agir.donations.apps import DonsConfig
from agir.payments import payment_modes
from agir.payments.models import Subscription
from django.urls import reverse
from agir.donations.views import DONATION_SESSION_NAMESPACE
from agir.donations.tasks import send_monthly_donation_confirmation_email

class CreateDonationAPIView(CreateAPIView):
    permission_classes = (permissions.AllowAny,)
    serializer_class = CreateDonationSerializer
    queryset = Person.objects.none()

class SendDonationAPIView(CreateAPIView):
    permission_classes = (permissions.AllowAny,)
    serializer_class = SendDonationSerializer
    queryset = Person.objects.none()

    def clear_session(self):
        del self.request.session[DONATION_SESSION_NAMESPACE]

    # Create person with only its model fields in validated_data
    def create_person(self, validated_data):
        clean_data = {}
        for attr, value in validated_data.items():
            if getattr(Person, attr, False):
                clean_data[attr] = value

        person = Person.objects.create(**clean_data)
        person.save()
        return person

    def update_person(self, instance, validated_data):
        for attr, value in validated_data.items():
            # Add newsletters
            if attr == "subscribed_lfi":
                if Person.NEWSLETTER_LFI not in instance.newsletters:
                    instance.newsletters.append(Person.NEWSLETTER_LFI)
                continue
            if attr == "subscribed_2022":
                if Person.NEWSLETTER_2022 not in instance.newsletters:
                    instance.newsletters.append(Person.NEWSLETTER_2022)
                if Person.NEWSLETTER_2022_EXCEPTIONNEL not in instance.newsletters:
                    instance.newsletters.append(Person.NEWSLETTER_2022_EXCEPTIONNEL)
                continue
            setattr(instance, attr, value)
        instance.save()
        return instance

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data
        amount = validated_data["amount"]
        payment_mode = validated_data["payment_mode"]
        connected_user = False
        person = None

        # Check user connected
        if request.user.is_authenticated and request.user.person is not None:
            if validated_data["email"] == request.user.person.email:
                connected_user = True
                del validated_data["email"]

        # User exist and connected : update user informations
        if connected_user:
            person = Person.objects.get(pk=request.user.person.id)
            # Update newsletters only if checked
            if not validated_data["subscribed_lfi"]:
                del validated_data["subscribed_lfi"]

            if not validated_data["subscribed_2022"]:
                del validated_data["subscribed_2022"]

            self.update_person(person, validated_data)

        allocations = {
            str(allocation["group"].id): allocation["amount"]
            for allocation in validated_data.get("allocations", [])
        }

        if "allocations" in validated_data:
            validated_data["allocations"] = json.dumps(allocations)

        payment_type = DonsConfig.PAYMENT_TYPE

        # Monthly payments
        if validated_data["type"] == TYPE_MONTHLY:
            payment_type = DonsConfig.SUBSCRIPTION_TYPE

            # Confirm email if the user is unknown
            if not connected_user:
                email = validated_data["email"]
                del validated_data["email"]
                send_monthly_donation_confirmation_email.delay(
                    confirmation_view_name="monthly_donation_confirm",
                    email=email,
                    subscription_total=amount,
                    **validated_data,
                )
                self.clear_session()
                return JsonResponse(
                    {"next": reverse("monthly_donation_confirmation_email_sent")}
                )

            # Check user already monthly donator
            if Subscription.objects.filter(
                person=person, status=Subscription.STATUS_ACTIVE, mode=payment_mode,
            ):
                # stocker toutes les infos en session
                # attention à ne pas juste modifier le dictionnaire existant,
                # parce que la session ne se "rendrait pas compte" qu'elle a changé
                # et cela ne serait donc pas persisté
                self.request.session[DONATION_SESSION_NAMESPACE] = {
                    "new_subscription": {
                        "type": payment_type,
                        "mode": payment_mode,
                        "subscription_total": amount,
                        "meta": validated_data,
                    },
                    **self.request.session.get(DONATION_SESSION_NAMESPACE, {}),
                }
                return JsonResponse({"next": reverse("already_has_subscription")})

            with transaction.atomic():
                subscription = create_monthly_donation(
                    person=person,
                    mode=payment_mode,
                    subscription_total=amount,
                    allocations=allocations,
                    meta=validated_data,
                    type=payment_type,
                )

            self.clear_session()
            return JsonResponse(
                {"next": reverse("subscription_page", args=[subscription.pk])}
            )

        # Direct payments
        with transaction.atomic():
            payment = create_payment(
                person=person,
                type=payment_type,
                mode=payment_mode,
                price=amount,
                meta=validated_data,
                **kwargs,
            )

        self.clear_session()
        return JsonResponse({"next": payment.get_payment_url()})
<|endoftext|>


<commit_before>"""
A decorator for management commands (or any class method) to ensure that there is
only ever one process running the method at any one time.

Requires lockfile - (pip install lockfile)

Author: Ross Lawley
"""

import time
import logging

from lockfile import FileLock, AlreadyLocked, LockTimeout
from django.conf import settings

# Lock timeout value - how long to wait for the lock to become available.
# Default behavior is to never wait for the lock to be available (fail fast)
LOCK_WAIT_TIMEOUT = getattr(settings, "DEFAULT_LOCK_WAIT_TIMEOUT", -1)

def handle_lock(handle):
    """
    Decorate the handle method with a file lock to ensure there is only ever
    one process running at any one time.
    """

    def wrapper(self, *args, **options):
        start_time = time.time()
        try:
            verbosity = int(options.get('verbosity', 0))
        except ValueError:
            verbosity = 0
        logger = logging.getLogger(self.__module__)
        if verbosity == 0:
            logger.level = logging.WARNING
        elif verbosity == 1:
            logger.level = logging.INFO
        else:
            logger.level = logging.DEBUG

        logger.debug("-" * 72)

        lock_name = self.__module__.split('.').pop()
        lock = FileLock(lock_name)

        logger.debug("%s - acquiring lock..." % lock_name)
        try:
            lock.acquire(LOCK_WAIT_TIMEOUT)
        except AlreadyLocked:
            logger.debug("lock already in place. quitting.")
            return
        except LockTimeout:
            logger.debug("waiting for the lock timed out. quitting.")
            return
        logger.debug("acquired.")

        try:
            handle(self, logger, *args, **options)
        except:
            import traceback
            logging.warn("Command Failed")
            logging.warn('=' * 72)
            logging.warn(traceback.format_exc())
            logging.warn('=' * 72)

        logger.debug("releasing lock...")
        lock.release()
        logger.debug("released.")

        logger.info("done in %.2f seconds" % (time.time() - start_time))
        return

    return wrapper
<commit_msg>add LOCK_ROOT for lock_handler<commit_after>"""
A decorator for management commands (or any class method) to ensure that there is
only ever one process running the method at any one time.

Requires lockfile - (pip install lockfile)

Author: Ross Lawley
"""

import logging
import os
import time

from lockfile import FileLock, AlreadyLocked, LockTimeout
from django.conf import settings

# Lock timeout value - how long to wait for the lock to become available.
# Default behavior is to never wait for the lock to be available (fail fast)
LOCK_WAIT_TIMEOUT = getattr(settings, 'DEFAULT_LOCK_WAIT_TIMEOUT', -1)
LOCK_ROOT = getattr(settings, 'LOCK_ROOT', '')

def handle_lock(handle):
    """
    Decorate the handle method with a file lock to ensure there is only ever
    one process running at any one time.
    """

    def wrapper(self, *args, **options):
        start_time = time.time()
        try:
            verbosity = int(options.get('verbosity', 0))
        except ValueError:
            verbosity = 0
        logger = logging.getLogger(self.__module__)
        if verbosity == 0:
            logger.level = logging.WARNING
        elif verbosity == 1:
            logger.level = logging.INFO
        else:
            logger.level = logging.DEBUG

        logger.debug("-" * 72)

        lock_name = self.__module__.split('.').pop()
        lock = FileLock(os.path.join(LOCK_ROOT, lock_name))

        logger.debug("%s - acquiring lock..." % lock_name)
        try:
            lock.acquire(LOCK_WAIT_TIMEOUT)
        except AlreadyLocked:
            logger.debug("lock already in place. quitting.")
            return
        except LockTimeout:
            logger.debug("waiting for the lock timed out. quitting.")
            return
        logger.debug("acquired.")

        try:
            handle(self, logger, *args, **options)
        except:
            import traceback
            logging.warn("Command Failed")
            logging.warn('=' * 72)
            logging.warn(traceback.format_exc())
            logging.warn('=' * 72)

        logger.debug("releasing lock...")
        lock.release()
        logger.debug("released.")

        logger.info("done in %.2f seconds" % (time.time() - start_time))
        return

    return wrapper
<|endoftext|>


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

import argparse

import numpy as np

import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

import h5py
import qusp

def main():
    # parse command-line arguments
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("--verbose", action="store_true",
        help="print verbose output")
    parser.add_argument("-i","--input", type=str, default=None,
        help="fitspec results file")
    parser.add_argument("-o","--output", type=str, default=None,
        help="output filename base")
    parser.add_argument("--max-rows", type=int, default=0,
        help="max number of entries to plot")
    parser.add_argument("--elev", type=float, default=None,
        help="elevation angle")
    parser.add_argument("--azim", type=float, default=None,
        help="azimuthal angle")
    parser.add_argument("--stride", type=int, default=1,
        help="stride")
    args = parser.parse_args()

    infile = h5py.File(args.input)

    ra_list = []
    dec_list = []
    redshift_list = []

    counter = 0

    for (target_string, h5group) in infile['delta_field'].iteritems():
        counter += 1
        if (counter % 10000) == 0:
            print ' processing target # %d ...' % (counter)
        if args.max_rows and counter > args.max_rows:
            break
        ra = np.radians(h5group.attrs['ra'])
        dec = np.radians(h5group.attrs['dec'])
        z = h5group.attrs['z']
        #redshift = h5group['absorber_z'].value
        #redshift = np.array([max(1.9, 1026*(1+3.5)/1216-1), z])

        redshift = np.array([z])

        redshift_list.append(redshift)
        ra_list.append(ra*np.ones_like(redshift))
        dec_list.append(dec*np.ones_like(redshift))

    # flatten lists
    ra = np.concatenate(ra_list)[::args.stride]
    dec = np.concatenate(dec_list)[::args.stride]
    redshift = np.concatenate(redshift_list)[::args.stride]

    zmax = 7
    max_scale = 1.2

    if args.output:

        fig = plt.figure(figsize=(14,8))
        ax = plt.subplot(111, polar=True)

        ax.plot(ra, redshift, marker='.', markersize=1, lw=0)

        ax.set_rmax(max_scale*zmax)
        az.set_rlabel_position(90)
        ax.grid(True)
        fig.savefig(args.output+'flat.png')

        ab_x = redshift * np.cos(ra) * np.sin(dec)
        ab_y = redshift * np.sin(ra) * np.sin(dec)
        ab_z = redshift * np.cos(dec)

        fig = plt.figure(figsize=(14,8))
        ax = fig.add_subplot(111, projection='3d')
        #ax.set_aspect('equal')

        ax.scatter(ab_x, ab_y, ab_z, marker='.', s=.1)

        ax.scatter(ab_x, ab_y, zs=0, zdir='z', marker='.', s=.1)
        ax.scatter(ab_y, ab_z, zs=-max_scale*zmax, zdir='x', marker='.', s=.1)
        ax.scatter(ab_x, ab_z, zs=+max_scale*zmax, zdir='y', marker='.', s=.1)

        def plot_shell(r):
            u = np.linspace(0, 2 * np.pi, 100)
            v = np.linspace(0, np.pi/2, 100)

            x = r * np.outer(np.cos(u), np.sin(v))
            y = r * np.outer(np.sin(u), np.sin(v))
            z = r * np.outer(np.ones(np.size(u)), np.cos(v))
            ax.plot_surface(x, y, z,  rstride=4, cstride=4, color='r', alpha=.05, edgecolor='None')

            x = r * np.cos(u)
            y = r * np.sin(u)
            ax.plot(x, y, zs=0, zdir='z', color='r', alpha=.2)
            ax.plot(x[:50], y[:50], zs=-max_scale*zmax, zdir='x', color='r', alpha=.2)
            ax.plot(x[:50], y[:50], zs=+max_scale*zmax, zdir='y', color='r', alpha=.2)

        for r in np.arange(1, zmax+1, 1):
            plot_shell(r)

        ax.set_xlim3d(-max_scale*zmax, max_scale*zmax)
        ax.set_ylim3d(-max_scale*zmax, max_scale*zmax)
        ax.set_zlim3d(0, max_scale*zmax)

        ax.view_init(args.elev, args.azim)

        fig.savefig(args.output+'3d.png', bbox_inches='tight')

if __name__ == '__main__':
    main()

<commit_msg>add ra, dec distribution plot<commit_after>#!/usr/bin/env python

import argparse

import numpy as np

import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

import h5py
import qusp

from astropy import units as u
from astropy.coordinates import SkyCoord

def main():
    # parse command-line arguments
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("--verbose", action="store_true",
        help="print verbose output")
    parser.add_argument("-i","--input", type=str, default=None,
        help="fitspec results file")
    parser.add_argument("-o","--output", type=str, default=None,
        help="output filename base")
    parser.add_argument("--max-rows", type=int, default=0,
        help="max number of entries to plot")
    parser.add_argument("--elev", type=float, default=None,
        help="elevation angle")
    parser.add_argument("--azim", type=float, default=None,
        help="azimuthal angle")
    parser.add_argument("--stride", type=int, default=1,
        help="stride")
    args = parser.parse_args()

    infile = h5py.File(args.input)

    ra_list = []
    dec_list = []
    redshift_list = []

    counter = 0

    for (target_string, h5group) in infile['delta_field'].iteritems():
        counter += 1
        if (counter % 10000) == 0:
            print ' processing target # %d ...' % (counter)
        if args.max_rows and counter > args.max_rows:
            break
        ra = np.radians(h5group.attrs['ra'])
        dec = np.radians(h5group.attrs['dec'])
        z = h5group.attrs['z']
        #redshift = h5group['absorber_z'].value
        #redshift = np.array([max(1.9, 1026*(1+3.5)/1216-1), z])

        redshift = np.array([z])

        redshift_list.append(redshift)
        ra_list.append(ra*np.ones_like(redshift))
        dec_list.append(dec*np.ones_like(redshift))

    # flatten lists
    ra = np.concatenate(ra_list)[::args.stride]
    dec = np.concatenate(dec_list)[::args.stride]
    redshift = np.concatenate(redshift_list)[::args.stride]

    zmax = 7
    max_scale = 1.2

    print ra.min(), ra.max()
    print dec.min(), dec.max()

    if args.output:

        ######################
        # z distribution
        ######################

        fig = plt.figure(figsize=(14,8))
        ax = plt.subplot(111, polar=True)

        ax.plot(ra, redshift, marker='.', markersize=1, lw=0)

        ax.set_rmax(max_scale*zmax)
        ax.set_rlabel_position(90)
        ax.grid(True)
        fig.savefig(args.output+'flat.png')

        #######################
        # ra, dec distribution
        #######################

        fig = plt.figure(figsize=(14,8))
        ax = plt.subplot(111, projection='hammer')

        l = np.linspace(0, 360, 100, endpoint=False)
        galactic_plane = SkyCoord(l=l*u.degree, b=np.zeros_like(l)*u.degree, frame='galactic').icrs

        aitoff_ra = np.remainder(galactic_plane.ra.degree+90+360-0,360)
        ind = aitoff_ra > 180
        aitoff_ra[ind] -= 360
        aitoff_ra = -aitoff_ra

        ax.plot(np.radians(aitoff_ra), galactic_plane.dec.radian, lw=0, marker='.')

        tick_labels = np.array([210, 240, 270, 300, 330, 0, 30, 60, 90, 120, 150])
        #tick_labels = np.remainder(tick_labels+360+org,360)
        ax.set_xticklabels(tick_labels)

        ax.plot(ra, dec, marker='.', markersize=1, lw=0)
        ax.grid(True)
        fig.savefig(args.output+'aitoff.png')

        #######################
        # 3D distribution
        #######################

        fig = plt.figure(figsize=(14,8))
        ax = fig.add_subplot(111, projection='3d')
        #ax.set_aspect('equal')

        # plot points in 3d
        ab_x = redshift * np.cos(ra) * np.sin(np.pi/2-dec)
        ab_y = redshift * np.sin(ra) * np.sin(np.pi/2-dec)
        ab_z = redshift * np.cos(np.pi/2-dec)
        ax.scatter(ab_x, ab_y, ab_z, marker='.', s=.1)

        # 2d projections
        ax.scatter(ab_x, ab_y, zs=-0.17*max_scale*zmax, zdir='z', marker='.', s=.1)
        ax.scatter(ab_y, ab_z, zs=-max_scale*zmax, zdir='x', marker='.', s=.1)
        ax.scatter(ab_x, ab_z, zs=+max_scale*zmax, zdir='y', marker='.', s=.1)

        # draw shells
        def plot_shell(r):
            # 3d
            u = np.linspace(0, 2 * np.pi, 100)
            v = np.linspace(0, np.pi/2, 100)
            x = r * np.outer(np.cos(u), np.sin(v))
            y = r * np.outer(np.sin(u), np.sin(v))
            z = r * np.outer(np.ones(np.size(u)), np.cos(v))
            ax.plot_surface(x, y, z,  rstride=4, cstride=4, color='r', alpha=.05, edgecolor='None')
            # 2d
            x = r * np.cos(u)
            y = r * np.sin(u)

            ind = (y > -0.17*max_scale*zmax)
            ax.plot(x, y, zs=-0.17*max_scale*zmax, zdir='z', color='r', alpha=.4, marker='.', lw=0, ms=1)
            ax.plot(x[ind], y[ind], zs=-max_scale*zmax, zdir='x', color='r', alpha=.4, marker='.', lw=0, ms=1)
            ax.plot(x[ind], y[ind], zs=+max_scale*zmax, zdir='y', color='r', alpha=.4, marker='.', lw=0, ms=1)
        for r in np.arange(1, zmax+1, 1):
            plot_shell(r)

        ax.set_xlim3d(-max_scale*zmax, max_scale*zmax)
        ax.set_ylim3d(-max_scale*zmax, max_scale*zmax)
        ax.set_zlim3d(-0.17*max_scale*zmax, max_scale*zmax)
        # set viewing angle
        ax.view_init(args.elev, args.azim)
        fig.savefig(args.output+'3d.png', bbox_inches='tight')

if __name__ == '__main__':
    main()

<|endoftext|>