<commit_before>import os
import errno
import shutil
from pprint import pformat

import pyblish.api
from mindbender import api, io

class IntegrateMindbenderAsset(pyblish.api.InstancePlugin):
    """Write to files and metadata

    This plug-in exposes your data to others by encapsulating it
    into a new version.

    Schema:
        Data is written in the following format.
         ____________________
        |                    |
        | version            |
        |  ________________  |
        | |                | |
        | | representation | |
        | |________________| |
        | |                | |
        | | ...            | |
        | |________________| |
        |____________________|

    """

    label = "Integrate Mindbender Asset"
    order = pyblish.api.IntegratorOrder
    families = [
        "mindbender.model",
        "mindbender.rig",
        "mindbender.animation",
        "mindbender.lookdev",
        "mindbender.historyLookdev",
        "mindbender.group",
    ]

    def process(self, instance):
        # Required environment variables
        PROJECT = os.environ["MINDBENDER_PROJECT"]
        ASSET = instance.data.get("asset") or os.environ["MINDBENDER_ASSET"]
        SILO = os.environ["MINDBENDER_SILO"]
        LOCATION = os.getenv("MINDBENDER_LOCATION")

        representation_lables = {".ma": "Maya Ascii",
                                 ".source": "Original source file",
                                 ".abc": "Alembic"}

        context = instance.context
        # Atomicity
        #
        # Guarantee atomic publishes - each asset contains
        # an identical set of members.
        #     __
        #    /     o
        #   /       \
        #  |    o    |
        #   \       /
        #    o   __/
        #
        assert all(result["success"] for result in context.data["results"]), (
            "Atomicity not held, aborting.")

        # Assemble
        #
        #       |
        #       v
        #  --->   <----
        #       ^
        #       |
        #
        stagingdir = instance.data.get("stagingDir")
        assert stagingdir, ("Incomplete instance \"%s\": "
                            "Missing reference to staging area." % instance)

        self.log.debug("Establishing staging directory @ %s" % stagingdir)

        project = io.find_one({"type": "project"})
        asset = io.find_one({"name": ASSET})

        assert all([project, asset]), "This is bug"

        subset = io.find_one({
            "type": "subset",
            "parent": asset["_id"],
            "name": instance.data["subset"]
        })

        if subset is None:
            subset_name = instance.data["subset"]
            self.log.info("Subset '%s' not found, creating.." % subset_name)

            _id = io.insert_one({
                "schema": "mindbender-core:subset-2.0",
                "type": "subset",
                "name": subset_name,
                "data": {},
                "parent": asset["_id"]
            }).inserted_id

            subset = io.find_one({"_id": _id})

        # get next version
        latest_version = io.find_one({"type": "version",
                                      "parent": subset["_id"]},
                                     {"name": True},
                                     sort={"name": -1})
        next_version = latest_version["name"] + 1 or 1

        self.log.debug("Next version: %i" % next_version)

        version = self.create_version(subset, next_version, [LOCATION])
        version["data"] = self.create_data(context, instance)

        self.backwards_compatiblity(instance, subset, version)

        self.log.debug("Creating version: %s" % pformat(version))
        version_id = io.insert_one(version).inserted_id

        # Write to disk
        #          _
        #         | |
        #        _| |_
        #    ____\   /
        #   |\    \ / \
        #   \ \    v   \
        #    \ \________.
        #     \|________|
        #
        template_data = {
            "root": api.registered_root(),
            "project": PROJECT,
            "silo": SILO,
            "asset": ASSET,
            "subset": subset["name"],
            "version": version["name"],
        }

        template_publish = project["config"]["template"]["publish"]

        for fname in os.listdir(stagingdir):
            name, ext = os.path.splitext(fname)
            template_data["representation"] = ext[1:]

            src = os.path.join(stagingdir, fname)
            dst = template_publish.format(**template_data)

            # Backwards compatibility
            if fname == ".metadata.json":
                dirname = os.path.dirname(dst)
                dst = os.path.join(dirname, ".metadata.json")

            self.log.info("Copying %s -> %s" % (src, dst))

            self.copy_source(src, dst)

            representation = {
                "schema": "mindbender-core:representation-2.0",
                "type": "representation",
                "parent": version_id,
                "name": ext[1:],
                "data": {"label": representation_lables.get(ext)},
                "dependencies": instance.data.get("dependencies", "").split(),

                # Imprint shortcut to context
                # for performance reasons.
                "context": {
                    "project": PROJECT,
                    "asset": ASSET,
                    "silo": SILO,
                    "subset": subset["name"],
                    "version": version["name"],
                    "representation": ext[1:]
                }
            }

            io.insert_one(representation)

        self.log.info("Successfully integrated \"%s\" to \"%s\"" % (
            instance, dst))

    def create_version(self, subset, version_number, locations):
        """ Copy given source to destination

        Arguments:
            subset (dict): the registered subset of the asset
            version_number (int): the version number
            locations (list): the currently registered locations
        """
        # Imprint currently registered location
        version_locations = [location for location in locations if
                             location is not None]

        return {"schema": "mindbender-core:version-2.0",
                "type": "version",
                "parent": subset["_id"],
                "name": version_number,
                "locations": version_locations,
                "data": None}

    def create_data(self, context, instance):
        """
        Create the data colllection for th verison
        Args:
            context (object): the current context
            instance(object): the current instance being published

        Returns:
            dict: the required information with instance.data as key
        """

        current_families = instance.data.get("families", list())
        families = current_families.append(instance.data.get("family"))

        # create relative source path for DB
        relative_path = os.path.relpath(context.data["currentFile"],
                                        api.registered_root())
        source = os.path.join("{root}", relative_path).replace("\\", "/")

        return {instance.data: {"families": families,
                                "time": context.data["time"],
                                "author": context.data["user"],
                                "source": source,
                                "comment": context.data.get("comment")
                                }}

    def copy_source(self, src, dst):
        """ Copy given source to destination

        Arguments:
            src (str): the source file which needs to be copied
            dst (str): the destination of the sourc file
        Returns:
            None
        """

        dirname = os.path.dirname(dst)
        try:
            os.makedirs(dirname)
        except OSError as e:
            if e.errno == errno.EEXIST:
                pass
            else:
                self.log.critical("An unexpected error occurred.")
                raise

        shutil.copy(src, dst)

    def backwards_compatiblity(self, instance, subset, version):
        """Maintain backwards compatibility with newly published assets

        With the introduction of the database in 2.0, the artist would be
        unable to publish in 2.0 and use the files in 1.0. Therefore, we
        introduce this mechanism which continue to write for 1.0 even
        when writing from the 2.0 pipeline.

        This behaviour is deprecated and is to be removed in a future release.

        """

        import os
        import json
        import errno
        from mindbender import api

        MINDBENDER_PROJECT = os.environ["MINDBENDER_PROJECT"]
        MINDBENDER_ASSET = os.environ["MINDBENDER_ASSET"]
        MINDBENDER_SILO = os.environ["MINDBENDER_SILO"]

        context = instance.context

        # Metadata
        #  _________
        # |         |.key = value
        # |         |
        # |         |
        # |         |
        # |         |
        # |_________|
        #
        stagingdir = instance.data.get("stagingDir")
        fname = os.path.join(stagingdir, ".metadata.json")

        root = os.environ["MINDBENDER_ASSETPATH"]
        instancedir = os.path.join(root, "publish", instance.data["subset"])

        try:
            os.makedirs(instancedir)
        except OSError as e:
            if e.errno != errno.EEXIST:  # Already exists
                self.log.critical("An unexpected error occurred.")
                raise

        versiondir = os.path.join(
            instancedir,
            api.format_version(version["name"])
        )

        try:
            with open(fname) as f:
                version_1_0 = json.load(f)

        except IOError:
            version_1_0 = dict(version, **{
                "schema": "mindbender-core:version-1.0",

                # Hard-coded during transition
                "path": versiondir.replace("\\", "/"),
                "representations": list(),

                "version": version["name"],

                # Used to identify family of assets already on disk
                "families": instance.data.get("families", list()) + [
                    instance.data.get("family")
                ],

                "time": context.data["time"],
                "timeFormat": "%Y%m%dT%H%M%SZ",
                "author": context.data["user"],

                # Record within which silo this asset was made.
                "silo": os.environ["MINDBENDER_SILO"],

                # Collected by pyblish-maya
                "source": os.path.join(
                    "{root}",
                    os.path.relpath(
                        context.data["currentFile"],
                        os.path.join(
                            api.registered_root(),
                            os.environ["MINDBENDER_PROJECT"]
                        )
                    )
                ).replace("\\", "/"),

                # Discard database keys
                "parent": None,
            })

        for filename in instance.data.get("files", list()):
            name, ext = os.path.splitext(filename)
            version_1_0["representations"].append(
                {
                    "schema": "mindbender-core:representation-1.0",
                    "format": ext,
                    "path": os.path.join(
                        "{dirname}",
                        "%s{format}" % name,
                    ).replace("\\", "/"),

                    # Imprint shortcut to context
                    # for performance reasons.
                    "context": {
                        "project": MINDBENDER_PROJECT,
                        "asset": MINDBENDER_ASSET,
                        "silo": MINDBENDER_SILO,
                        "subset": subset["name"],
                        "version": version["name"],
                        "representation": ext[1:]
                    }
                }
            )

        # Write to disk
        #          _
        #         | |
        #        _| |_
        #    ____\   /
        #   |\    \ / \
        #   \ \    v   \
        #    \ \________.
        #     \|________|
        #
        with open(fname, "w") as f:
            json.dump(version_1_0, f, indent=4)

        self.log.info("Successfully wrote %s." % fname)
<commit_msg>changed name of method<commit_after>import os
import errno
import shutil
from pprint import pformat

import pyblish.api
from mindbender import api, io

class IntegrateMindbenderAsset(pyblish.api.InstancePlugin):
    """Write to files and metadata

    This plug-in exposes your data to others by encapsulating it
    into a new version.

    Schema:
        Data is written in the following format.
         ____________________
        |                    |
        | version            |
        |  ________________  |
        | |                | |
        | | representation | |
        | |________________| |
        | |                | |
        | | ...            | |
        | |________________| |
        |____________________|

    """

    label = "Integrate Mindbender Asset"
    order = pyblish.api.IntegratorOrder
    families = [
        "mindbender.model",
        "mindbender.rig",
        "mindbender.animation",
        "mindbender.lookdev",
        "mindbender.historyLookdev",
        "mindbender.group",
    ]

    def process(self, instance):
        # Required environment variables
        PROJECT = os.environ["MINDBENDER_PROJECT"]
        ASSET = instance.data.get("asset") or os.environ["MINDBENDER_ASSET"]
        SILO = os.environ["MINDBENDER_SILO"]
        LOCATION = os.getenv("MINDBENDER_LOCATION")

        representation_lables = {".ma": "Maya Ascii",
                                 ".source": "Original source file",
                                 ".abc": "Alembic"}

        context = instance.context
        # Atomicity
        #
        # Guarantee atomic publishes - each asset contains
        # an identical set of members.
        #     __
        #    /     o
        #   /       \
        #  |    o    |
        #   \       /
        #    o   __/
        #
        assert all(result["success"] for result in context.data["results"]), (
            "Atomicity not held, aborting.")

        # Assemble
        #
        #       |
        #       v
        #  --->   <----
        #       ^
        #       |
        #
        stagingdir = instance.data.get("stagingDir")
        assert stagingdir, ("Incomplete instance \"%s\": "
                            "Missing reference to staging area." % instance)

        self.log.debug("Establishing staging directory @ %s" % stagingdir)

        project = io.find_one({"type": "project"})
        asset = io.find_one({"name": ASSET})

        assert all([project, asset]), "This is bug"

        subset = io.find_one({
            "type": "subset",
            "parent": asset["_id"],
            "name": instance.data["subset"]
        })

        if subset is None:
            subset_name = instance.data["subset"]
            self.log.info("Subset '%s' not found, creating.." % subset_name)

            _id = io.insert_one({
                "schema": "mindbender-core:subset-2.0",
                "type": "subset",
                "name": subset_name,
                "data": {},
                "parent": asset["_id"]
            }).inserted_id

            subset = io.find_one({"_id": _id})

        # get next version
        latest_version = io.find_one({"type": "version",
                                      "parent": subset["_id"]},
                                     {"name": True},
                                     sort={"name": -1})
        next_version = latest_version["name"] + 1 or 1

        self.log.debug("Next version: %i" % next_version)

        version = self.create_version(subset, next_version, [LOCATION])
        version["data"] = self.create_version_data(context, instance)

        self.backwards_compatiblity(instance, subset, version)

        self.log.debug("Creating version: %s" % pformat(version))
        version_id = io.insert_one(version).inserted_id

        # Write to disk
        #          _
        #         | |
        #        _| |_
        #    ____\   /
        #   |\    \ / \
        #   \ \    v   \
        #    \ \________.
        #     \|________|
        #
        template_data = {
            "root": api.registered_root(),
            "project": PROJECT,
            "silo": SILO,
            "asset": ASSET,
            "subset": subset["name"],
            "version": version["name"],
        }

        template_publish = project["config"]["template"]["publish"]

        for fname in os.listdir(stagingdir):
            name, ext = os.path.splitext(fname)
            template_data["representation"] = ext[1:]

            src = os.path.join(stagingdir, fname)
            dst = template_publish.format(**template_data)

            # Backwards compatibility
            if fname == ".metadata.json":
                dirname = os.path.dirname(dst)
                dst = os.path.join(dirname, ".metadata.json")

            self.log.info("Copying %s -> %s" % (src, dst))

            self.copy_source(src, dst)

            representation = {
                "schema": "mindbender-core:representation-2.0",
                "type": "representation",
                "parent": version_id,
                "name": ext[1:],
                "data": {"label": representation_lables.get(ext)},
                "dependencies": instance.data.get("dependencies", "").split(),

                # Imprint shortcut to context
                # for performance reasons.
                "context": {
                    "project": PROJECT,
                    "asset": ASSET,
                    "silo": SILO,
                    "subset": subset["name"],
                    "version": version["name"],
                    "representation": ext[1:]
                }
            }

            io.insert_one(representation)

        self.log.info("Successfully integrated \"%s\" to \"%s\"" % (
            instance, dst))

    def create_version(self, subset, version_number, locations):
        """ Copy given source to destination

        Arguments:
            subset (dict): the registered subset of the asset
            version_number (int): the version number
            locations (list): the currently registered locations
        """
        # Imprint currently registered location
        version_locations = [location for location in locations if
                             location is not None]

        return {"schema": "mindbender-core:version-2.0",
                "type": "version",
                "parent": subset["_id"],
                "name": version_number,
                "locations": version_locations,
                "data": None}

    def create_version_data(self, context, instance):
        """
        Create the data colllection for th verison
        Args:
            context (object): the current context
            instance(object): the current instance being published

        Returns:
            dict: the required information with instance.data as key
        """

        current_families = instance.data.get("families", list())
        families = current_families.append(instance.data.get("family"))

        # create relative source path for DB
        relative_path = os.path.relpath(context.data["currentFile"],
                                        api.registered_root())
        source = os.path.join("{root}", relative_path).replace("\\", "/")

        return {instance.data: {"families": families,
                                "time": context.data["time"],
                                "author": context.data["user"],
                                "source": source,
                                "comment": context.data.get("comment")
                                }}

    def copy_source(self, src, dst):
        """ Copy given source to destination

        Arguments:
            src (str): the source file which needs to be copied
            dst (str): the destination of the sourc file
        Returns:
            None
        """

        dirname = os.path.dirname(dst)
        try:
            os.makedirs(dirname)
        except OSError as e:
            if e.errno == errno.EEXIST:
                pass
            else:
                self.log.critical("An unexpected error occurred.")
                raise

        shutil.copy(src, dst)

    def backwards_compatiblity(self, instance, subset, version):
        """Maintain backwards compatibility with newly published assets

        With the introduction of the database in 2.0, the artist would be
        unable to publish in 2.0 and use the files in 1.0. Therefore, we
        introduce this mechanism which continue to write for 1.0 even
        when writing from the 2.0 pipeline.

        This behaviour is deprecated and is to be removed in a future release.

        """

        import os
        import json
        import errno
        from mindbender import api

        MINDBENDER_PROJECT = os.environ["MINDBENDER_PROJECT"]
        MINDBENDER_ASSET = os.environ["MINDBENDER_ASSET"]
        MINDBENDER_SILO = os.environ["MINDBENDER_SILO"]

        context = instance.context

        # Metadata
        #  _________
        # |         |.key = value
        # |         |
        # |         |
        # |         |
        # |         |
        # |_________|
        #
        stagingdir = instance.data.get("stagingDir")
        fname = os.path.join(stagingdir, ".metadata.json")

        root = os.environ["MINDBENDER_ASSETPATH"]
        instancedir = os.path.join(root, "publish", instance.data["subset"])

        try:
            os.makedirs(instancedir)
        except OSError as e:
            if e.errno != errno.EEXIST:  # Already exists
                self.log.critical("An unexpected error occurred.")
                raise

        versiondir = os.path.join(
            instancedir,
            api.format_version(version["name"])
        )

        try:
            with open(fname) as f:
                version_1_0 = json.load(f)

        except IOError:
            version_1_0 = dict(version, **{
                "schema": "mindbender-core:version-1.0",

                # Hard-coded during transition
                "path": versiondir.replace("\\", "/"),
                "representations": list(),

                "version": version["name"],

                # Used to identify family of assets already on disk
                "families": instance.data.get("families", list()) + [
                    instance.data.get("family")
                ],

                "time": context.data["time"],
                "timeFormat": "%Y%m%dT%H%M%SZ",
                "author": context.data["user"],

                # Record within which silo this asset was made.
                "silo": os.environ["MINDBENDER_SILO"],

                # Collected by pyblish-maya
                "source": os.path.join(
                    "{root}",
                    os.path.relpath(
                        context.data["currentFile"],
                        os.path.join(
                            api.registered_root(),
                            os.environ["MINDBENDER_PROJECT"]
                        )
                    )
                ).replace("\\", "/"),

                # Discard database keys
                "parent": None,
            })

        for filename in instance.data.get("files", list()):
            name, ext = os.path.splitext(filename)
            version_1_0["representations"].append(
                {
                    "schema": "mindbender-core:representation-1.0",
                    "format": ext,
                    "path": os.path.join(
                        "{dirname}",
                        "%s{format}" % name,
                    ).replace("\\", "/"),

                    # Imprint shortcut to context
                    # for performance reasons.
                    "context": {
                        "project": MINDBENDER_PROJECT,
                        "asset": MINDBENDER_ASSET,
                        "silo": MINDBENDER_SILO,
                        "subset": subset["name"],
                        "version": version["name"],
                        "representation": ext[1:]
                    }
                }
            )

        # Write to disk
        #          _
        #         | |
        #        _| |_
        #    ____\   /
        #   |\    \ / \
        #   \ \    v   \
        #    \ \________.
        #     \|________|
        #
        with open(fname, "w") as f:
            json.dump(version_1_0, f, indent=4)

        self.log.info("Successfully wrote %s." % fname)
<|endoftext|>


<commit_before>from constants import *
import os
import logging

logger = logging.getLogger(APP_NAME)
_RESERVED_ATTRIBUTES = {'bool_options', 'int_options', 'float_options',
    'path_options', 'str_options', 'list_options', 'all_options'}

class Config:
    bool_options = set()
    int_options = set()
    float_options = set()
    path_options = set()
    str_options = set()
    list_options = set()

    def __init__(self, path=None):
        self.all_options = self.bool_options | self.int_options | \
            self.float_options | self.path_options | self.str_options
        self._conf_path = path
        self._loaded = False
        self.set_state(SAVED)

    def __setattr__(self, name, value):
        if name in _RESERVED_ATTRIBUTES:
            pass
        elif name in self.all_options:
            self.set_state(UNSAVED)
        self.__dict__[name] = value

    def __getattr__(self, name):
        if name in _RESERVED_ATTRIBUTES:
            pass
        elif name in self.all_options:
            if not self._loaded:
                self.load()
            if name not in self.__dict__:
                return [] if name in self.list_options else None
        elif name not in self.__dict__:
            raise AttributeError('Config instance has no attribute %r' % name)
        return self.__dict__[name]

    def get_state(self):
        return self._state

    def set_state(self, state):
        self._state = state

    def get_path(self):
        return self._conf_path

    def set_path(self, path):
        self._conf_path = path

    def _encode_line(self, name, value):
        if name in self.bool_options:
            value = 'true' if value else 'false'
        elif name in self.list_options:
            value = ','.join(value)

        return '%s=%s\n' % (name, value)

    def _decode_bool(self, value):
        value = value.lower()
        if value in {'true', 't', 'yes', 'y'}:
            return True
        elif value in {'false', 'f', 'no', 'n'}:
            return False
        else:
            raise ValueError('Value is not boolean')

    def _decode_int(self, value):
        return int(value)

    def _decode_float(self, value):
        return float(value)

    def _decode_path(self, value):
        try:
            value = os.path.normpath(value)
        except AttributeError:
            logger.error('Failed to normalize path. %r' % {
                'path': value,
            })
        return value

    def _decode_list(self, value):
        return filter(None, value.split(','))

    def _decode_line(self, line):
        line_split = line.split('=')
        name = line_split[0]
        value = '='.join(line_split[1:])

        if value:
            if name not in self.all_options:
                raise ValueError('Unknown option')

            if not value:
                raise ValueError('Empty option')

            if name in self.list_options:
                values = self._decode_list(value)

                decoder = None
                if name in self.int_options:
                    decoder = self._decode_int
                elif name in self.float_options:
                    decoder = self._decode_float
                elif name in self.bool_options:
                    decoder = self._decode_bool
                elif name in self.path_options:
                    decoder = self._decode_path

                if decoder:
                    for i, value in enumerate(values):
                        values[i] = decoder(value)

                value = values
            elif name in self.str_options:
                pass
            elif name in self.int_options:
                value = self._decode_int(value)
            elif name in self.float_options:
                value = self._decode_float(value)
            elif name in self.bool_options:
                value = self._decode_bool(value)
            elif name in self.path_options:
                value = self._decode_path(value)

        else:
            value = [] if name in self.list_options else None

        return name, value

    def load(self, merge=False):
        logger.debug('Loading config.')
        self._loaded = True

        try:
            with open(self._conf_path) as config:
                for line in config:
                    line = line.rstrip('\n')

                    if line.strip() == '':
                        continue
                    elif line[0] == '#':
                        continue
                    elif '=' in line:
                        pass
                    else:
                        logger.warning('Ignoring invalid line. %r' % {
                            'line': line,
                        })
                        continue

                    try:
                        name, value = self._decode_line(line)
                        if merge and name in self.__dict__:
                            continue
                        self.__dict__[name] = value
                    except ValueError:
                        logger.warning('Ignoring invalid line. %r' % {
                            'line': line,
                        })
        except IOError:
            if not merge:
                raise

    def commit(self, chmod_mode=None):
        logger.debug('Committing config.')
        if not self._loaded:
            self.load(True)

        try:
            temp_conf_path = self._conf_path + CONF_TEMP_EXT
            with open(temp_conf_path, 'w') as config:
                if chmod_mode:
                    os.chmod(temp_conf_path, chmod_mode)

                for name in self.all_options:
                    if name not in self.__dict__:
                        continue
                    value = self.__dict__[name]
                    if value is None:
                        continue
                    config.write(self._encode_line(name, value))
            os.rename(temp_conf_path, self._conf_path)
        except:
            try:
                os.remove(temp_conf_path)
            except OSError:
                pass
            raise

        self.set_state(SAVED)
<commit_msg>Change config chmod method<commit_after>from constants import *
import os
import logging

logger = logging.getLogger(APP_NAME)
_RESERVED_ATTRIBUTES = {'bool_options', 'int_options', 'float_options',
    'path_options', 'str_options', 'list_options', 'all_options'}

class Config:
    bool_options = set()
    int_options = set()
    float_options = set()
    path_options = set()
    str_options = set()
    list_options = set()
    chmod_mode = None

    def __init__(self, path=None):
        self.all_options = self.bool_options | self.int_options | \
            self.float_options | self.path_options | self.str_options
        self._conf_path = path
        self._loaded = False
        self.set_state(SAVED)

    def __setattr__(self, name, value):
        if name in _RESERVED_ATTRIBUTES:
            pass
        elif name in self.all_options:
            self.set_state(UNSAVED)
        self.__dict__[name] = value

    def __getattr__(self, name):
        if name in _RESERVED_ATTRIBUTES:
            pass
        elif name in self.all_options:
            if not self._loaded:
                self.load()
            if name not in self.__dict__:
                return [] if name in self.list_options else None
        elif name not in self.__dict__:
            raise AttributeError('Config instance has no attribute %r' % name)
        return self.__dict__[name]

    def get_state(self):
        return self._state

    def set_state(self, state):
        self._state = state

    def get_path(self):
        return self._conf_path

    def set_path(self, path):
        self._conf_path = path

    def _encode_line(self, name, value):
        if name in self.bool_options:
            value = 'true' if value else 'false'
        elif name in self.list_options:
            value = ','.join(value)

        return '%s=%s\n' % (name, value)

    def _decode_bool(self, value):
        value = value.lower()
        if value in {'true', 't', 'yes', 'y'}:
            return True
        elif value in {'false', 'f', 'no', 'n'}:
            return False
        else:
            raise ValueError('Value is not boolean')

    def _decode_int(self, value):
        return int(value)

    def _decode_float(self, value):
        return float(value)

    def _decode_path(self, value):
        try:
            value = os.path.normpath(value)
        except AttributeError:
            logger.error('Failed to normalize path. %r' % {
                'path': value,
            })
        return value

    def _decode_list(self, value):
        return filter(None, value.split(','))

    def _decode_line(self, line):
        line_split = line.split('=')
        name = line_split[0]
        value = '='.join(line_split[1:])

        if value:
            if name not in self.all_options:
                raise ValueError('Unknown option')

            if not value:
                raise ValueError('Empty option')

            if name in self.list_options:
                values = self._decode_list(value)

                decoder = None
                if name in self.int_options:
                    decoder = self._decode_int
                elif name in self.float_options:
                    decoder = self._decode_float
                elif name in self.bool_options:
                    decoder = self._decode_bool
                elif name in self.path_options:
                    decoder = self._decode_path

                if decoder:
                    for i, value in enumerate(values):
                        values[i] = decoder(value)

                value = values
            elif name in self.str_options:
                pass
            elif name in self.int_options:
                value = self._decode_int(value)
            elif name in self.float_options:
                value = self._decode_float(value)
            elif name in self.bool_options:
                value = self._decode_bool(value)
            elif name in self.path_options:
                value = self._decode_path(value)

        else:
            value = [] if name in self.list_options else None

        return name, value

    def load(self, merge=False):
        logger.debug('Loading config.')
        self._loaded = True

        try:
            with open(self._conf_path) as config:
                for line in config:
                    line = line.rstrip('\n')

                    if line.strip() == '':
                        continue
                    elif line[0] == '#':
                        continue
                    elif '=' in line:
                        pass
                    else:
                        logger.warning('Ignoring invalid line. %r' % {
                            'line': line,
                        })
                        continue

                    try:
                        name, value = self._decode_line(line)
                        if merge and name in self.__dict__:
                            continue
                        self.__dict__[name] = value
                    except ValueError:
                        logger.warning('Ignoring invalid line. %r' % {
                            'line': line,
                        })
        except IOError:
            if not merge:
                raise

    def commit(self):
        logger.debug('Committing config.')
        if not self._loaded:
            self.load(True)

        try:
            temp_conf_path = self._conf_path + CONF_TEMP_EXT
            with open(temp_conf_path, 'w') as config:
                if self.chmod_mode:
                    os.chmod(temp_conf_path, self.chmod_mode)

                for name in self.all_options:
                    if name not in self.__dict__:
                        continue
                    value = self.__dict__[name]
                    if value is None:
                        continue
                    config.write(self._encode_line(name, value))
            os.rename(temp_conf_path, self._conf_path)
        except:
            try:
                os.remove(temp_conf_path)
            except OSError:
                pass
            raise

        self.set_state(SAVED)
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

"""
Verify that we can import and use the contents of Platform and Tool
modules directly.
"""

import os
import re
import sys

import TestSCons

test = TestSCons.TestSCons()

# Before executing the any of the platform or tool modules, add some
# null entries to the environment $PATH variable to make sure there's
# no code that tries to index elements from the list before making sure
# they're non-null.
# (This was a problem in checkpoint release 0.97.d020070809.)
os.environ['PATH'] = os.pathsep + os.environ['PATH'] + \
                     os.pathsep + os.pathsep + '/no/such/dir' + os.pathsep

SConstruct_path = test.workpath('SConstruct')

platforms = [
    'aix',
    'cygwin',
    'darwin',
    'hpux',
    'irix',
    'os2',
    'posix',
    'sunos',
    'win32'
]

for platform in platforms:
    test.write('SConstruct', """
print "Platform %(platform)s"
env = Environment(platform = '%(platform)s')
import SCons.Platform.%(platform)s
x = SCons.Platform.%(platform)s.generate
""" % locals())
    test.run()

tools = [
    # Can't import '386asm' everywhere due to Windows registry dependency.
    'aixc++',
    'aixcc',
    'aixf77',
    'aixlink',
    'applelink',
    'ar',
    'as',
    'bcc32',
    'BitKeeper',
    'c++',
    'cc',
    'cvf',
    'CVS',
    'default',
    'dmd',
    'dvi',
    'dvipdf',
    'dvips',
    'f77',
    'f90',
    'f95',
    'fortran',
    'g++',
    'g77',
    'gas',
    'gcc',
    'gfortran',
    'gnulink',
    'gs',
    'hpc++',
    'hpcc',
    'hplink',
    'icc',
    'icl',
    'ifort',
    'ifl',
    'ilink',
    'ilink32',
    'intelc',
    'jar',
    'javac',
    'javah',
    'latex',
    'lex',
    'link',
    # Can't import 'linkloc' everywhere due to Windows registry dependency.
    'm4',
    'masm',
    'midl',
    'mingw',
    'mslib',
    'mslink',
    'msvc',
    'msvs',
    'mwcc',
    'mwld',
    'nasm',
    'pdf',
    'pdflatex',
    'pdftex',
    'Perforce',
    'qt',
    'RCS',
    'rmic',
    'rpcgen',
    'SCCS',
    'sgiar',
    'sgic++',
    'sgicc',
    'sgilink',
    'Subversion',
    'sunar',
    'sunc++',
    'suncc',
    'sunlink',
    'swig',
    'tar',
    'tex',
    'tlib',
    'yacc',
    'zip',
]

#if sys.platform == 'win32':
# Just comment out (for now?) due to registry dependency.
#    tools.extend([
#        '386asm',
#        'linkloc',
#    ])

# Intel no compiler warning..
intel_no_compiler_warning = """
scons: warning: Failed to find Intel compiler for version='None', abi='[^']*'
""" + TestSCons.file_expr

# Intel no top dir warning.
intel_no_top_dir_warning = """
scons: warning: Can't find Intel compiler top dir for version='None', abi='[^']*'
""" + TestSCons.file_expr

# Intel no license directory warning
intel_license_warning = re.escape("""
scons: warning: Intel license dir was not found.  Tried using the INTEL_LICENSE_FILE environment variable (), the registry () and the default path (C:\Program Files\Common Files\Intel\Licenses).  Using the default path as a last resort.
""") + TestSCons.file_expr

intel_warnings = [
    re.compile(intel_license_warning),
    re.compile(intel_no_compiler_warning),
    re.compile(intel_no_compiler_warning + intel_license_warning),
    re.compile(intel_no_top_dir_warning),
    re.compile(intel_no_top_dir_warning + intel_license_warning),
]

moc = test.where_is('moc')
if moc:
    import os.path

    qtdir = os.path.dirname(os.path.dirname(moc))

    qt_err = r"""
scons: warning: Could not detect qt, using moc executable as a hint \(QTDIR=%(qtdir)s\)
""" % locals()

else:

    qt_err = """
scons: warning: Could not detect qt, using empty QTDIR
"""

qt_warnings = [ re.compile(qt_err + TestSCons.file_expr) ]

error_output = {
    'icl' : intel_warnings,
    'intelc' : intel_warnings,
    'qt' : qt_warnings,
}

# An SConstruct for importing Tool names that have illegal characters
# for Python variable names.
indirect_import = """\
print "Tool %(tool)s (indirect)"
env = Environment(tools = ['%(tool)s'])

SCons = __import__('SCons.Tool.%(tool)s', globals(), locals(), [])
m = getattr(SCons.Tool, '%(tool)s')
env = Environment()
m.generate(env)
"""

# An SConstruct for importing Tool names "normally."
direct_import = """\
print "Tool %(tool)s (direct)"
env = Environment(tools = ['%(tool)s'])

import SCons.Tool.%(tool)s
env = Environment()
SCons.Tool.%(tool)s.exists(env)
SCons.Tool.%(tool)s.generate(env)
"""

failures = []
for tool in tools:
    if tool[0] in '0123456789' or '+' in tool:
        test.write('SConstruct', indirect_import % locals())
    else:
        test.write('SConstruct', direct_import % locals())
    test.run(stderr=None)
    stderr = test.stderr()
    if stderr:
        matched = None
        for expression in error_output.get(tool, []):
            if expression.match(stderr):
                matched = 1
                break
        if not matched:
            print "Failed importing '%s', stderr:" % tool
            print stderr
            failures.append(tool)

test.fail_test(len(failures))

test.pass_test()
<commit_msg>Python 2.6 made "as" a keyword, so test the importability of the Tool.as module indirectly, not with a direct import statement.<commit_after>#!/usr/bin/env python
#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

"""
Verify that we can import and use the contents of Platform and Tool
modules directly.
"""

import os
import re
import sys

import TestSCons

test = TestSCons.TestSCons()

# Before executing the any of the platform or tool modules, add some
# null entries to the environment $PATH variable to make sure there's
# no code that tries to index elements from the list before making sure
# they're non-null.
# (This was a problem in checkpoint release 0.97.d020070809.)
os.environ['PATH'] = os.pathsep + os.environ['PATH'] + \
                     os.pathsep + os.pathsep + '/no/such/dir' + os.pathsep

SConstruct_path = test.workpath('SConstruct')

platforms = [
    'aix',
    'cygwin',
    'darwin',
    'hpux',
    'irix',
    'os2',
    'posix',
    'sunos',
    'win32'
]

for platform in platforms:
    test.write('SConstruct', """
print "Platform %(platform)s"
env = Environment(platform = '%(platform)s')
import SCons.Platform.%(platform)s
x = SCons.Platform.%(platform)s.generate
""" % locals())
    test.run()

tools = [
    # Can't import '386asm' everywhere due to Windows registry dependency.
    'aixc++',
    'aixcc',
    'aixf77',
    'aixlink',
    'applelink',
    'ar',
    'as',
    'bcc32',
    'BitKeeper',
    'c++',
    'cc',
    'cvf',
    'CVS',
    'default',
    'dmd',
    'dvi',
    'dvipdf',
    'dvips',
    'f77',
    'f90',
    'f95',
    'fortran',
    'g++',
    'g77',
    'gas',
    'gcc',
    'gfortran',
    'gnulink',
    'gs',
    'hpc++',
    'hpcc',
    'hplink',
    'icc',
    'icl',
    'ifort',
    'ifl',
    'ilink',
    'ilink32',
    'intelc',
    'jar',
    'javac',
    'javah',
    'latex',
    'lex',
    'link',
    # Can't import 'linkloc' everywhere due to Windows registry dependency.
    'm4',
    'masm',
    'midl',
    'mingw',
    'mslib',
    'mslink',
    'msvc',
    'msvs',
    'mwcc',
    'mwld',
    'nasm',
    'pdf',
    'pdflatex',
    'pdftex',
    'Perforce',
    'qt',
    'RCS',
    'rmic',
    'rpcgen',
    'SCCS',
    'sgiar',
    'sgic++',
    'sgicc',
    'sgilink',
    'Subversion',
    'sunar',
    'sunc++',
    'suncc',
    'sunlink',
    'swig',
    'tar',
    'tex',
    'tlib',
    'yacc',
    'zip',
]

#if sys.platform == 'win32':
# Just comment out (for now?) due to registry dependency.
#    tools.extend([
#        '386asm',
#        'linkloc',
#    ])

# Intel no compiler warning..
intel_no_compiler_warning = """
scons: warning: Failed to find Intel compiler for version='None', abi='[^']*'
""" + TestSCons.file_expr

# Intel no top dir warning.
intel_no_top_dir_warning = """
scons: warning: Can't find Intel compiler top dir for version='None', abi='[^']*'
""" + TestSCons.file_expr

# Intel no license directory warning
intel_license_warning = re.escape("""
scons: warning: Intel license dir was not found.  Tried using the INTEL_LICENSE_FILE environment variable (), the registry () and the default path (C:\Program Files\Common Files\Intel\Licenses).  Using the default path as a last resort.
""") + TestSCons.file_expr

intel_warnings = [
    re.compile(intel_license_warning),
    re.compile(intel_no_compiler_warning),
    re.compile(intel_no_compiler_warning + intel_license_warning),
    re.compile(intel_no_top_dir_warning),
    re.compile(intel_no_top_dir_warning + intel_license_warning),
]

moc = test.where_is('moc')
if moc:
    import os.path

    qtdir = os.path.dirname(os.path.dirname(moc))

    qt_err = r"""
scons: warning: Could not detect qt, using moc executable as a hint \(QTDIR=%(qtdir)s\)
""" % locals()

else:

    qt_err = """
scons: warning: Could not detect qt, using empty QTDIR
"""

qt_warnings = [ re.compile(qt_err + TestSCons.file_expr) ]

error_output = {
    'icl' : intel_warnings,
    'intelc' : intel_warnings,
    'qt' : qt_warnings,
}

# An SConstruct for importing Tool names that have illegal characters
# for Python variable names.
indirect_import = """\
print "Tool %(tool)s (indirect)"
env = Environment(tools = ['%(tool)s'])

SCons = __import__('SCons.Tool.%(tool)s', globals(), locals(), [])
m = getattr(SCons.Tool, '%(tool)s')
env = Environment()
m.generate(env)
"""

# An SConstruct for importing Tool names "normally."
direct_import = """\
print "Tool %(tool)s (direct)"
env = Environment(tools = ['%(tool)s'])

import SCons.Tool.%(tool)s
env = Environment()
SCons.Tool.%(tool)s.exists(env)
SCons.Tool.%(tool)s.generate(env)
"""

failures = []
for tool in tools:
    if tool[0] in '0123456789' or '+' in tool or tool in ('as'):
        test.write('SConstruct', indirect_import % locals())
    else:
        test.write('SConstruct', direct_import % locals())
    test.run(stderr=None)
    stderr = test.stderr()
    if stderr:
        matched = None
        for expression in error_output.get(tool, []):
            if expression.match(stderr):
                matched = 1
                break
        if not matched:
            print "Failed importing '%s', stderr:" % tool
            print stderr
            failures.append(tool)

test.fail_test(len(failures))

test.pass_test()
<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# 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.

"""Tests for invite related views.
"""

__authors__ = [
  '"Daniel Hans" <daniel.m.hans@gmail.com>',
  ]

from soc.modules.gci.models.request import GCIRequest

from tests.profile_utils import GCIProfileHelper
from tests.test_utils import GCIDjangoTestCase
from tests.utils.invite_utils import GCIInviteHelper

class InviteViewTest(GCIDjangoTestCase):
  """Tests user invite views.
  """

  def setUp(self):
    super(InviteViewTest, self).setUp()
    self.init()

  def assertInviteTemplatesUsed(self, response):
    """Asserts that all the templates are used.
    """
    self.assertGCITemplatesUsed(response)
    self.assertTemplateUsed(response, 'v2/modules/gci/invite/base.html')

  def testLoggedInCannotInvite(self):
    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

  def testUserCannotInvite(self):
    self.data.createUser()

    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

  def testMentorCannotInvite(self):
    self.data.createMentor(self.org)

    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

  def testOrgAdminCanInvite(self):
    self.data.createOrgAdmin(self.org)

    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertInviteTemplatesUsed(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertInviteTemplatesUsed(response)

  def testInviteOrgAdmin(self):
    self.data.createOrgAdmin(self.org)

    invitee = self._invitee()

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteOrgAdminUrl(), post_data)
    self.assertResponseRedirect(response,
        '/gci/dashboard/%s' % self.gci.key().name())

    invite = GCIRequest.all().get()
    self.assertPropertiesEqual(self._defaultOrgAdminInviteProperties(), invite)

  def testInviteMentor(self):
    self.data.createOrgAdmin(self.org)

    invitee = self._invitee()

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteMentorUrl(), post_data)
    self.assertResponseRedirect(response,
        '/gci/dashboard/%s' % self.gci.key().name())

    invite = GCIRequest.all().get()
    self.assertPropertiesEqual(self._defaultMentorInviteProperties(), invite)

  def testSecondInviteForbidden(self):
    self.data.createOrgAdmin(self.org)

    invitee = self._invitee()

    GCIInviteHelper().createMentorInvite(self.org, invitee.user)

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteMentorUrl(), post_data)
    self.assertResponseOK(response)
    self._assertFormValidationError(response, 'identifiers')

  def _invitee(self):
    invitee_data = GCIProfileHelper(self.gci, self.dev_test)
    invitee_data.createOtherUser('invitee@example.com')
    invitee_data.createProfile()
    invitee_data.notificationSettings(new_invites=True)
    return invitee_data.profile

  def _inviteOrgAdminUrl(self):
    return '/gci/invite/org_admin/%s' % self.org.key().name()

  def _inviteMentorUrl(self):
    return '/gci/invite/mentor/%s' % self.org.key().name()

  def _defaultMentorInviteProperties(self):
    properties = self._defaultInviteProperties()
    properties['role'] = 'mentor'
    return properties

  def _defaultOrgAdminInviteProperties(self):
    properties = self._defaultInviteProperties()
    properties['role'] = 'org_admin'
    return properties

  def _defaultInviteProperties(self):
    return {
        'org': self.org,
        'type': 'Invitation',
        'status': 'pending',
        }

  def _assertFormValidationError(self, response, error_field):
    assert response.context['form'].errors.get(error_field) is not None
<commit_msg>testOrgAdminInviteAfterMentorInvite added.<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# 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.

"""Tests for invite related views.
"""

__authors__ = [
  '"Daniel Hans" <daniel.m.hans@gmail.com>',
  ]

from soc.modules.gci.models.request import GCIRequest

from tests.profile_utils import GCIProfileHelper
from tests.test_utils import GCIDjangoTestCase
from tests.utils.invite_utils import GCIInviteHelper

class InviteViewTest(GCIDjangoTestCase):
  """Tests user invite views.
  """

  def setUp(self):
    super(InviteViewTest, self).setUp()
    self.init()

  def assertInviteTemplatesUsed(self, response):
    """Asserts that all the templates are used.
    """
    self.assertGCITemplatesUsed(response)
    self.assertTemplateUsed(response, 'v2/modules/gci/invite/base.html')

  def testLoggedInCannotInvite(self):
    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

  def testUserCannotInvite(self):
    self.data.createUser()

    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

  def testMentorCannotInvite(self):
    self.data.createMentor(self.org)

    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertResponseForbidden(response)

  def testOrgAdminCanInvite(self):
    self.data.createOrgAdmin(self.org)

    url = self._inviteMentorUrl()
    response = self.get(url)
    self.assertInviteTemplatesUsed(response)

    url = self._inviteOrgAdminUrl()
    response = self.get(url)
    self.assertInviteTemplatesUsed(response)

  def testInviteOrgAdmin(self):
    self.data.createOrgAdmin(self.org)

    invitee = self._invitee()

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteOrgAdminUrl(), post_data)
    self.assertResponseRedirect(response,
        '/gci/dashboard/%s' % self.gci.key().name())

    invite = GCIRequest.all().get()
    self.assertPropertiesEqual(self._defaultOrgAdminInviteProperties(), invite)

  def testInviteMentor(self):
    self.data.createOrgAdmin(self.org)

    invitee = self._invitee()

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteMentorUrl(), post_data)
    self.assertResponseRedirect(response,
        '/gci/dashboard/%s' % self.gci.key().name())

    invite = GCIRequest.all().get()
    self.assertPropertiesEqual(self._defaultMentorInviteProperties(), invite)

  def testSecondInviteForbidden(self):
    self.data.createOrgAdmin(self.org)
    invitee = self._invitee()

    GCIInviteHelper().createMentorInvite(self.org, invitee.user)

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteMentorUrl(), post_data)
    self.assertResponseOK(response)
    self._assertFormValidationError(response, 'identifiers')

  def testOrgAdminInviteAfterMentorInvite(self):
    self.data.createOrgAdmin(self.org)
    invitee = self._invitee()

    GCIInviteHelper().createMentorInvite(self.org, invitee.user)

    post_data = {
        'identifiers': invitee.user.link_id,
        }
    response = self.post(self._inviteOrgAdminUrl(), post_data)
    self.assertResponseRedirect(response,
        '/gci/dashboard/%s' % self.gci.key().name())

    invite = GCIRequest.all().filter('role =', 'org_admin').get()
    self.assertPropertiesEqual(self._defaultOrgAdminInviteProperties(), invite)

  def _invitee(self):
    invitee_data = GCIProfileHelper(self.gci, self.dev_test)
    invitee_data.createOtherUser('invitee@example.com')
    invitee_data.createProfile()
    invitee_data.notificationSettings(new_invites=True)
    return invitee_data.profile

  def _inviteOrgAdminUrl(self):
    return '/gci/invite/org_admin/%s' % self.org.key().name()

  def _inviteMentorUrl(self):
    return '/gci/invite/mentor/%s' % self.org.key().name()

  def _defaultMentorInviteProperties(self):
    properties = self._defaultInviteProperties()
    properties['role'] = 'mentor'
    return properties

  def _defaultOrgAdminInviteProperties(self):
    properties = self._defaultInviteProperties()
    properties['role'] = 'org_admin'
    return properties

  def _defaultInviteProperties(self):
    return {
        'org': self.org,
        'type': 'Invitation',
        'status': 'pending',
        }

  def _assertFormValidationError(self, response, error_field):
    assert response.context['form'].errors.get(error_field) is not None
<|endoftext|>


<commit_before>import sublime, sublime_plugin, os, functools, tempfile, Default.exec

class CmakeConfigureCommand(Default.exec.ExecCommand):
	"""Configures a CMake project with options set in the sublime project
	file."""

	def is_enabled(self):
		project = self.window.project_data()
		if project is None:
			return False
		project_file_name = self.window.project_file_name()
		if not project_file_name:
			return False
		return True

	def description(self):
		return 'Configure'

	def run(self, write_build_targets=False):
		self.write_build_targets = write_build_targets
		project = self.window.project_data()
		project_file_name = self.window.project_file_name()
		project_name = os.path.splitext(project_file_name)[0]
		project_path = os.path.dirname(project_file_name)
		if not os.path.isfile(os.path.join(project_path, 'CMakeLists.txt')):
			must_have_root_path = True
		else:
			must_have_root_path = False
		tempdir = tempfile.mkdtemp()
		cmake = project.get('cmake')
		if cmake is None:
			project['cmake'] = {'build_folder': tempdir}
			print('CMakeBuilder: Temporary directory shall be "{}"'
				.format(tempdir))
			self.window.set_project_data(project)
			project = self.window.project_data()
			cmake = project['cmake']
		build_folder_before_expansion = cmake.get('build_folder')
		if build_folder_before_expansion is None:
			cmake['build_folder'] = tempdir
			print('CMakeBuilder: Temporary directory shall be "{}"'
				.format(tempdir))
			project['cmake'] = cmake
			self.window.set_project_data(project)
			project = self.window.project_data()
			cmake = project['cmake']
		cmake = sublime.expand_variables(cmake, self.window.extract_variables())
		# Guaranteed to exist at this point.
		build_folder = cmake.get('build_folder')
		build_folder = os.path.realpath(build_folder)
		generator = cmake.get('generator')
		overrides = cmake.get('command_line_overrides')
		if build_folder is None:
			sublime.error_message(
				'No "cmake: build_folder" variable found in {}.'.format(
					project_path))
			return
		os.makedirs(build_folder, exist_ok=True)
		try:
			os.remove(os.path.join(build_folder, 'CMakeCache.txt'))
		except FileNotFoundError as e:
			pass
		root_folder = cmake.get('root_folder')
		if root_folder:
			root_folder = os.path.realpath(root_folder)
		elif must_have_root_path:
			sublime.error_message(
				'No "CMakeLists.txt" file in the project folder is present and \
				no "root_folder" specified in the "cmake" dictionary of the \
				sublime-project file.')
		cmd = 'cmake "{}"'.format(
			root_folder if root_folder else project_path)
		if generator:
			cmd += ' -G "{}"'.format(generator)
		try:
			for key, value in overrides.items():
				if type(value) is bool:
					cmd += ' -D{}={}'.format(key, 'ON' if value else 'OFF')
				else:
					cmd += ' -D{}={}'.format(key, str(value))
		except AttributeError as e:
			pass
		except ValueError as e:
			pass
		super().run(shell_cmd=cmd, working_dir=build_folder)

	def on_finished(self, proc):
		super().on_finished(proc)
		if self.write_build_targets:
			sublime.set_timeout(
				functools.partial(
					self.window.run_command,
					'cmake_write_build_targets'), 0)
<commit_msg>Added extra check for creating build folder.<commit_after>import sublime, sublime_plugin, os, functools, tempfile, Default.exec

class CmakeConfigureCommand(Default.exec.ExecCommand):
	"""Configures a CMake project with options set in the sublime project
	file."""

	def is_enabled(self):
		project = self.window.project_data()
		if project is None:
			return False
		project_file_name = self.window.project_file_name()
		if not project_file_name:
			return False
		return True

	def description(self):
		return 'Configure'

	def run(self, write_build_targets=False):
		self.write_build_targets = write_build_targets
		project = self.window.project_data()
		project_file_name = self.window.project_file_name()
		project_name = os.path.splitext(project_file_name)[0]
		project_path = os.path.dirname(project_file_name)
		if not os.path.isfile(os.path.join(project_path, 'CMakeLists.txt')):
			must_have_root_path = True
		else:
			must_have_root_path = False
		tempdir = tempfile.mkdtemp()
		cmake = project.get('cmake')
		if cmake is None:
			project['cmake'] = {'build_folder': tempdir}
			print('CMakeBuilder: Temporary directory shall be "{}"'
				.format(tempdir))
			self.window.set_project_data(project)
			project = self.window.project_data()
			cmake = project['cmake']
		build_folder_before_expansion = cmake.get('build_folder')
		if build_folder_before_expansion is None:
			cmake['build_folder'] = tempdir
			print('CMakeBuilder: Temporary directory shall be "{}"'
				.format(tempdir))
			project['cmake'] = cmake
			self.window.set_project_data(project)
			project = self.window.project_data()
			cmake = project['cmake']
		cmake = sublime.expand_variables(cmake, self.window.extract_variables())
		# Guaranteed to exist at this point.
		build_folder = cmake.get('build_folder')
		build_folder = os.path.realpath(build_folder)
		generator = cmake.get('generator')
		overrides = cmake.get('command_line_overrides')
		if build_folder is None:
			sublime.error_message(
				'No "cmake: build_folder" variable found in {}.'.format(
					project_path))
			return
		try:
			os.makedirs(build_folder, exist_ok=True)
		except OSError as e:
			sublime.error_message("Failed to create build directory: {}"
				.format(str(e)))
			return
		try:
			os.remove(os.path.join(build_folder, 'CMakeCache.txt'))
		except FileNotFoundError as e:
			pass
		root_folder = cmake.get('root_folder')
		if root_folder:
			root_folder = os.path.realpath(root_folder)
		elif must_have_root_path:
			sublime.error_message(
				'No "CMakeLists.txt" file in the project folder is present and \
				no "root_folder" specified in the "cmake" dictionary of the \
				sublime-project file.')
		cmd = 'cmake "{}"'.format(
			root_folder if root_folder else project_path)
		if generator:
			cmd += ' -G "{}"'.format(generator)
		try:
			for key, value in overrides.items():
				if type(value) is bool:
					cmd += ' -D{}={}'.format(key, 'ON' if value else 'OFF')
				else:
					cmd += ' -D{}={}'.format(key, str(value))
		except AttributeError as e:
			pass
		except ValueError as e:
			pass
		super().run(shell_cmd=cmd, working_dir=build_folder)

	def on_finished(self, proc):
		super().on_finished(proc)
		if self.write_build_targets:
			sublime.set_timeout(
				functools.partial(
					self.window.run_command,
					'cmake_write_build_targets'), 0)
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# Copyright 2011 Gaurav Vaidya
#
# 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.
#

"""This script downloads the field information Fusion Table, and
prints out PostgreSQL ALTER TABLE instructions which will create
a table for storing the fields specified in it.
"""

import codecs
import csv
import logging
import simplejson
import urllib
from optparse import OptionParser

from cartodb import CartoDB

class TableSchema(object):
    """Represents the table schema."""

    def __init__(self):
        """Creates a table schema object."""

        self.schema = {}
        self.indexed_fields = []

    def load_from_ft(self):
        """ Loads the format from our Fusion Table at
        http://www.google.com/fusiontables/DataSource?dsrcid=1348212
        and sets up the schema in this object.
        """

        fusiontable_id = 1348212
        ft_partial_url = "http://www.google.com/fusiontables/api/query?sql="

        try:
            urlconn = urllib.urlopen(
                ft_partial_url +
                urllib.quote_plus(
                    "SELECT alias, required, indexed, type, source FROM %d WHERE alias NOT EQUAL TO ''"
                        % (fusiontable_id)
                )
            )
        except IOError as (errno, strerror):
            logging.error("Could not connect to the internet to load Fusion Table %s: %s",
                fusiontable_id, strerror)
            exit(1)

        # Read the field names into a dictionary.
        rows = csv.DictReader(urlconn)
        for row in rows:
            # We don't need to test for row['alias'], because our SQL statement already
            # removes any blank aliases.
            row_alias = row['alias']

            if row_alias in self.schema:
                logging.error("Field alias '%s' is used twice in the Fusion Table, aborting.",
                    row_alias
                )
                exit(1)

            # Add this field name to the list of fields we must include in our schema.
            is_required = 1
            if row['required'] is None or row['required'] != 'y':
                is_required = 0

            self.schema[row_alias] = {'required': is_required, 'type': row['type']}

            # Check if this field should be indexed.
            if row['indexed'] is not None and row['indexed'] == 'y':
                self.schema[row_alias]['indexed'] = 1
                self.indexed_fields.append(row_alias)
            else:
                self.schema[row_alias]['indexed'] = 0

        urlconn.close()

    def setup_cartodb_table(self, table_name):
        """ Set up the schema we need on CartoDB table 'table_name' """

        print "Logging in to CartoDB using the settings in 'cartodb.json'."
        try:
            cartodb_settings = simplejson.loads(
                codecs.open('cartodb.json', encoding='utf-8').read(),
                encoding='utf-8')
        except Exception as ex:
            logging.error("Could not load CartoDB setting file 'cartodb.json': %s" % ex)
            exit(1)

        print "Updating table %s." % table_name
        cdb = CartoDB(
            cartodb_settings['CONSUMER_KEY'],
            cartodb_settings['CONSUMER_SECRET'],
            cartodb_settings['user'],
            cartodb_settings['password'],
            cartodb_settings['cartodb_domain']
        )

        for field in self.schema.keys():
            column_schema = self.schema[field]

	    cdb.sql("ALTER TABLE %s ADD COLUMN %s %s %s" % (
                table_name,
		field,
                column_schema['type'] if column_schema['type'] else "TEXT",
		"NOT NULL" if column_schema['required'] else "NULL"
	    ))
            print "\tField '%s' created." % field

	return

    def __repr__(self):
        """ Returns a string representation of this object. """
        return ("Fields: %s\n\nIndexed fields: %s" %
            (self.schema.__repr__(), ', '.join(self.indexed_fields)))

def _getoptions():
    ''' Parses command line options and returns them.'''
    parser = OptionParser()
    parser.add_option("-t", "--table",
        action="store",
        dest="tablename",
        default="temp_geodb",
        help="The name of the table to add the required columns to (default: 'temp_geodb')."
    )

    return parser.parse_args()[0]

def main():
    logging.basicConfig(level=logging.DEBUG)
    options = _getoptions()

    schema = TableSchema()
    schema.load_from_ft()
    schema.setup_cartodb_table(options.tablename)
    print "Exiting."

if __name__ == '__main__':
    main()
<commit_msg>Added a caveat to add-cartodb-columns to delete the 'description' field before running this script.<commit_after>#!/usr/bin/env python
#
# Copyright 2011 Gaurav Vaidya
#
# 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.
#

"""This script downloads the field information Fusion Table, and
prints out PostgreSQL ALTER TABLE instructions which will create
a table for storing the fields specified in it.

AN IMPORTANT CAVEAT: If the field spec defines a field which
overlaps with an existing CartoDB field, you are responsible
for deleting that field before running this script. Currently,
as of Dec 2011, the only field which conflicts in this way
is the 'description' field.
"""

import codecs
import csv
import logging
import simplejson
import urllib
from optparse import OptionParser

from cartodb import CartoDB

class TableSchema(object):
    """Represents the table schema."""

    def __init__(self):
        """Creates a table schema object."""

        self.schema = {}
        self.indexed_fields = []

    def load_from_ft(self):
        """ Loads the format from our Fusion Table at
        http://www.google.com/fusiontables/DataSource?dsrcid=1348212
        and sets up the schema in this object.
        """

        fusiontable_id = 1348212
        ft_partial_url = "http://www.google.com/fusiontables/api/query?sql="

        try:
            urlconn = urllib.urlopen(
                ft_partial_url +
                urllib.quote_plus(
                    "SELECT alias, required, indexed, type, source FROM %d WHERE alias NOT EQUAL TO ''"
                        % (fusiontable_id)
                )
            )
        except IOError as (errno, strerror):
            logging.error("Could not connect to the internet to load Fusion Table %s: %s",
                fusiontable_id, strerror)
            exit(1)

        # Read the field names into a dictionary.
        rows = csv.DictReader(urlconn)
        for row in rows:
            # We don't need to test for row['alias'], because our SQL statement already
            # removes any blank aliases.
            row_alias = row['alias']

            if row_alias in self.schema:
                logging.error("Field alias '%s' is used twice in the Fusion Table, aborting.",
                    row_alias
                )
                exit(1)

            # Add this field name to the list of fields we must include in our schema.
            is_required = 1
            if row['required'] is None or row['required'] != 'y':
                is_required = 0

            self.schema[row_alias] = {'required': is_required, 'type': row['type']}

            # Check if this field should be indexed.
            if row['indexed'] is not None and row['indexed'] == 'y':
                self.schema[row_alias]['indexed'] = 1
                self.indexed_fields.append(row_alias)
            else:
                self.schema[row_alias]['indexed'] = 0

        urlconn.close()

    def setup_cartodb_table(self, table_name):
        """ Set up the schema we need on CartoDB table 'table_name' """

        print "Logging in to CartoDB using the settings in 'cartodb.json'."
        try:
            cartodb_settings = simplejson.loads(
                codecs.open('cartodb.json', encoding='utf-8').read(),
                encoding='utf-8')
        except Exception as ex:
            logging.error("Could not load CartoDB setting file 'cartodb.json': %s" % ex)
            exit(1)

        print "Updating table %s." % table_name
        cdb = CartoDB(
            cartodb_settings['CONSUMER_KEY'],
            cartodb_settings['CONSUMER_SECRET'],
            cartodb_settings['user'],
            cartodb_settings['password'],
            cartodb_settings['cartodb_domain']
        )

        for field in self.schema.keys():
            column_schema = self.schema[field]

	    cdb.sql("ALTER TABLE %s ADD COLUMN %s %s %s" % (
                table_name,
		field,
                column_schema['type'] if column_schema['type'] else "TEXT",
		"NOT NULL" if column_schema['required'] else "NULL"
	    ))
            print "\tField '%s' created." % field

	return

    def __repr__(self):
        """ Returns a string representation of this object. """
        return ("Fields: %s\n\nIndexed fields: %s" %
            (self.schema.__repr__(), ', '.join(self.indexed_fields)))

def _getoptions():
    ''' Parses command line options and returns them.'''
    parser = OptionParser()
    parser.add_option("-t", "--table",
        action="store",
        dest="tablename",
        default="temp_geodb",
        help="The name of the table to add the required columns to (default: 'temp_geodb')."
    )

    return parser.parse_args()[0]

def main():
    logging.basicConfig(level=logging.DEBUG)
    options = _getoptions()

    schema = TableSchema()
    schema.load_from_ft()
    schema.setup_cartodb_table(options.tablename)
    print "Exiting."

if __name__ == '__main__':
    main()
<|endoftext|>


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

__author__ = 'omar'
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
from reportlab.lib.pagesizes import landscape, A4
import arabicreshaper
from bidi.algorithm import get_display
import re
from os import path
from django.core.files.temp import NamedTemporaryFile

static_dir = path.join(path.dirname(__file__), 'assets')

light_font_url = path.join(static_dir, "DINNextLTArabic-Light.ttf")
pdfmetrics.registerFont(TTFont("DIN Next LT Arabic Light", light_font_url, validate=True))

bold_font_url = path.join(static_dir, "DinTextArabic-Bold.ttf")
pdfmetrics.registerFont(TTFont("DIN Next LT Arabic Bold", bold_font_url, validate=True))

SIZE = landscape(A4)

def course_org_to_logo(course_org):
    if course_org == 'MITX' or course_org == 'HarvardX':
        return 'edx.png'
    elif course_org == u'بيت.كوم':
        return 'bayt-logo2-en.png'
    elif course_org == u'إدراك':
        return 'qrta_logo.jpg'
    elif course_org == 'AUB':
        return 'Full-AUB-Seal.jpg'
    else:
        return ''

def text_to_bidi(text):
    text = normalize_spaces(text)

    reshaped_text = arabicreshaper.reshape(text)
    bidi_text = get_display(reshaped_text)
    return bidi_text

def course_org_disclaimer(course_org):
    if course_org == 'MITX':
        return (u'تم طرح هذا المساق من قبل إدراك تحت إشراف فريق من الأكاديمين الذين اشرفوا' +
                u' على تعليم وإدارة النقاش وتقييم الأجوبة والإمتحانات، و ذلك بالتعاون مع معهد' +
                u' ماسشوستس للتكنولوجيا .')
    else:
        return (u'تم طرح هذا المساق من قبل إدراك وتحت إشراف فريق من الأكاديمين ' +
                u'الذين اشرفوا على تعليم وإدارة النقاش وتقييم الأجوبة والإمتحانات.')

def normalize_spaces(text):
    return re.sub(' +', ' ', text)

class EdraakCertificate(object):
    def __init__(self, user_profile_name, course_name, course_desc, instructor, course_end_date, course_org=None):
        self.user_profile_name = user_profile_name
        self.course_name = course_name
        self.course_desc = course_desc
        self.instructor = instructor
        self.course_end_date = course_end_date
        self.course_org = course_org

        self.temp_file = NamedTemporaryFile(suffix='-cert.pdf')

        self.ctx = None

    def init_context(self):
        ctx = canvas.Canvas(self.temp_file.name)
        ctx.setPageSize(SIZE)
        self.ctx = ctx

    def add_certificate_bg(self):
        width, height = SIZE
        bg_path = path.join(static_dir, 'certificate_layout3.jpg')
        self.ctx.drawImage(bg_path, 0, 0, width, height)

    def _set_font(self, size, is_bold):
        if is_bold:
            font = "DIN Next LT Arabic Bold"
        else:
            font = "DIN Next LT Arabic Light"

        self.ctx.setFont(font, size)
        self.ctx.setFillColorRGB(66 / 255.0, 74 / 255.0, 82 / 255.0)

    def draw_single_line_bidi_text(self, text, x, y, size, bold=False, max_width=7.494):
        x *= inch
        y *= inch
        size *= inch
        max_width *= inch

        text = text_to_bidi(text)

        while True:
            self._set_font(size, bold)
            lines = list(self._wrap_text(text, max_width))

            if len(lines) > 1:
                size *= 0.9  # reduce font size by 10%
            else:
                self.ctx.drawRightString(x, y, lines[0])
                break

    def draw_bidi_text(self, text, x, y, size, bold=False, max_width=7.494, lh_factor=1.3):
        x *= inch
        y *= inch
        size *= inch
        max_width *= inch
        line_height = size * lh_factor

        self._set_font(size, bold)

        text = text_to_bidi(text)

        for line in self._wrap_text(text, max_width):
            self.ctx.drawRightString(x, y, line)
            y -= line_height

    def add_course_org_logo(self, course_org):
        if course_org:
            image = path.join(static_dir, course_org_to_logo(course_org))
            self.ctx.drawImage(image, 3.519 * inch, 6.444 * inch, 2.467 * inch, 1.378 * inch)

    def _wrap_text(self, text, max_width):
        words = reversed(text.split(u' '))

        def de_reverse(text_to_reverse):
            return u' '.join(reversed(text_to_reverse.split(u' ')))

        line = u''
        for next_word in words:
            next_width = self.ctx.stringWidth(line + u' ' + next_word)

            if next_width >= max_width:
                yield de_reverse(line).strip()
                line = next_word
            else:
                line += u' ' + next_word

        if line:
            yield de_reverse(line).strip()

    def save(self):
        self.ctx.showPage()
        self.ctx.save()

    def generate_and_save(self):
        self.init_context()

        x = 10.8
        self.add_certificate_bg()
        self.add_course_org_logo(self.course_org)

        self.draw_bidi_text(u'تم منح شهادة إتمام المساق هذﮦ إلى:', x, 5.8, size=0.25)

        self.draw_single_line_bidi_text(self.user_profile_name, x, 5.124, size=0.5, bold=True)

        self.draw_bidi_text(u'لإتمام المساق التالي بنجاح:', x, 4.63, size=0.25)
        self.draw_bidi_text(self.course_name, x, 4.1, size=0.33, bold=True)
        self.draw_bidi_text(self.course_desc, x, 3.78, size=0.16)

        self.draw_single_line_bidi_text(self.instructor, x, 1.8, size=0.26, bold=True)
        self.draw_bidi_text(course_org_disclaimer(self.course_org), x, 1.48, size=0.16)
        self.draw_bidi_text(self.course_end_date, 2.7, 4.82, size=0.27)

        self.save()<commit_msg>fixed English certificates.<commit_after># -*- coding: utf-8 -*-

__author__ = 'omar'
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
from reportlab.lib.pagesizes import landscape, A4
import arabicreshaper
from bidi.algorithm import get_display
import re
from os import path
from django.core.files.temp import NamedTemporaryFile

static_dir = path.join(path.dirname(__file__), 'assets')

light_font_url = path.join(static_dir, "DINNextLTArabic-Light.ttf")
pdfmetrics.registerFont(TTFont("DIN Next LT Arabic Light", light_font_url, validate=True))

bold_font_url = path.join(static_dir, "DinTextArabic-Bold.ttf")
pdfmetrics.registerFont(TTFont("DIN Next LT Arabic Bold", bold_font_url, validate=True))

SIZE = landscape(A4)

def course_org_to_logo(course_org):
    if course_org == 'MITX' or course_org == 'HarvardX':
        return 'edx.png'
    elif course_org == u'بيت.كوم':
        return 'bayt-logo2-en.png'
    elif course_org == u'إدراك':
        return 'qrta_logo.jpg'
    elif course_org == 'AUB':
        return 'Full-AUB-Seal.jpg'
    else:
        return ''

def text_to_bidi(text):
    text = normalize_spaces(text)

    reshaped_text = arabicreshaper.reshape(text)
    bidi_text = get_display(reshaped_text)
    return bidi_text

def course_org_disclaimer(course_org):
    if course_org == 'MITX':
        return (u'تم طرح هذا المساق من قبل إدراك تحت إشراف فريق من الأكاديمين الذين اشرفوا' +
                u' على تعليم وإدارة النقاش وتقييم الأجوبة والإمتحانات، و ذلك بالتعاون مع معهد' +
                u' ماسشوستس للتكنولوجيا .')
    else:
        return (u'تم طرح هذا المساق من قبل إدراك وتحت إشراف فريق من الأكاديمين ' +
                u'الذين اشرفوا على تعليم وإدارة النقاش وتقييم الأجوبة والإمتحانات.')

def normalize_spaces(text):
    return re.sub(' +', ' ', text)

class EdraakCertificate(object):
    def __init__(self, user_profile_name, course_name, course_desc, instructor, course_end_date, course_org=None):
        self.user_profile_name = user_profile_name
        self.course_name = course_name
        self.course_desc = course_desc
        self.instructor = instructor
        self.course_end_date = course_end_date
        self.course_org = course_org
        self.temp_file = NamedTemporaryFile(suffix='-cert.pdf')
        self.ctx = None

    def init_context(self):
        ctx = canvas.Canvas(self.temp_file.name)
        ctx.setPageSize(SIZE)
        self.ctx = ctx

    def add_certificate_bg(self):
        width, height = SIZE
        bg_path = path.join(static_dir, 'certificate_layout3.jpg')
        self.ctx.drawImage(bg_path, 0, 0, width, height)

    def _set_font(self, size, is_bold):
        if is_bold:
            font = "DIN Next LT Arabic Bold"
        else:
            font = "DIN Next LT Arabic Light"
        self.ctx.setFont(font, size)
        self.ctx.setFillColorRGB(66 / 255.0, 74 / 255.0, 82 / 255.0)

    def draw_single_line_bidi_text(self, text, x, y, size, bold=False, max_width=7.494):
        x *= inch
        y *= inch
        size *= inch
        max_width *= inch
        text = text_to_bidi(text)
        while True:
            self._set_font(size, bold)
            lines = list(self._wrap_text(text, max_width))

            if len(lines) > 1:
                size *= 0.9  # reduce font size by 10%
            else:
                self.ctx.drawRightString(x, y, lines[0])
                break

    def draw_bidi_text(self, text, x, y, size, bold=False, max_width=7.494, lh_factor=1.3):
        x *= inch
        y *= inch
        size *= inch
        max_width *= inch
        line_height = size * lh_factor
        self._set_font(size, bold)
        text = text_to_bidi(text)
        for line in self._wrap_text(text, max_width):
            self.ctx.drawRightString(x, y, line)
            y -= line_height

    def draw_bidi_text_english(self, text, x, y, size, bold=False, max_width=7.494, lh_factor=1.3):
        x *= inch
        y *= inch
        size *= inch
        max_width *= inch
        line_height = size * lh_factor
        self._set_font(size, bold)
        text = text_to_bidi(text)
        for line in self._wrap_text(text, max_width):
            self.ctx.drawString(x, y, line)
            y += line_height

    def add_course_org_logo(self, course_org):
        if course_org:
            image = path.join(static_dir, course_org_to_logo(course_org))
            self.ctx.drawImage(image, 3.519 * inch, 6.444 * inch, 2.467 * inch, 1.378 * inch)

    def _wrap_text(self, text, max_width):
        words = reversed(text.split(u' '))

        def de_reverse(text_to_reverse):
            return u' '.join(reversed(text_to_reverse.split(u' ')))

        line = u''
        for next_word in words:
            next_width = self.ctx.stringWidth(line.strip() + u' ' + next_word.strip())

            if next_width >= max_width:
                yield de_reverse(line).strip()
                line = next_word
            else:
                line += u' ' + next_word.strip()

        if line:
            yield de_reverse(line).strip()

    def save(self):
        self.ctx.showPage()
        self.ctx.save()

    def is_unicode(self,string):
        try:
            string.decode('ascii')
        except (UnicodeDecodeError, UnicodeEncodeError) as e:
            return True
        else:
            return False

    def generate_and_save(self):
        self.init_context()
        x = 10.8
        self.add_certificate_bg()
        self.add_course_org_logo(self.course_org)
        self.draw_bidi_text(u'تم منح شهادة إتمام المساق هذﮦ إلى:', x, 5.8, size=0.25)
        self.draw_single_line_bidi_text(self.user_profile_name, x, 5.124, size=0.5, bold=True)
        self.draw_bidi_text(u'لإتمام المساق التالي بنجاح:', x, 4.63, size=0.25)
        if self.is_unicode(self.course_name):
            self.draw_bidi_text(self.course_name, x, 4.1, size=0.33, bold=True)
        else:
            self.draw_bidi_text_english(self.course_name, x-7, 4.1, size=0.33, bold=True)

        if self.is_unicode(self.course_desc):
            self.draw_bidi_text(self.course_desc, x, 3.78, size=0.16)
        else:
            self.draw_bidi_text_english(self.course_desc, x-7, 2.90, size=0.16)

        self.draw_single_line_bidi_text(self.instructor, x, 1.8, size=0.26, bold=True)
        self.draw_bidi_text(course_org_disclaimer(self.course_org), x, 1.48, size=0.16)
        self.draw_bidi_text(self.course_end_date, 2.7, 4.82, size=0.27)
        self.save()<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
This file contains the constants used in the building energy demand calculations
"""
__author__ = "Gabriel Happle"
__copyright__ = "Copyright 2018, Architecture and Building Systems - ETH Zurich"
__credits__ = ["Gabriel Happle"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Daren Thomas"
__email__ = "cea@arch.ethz.ch"
__status__ = "Production"

# all values are refactored from legacy Globalvars unless stated otherwise

# DEFAULT BUILDING GEOMETRY
H_F = 3  # average height per floor in m
E_S = 0.9  # franction of NFA that has electricity in every building
D = 20  # in mm the diameter of the pipe to calculate losses

# SOLAR
RSE = 0.04  # thermal resistance of external surfaces according to ISO 6946
F_F = 0.2  # Frame area faction coefficient
F_F_SIN = 0.1  # Frame area faction coefficient for Singapore [assumption]

# HVAC SYSTEMS & VENTILATION
ETA_REC = 0.75  # constant efficiency of Heat recovery
DELTA_P_DIM = 5  # (Pa) dimensioning differential pressure for multi-storey building shielded from wind,
                 # according to DIN 1946-6
SHIELDING_CLASS = 2  # according to ISO 16798-7, 0 = open terrain, 1 = partly shielded from wind,
        #  2 = fully shielded from wind
P_FAN = 0.55  # specific fan consumption in W/m3/h

# pumps ?
# TODO: Document
DELTA_P_1 = 0.1  # delta of pressure
F_SR = 0.3  # factor for pressure calculation
HOURS_OP = 5  # assuming around 2000 hours of operation per year. It is charged to the electrical system from 11 am to 4 pm
GR = 9.81  # m/s2 gravity
EFFI = 0.6  # efficiency of pumps

# WATER
FLOWTAP = 0.036  # in m3 == 12 l/min during 3 min every tap opening
TWW_SETPOINT = 60  # dhw tank set point temperature in C

# PHYSICAL
H_WE = 2466e3  # (J/kg) Latent heat of vaporization of water [section 6.3.6 in ISO 52016-1:2007]
C_A = 1006  # (J/(kg*K)) Specific heat of air at constant pressure [section 6.3.6 in ISO 52016-1:2007]

# RC-MODEL
B_F = 0.7  # it calculates the coefficient of reduction in transmittance for surfaces in contact with the ground according to values of SIA 380/1
H_IS = 3.45  # heat transfer coefficient between air and the surfacein W/(m2K)
H_MS = 9.1  # heat transfer coefficient between nodes m and s in W/m2K
LAMBDA_AT = 4.5 # dimensionless ratio between the internal surfaces area and the floor area from ISO 13790 Eq. 9<commit_msg>Minor change in E_S documentation<commit_after># -*- coding: utf-8 -*-
"""
This file contains the constants used in the building energy demand calculations
"""
__author__ = "Gabriel Happle"
__copyright__ = "Copyright 2018, Architecture and Building Systems - ETH Zurich"
__credits__ = ["Gabriel Happle"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Daren Thomas"
__email__ = "cea@arch.ethz.ch"
__status__ = "Production"

# all values are refactored from legacy Globalvars unless stated otherwise

# DEFAULT BUILDING GEOMETRY
H_F = 3  # average height per floor in m
E_S = 0.9  # fraction of GFA that has electricity in every building
D = 20  # in mm the diameter of the pipe to calculate losses

# SOLAR
RSE = 0.04  # thermal resistance of external surfaces according to ISO 6946
F_F = 0.2  # Frame area faction coefficient
F_F_SIN = 0.1  # Frame area faction coefficient for Singapore [assumption]

# HVAC SYSTEMS & VENTILATION
ETA_REC = 0.75  # constant efficiency of Heat recovery
DELTA_P_DIM = 5  # (Pa) dimensioning differential pressure for multi-storey building shielded from wind,
                 # according to DIN 1946-6
SHIELDING_CLASS = 2  # according to ISO 16798-7, 0 = open terrain, 1 = partly shielded from wind,
        #  2 = fully shielded from wind
P_FAN = 0.55  # specific fan consumption in W/m3/h

# pumps ?
# TODO: Document
DELTA_P_1 = 0.1  # delta of pressure
F_SR = 0.3  # factor for pressure calculation
HOURS_OP = 5  # assuming around 2000 hours of operation per year. It is charged to the electrical system from 11 am to 4 pm
GR = 9.81  # m/s2 gravity
EFFI = 0.6  # efficiency of pumps

# WATER
FLOWTAP = 0.036  # in m3 == 12 l/min during 3 min every tap opening
TWW_SETPOINT = 60  # dhw tank set point temperature in C

# PHYSICAL
H_WE = 2466e3  # (J/kg) Latent heat of vaporization of water [section 6.3.6 in ISO 52016-1:2007]
C_A = 1006  # (J/(kg*K)) Specific heat of air at constant pressure [section 6.3.6 in ISO 52016-1:2007]

# RC-MODEL
B_F = 0.7  # it calculates the coefficient of reduction in transmittance for surfaces in contact with the ground according to values of SIA 380/1
H_IS = 3.45  # heat transfer coefficient between air and the surfacein W/(m2K)
H_MS = 9.1  # heat transfer coefficient between nodes m and s in W/m2K
LAMBDA_AT = 4.5 # dimensionless ratio between the internal surfaces area and the floor area from ISO 13790 Eq. 9<|endoftext|>