<commit_before>"""
Classes related (dependency, implementation) adapter connections.
"""

from gaphor.adapters.connectors import RelationshipConnect
from zope import interface, component
from gaphor import UML
from gaphor.diagram import items

class DependencyConnect(RelationshipConnect):
    """
    Connect two NamedItem elements using a Dependency
    """
    component.adapts(items.NamedItem, items.DependencyItem)

    CAN_RECONNECT = True

    def allow(self, handle, port):
        line = self.line
        element = self.element

        # Element should be a NamedElement
        if not element.subject or \
                not isinstance(element.subject, UML.NamedElement):
                    return False

        return super(DependencyConnect, self).allow(handle, port)

    def reconnect(self, handle, port):
        line = self.line
        dep = line.subject
        if handle is line.head:
            for s in dep.supplier:
                del dep.supplier[s]
        elif handle is line.tail:
            for c in dep.client:
                del dep.client[c]
        self.reconnect_relationship(handle, 'supplier', 'client')

    def connect_subject(self, handle):
        """
        TODO: cleck for existing relationships (use self.relation())
        """
        line = self.line

        if line.auto_dependency:
            canvas = line.canvas
            opposite = line.opposite(handle)

            if handle is line.head:
                client = self.get_connected(opposite).subject
                supplier = self.element.subject
            else:
                client = self.element.subject
                supplier = self.get_connected(opposite).subject
            line.dependency_type = UML.model.dependency_type(client, supplier)

        relation = self.relationship_or_new(line.dependency_type,
                            ('supplier', 'supplierDependency'),
                            ('client', 'clientDependency'))
        line.subject = relation

component.provideAdapter(DependencyConnect)

class GeneralizationConnect(RelationshipConnect):
    """
    Connect Classifiers with a Generalization relationship.
    """
    # FixMe: Both ends of the generalization should be of the same  type?
    component.adapts(items.ClassifierItem, items.GeneralizationItem)

    CAN_RECONNECT = True

    def reconnect(self, handle, port):
        self.reconnect_relationship(handle, 'general', 'specific')

    def connect_subject(self, handle):
        log.debug('connect_subject: ' % handle)
        relation = self.relationship_or_new(UML.Generalization,
                    ('general', None),
                    ('specific', 'generalization'))
        log.debug('found: ' % relation)
        self.line.subject = relation

component.provideAdapter(GeneralizationConnect)

class AssociationConnect(RelationshipConnect):
    """
    Connect association to classifier.
    """
    component.adapts(items.ClassifierItem, items.AssociationItem)

    CAN_BE_UNARY = True    # allow one classifier to be connected by association
    CAN_RECONNECT = True

    def allow(self, handle, port):
        element = self.element

        # Element should be a Classifier
        if not isinstance(element.subject, UML.Classifier):
            return None

        return super(AssociationConnect, self).allow(handle, port)

    def connect_subject(self, handle):
        element = self.element
        line = self.line

        c1 = self.get_connected(line.head)
        c2 = self.get_connected(line.tail)
        if c1 and c2:
            head_type = c1.subject
            tail_type = c2.subject

            # First check if we do not already contain the right subject:
            if line.subject:
                end1 = line.subject.memberEnd[0]
                end2 = line.subject.memberEnd[1]
                if (end1.type is head_type and end2.type is tail_type) \
                   or (end2.type is head_type and end1.type is tail_type):
                    return

            # Create new association
            relation = UML.model.create_association(self.element_factory, head_type, tail_type)
            relation.package = element.canvas.diagram.namespace

            line.head_end.subject = relation.memberEnd[0]
            line.tail_end.subject = relation.memberEnd[1]

            # Do subject itself last, so event handlers can trigger
            line.subject = relation

    def reconnect(self, handle, port):
        line = self.line
        c = self.get_connected(handle)
        if handle is line.head:
            end = line.tail_end
            oend = line.head_end
        elif handle is line.tail:
            end = line.head_end
            oend = line.tail_end
        else:
            raise ValueError('Incorrect handle passed to adapter')

        nav = oend.subject.navigability

        UML.model.set_navigability(line.subject, end.subject, None) # clear old data

        end.subject.type = c.subject
        UML.model.set_navigability(line.subject, oend.subject, nav)

    def disconnect_subject(self, handle):
        """
        Disconnect model element.
        Disconnect property (memberEnd) too, in case of end of life for
        Extension
        """
        opposite = self.line.opposite(handle)
        c1 = self.get_connected(handle)
        c2 = self.get_connected(opposite)
        if c1 and c2:
            old = self.line.subject
            del self.line.subject
            del self.line.head_end.subject
            del self.line.tail_end.subject
            if old and len(old.presentation) == 0:
                for e in list(old.memberEnd):
                    e.unlink()
                old.unlink()

component.provideAdapter(AssociationConnect)

class ImplementationConnect(RelationshipConnect):
    """
    Connect Interface and a BehavioredClassifier using an Implementation.
    """
    component.adapts(items.NamedItem, items.ImplementationItem)

    CAN_RECONNECT = True

    def allow(self, handle, port):
        line = self.line
        element = self.element

        # Element at the head should be an Interface
        if handle is line.head and \
           not isinstance(element.subject, UML.Interface):
            return None

        # Element at the tail should be a BehavioredClassifier
        if handle is line.tail and \
           not isinstance(element.subject, UML.BehavioredClassifier):
            return None

        return super(ImplementationConnect, self).allow(handle, port)

    def reconnect(self, handle, port):
        line = self.line
        impl = line.subject
        if handle is line.head:
            for s in impl.contract:
                del impl.contract[s]
        elif handle is line.tail:
            for c in impl.implementatingClassifier:
                del impl.implementatingClassifier[c]
        self.reconnect_relationship(handle, 'contract', 'implementatingClassifier')

    def connect_subject(self, handle):
        """
        Perform implementation relationship connection.
        """
        relation = self.relationship_or_new(UML.Implementation,
                    ('contract', None),
                    ('implementatingClassifier', 'implementation'))
        self.line.subject = relation

component.provideAdapter(ImplementationConnect)

# vim:sw=4:et:ai
<commit_msg>Fixed end type on reconnect.<commit_after>"""
Classes related (dependency, implementation) adapter connections.
"""

from gaphor.adapters.connectors import RelationshipConnect
from zope import interface, component
from gaphor import UML
from gaphor.diagram import items

class DependencyConnect(RelationshipConnect):
    """
    Connect two NamedItem elements using a Dependency
    """
    component.adapts(items.NamedItem, items.DependencyItem)

    CAN_RECONNECT = True

    def allow(self, handle, port):
        line = self.line
        element = self.element

        # Element should be a NamedElement
        if not element.subject or \
                not isinstance(element.subject, UML.NamedElement):
                    return False

        return super(DependencyConnect, self).allow(handle, port)

    def reconnect(self, handle, port):
        line = self.line
        dep = line.subject
        if handle is line.head:
            for s in dep.supplier:
                del dep.supplier[s]
        elif handle is line.tail:
            for c in dep.client:
                del dep.client[c]
        self.reconnect_relationship(handle, 'supplier', 'client')

    def connect_subject(self, handle):
        """
        TODO: cleck for existing relationships (use self.relation())
        """
        line = self.line

        if line.auto_dependency:
            canvas = line.canvas
            opposite = line.opposite(handle)

            if handle is line.head:
                client = self.get_connected(opposite).subject
                supplier = self.element.subject
            else:
                client = self.element.subject
                supplier = self.get_connected(opposite).subject
            line.dependency_type = UML.model.dependency_type(client, supplier)

        relation = self.relationship_or_new(line.dependency_type,
                            ('supplier', 'supplierDependency'),
                            ('client', 'clientDependency'))
        line.subject = relation

component.provideAdapter(DependencyConnect)

class GeneralizationConnect(RelationshipConnect):
    """
    Connect Classifiers with a Generalization relationship.
    """
    # FixMe: Both ends of the generalization should be of the same  type?
    component.adapts(items.ClassifierItem, items.GeneralizationItem)

    CAN_RECONNECT = True

    def reconnect(self, handle, port):
        self.reconnect_relationship(handle, 'general', 'specific')

    def connect_subject(self, handle):
        log.debug('connect_subject: ' % handle)
        relation = self.relationship_or_new(UML.Generalization,
                    ('general', None),
                    ('specific', 'generalization'))
        log.debug('found: ' % relation)
        self.line.subject = relation

component.provideAdapter(GeneralizationConnect)

class AssociationConnect(RelationshipConnect):
    """
    Connect association to classifier.
    """
    component.adapts(items.ClassifierItem, items.AssociationItem)

    CAN_BE_UNARY = True    # allow one classifier to be connected by association
    CAN_RECONNECT = True

    def allow(self, handle, port):
        element = self.element

        # Element should be a Classifier
        if not isinstance(element.subject, UML.Classifier):
            return None

        return super(AssociationConnect, self).allow(handle, port)

    def connect_subject(self, handle):
        element = self.element
        line = self.line

        c1 = self.get_connected(line.head)
        c2 = self.get_connected(line.tail)
        if c1 and c2:
            head_type = c1.subject
            tail_type = c2.subject

            # First check if we do not already contain the right subject:
            if line.subject:
                end1 = line.subject.memberEnd[0]
                end2 = line.subject.memberEnd[1]
                if (end1.type is head_type and end2.type is tail_type) \
                   or (end2.type is head_type and end1.type is tail_type):
                    return

            # Create new association
            relation = UML.model.create_association(self.element_factory, head_type, tail_type)
            relation.package = element.canvas.diagram.namespace

            line.head_end.subject = relation.memberEnd[0]
            line.tail_end.subject = relation.memberEnd[1]

            # Do subject itself last, so event handlers can trigger
            line.subject = relation

    def reconnect(self, handle, port):
        line = self.line
        c = self.get_connected(handle)
        if handle is line.head:
            end = line.tail_end
            oend = line.head_end
        elif handle is line.tail:
            end = line.head_end
            oend = line.tail_end
        else:
            raise ValueError('Incorrect handle passed to adapter')

        nav = oend.subject.navigability

        UML.model.set_navigability(line.subject, end.subject, None) # clear old data

        oend.subject.type = c.subject
        UML.model.set_navigability(line.subject, oend.subject, nav)

    def disconnect_subject(self, handle):
        """
        Disconnect model element.
        Disconnect property (memberEnd) too, in case of end of life for
        Extension
        """
        opposite = self.line.opposite(handle)
        c1 = self.get_connected(handle)
        c2 = self.get_connected(opposite)
        if c1 and c2:
            old = self.line.subject
            del self.line.subject
            del self.line.head_end.subject
            del self.line.tail_end.subject
            if old and len(old.presentation) == 0:
                for e in list(old.memberEnd):
                    e.unlink()
                old.unlink()

component.provideAdapter(AssociationConnect)

class ImplementationConnect(RelationshipConnect):
    """
    Connect Interface and a BehavioredClassifier using an Implementation.
    """
    component.adapts(items.NamedItem, items.ImplementationItem)

    CAN_RECONNECT = True

    def allow(self, handle, port):
        line = self.line
        element = self.element

        # Element at the head should be an Interface
        if handle is line.head and \
           not isinstance(element.subject, UML.Interface):
            return None

        # Element at the tail should be a BehavioredClassifier
        if handle is line.tail and \
           not isinstance(element.subject, UML.BehavioredClassifier):
            return None

        return super(ImplementationConnect, self).allow(handle, port)

    def reconnect(self, handle, port):
        line = self.line
        impl = line.subject
        if handle is line.head:
            for s in impl.contract:
                del impl.contract[s]
        elif handle is line.tail:
            for c in impl.implementatingClassifier:
                del impl.implementatingClassifier[c]
        self.reconnect_relationship(handle, 'contract', 'implementatingClassifier')

    def connect_subject(self, handle):
        """
        Perform implementation relationship connection.
        """
        relation = self.relationship_or_new(UML.Implementation,
                    ('contract', None),
                    ('implementatingClassifier', 'implementation'))
        self.line.subject = relation

component.provideAdapter(ImplementationConnect)

# vim:sw=4:et:ai
<|endoftext|>


<commit_before># Copyright 2013 Google Inc. All Rights Reserved.
#
# 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.

"""Utilities for image bundling tool."""

import logging
import os
import subprocess
import time
import urllib2

class MakeFileSystemException(Exception):
  """Error occurred in file system creation."""

class TarAndGzipFileException(Exception):
  """Error occurred in creating the tarball."""

class LoadDiskImage(object):
  """Loads raw disk image using kpartx."""

  def __init__(self, file_path):
    """Initializes LoadDiskImage object.

    Args:
      file_path: a path to a file containing raw disk image.

    Returns:
      A list of devices for every partition found in an image.
    """
    self._file_path = file_path

  def __enter__(self):
    """Map disk image as a device."""
    kpartx_cmd = ['kpartx', '-a', '-v', '-s', self._file_path]
    output = RunCommand(kpartx_cmd)
    devs = []
    for line in output.splitlines():
      split_line = line.split()
      if (len(split_line) > 2 and split_line[0] == 'add'
          and split_line[1] == 'map'):
        devs.append('/dev/mapper/' + split_line[2])
    # Sleep for two seconds. At times the loopback device is not ready
    # instantly. Sleeping for two seconds solves it.
    time.sleep(2)
    return devs

  def __exit__(self, unused_exc_type, unused_exc_value, unused_exc_tb):
    """Unmap disk image as a device.

    Args:
      unused_exc_type: unused.
      unused_exc_value: unused.
      unused_exc_tb: unused.
    """
    # Sleep for two seconds. At times the loopback device is not ready
    # instantly. Sleeping for two seconds solves it.
    time.sleep(2)
    kpartx_cmd = ['kpartx', '-d', '-v', '-s', self._file_path]
    RunCommand(kpartx_cmd)

class MountFileSystem(object):
  """Mounts a file system."""

  def __init__(self, dev_path, dir_path):
    """Initializes MountFileSystem object.

    Args:
      dev_path: A path to a device to mount.
      dir_path: A path to a directory where a device is to be mounted.
    """
    self._dev_path = dev_path
    self._dir_path = dir_path

  def __enter__(self):
    """Mounts a device.
    """
    mount_cmd = ['mount', self._dev_path, self._dir_path]
    RunCommand(mount_cmd)

  def __exit__(self, unused_exc_type, unused_exc_value, unused_exc_tb):
    """Unmounts a file system.

    Args:
      unused_exc_type: unused.
      unused_exc_value: unused.
      unused_exc_tb: unused.
    """
    umount_cmd = ['umount', self._dir_path]
    RunCommand(umount_cmd)
    SyncFileSystem()

def SyncFileSystem():
  RunCommand(['sync'])

def GetMounts(root='/'):
  """Find all mount points under the specified root.

  Args:
    root: a path to look for a mount points.

  Returns:
    A list of mount points.
  """
  output = RunCommand(['/bin/mount', '-l'])
  mounts = []
  for line in output.splitlines():
    split_line = line.split()
    mount_point = split_line[2]
    if mount_point == root:
      continue
    # We are simply ignoring the fs_type of fs for now. But we can use that
    # later Just verify that these are actually mount points.
    if os.path.ismount(mount_point) and mount_point.startswith(root):
      mounts.append(mount_point)
  return mounts

def MakePartitionTable(file_path):
  """Create a partition table in a file.

  Args:
    file_path: A path to a file where a partition table will be created.
  """
  RunCommand(['parted', file_path, 'mklabel', 'msdos'])

def MakePartition(file_path, partition_type, fs_type, start, end):
  """Create a partition in a file.

  Args:
    file_path: A path to a file where a partition will be created.
    partition_type: A type of a partition to be created. Tested option is msdos.
    fs_type: A type of a file system to be created. For example, ext2, ext3,
      etc.
    start: Start offset of a partition in bytes.
    end: End offset of a partition in bytes.
  """
  parted_cmd = ['parted', file_path, 'unit B', 'mkpart', partition_type,
                fs_type, str(start), str(end)]
  RunCommand(parted_cmd)

def MakeFileSystem(dev_path, fs_type, uuid=None):
  """Create a file system in a device.

  Args:
    dev_path: A path to a device.
    fs_type: A type of a file system to be created. For example ext2, ext3, etc.
    uuid: The value to use as the UUID for the filesystem. If none, a random
          UUID will be generated and used.

  Returns:
    The uuid of the filesystem. This will be the same as the passed value if
    a value was specified. If no uuid was passed in, this will be the randomly
    generated uuid.

  Raises:
    MakeFileSystemException: If mkfs encounters an error.
  """
  if uuid is None:
    uuid = RunCommand(['uuidgen']).strip()
  if uuid is None:
    raise MakeFileSystemException(dev_path)

  mkfs_cmd = ['mkfs', '-t', fs_type, dev_path]
  RunCommand(mkfs_cmd)

  set_uuid_cmd = ['tune2fs', '-U', uuid, dev_path]
  RunCommand(set_uuid_cmd)

  return uuid

def Rsync(src, dest, exclude_file, ignore_hard_links, recursive, xattrs):
  """Copy files from specified directory using rsync.

  Args:
    src: Source location to copy.
    dest: Destination to copy files to.
    exclude_file: A path to a file which contains a list of exclude from copy
      filters.
    ignore_hard_links: If True a hard links are copied as a separate files. If
      False, hard link are recreated in dest.
    recursive: Specifies if directories are copied recursively or not.
    xattrs: Specifies if extended attributes are preserved or not.
  """
  rsync_cmd = ['rsync', '--times', '--perms', '--owner', '--group', '--links',
               '--devices', '--acls', '--sparse']
  if not ignore_hard_links:
    rsync_cmd.append('--hard-links')
  if recursive:
    rsync_cmd.append('--recursive')
  else:
    rsync_cmd.append('--dirs')
  if xattrs:
    rsync_cmd.append('--xattrs')
  if exclude_file:
    rsync_cmd.append('--exclude-from=' + exclude_file)
  rsync_cmd.extend([src, dest])

  logging.debug('Calling: %s', repr(rsync_cmd))
  if exclude_file:
    logging.debug('Contents of exclude file %s:', exclude_file)
    with open(exclude_file, 'rb') as excludes:
      for line in excludes:
        logging.debug('  %s', line.rstrip())

  RunCommand(rsync_cmd)

def GetUUID(partition_path):
  """Fetches the UUID of the filesystem on the specified partition.

  Args:
    partition_path: The path to the partition.

  Returns:
    The uuid of the filesystem.
  """
  output = RunCommand(['blkid', partition_path])
  for token in output.split():
    if token.startswith('UUID='):
      uuid = token.strip()[len('UUID="'):-1]

  logging.debug('found uuid = %s', uuid)
  return uuid

def CopyBytes(src, dest, count):
  """Copies count bytes from the src to dest file.

  Args:
    src: The source to read bytes from.
    dest: The destination to copy bytes to.
    count: Number of bytes to copy.
  """
  block_size = 4096
  block_count = count / block_size
  dd_command = ['dd',
                'if=%s' % src,
                'of=%s' % dest,
                'conv=notrunc',
                'bs=%s' % block_size,
                'count=%s' % block_count]
  RunCommand(dd_command)
  remaining_bytes = count - block_count * block_size
  if remaining_bytes:
    logging.debug('remaining bytes to copy = %s', remaining_bytes)
    dd_command = ['dd',
                  'if=%s' % src,
                  'of=%s' % dest,
                  'seek=%s' % block_count,
                  'skip=%s' % block_count,
                  'conv=notrunc',
                  'bs=1',
                  'count=%s' % remaining_bytes]
    RunCommand(dd_command)

def GetPartitionStart(disk_path, partition_number):
  """Returns the starting position in bytes of the partition.

  Args:
    disk_path: The path to disk device.
    partition_number: The partition number to lookup. 1 based.

  Returns:
    The starting position of the first partition in bytes.

  Raises:
    subprocess.CalledProcessError: If running parted fails.
    IndexError: If there is no partition at the given number.
  """
  parted_cmd = ['parted',
                disk_path,
                'unit B',
                'print']
  # In case the device is not valid and parted throws the retry/cancel prompt
  # write c to stdin.
  output = RunCommand(parted_cmd, input_str='c')
  for line in output.splitlines():
    split_line = line.split()
    if len(split_line) > 4 and split_line[0] == str(partition_number):
      return int(split_line[1][:-1])
  raise IndexError()

def RemovePartition(disk_path, partition_number):
  """Removes the partition number from the disk.

  Args:
    disk_path: The disk to remove the partition from.
    partition_number: The partition number to remove.
  """
  parted_cmd = ['parted',
                disk_path,
                'rm',
                str(partition_number)]
  # In case the device is not valid and parted throws the retry/cancel prompt
  # write c to stdin.
  RunCommand(parted_cmd, input_str='c')

def GetDiskSize(disk_file):
  """Returns the size of the disk device in bytes.

  Args:
    disk_file: The full path to the disk device.

  Returns:
    The size of the disk device in bytes.

  Raises:
    subprocess.CalledProcessError: If fdisk command fails for the disk file.
  """
  output = RunCommand(['fdisk', '-s', disk_file])
  return int(output) * 1024

def RunCommand(command, input_str=None):
  """Runs the command and returns the output printed on stdout.

  Args:
    command: The command to run.
    input_str: The input to pass to subprocess via stdin.

  Returns:
    The stdout from running the command.

  Raises:
    subprocess.CalledProcessError: if the command fails.
  """
  logging.debug('running %s with input=%s', command, input_str)
  p = subprocess.Popen(command, stdin=subprocess.PIPE,
                       stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  cmd_output = p.communicate(input_str)
  logging.debug('stdout %s', cmd_output[0])
  logging.debug('stderr %s', cmd_output[1])
  logging.debug('returncode %s', p.returncode)
  if p.returncode:
    logging.warning('Error while running %s return_code = %s\n'
                    'stdout=%s\nstderr=%s',
                    command, p.returncode, cmd_output[0],
                    cmd_output[1])
    raise subprocess.CalledProcessError(p.returncode,
                                        cmd=command)
  return cmd_output[0]

def ExpandPath(relative_path):
  return os.path.abspath(os.path.expandvars(os.path.expanduser(relative_path)))

def GetFilesystemForFile(file_path):
  fs_table = GetFilesystemTable()
  best_entry = None
  for entry in fs_table:
    if file_path.startswith(entry['mounted']):
      if not best_entry or (best_entry and (len(best_entry['mounted']) < len(best_entry['mounted']))):
        best_entry = entry

  return best_entry

def GetFilesystemTable(fs_path_filter=None):
  out = RunCommand(['df', '-T'])
  fs_table = TableToDict(out)
  if fs_path_filter:
    fs_table = [x for x in fs_table if x['filesystem'].startswith(fs_path_filter)]
  return fs_table

def TableToDict(stdout_table):
  """Converts a table typically from a command's stdout to a dictionary set."""
  items = []
  lines = stdout_table.splitlines()
  keys = [x.lower() for x in lines[0].split()]
  for line in lines[1:]:
    item = {}
    i = 0
    for line_item in line.split():
      item[keys[i]] = line_item
      i += 1
      items.append(item)
  return items

def TarAndGzipFile(src_paths, dest):
  """Pack file in tar archive and optionally gzip it.

  Args:
    src_paths: A list of files that will be archived.
               (Must be in the same directory.)
    dest: An archive name. If a file ends with .gz or .tgz an archive is gzipped
      as well.

  Raises:
    TarAndGzipFileException: If tar encounters an error.
  """
  if dest.endswith('.gz') or dest.endswith('.tgz'):
    mode = 'czSf'
  else:
    mode = 'cSf'
  src_names = [os.path.basename(src_path) for src_path in src_paths]
  # Take the directory of the first file in the list, all files are expected
  # to be in the same directory.
  src_dir = os.path.dirname(src_paths[0])
  tar_cmd = ['tar', mode, dest, '-C', src_dir] + src_names
  retcode = subprocess.call(tar_cmd)
  if retcode:
    raise TarAndGzipFileException(','.join(src_paths))

class Http(object):
  def Get(self, request):
    return urllib2.urlopen(request).read()

  def GetMetadata(self, url_path, recursive=False):
    """Retrieves instance metadata.

    Args:
      url_path: The path of the metadata url after the api version.
                http://metadata/computeMetadata/v1/url_path
      recursive: If set, returns the tree of metadata starting at url_path as
                 a json string.
    Returns:
      The metadata returned based on the url path.

    """
    # Use the latest version of the metadata.
    base_url = 'http://metadata/computeMetadata/v1/'
    suffix = ''
    if recursive:
      suffix = '?recursive=true'
    url = '{0}{1}{2}'.format(base_url, url_path, suffix)
    request = urllib2.Request(url)
    request.add_unredirected_header('X-Google-Metadata-Request', 'True')
    return self.Get(request)
<commit_msg>Fix fs table bug.<commit_after># Copyright 2013 Google Inc. All Rights Reserved.
#
# 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.

"""Utilities for image bundling tool."""

import logging
import os
import subprocess
import time
import urllib2

class MakeFileSystemException(Exception):
  """Error occurred in file system creation."""

class TarAndGzipFileException(Exception):
  """Error occurred in creating the tarball."""

class LoadDiskImage(object):
  """Loads raw disk image using kpartx."""

  def __init__(self, file_path):
    """Initializes LoadDiskImage object.

    Args:
      file_path: a path to a file containing raw disk image.

    Returns:
      A list of devices for every partition found in an image.
    """
    self._file_path = file_path

  def __enter__(self):
    """Map disk image as a device."""
    kpartx_cmd = ['kpartx', '-a', '-v', '-s', self._file_path]
    output = RunCommand(kpartx_cmd)
    devs = []
    for line in output.splitlines():
      split_line = line.split()
      if (len(split_line) > 2 and split_line[0] == 'add'
          and split_line[1] == 'map'):
        devs.append('/dev/mapper/' + split_line[2])
    # Sleep for two seconds. At times the loopback device is not ready
    # instantly. Sleeping for two seconds solves it.
    time.sleep(2)
    return devs

  def __exit__(self, unused_exc_type, unused_exc_value, unused_exc_tb):
    """Unmap disk image as a device.

    Args:
      unused_exc_type: unused.
      unused_exc_value: unused.
      unused_exc_tb: unused.
    """
    # Sleep for two seconds. At times the loopback device is not ready
    # instantly. Sleeping for two seconds solves it.
    time.sleep(2)
    kpartx_cmd = ['kpartx', '-d', '-v', '-s', self._file_path]
    RunCommand(kpartx_cmd)

class MountFileSystem(object):
  """Mounts a file system."""

  def __init__(self, dev_path, dir_path):
    """Initializes MountFileSystem object.

    Args:
      dev_path: A path to a device to mount.
      dir_path: A path to a directory where a device is to be mounted.
    """
    self._dev_path = dev_path
    self._dir_path = dir_path

  def __enter__(self):
    """Mounts a device.
    """
    mount_cmd = ['mount', self._dev_path, self._dir_path]
    RunCommand(mount_cmd)

  def __exit__(self, unused_exc_type, unused_exc_value, unused_exc_tb):
    """Unmounts a file system.

    Args:
      unused_exc_type: unused.
      unused_exc_value: unused.
      unused_exc_tb: unused.
    """
    umount_cmd = ['umount', self._dir_path]
    RunCommand(umount_cmd)
    SyncFileSystem()

def SyncFileSystem():
  RunCommand(['sync'])

def GetMounts(root='/'):
  """Find all mount points under the specified root.

  Args:
    root: a path to look for a mount points.

  Returns:
    A list of mount points.
  """
  output = RunCommand(['/bin/mount', '-l'])
  mounts = []
  for line in output.splitlines():
    split_line = line.split()
    mount_point = split_line[2]
    if mount_point == root:
      continue
    # We are simply ignoring the fs_type of fs for now. But we can use that
    # later Just verify that these are actually mount points.
    if os.path.ismount(mount_point) and mount_point.startswith(root):
      mounts.append(mount_point)
  return mounts

def MakePartitionTable(file_path):
  """Create a partition table in a file.

  Args:
    file_path: A path to a file where a partition table will be created.
  """
  RunCommand(['parted', file_path, 'mklabel', 'msdos'])

def MakePartition(file_path, partition_type, fs_type, start, end):
  """Create a partition in a file.

  Args:
    file_path: A path to a file where a partition will be created.
    partition_type: A type of a partition to be created. Tested option is msdos.
    fs_type: A type of a file system to be created. For example, ext2, ext3,
      etc.
    start: Start offset of a partition in bytes.
    end: End offset of a partition in bytes.
  """
  parted_cmd = ['parted', file_path, 'unit B', 'mkpart', partition_type,
                fs_type, str(start), str(end)]
  RunCommand(parted_cmd)

def MakeFileSystem(dev_path, fs_type, uuid=None):
  """Create a file system in a device.

  Args:
    dev_path: A path to a device.
    fs_type: A type of a file system to be created. For example ext2, ext3, etc.
    uuid: The value to use as the UUID for the filesystem. If none, a random
          UUID will be generated and used.

  Returns:
    The uuid of the filesystem. This will be the same as the passed value if
    a value was specified. If no uuid was passed in, this will be the randomly
    generated uuid.

  Raises:
    MakeFileSystemException: If mkfs encounters an error.
  """
  if uuid is None:
    uuid = RunCommand(['uuidgen']).strip()
  if uuid is None:
    raise MakeFileSystemException(dev_path)

  mkfs_cmd = ['mkfs', '-t', fs_type, dev_path]
  RunCommand(mkfs_cmd)

  set_uuid_cmd = ['tune2fs', '-U', uuid, dev_path]
  RunCommand(set_uuid_cmd)

  return uuid

def Rsync(src, dest, exclude_file, ignore_hard_links, recursive, xattrs):
  """Copy files from specified directory using rsync.

  Args:
    src: Source location to copy.
    dest: Destination to copy files to.
    exclude_file: A path to a file which contains a list of exclude from copy
      filters.
    ignore_hard_links: If True a hard links are copied as a separate files. If
      False, hard link are recreated in dest.
    recursive: Specifies if directories are copied recursively or not.
    xattrs: Specifies if extended attributes are preserved or not.
  """
  rsync_cmd = ['rsync', '--times', '--perms', '--owner', '--group', '--links',
               '--devices', '--acls', '--sparse']
  if not ignore_hard_links:
    rsync_cmd.append('--hard-links')
  if recursive:
    rsync_cmd.append('--recursive')
  else:
    rsync_cmd.append('--dirs')
  if xattrs:
    rsync_cmd.append('--xattrs')
  if exclude_file:
    rsync_cmd.append('--exclude-from=' + exclude_file)
  rsync_cmd.extend([src, dest])

  logging.debug('Calling: %s', repr(rsync_cmd))
  if exclude_file:
    logging.debug('Contents of exclude file %s:', exclude_file)
    with open(exclude_file, 'rb') as excludes:
      for line in excludes:
        logging.debug('  %s', line.rstrip())

  RunCommand(rsync_cmd)

def GetUUID(partition_path):
  """Fetches the UUID of the filesystem on the specified partition.

  Args:
    partition_path: The path to the partition.

  Returns:
    The uuid of the filesystem.
  """
  output = RunCommand(['blkid', partition_path])
  for token in output.split():
    if token.startswith('UUID='):
      uuid = token.strip()[len('UUID="'):-1]

  logging.debug('found uuid = %s', uuid)
  return uuid

def CopyBytes(src, dest, count):
  """Copies count bytes from the src to dest file.

  Args:
    src: The source to read bytes from.
    dest: The destination to copy bytes to.
    count: Number of bytes to copy.
  """
  block_size = 4096
  block_count = count / block_size
  dd_command = ['dd',
                'if=%s' % src,
                'of=%s' % dest,
                'conv=notrunc',
                'bs=%s' % block_size,
                'count=%s' % block_count]
  RunCommand(dd_command)
  remaining_bytes = count - block_count * block_size
  if remaining_bytes:
    logging.debug('remaining bytes to copy = %s', remaining_bytes)
    dd_command = ['dd',
                  'if=%s' % src,
                  'of=%s' % dest,
                  'seek=%s' % block_count,
                  'skip=%s' % block_count,
                  'conv=notrunc',
                  'bs=1',
                  'count=%s' % remaining_bytes]
    RunCommand(dd_command)

def GetPartitionStart(disk_path, partition_number):
  """Returns the starting position in bytes of the partition.

  Args:
    disk_path: The path to disk device.
    partition_number: The partition number to lookup. 1 based.

  Returns:
    The starting position of the first partition in bytes.

  Raises:
    subprocess.CalledProcessError: If running parted fails.
    IndexError: If there is no partition at the given number.
  """
  parted_cmd = ['parted',
                disk_path,
                'unit B',
                'print']
  # In case the device is not valid and parted throws the retry/cancel prompt
  # write c to stdin.
  output = RunCommand(parted_cmd, input_str='c')
  for line in output.splitlines():
    split_line = line.split()
    if len(split_line) > 4 and split_line[0] == str(partition_number):
      return int(split_line[1][:-1])
  raise IndexError()

def RemovePartition(disk_path, partition_number):
  """Removes the partition number from the disk.

  Args:
    disk_path: The disk to remove the partition from.
    partition_number: The partition number to remove.
  """
  parted_cmd = ['parted',
                disk_path,
                'rm',
                str(partition_number)]
  # In case the device is not valid and parted throws the retry/cancel prompt
  # write c to stdin.
  RunCommand(parted_cmd, input_str='c')

def GetDiskSize(disk_file):
  """Returns the size of the disk device in bytes.

  Args:
    disk_file: The full path to the disk device.

  Returns:
    The size of the disk device in bytes.

  Raises:
    subprocess.CalledProcessError: If fdisk command fails for the disk file.
  """
  output = RunCommand(['fdisk', '-s', disk_file])
  return int(output) * 1024

def RunCommand(command, input_str=None):
  """Runs the command and returns the output printed on stdout.

  Args:
    command: The command to run.
    input_str: The input to pass to subprocess via stdin.

  Returns:
    The stdout from running the command.

  Raises:
    subprocess.CalledProcessError: if the command fails.
  """
  logging.debug('running %s with input=%s', command, input_str)
  p = subprocess.Popen(command, stdin=subprocess.PIPE,
                       stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  cmd_output = p.communicate(input_str)
  logging.debug('stdout %s', cmd_output[0])
  logging.debug('stderr %s', cmd_output[1])
  logging.debug('returncode %s', p.returncode)
  if p.returncode:
    logging.warning('Error while running %s return_code = %s\n'
                    'stdout=%s\nstderr=%s',
                    command, p.returncode, cmd_output[0],
                    cmd_output[1])
    raise subprocess.CalledProcessError(p.returncode,
                                        cmd=command)
  return cmd_output[0]

def ExpandPath(relative_path):
  return os.path.abspath(os.path.expandvars(os.path.expanduser(relative_path)))

def GetFilesystemForFile(file_path):
  fs_table = GetFilesystemTable()
  best_entry = None
  for entry in fs_table:
    if file_path.startswith(entry['mounted']):
      if not best_entry or (best_entry and (len(best_entry['mounted']) < len(best_entry['mounted']))):
        best_entry = entry

  return best_entry

def GetFilesystemTable(fs_path_filter=None):
  out = RunCommand(['df', '-T'])
  fs_table = TableToDict(out)
  if fs_path_filter:
    fs_table = [x for x in fs_table if x['filesystem'].startswith(fs_path_filter)]
  return fs_table

def TableToDict(stdout_table):
  """Converts a table typically from a command's stdout to a dictionary set."""
  items = []
  lines = stdout_table.splitlines()
  keys = [x.lower() for x in lines[0].split()]
  for line in lines[1:]:
    item = {}
    i = 0
    for line_item in line.split():
      item[keys[i]] = line_item
      i += 1
    items.append(item)
  return items

def TarAndGzipFile(src_paths, dest):
  """Pack file in tar archive and optionally gzip it.

  Args:
    src_paths: A list of files that will be archived.
               (Must be in the same directory.)
    dest: An archive name. If a file ends with .gz or .tgz an archive is gzipped
      as well.

  Raises:
    TarAndGzipFileException: If tar encounters an error.
  """
  if dest.endswith('.gz') or dest.endswith('.tgz'):
    mode = 'czSf'
  else:
    mode = 'cSf'
  src_names = [os.path.basename(src_path) for src_path in src_paths]
  # Take the directory of the first file in the list, all files are expected
  # to be in the same directory.
  src_dir = os.path.dirname(src_paths[0])
  tar_cmd = ['tar', mode, dest, '-C', src_dir] + src_names
  retcode = subprocess.call(tar_cmd)
  if retcode:
    raise TarAndGzipFileException(','.join(src_paths))

class Http(object):
  def Get(self, request):
    return urllib2.urlopen(request).read()

  def GetMetadata(self, url_path, recursive=False):
    """Retrieves instance metadata.

    Args:
      url_path: The path of the metadata url after the api version.
                http://metadata/computeMetadata/v1/url_path
      recursive: If set, returns the tree of metadata starting at url_path as
                 a json string.
    Returns:
      The metadata returned based on the url path.

    """
    # Use the latest version of the metadata.
    base_url = 'http://metadata/computeMetadata/v1/'
    suffix = ''
    if recursive:
      suffix = '?recursive=true'
    url = '{0}{1}{2}'.format(base_url, url_path, suffix)
    request = urllib2.Request(url)
    request.add_unredirected_header('X-Google-Metadata-Request', 'True')
    return self.Get(request)
<|endoftext|>


<commit_before>from typing import Dict

import numpy as np
import skfem
from skfem import (
    Basis,
    BilinearForm,
    ElementTriP0,
    ElementTriP1,
    LinearForm,
    asm,
    condense,
    solve,
)
from skfem.helpers import dot, grad

def solve_thermal(
    mesh_filename: str,
    thermal_conductivity: Dict[str, float],
    specific_conductivity: Dict[str, float],
    currents: Dict[str, float],
):
    """Thermal simulation.

    Args:
        mesh_filename: Name of the mesh to load
        thermal_conductivity: thermal conductivity in W/m‧K
        specific_conductivity: specific conductivity in S/m
        currents: current flowing through the layer in A

    Returns:
        nothing yet, WIP
    """
    mesh = skfem.Mesh.load(mesh_filename)

    @BilinearForm
    def conduction(u, v, w):
        return dot(w["thermal_conductivity"] * u.grad, grad(v))

    @LinearForm
    def unit_load(v, _):
        return v

    basis = Basis(mesh, ElementTriP1())
    joule_heating_rhs = basis.zeros()
    for domain, current in currents.items():  # sum up the sources for the heating
        core_basis = Basis(mesh, basis.elem, elements=mesh.subdomains[domain])
        asm_core_unit_load = asm(unit_load, core_basis)
        core_area = np.sum(asm_core_unit_load)
        joule_heating = (current / core_area) ** 2 / specific_conductivity[domain]
        joule_heating_rhs += joule_heating * asm_core_unit_load

    basis0 = basis.with_element(ElementTriP0())
    thermal_conductivity_p0 = basis0.zeros()
    for domain in thermal_conductivity.keys():
        thermal_conductivity_p0[
            basis0.get_dofs(elements=domain)
        ] = thermal_conductivity[domain]
    thermal_conductivity_p0 *= 1e-12  # 1e-12 -> conversion from 1/m^2 -> 1/um^2

    thermal_conductivity_lhs = asm(
        conduction,
        basis,
        thermal_conductivity=basis0.interpolate(thermal_conductivity_p0),
    )

    temperature = solve(
        *condense(
            thermal_conductivity_lhs,
            joule_heating_rhs,
            D=basis.get_dofs(mesh.boundaries["bottom"]),
        )
    )

    from skfem.visuals.matplotlib import draw, plot

    ax = draw(mesh)
    ax.show()

    ax = draw(mesh, boundaries_only=True)
    plot(basis0, thermal_conductivity_p0 * 1e12, ax=ax, colorbar=True)
    ax.figure.set_size_inches(10, 7)
    ax.set_axis_on()
    ax.figure.tight_layout()
    ax.show()

    ax = draw(mesh, boundaries_only=True)
    plot(basis, temperature, ax=ax, colorbar=True, shading="gouraud")
    ax.figure.set_size_inches(10, 7)
    ax.set_axis_on()
    ax.figure.tight_layout()
    ax.show()

if __name__ == "__main__":
    import gdsfactory as gf
    from gdsfactory.simulation.gmsh.mesh2D import mesh2D

    gf.tech.LAYER_STACK.layers["heater"].thickness = 0.13
    gf.tech.LAYER_STACK.layers["heater"].zmin = 2.2

    heater1 = gf.components.straight_heater_metal(length=50, heater_width=2)
    heater2 = gf.components.straight_heater_metal(length=50, heater_width=2).move(
        [0, -10]
    )

    heaters = gf.Component("heaters")
    heaters << heater1
    heaters << heater2
    heaters.show()

    geometry = mesh2D(
        heaters,
        ((25, -25), (25, 25)),
        base_resolution=0.4,
        exclude_layers=((1, 10),),
        padding=(10, 10, 1, 1),
        refine_resolution={(1, 0): 0.05, (47, 0): 0.02},
    )

    import gmsh

    gmsh.write("mesh.msh")
    gmsh.clear()
    geometry.__exit__()

    solve_thermal(
        mesh_filename="mesh.msh",
        thermal_conductivity={"(47, 0)": 28, "oxide": 1.38, "(1, 0)": 148},
        specific_conductivity={"(47, 0)_0": 2.3e6},
        currents={"(47, 0)_0": 0.007},
    )
<commit_msg>started dynamic simulations, off by a factor of 2<commit_after>from typing import Dict, Iterator, Tuple

import numpy as np
import skfem
from skfem import (
    Basis,
    BilinearForm,
    ElementTriP0,
    ElementTriP1,
    LinearForm,
    asm,
    condense,
    penalize,
    solve,
)
from skfem.helpers import dot, grad

def solve_thermal(
    mesh_filename: str,
    thermal_conductivity: Dict[str, float],
    specific_conductivity: Dict[str, float],
    thermal_diffusivity: Dict[str, float],
    currents: Dict[str, float],
):
    """Thermal simulation.

    Args:
        mesh_filename: Name of the mesh to load
        thermal_conductivity: thermal conductivity in W/m‧K
        specific_conductivity: specific conductivity in S/m
        thermal_diffusivity:
        currents: current flowing through the layer in A

    Returns:
        nothing yet, WIP
    """
    mesh = skfem.Mesh.load(mesh_filename)

    @BilinearForm
    def conduction(u, v, w):
        return dot(w["thermal_conductivity"] * u.grad, grad(v))

    @LinearForm
    def unit_load(v, _):
        return v

    basis = Basis(mesh, ElementTriP1())
    joule_heating_rhs = basis.zeros()
    for domain, current in currents.items():  # sum up the sources for the heating
        core_basis = Basis(mesh, basis.elem, elements=mesh.subdomains[domain])
        asm_core_unit_load = asm(unit_load, core_basis)
        core_area = np.sum(asm_core_unit_load)
        joule_heating = (current / core_area) ** 2 / specific_conductivity[domain]
        joule_heating_rhs += joule_heating * asm_core_unit_load

    basis0 = basis.with_element(ElementTriP0())
    thermal_conductivity_p0 = basis0.zeros()
    for domain in thermal_conductivity.keys():
        thermal_conductivity_p0[
            basis0.get_dofs(elements=domain)
        ] = thermal_conductivity[domain]
    thermal_conductivity_p0 *= 1e-12  # 1e-12 -> conversion from 1/m^2 -> 1/um^2

    thermal_conductivity_lhs = asm(
        conduction,
        basis,
        thermal_conductivity=basis0.interpolate(thermal_conductivity_p0),
    )

    temperature = solve(
        *condense(
            thermal_conductivity_lhs,
            joule_heating_rhs,
            D=basis.get_dofs(mesh.boundaries["bottom"]),
        )
    )

    from skfem.visuals.matplotlib import draw, plot

    ax = draw(mesh)
    ax.show()

    ax = draw(mesh, boundaries_only=True)
    plot(basis0, thermal_conductivity_p0 * 1e12, ax=ax, colorbar=True)
    ax.figure.set_size_inches(10, 7)
    ax.set_axis_on()
    ax.figure.tight_layout()
    ax.show()

    ax = draw(mesh, boundaries_only=True)
    plot(basis, temperature, ax=ax, colorbar=True, shading="gouraud")
    ax.figure.set_size_inches(10, 7)
    ax.set_axis_on()
    ax.figure.tight_layout()
    ax.show()
    from scipy.sparse.linalg import splu

    print("max temp steady", np.max(temperature))
    u_init = temperature * 0.01

    thermal_diffusivity_p0 = basis0.zeros()
    for domain in thermal_diffusivity.keys():
        thermal_diffusivity_p0[basis0.get_dofs(elements=domain)] = thermal_diffusivity[
            domain
        ]

    thermal_diffusivity_p0 *= 1e12  # 1e-12 -> conversion from m^2 -> um^2

    @BilinearForm
    def diffusivity_laplace(u, v, w):
        print(
            "factor-laplace",
            np.unique(w["thermal_diffusivity"] / w["thermal_conductivity"]),
        )
        return (
            dot(grad(u) * w["thermal_conductivity"], grad(v))
            * w["thermal_diffusivity"]
            / w["thermal_conductivity"]
        )

    @BilinearForm
    def mass(u, v, _):
        return u * v

    @LinearForm
    def pre_factor(_, v, w):
        return w["thermal_diffusivity"] / w["thermal_conductivity"] * v

    L = asm(
        diffusivity_laplace,
        basis,
        thermal_diffusivity=basis0.interpolate(thermal_diffusivity_p0),
        thermal_conductivity=basis0.interpolate(thermal_conductivity_p0),
    )
    M = asm(mass, basis)

    dt = 0.2e-6
    print("dt =", dt)
    theta = 0.5  # Crank–Nicolson
    L0, M0 = penalize(L, M, D=basis.get_dofs(mesh.boundaries["bottom"]))
    A = M0 + theta * L0 * dt
    B = M0 - (1 - theta) * L0 * dt

    backsolve = splu(A.T).solve  # .T as splu prefers CSC

    def evolve(t: float, u: np.ndarray) -> Iterator[Tuple[float, np.ndarray]]:
        while True:
            # print(np.linalg.norm(u, np.inf))
            yield t, u
            t, u = t + dt, backsolve(
                B @ u
                + thermal_diffusivity["(47, 0)"]
                / thermal_conductivity["(47, 0)"]
                * 1e24
                * joule_heating_rhs
                * dt
            )
            print("max temp step", np.max(u))
            print(
                "factor",
                thermal_diffusivity["(47, 0)"] / thermal_conductivity["(47, 0)"] * 1e24,
            )

    from pathlib import Path

    from matplotlib.animation import FuncAnimation
    from skfem.visuals.matplotlib import plot

    ax = draw(mesh, boundaries_only=True)
    ax.set_axis_on()
    ax = plot(mesh, temperature, ax=ax, shading="gouraud")
    title = ax.set_title("t = 0.00")
    field = ax.get_children()[1]  # vertex-based temperature-colour
    fig = ax.get_figure()
    from mpl_toolkits.axes_grid1 import make_axes_locatable

    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.05)
    fig.colorbar(field, cax=cax)

    def update(event):
        t, u = event
        title.set_text(f"$t$ = {t * 1e6:.2f}us")
        field.set_array(u)

    animation = FuncAnimation(
        fig, update, evolve(0.0, u_init), repeat=False, interval=30, save_count=200
    )

    animation.save(str(Path(__file__).with_suffix(".gif")), "imagemagick")

if __name__ == "__main__":
    import gdsfactory as gf
    from gdsfactory.simulation.gmsh.mesh2D import mesh2D

    gf.tech.LAYER_STACK.layers["heater"].thickness = 0.13
    gf.tech.LAYER_STACK.layers["heater"].zmin = 2.2
    print(gf.tech.LAYER_STACK.layers.keys())
    # gf.tech.LAYER_STACK.layers["core"].thickness = 2

    heater1 = gf.components.straight_heater_metal(length=50, heater_width=2)
    heater2 = gf.components.straight_heater_metal(length=50, heater_width=2).move(
        [0, -10]
    )

    heaters = gf.Component("heaters")
    heaters << heater1
    # heaters << heater2
    heaters.show()

    geometry = mesh2D(
        heaters,
        ((25, -25), (25, 25)),
        base_resolution=0.4,
        exclude_layers=((1, 10),),
        padding=(10, 10, 1, 1),
        refine_resolution={(1, 0): 0.1, (47, 0): 0.1},
    )

    import gmsh

    gmsh.write("mesh.msh")
    gmsh.clear()
    geometry.__exit__()

    solve_thermal(
        mesh_filename="mesh.msh",
        thermal_conductivity={"(47, 0)": 28, "oxide": 1.38, "(1, 0)": 148},
        specific_conductivity={"(47, 0)_0": 2.3e6},
        thermal_diffusivity={
            "(47, 0)": 28 / 598 / 5240,
            "oxide": 1.38 / 709 / 2203,
            "(1, 0)": 148 / 711 / 2330,
        },
        # specific_heat={"(47, 0)_0": 598, 'oxide': 709, '(1, 0)': 711},
        # density={"(47, 0)_0": 5240, 'oxide': 2203, '(1, 0)': 2330},
        currents={"(47, 0)_0": 0.007},
    )
<|endoftext|>


<commit_before>#!/usr/bin/env python
# encoding: utf-8

"""
This module generates documentation for a TextMate bundle by parsing the .tmCommand files.
FIXME: The formatting is slightly messed up (underlined links, extra table header, etc.)
FIXME: Also parse bash/ruby/perl scripts for docstring equivalents
FIXME: List tab-triggers
"""

import os
import sys
import re
import json
from subprocess import Popen, PIPE

def parse_keycode(keycode):
    # a => A
    # A => ⇧A
    # ~ => ⌥
    # ^ => ⌃
    # @ => ⌘
    # $ ⌅ ⎋ ⇥
    # *
    mappings = {
        u'~':u'⌥',
        u'^':u'⌃',
        u'@':u'⌘',
        u'\x0A':u'↩',
        u'\x09':u'⇥',
        u'\x1B':u'⎋',
        u' ':u'␣'
    }
    printable = []
    shifted = False
    keycode = list(keycode)
    key = keycode.pop().decode('utf-8')
    key = mappings.get(key, key)
    printable.append(key.upper())
    if key >= 'A' and key <= 'Z':
        shifted = True

    while keycode:
        key = keycode.pop().decode('utf-8')
        printable.append(mappings.get(key, u'¿'))

    if shifted:
        printable.append(u'⇧')

    printable.reverse()

    return printable

def commandlist(cmd_dir):

    def json_from_plist(path):
        p = Popen(['plutil', '-convert', 'json', path, '-o', '-'], stdout=PIPE, stderr=PIPE)
        res, err = p.communicate()
        return json.loads(res) if not err else {}

    commands = [];
    for f in os.listdir(cmd_dir):
        path = os.path.join(cmd_dir, f)
        pl = json_from_plist(path)
        if not pl or pl.get('isDisabled', False):
            continue
        raw_combo = pl.get('keyEquivalent', '')
        name = pl.get('name', 'NONAME')
        docstring = extract_docstring(pl.get('command', ''))
        commands.append((raw_combo, name, docstring))

    return commands

def extract_docstring(string):
    LANG = r'^#!.+[/|\s+]([a-z]+)'
    match = re.match(LANG, string)
    if not match:
        return u''
    lang = match.group(1)
    if lang == 'python':
        return extract_python_docstring(string)
    elif lang in ['ruby', 'bash', 'sh']:
        return extract_comment_docstring(string)
    else:
        return u''

def extract_python_docstring(string):
    DOCSTRING = r'\s*#!.+?python.*?"""(.*?)"""'
    match = re.match(DOCSTRING, string, re.DOTALL)
    if match:
        return match.group(1)
    return u''

def extract_comment_docstring(string):
    DOCSTRING = r'#!.+\n\n((?:\s*#.*\n)+)'
    match = re.match(DOCSTRING, string, re.MULTILINE)
    if match:
        lines = [line.lstrip('# \t') for line in match.group(1).split('\n')]
        docs = '\n'.join(lines)
        return docs
    return u''

def generate_keyboard_shortcut_docs(cmd_dir):
    # Auto-generate keyboard shortcut list
    print u'

Keys	Command	Comment
\n'.encode('utf-8')

    cmds = commandlist(cmd_dir)
    for (raw_combo, cmd_name, docstring) in cmds:
        if not raw_combo:
            continue
        combo = parse_keycode(raw_combo)
        help = u''.join(combo)
        if not help.strip():
            continue
        line = u'
%s	%s	%s
\n' % (help, cmd_name, docstring)

        ## NOTE!
        ## THIS is where we need to ENCODE (= turn a unicode string into bytes)
        ## AND specify the format to use (UTF-8) in the encoding process,
        ## the default encoding is ASCII which is SOO WRONG for unicode strings.
        print line.encode('utf-8')

    print u'
'.encode('utf-8')

if __name__ == '__main__':
    CMD_DIR = '/Users/eperspe/Source/FOSS/TextTasks.tmbundle/Commands'

    cmds = commandlist(CMD_DIR)
    print u'Command files:'
    for t in cmds:
        print type(t[0]), t[0], ' : ', type(t[1]), t[1]

    generate_keyboard_shortcut_docs(CMD_DIR)<commit_msg>Minor changes<commit_after>#!/usr/bin/env python
# encoding: utf-8

"""
This module generates documentation for a TextMate bundle by parsing the .tmCommand files.
FIXME: The formatting is slightly messed up (underlined links, extra table header, etc.)
FIXME: Also parse bash/ruby/perl scripts for docstring equivalents
FIXME: List tab-triggers
"""

import os
import sys
import re
import json
from subprocess import Popen, PIPE

def parse_keycode(keycode):
    # a => A
    # A => ⇧A
    # ~ => ⌥
    # ^ => ⌃
    # @ => ⌘
    # $ ⌅ ⎋ ⇥
    # *
    mappings = {
        u'~':u'⌥',
        u'^':u'⌃',
        u'@':u'⌘',
        u'\x0A':u'↩',
        u'\x09':u'⇥',
        u'\x1B':u'⎋',
        u' ':u'␣'
    }
    printable = []
    shifted = False
    keycode = list(keycode)
    key = keycode.pop().decode('utf-8')
    key = mappings.get(key, key)
    printable.append(key.upper())
    if key >= 'A' and key <= 'Z':
        shifted = True

    while keycode:
        key = keycode.pop().decode('utf-8')
        printable.append(mappings.get(key, u'¿'))

    if shifted:
        printable.append(u'⇧')

    printable.reverse()

    return printable

def commandlist(cmd_dir):

    def json_from_plist(path):
        p = Popen(['plutil', '-convert', 'json', path, '-o', '-'], stdout=PIPE, stderr=PIPE)
        res, err = p.communicate()
        return json.loads(res) if not err else {}

    commands = [];
    for f in os.listdir(cmd_dir):
        path = os.path.join(cmd_dir, f)
        pl = json_from_plist(path)
        if not pl or pl.get('isDisabled', False):
            continue
        raw_combo = pl.get('keyEquivalent', '')
        name = pl.get('name', 'NONAME')
        docstring = extract_docstring(pl.get('command', ''))
        commands.append((raw_combo, name, docstring))

    return commands

def extract_docstring(string):
    LANG = r'^#!.+[/|\s+]([a-z]+)'
    match = re.match(LANG, string)
    if not match:
        return u''
    lang = match.group(1)
    if lang == 'python':
        return extract_python_docstring(string)
    elif lang in ['ruby', 'bash', 'sh']:
        return extract_comment_docstring(string)
    else:
        return u''

def extract_python_docstring(string):
    DOCSTRING = r'\s*#!.+?python.*?"""(.*?)"""'
    match = re.match(DOCSTRING, string, re.DOTALL)
    return match.group(1) if match else u''

def extract_comment_docstring(string):
    DOCSTRING = r'#!.+\n\n((?:\s*#.*\n)+)'
    match = re.match(DOCSTRING, string, re.MULTILINE)
    if not match:
        return u''
    lines = [line.lstrip('# \t') for line in match.group(1).split('\n')]
    return '\n'.join(lines)

def generate_keyboard_shortcut_docs(cmd_dir):
    # Auto-generate keyboard shortcut list
    print u'

Keys	Command	Comment
\n'.encode('utf-8')

    cmds = commandlist(cmd_dir)
    for (raw_combo, cmd_name, docstring) in cmds:
        if not raw_combo:
            continue
        combo = parse_keycode(raw_combo)
        help = u''.join(combo)
        if not help.strip():
            continue
        line = u'
%s	%s	%s
\n' % (help, cmd_name, docstring)

        ## NOTE!
        ## THIS is where we need to ENCODE (= turn a unicode string into bytes)
        ## AND specify the format to use (UTF-8) in the encoding process,
        ## the default encoding is ASCII which is SOO WRONG for unicode strings.
        print line.encode('utf-8')

    print u'
'.encode('utf-8')

if __name__ == '__main__':
    CMD_DIR = '/Users/eperspe/Source/FOSS/TextTasks.tmbundle/Commands'

    cmds = commandlist(CMD_DIR)
    print u'Command files:'
    for t in cmds:
        print type(t[0]), t[0], ' : ', type(t[1]), t[1]

    generate_keyboard_shortcut_docs(CMD_DIR)<|endoftext|>


<commit_before>import ephem
import pandas

from .objects import Objects

class Planets(Objects):
  def __init__(self, place):
   super(Planets, self).__init__(place)
   # Init object list with all planets
   self.objects = pandas.DataFrame([
      ephem.Mercury(),
      ephem.Venus(),
      ephem.Mars(),
      ephem.Jupiter(),
      ephem.Saturn(),
      ephem.Uranus(),
      ephem.Neptune()],
      columns=['Name'])
   # Compute transit of planets at given place
   self.objects['Transit'] = self.objects[['Name']].apply(
     lambda body: self.compute_tranzit(body.Name), axis=1)
   # Compute altitude of planets at transit (at given place)
   self.objects['Altitude'] = self.objects[['Name', 'Transit']].apply(
     lambda body: self.altitude_at_transit(body.Name, body.Transit), axis=1)
   # Calculate planets magnitude
   self.objects['Magnitude'] = self.objects[['Name']].apply(
     lambda body: body.Name.mag, axis=1)

<commit_msg>Fix RA for planets<commit_after>import ephem
import pandas
import numpy

from .objects import Objects

class Planets(Objects):
  def __init__(self, place):
   super(Planets, self).__init__(place)
   # Init object list with all planets
   self.objects = pandas.DataFrame([
      ephem.Mercury(),
      ephem.Venus(),
      ephem.Mars(),
      ephem.Jupiter(),
      ephem.Saturn(),
      ephem.Uranus(),
      ephem.Neptune()],
      columns=['Name'])
   # Compute transit of planets at given place
   self.objects['Transit'] = self.objects[['Name']].apply(
     lambda body: self.compute_tranzit(body.Name), axis=1)
   # Compute altitude of planets at transit (at given place)
   self.objects['Altitude'] = self.objects[['Name', 'Transit']].apply(
     lambda body: self.altitude_at_transit(body.Name, body.Transit), axis=1)
   # Calculate planets magnitude
   self.objects['Magnitude'] = self.objects[['Name']].apply(
     lambda body: body.Name.mag, axis=1)
   # Calculate planets Ra
   self.objects['RA'] = self.objects[['Name']].apply(
     lambda body: numpy.degrees(body.Name.ra)*24/360, axis=1)
   # Calculate planets Dec
   self.objects['Dec'] = self.objects[['Name']].apply(
     lambda body: numpy.degrees(body.Name.dec), axis=1)
   # Calculate planets distance from Earth
   self.objects['Distance'] = self.objects[['Name']].apply(
     lambda body: body.Name.earth_distance, axis=1)
   # Calculate planets phase
   self.objects['Phase'] = self.objects[['Name']].apply(
     lambda body: body.Name.phase, axis=1)

<|endoftext|>


<commit_before># Copyright: Damien Elmes <anki@ichi2.net>
# -*- coding: utf-8 -*-
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

from aqt.qt import *
from http import HTTPStatus
import http.server
import errno

class MediaServer(QThread):

    def run(self):
        self.port = 8080
        self.server = None
        while not self.server:
            try:
                self.server = http.server.HTTPServer(
                        ("localhost", self.port), RequestHandler)
            except OSError as e:
                if e.errno == errno.EADDRINUSE:
                    self.port += 1
                    continue
                raise
            break
        self.server.serve_forever()

class RequestHandler(http.server.SimpleHTTPRequestHandler):

    def send_head(self):
        path = self.translate_path(self.path)
        if os.path.isdir(path):
            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
            return None
        ctype = self.guess_type(path)
        try:
            f = open(path, 'rb')
        except OSError:
            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
            return None
        try:
            self.send_response(HTTPStatus.OK)
            self.send_header("Content-type", ctype)
            fs = os.fstat(f.fileno())
            self.send_header("Content-Length", str(fs[6]))
            self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
            self.end_headers()
            return f
        except:
            f.close()
            raise

    def log_message(self, format, *args):
        if not os.getenv("ANKIDEV"):
            return
        print("%s - - [%s] %s" %
                         (self.address_string(),
                          self.log_date_time_string(),
                          format%args))
<commit_msg>swallow http server errors<commit_after># Copyright: Damien Elmes <anki@ichi2.net>
# -*- coding: utf-8 -*-
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

from aqt.qt import *
from http import HTTPStatus
import http.server
import errno

class MediaServer(QThread):

    def run(self):
        self.port = 10000
        self.server = None
        while not self.server:
            try:
                self.server = http.server.HTTPServer(
                        ("localhost", self.port), RequestHandler)
            except OSError as e:
                if e.errno == errno.EADDRINUSE:
                    self.port += 1
                    continue
                raise
            break
        self.server.serve_forever()

class RequestHandler(http.server.SimpleHTTPRequestHandler):

    def do_GET(self):
        f = self.send_head()
        if f:
            try:
                self.copyfile(f, self.wfile)
            except Exception as e:
                if os.getenv("ANKIDEV"):
                    print("http server caught exception:", e)
                else:
                    # swallow it - user likely surfed away from
                    # review screen before an image had finished
                    # downloading
                    pass
            finally:
                f.close()

    def send_head(self):
        path = self.translate_path(self.path)
        if os.path.isdir(path):
            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
            return None
        ctype = self.guess_type(path)
        try:
            f = open(path, 'rb')
        except OSError:
            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
            return None
        try:
            self.send_response(HTTPStatus.OK)
            self.send_header("Content-type", ctype)
            fs = os.fstat(f.fileno())
            self.send_header("Content-Length", str(fs[6]))
            self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
            self.end_headers()
            return f
        except:
            f.close()
            raise

    def log_message(self, format, *args):
        if not os.getenv("ANKIDEV"):
            return
        print("%s - - [%s] %s" %
                         (self.address_string(),
                          self.log_date_time_string(),
                          format%args))
<|endoftext|>


<commit_before>import json
# from urllib import quote
from xml.etree.ElementTree import Element, SubElement, tostring

from twisted.internet.defer import inlineCallbacks
from twisted.web import http

from vumi.message import TransportUserMessage
from vumi.config import ConfigText
from vumi.transports.httprpc import HttpRpcTransport
from vumi import log

class BlastSMSUssdTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    base_url = ConfigText(
        'The base url of the transport',
        required=True, static=True)

class BlastSMSUssdTransport(HttpRpcTransport):
    """
    HTTP transport for USSD with BlastSMS
    """
    transport_type = 'ussd'
    transport_name = 'vumi-blastsms'
    ENCODING = 'utf-8'
    EXPECTED_FIELDS = set(['msisdn', 'shortcode', 'sessionid', 'type'])
    OPTIONAL_FIELDS = set(['msg', 'appid'])

    # errors
    RESPONSE_FAILURE_ERROR = "Response to http request failed."
    NOT_REPLY_ERROR = "Outbound message is not a reply"
    NO_CONTENT_ERROR = "Outbound message has no content."

    CONFIG_CLASS = BlastSMSUssdTransportConfig

    def get_optional_field_values(self, request, optional_fields=frozenset()):
        values = {}
        for field in optional_fields:
            if field in request.args:
                raw_value = request.args.get(field)[0]
                values[field] = raw_value.decode(self.ENCODING)
            else:
                values[field] = None
        return values

    @inlineCallbacks
    def handle_raw_inbound_message(self, message_id, request):
        values, errors = self.get_field_values(
            request,
            self.EXPECTED_FIELDS,
            self.OPTIONAL_FIELDS,  # pass this in for error checking
        )
        print('values')
        print(values)
        print('values')
        print('')

        print('errors')
        print(errors)
        print('errors')
        print('')

        optional_values = self.get_optional_field_values(
            request,
            self.OPTIONAL_FIELDS
        )
        print('optional_values')
        print(optional_values)
        print('optional_values')
        print('')

        if errors:
            log.info('Unhappy incoming message: %s ' % (errors,))
            yield self.finish_request(
                message_id, json.dumps(errors), code=http.BAD_REQUEST
            )
            return

        if values['type'] == '2':  # resume session
            session_event = TransportUserMessage.SESSION_RESUME
        elif values['type'] == '1':  # new session
            session_event = TransportUserMessage.SESSION_NEW
        else:
            # TODO: handle other types if necessary
            # Default to new session for 3 & 4 for now
            session_event = TransportUserMessage.SESSION_NEW

        if optional_values['msg'] is not None:
            content = optional_values['msg']
        else:
            content = None

        log.info(
            'BlastSMSUssdTransport receiving inbound message from %s to '
            '%s.' % (values['msisdn'], values['shortcode']))

        yield self.publish_message(
            message_id=message_id,
            content=content,
            to_addr=values['shortcode'],
            from_addr=values['msisdn'],
            # provider=None,
            session_event=session_event,
            transport_type=self.transport_type,
            # transport_name=self.transport_name,  # ?
            transport_metadata={
                'sessionid': values['sessionid'],
                'appid': optional_values['appid'],

            },
        )

    def generate_body(self, msisdn, sessionid, appid, in_reply_to,
                      reply_content, session_event):

        e_ussdresp = Element('ussdresp')

        se_msisdn = SubElement(e_ussdresp, 'msisdn')
        se_msisdn.text = msisdn

        se_sessionid = SubElement(e_ussdresp, 'sessionid')
        se_sessionid.text = sessionid
        # if sessionid
        #     se_sessionid.text = sessionid
        # else:
        #     se_sessionid.text = ''

        se_appid = SubElement(e_ussdresp, 'appid')
        if appid is not None:
            se_appid.text = appid
        else:
            # provide application session id - use reference to inbound
            # message that started the session
            se_appid.text = in_reply_to

        # Set Message Type: 2 for Response, 3 for Release
        se_type = SubElement(e_ussdresp, 'type')
        if session_event != TransportUserMessage.SESSION_CLOSE:
            se_type.text = '2'
        else:
            se_type.text = '3'

        se_msg = SubElement(e_ussdresp, 'msg')
        se_msg.text = reply_content

        return tostring(
            e_ussdresp,
            encoding='utf-8',
        )

    @inlineCallbacks
    def handle_outbound_message(self, message):

        # Generate outbound message
        message_id = message['message_id']
        body = self.generate_body(
            message['to_addr'],  # msisdn
            message['transport_metadata']['sessionid'],  # sessionid
            message['transport_metadata']['appid'],  # appid
            message['in_reply_to'],
            message['content'],
            message['session_event']
        )
        log.info('BlastSMSUssdTransport outbound message with content: %r'
                 % (body,))

        # Errors
        if not message['content']:
            yield self.publish_nack(message_id, self.NO_CONTENT_ERROR)
            return
        if not message['in_reply_to']:
            yield self.publish_nack(message_id, self.NOT_REPLY_ERROR)
            return

        # Finish Request
        response_id = self.finish_request(
            message['in_reply_to'],
            body,
        )

        # Response failure
        if response_id is None:
            # we don't yield on this publish because if a message store is
            # used, that causes the worker to wait for Riak before processing
            # the message and responding to USSD messages is time critical.
            self.publish_nack(message_id, self.RESPONSE_FAILURE_ERROR)
            return

        # we don't yield on this publish because if a message store is
        # used, that causes the worker to wait for Riak before processing
        # the message and responding to USSD messages is time critical.
        self.publish_ack(
            user_message_id=message_id, sent_message_id=message_id)
<commit_msg>uncomment transport_name<commit_after>import json
# from urllib import quote
from xml.etree.ElementTree import Element, SubElement, tostring

from twisted.internet.defer import inlineCallbacks
from twisted.web import http

from vumi.message import TransportUserMessage
from vumi.config import ConfigText
from vumi.transports.httprpc import HttpRpcTransport
from vumi import log

class BlastSMSUssdTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    base_url = ConfigText(
        'The base url of the transport',
        required=True, static=True)

class BlastSMSUssdTransport(HttpRpcTransport):
    """
    HTTP transport for USSD with BlastSMS
    """
    transport_type = 'ussd'
    transport_name = 'vumi-blastsms'
    ENCODING = 'utf-8'
    EXPECTED_FIELDS = set(['msisdn', 'shortcode', 'sessionid', 'type'])
    OPTIONAL_FIELDS = set(['msg', 'appid'])

    # errors
    RESPONSE_FAILURE_ERROR = "Response to http request failed."
    NOT_REPLY_ERROR = "Outbound message is not a reply"
    NO_CONTENT_ERROR = "Outbound message has no content."

    CONFIG_CLASS = BlastSMSUssdTransportConfig

    def get_optional_field_values(self, request, optional_fields=frozenset()):
        values = {}
        for field in optional_fields:
            if field in request.args:
                raw_value = request.args.get(field)[0]
                values[field] = raw_value.decode(self.ENCODING)
            else:
                values[field] = None
        return values

    @inlineCallbacks
    def handle_raw_inbound_message(self, message_id, request):
        values, errors = self.get_field_values(
            request,
            self.EXPECTED_FIELDS,
            self.OPTIONAL_FIELDS,  # pass this in for error checking
        )
        print('values')
        print(values)
        print('values')
        print('')

        print('errors')
        print(errors)
        print('errors')
        print('')

        optional_values = self.get_optional_field_values(
            request,
            self.OPTIONAL_FIELDS
        )
        print('optional_values')
        print(optional_values)
        print('optional_values')
        print('')

        if errors:
            log.info('Unhappy incoming message: %s ' % (errors,))
            yield self.finish_request(
                message_id, json.dumps(errors), code=http.BAD_REQUEST
            )
            return

        if values['type'] == '2':  # resume session
            session_event = TransportUserMessage.SESSION_RESUME
        elif values['type'] == '1':  # new session
            session_event = TransportUserMessage.SESSION_NEW
        else:
            # TODO: handle other types if necessary
            # Default to new session for 3 & 4 for now
            session_event = TransportUserMessage.SESSION_NEW

        if optional_values['msg'] is not None:
            content = optional_values['msg']
        else:
            content = None

        log.info(
            'BlastSMSUssdTransport receiving inbound message from %s to '
            '%s.' % (values['msisdn'], values['shortcode']))

        yield self.publish_message(
            message_id=message_id,
            content=content,
            to_addr=values['shortcode'],
            from_addr=values['msisdn'],
            # provider=None,
            session_event=session_event,
            transport_type=self.transport_type,
            transport_name=self.transport_name,
            transport_metadata={
                'sessionid': values['sessionid'],
                'appid': optional_values['appid'],

            },
        )

    def generate_body(self, msisdn, sessionid, appid, in_reply_to,
                      reply_content, session_event):

        e_ussdresp = Element('ussdresp')

        se_msisdn = SubElement(e_ussdresp, 'msisdn')
        se_msisdn.text = msisdn

        se_sessionid = SubElement(e_ussdresp, 'sessionid')
        se_sessionid.text = sessionid
        # if sessionid
        #     se_sessionid.text = sessionid
        # else:
        #     se_sessionid.text = ''

        se_appid = SubElement(e_ussdresp, 'appid')
        if appid is not None:
            se_appid.text = appid
        else:
            # provide application session id - use reference to inbound
            # message that started the session
            se_appid.text = in_reply_to

        # Set Message Type: 2 for Response, 3 for Release
        se_type = SubElement(e_ussdresp, 'type')
        if session_event != TransportUserMessage.SESSION_CLOSE:
            se_type.text = '2'
        else:
            se_type.text = '3'

        se_msg = SubElement(e_ussdresp, 'msg')
        se_msg.text = reply_content

        return tostring(
            e_ussdresp,
            encoding='utf-8',
        )

    @inlineCallbacks
    def handle_outbound_message(self, message):

        # Generate outbound message
        message_id = message['message_id']
        body = self.generate_body(
            message['to_addr'],  # msisdn
            message['transport_metadata']['sessionid'],  # sessionid
            message['transport_metadata']['appid'],  # appid
            message['in_reply_to'],
            message['content'],
            message['session_event']
        )
        log.info('BlastSMSUssdTransport outbound message with content: %r'
                 % (body,))

        # Errors
        if not message['content']:
            yield self.publish_nack(message_id, self.NO_CONTENT_ERROR)
            return
        if not message['in_reply_to']:
            yield self.publish_nack(message_id, self.NOT_REPLY_ERROR)
            return

        # Finish Request
        response_id = self.finish_request(
            message['in_reply_to'],
            body,
        )

        # Response failure
        if response_id is None:
            # we don't yield on this publish because if a message store is
            # used, that causes the worker to wait for Riak before processing
            # the message and responding to USSD messages is time critical.
            self.publish_nack(message_id, self.RESPONSE_FAILURE_ERROR)
            return

        # we don't yield on this publish because if a message store is
        # used, that causes the worker to wait for Riak before processing
        # the message and responding to USSD messages is time critical.
        self.publish_ack(
            user_message_id=message_id, sent_message_id=message_id)
<|endoftext|>


<commit_before>from decimal import Decimal
import random
import hashlib

from django.conf import settings
from django.core.cache import cache
from django.db.models.signals import post_save, post_delete, m2m_changed

from waffle.models import Flag, Sample, Switch

VERSION = (0, 10)
__version__ = '.'.join(map(str, VERSION))

CACHE_PREFIX = getattr(settings, 'WAFFLE_CACHE_PREFIX', u'waffle:')
FLAG_CACHE_KEY = u'flag:%s'
FLAGS_ALL_CACHE_KEY = u'flags:all'
FLAG_USERS_CACHE_KEY = u'flag:%s:users'
FLAG_GROUPS_CACHE_KEY = u'flag:%s:groups'
SAMPLE_CACHE_KEY = u'sample:%s'
SAMPLES_ALL_CACHE_KEY = u'samples:all'
SWITCH_CACHE_KEY = u'switch:%s'
SWITCHES_ALL_CACHE_KEY = u'switches:all'
COOKIE_NAME = getattr(settings, 'WAFFLE_COOKIE', 'dwf_%s')
TEST_COOKIE_NAME = getattr(settings, 'WAFFLE_TESTING_COOKIE', 'dwft_%s')

def keyfmt(k, v=None):
    if v is None:
        return CACHE_PREFIX + k
    return CACHE_PREFIX + hashlib.md5((k % v).encode('utf-8')).hexdigest()

class DoesNotExist(object):
    """The record does not exist."""
    @property
    def active(self):
        return getattr(settings, 'WAFFLE_SWITCH_DEFAULT', False)

def set_flag(request, flag_name, active=True, session_only=False):
    """Set a flag value on a request object."""
    if not hasattr(request, 'waffles'):
        request.waffles = {}
    request.waffles[flag_name] = [active, session_only]

def flag_is_active(request, flag_name):
    flag = cache.get(keyfmt(FLAG_CACHE_KEY, flag_name))
    if flag is None:
        try:
            flag = Flag.objects.get(name=flag_name)
            cache_flag(instance=flag)
        except Flag.DoesNotExist:
            return getattr(settings, 'WAFFLE_FLAG_DEFAULT', False)

    if getattr(settings, 'WAFFLE_OVERRIDE', False):
        if flag_name in request.GET:
            return request.GET[flag_name] == '1'

    if flag.everyone:
        return True
    elif flag.everyone is False:
        return False

    if flag.testing:  # Testing mode is on.
        tc = TEST_COOKIE_NAME % flag_name
        if tc in request.GET:
            on = request.GET[tc] == '1'
            if not hasattr(request, 'waffle_tests'):
                request.waffle_tests = {}
            request.waffle_tests[flag_name] = on
            return on
        if tc in request.COOKIES:
            return request.COOKIES[tc] == 'True'

    user = request.user

    if flag.authenticated and user.is_authenticated():
        return True

    if flag.staff and user.is_staff:
        return True

    if flag.superusers and user.is_superuser:
        return True

    if flag.languages:
        languages = flag.languages.split(',')
        if (hasattr(request, 'LANGUAGE_CODE') and
                request.LANGUAGE_CODE in languages):
            return True

    flag_users = cache.get(keyfmt(FLAG_USERS_CACHE_KEY, flag.name))
    if flag_users is None:
        flag_users = flag.users.all()
        cache_flag(instance=flag)
    if user in flag_users:
        return True

    flag_groups = cache.get(keyfmt(FLAG_GROUPS_CACHE_KEY, flag.name))
    if flag_groups is None:
        flag_groups = flag.groups.all()
        cache_flag(instance=flag)
    user_groups = user.groups.all()
    for group in flag_groups:
        if group in user_groups:
            return True

    if flag.percent and flag.percent > 0:
        if not hasattr(request, 'waffles'):
            request.waffles = {}
        elif flag_name in request.waffles:
            return request.waffles[flag_name][0]

        cookie = COOKIE_NAME % flag_name
        if cookie in request.COOKIES:
            flag_active = (request.COOKIES[cookie] == 'True')
            set_flag(request, flag_name, flag_active, flag.rollout)
            return flag_active

        if Decimal(str(random.uniform(0, 100))) <= flag.percent:
            set_flag(request, flag_name, True, flag.rollout)
            return True
        set_flag(request, flag_name, False, flag.rollout)

    return False

def switch_is_active(switch_name):
    switch = cache.get(keyfmt(SWITCH_CACHE_KEY, switch_name))
    if switch is None:
        try:
            switch = Switch.objects.get(name=switch_name)
            cache_switch(instance=switch)
        except Switch.DoesNotExist:
            switch = DoesNotExist()
            switch.name = switch_name
            cache_switch(instance=switch)
    return switch.active

def sample_is_active(sample_name):
    sample = cache.get(keyfmt(SAMPLE_CACHE_KEY, sample_name))
    if sample is None:
        try:
            sample = Sample.objects.get(name=sample_name)
            cache_sample(instance=sample)
        except Sample.DoesNotExist:
            return getattr(settings, 'WAFFLE_SAMPLE_DEFAULT', False)

    return Decimal(str(random.uniform(0, 100))) <= sample.percent

def cache_flag(**kwargs):
    action = kwargs.get('action', None)
    # action is included for m2m_changed signal. Only cache on the post_*.
    if not action or action in ['post_add', 'post_remove', 'post_clear']:
        f = kwargs.get('instance')
        cache.add(keyfmt(FLAG_CACHE_KEY, f.name), f)
        cache.add(keyfmt(FLAG_USERS_CACHE_KEY, f.name), f.users.all())
        cache.add(keyfmt(FLAG_GROUPS_CACHE_KEY, f.name), f.groups.all())

def uncache_flag(**kwargs):
    flag = kwargs.get('instance')
    data = {
        keyfmt(FLAG_CACHE_KEY, flag.name): None,
        keyfmt(FLAG_USERS_CACHE_KEY, flag.name): None,
        keyfmt(FLAG_GROUPS_CACHE_KEY, flag.name): None,
        keyfmt(FLAGS_ALL_CACHE_KEY): None
    }
    cache.set_many(data, 5)

post_save.connect(uncache_flag, sender=Flag, dispatch_uid='save_flag')
post_delete.connect(uncache_flag, sender=Flag, dispatch_uid='delete_flag')
m2m_changed.connect(uncache_flag, sender=Flag.users.through,
                    dispatch_uid='m2m_flag_users')
m2m_changed.connect(uncache_flag, sender=Flag.groups.through,
                    dispatch_uid='m2m_flag_groups')

def cache_sample(**kwargs):
    sample = kwargs.get('instance')
    cache.add(keyfmt(SAMPLE_CACHE_KEY, sample.name), sample)

def uncache_sample(**kwargs):
    sample = kwargs.get('instance')
    cache.set(keyfmt(SAMPLE_CACHE_KEY, sample.name), None, 5)
    cache.set(keyfmt(SAMPLES_ALL_CACHE_KEY), None, 5)

post_save.connect(uncache_sample, sender=Sample, dispatch_uid='save_sample')
post_delete.connect(uncache_sample, sender=Sample,
                    dispatch_uid='delete_sample')

def cache_switch(**kwargs):
    switch = kwargs.get('instance')
    cache.add(keyfmt(SWITCH_CACHE_KEY, switch.name), switch)

def uncache_switch(**kwargs):
    switch = kwargs.get('instance')
    cache.set(keyfmt(SWITCH_CACHE_KEY, switch.name), None, 5)
    cache.set(keyfmt(SWITCHES_ALL_CACHE_KEY), None, 5)

post_delete.connect(uncache_switch, sender=Switch,
                    dispatch_uid='delete_switch')
post_save.connect(uncache_switch, sender=Switch, dispatch_uid='save_switch')
<commit_msg>Drop u string prefixes.<commit_after>from decimal import Decimal
import random
import hashlib

from django.conf import settings
from django.core.cache import cache
from django.db.models.signals import post_save, post_delete, m2m_changed

from waffle.models import Flag, Sample, Switch

VERSION = (0, 10)
__version__ = '.'.join(map(str, VERSION))

CACHE_PREFIX = getattr(settings, 'WAFFLE_CACHE_PREFIX', 'waffle:')
FLAG_CACHE_KEY = 'flag:%s'
FLAGS_ALL_CACHE_KEY = 'flags:all'
FLAG_USERS_CACHE_KEY = 'flag:%s:users'
FLAG_GROUPS_CACHE_KEY = 'flag:%s:groups'
SAMPLE_CACHE_KEY = 'sample:%s'
SAMPLES_ALL_CACHE_KEY = 'samples:all'
SWITCH_CACHE_KEY = 'switch:%s'
SWITCHES_ALL_CACHE_KEY = 'switches:all'
COOKIE_NAME = getattr(settings, 'WAFFLE_COOKIE', 'dwf_%s')
TEST_COOKIE_NAME = getattr(settings, 'WAFFLE_TESTING_COOKIE', 'dwft_%s')

def keyfmt(k, v=None):
    if v is None:
        return CACHE_PREFIX + k
    return CACHE_PREFIX + hashlib.md5((k % v).encode('utf-8')).hexdigest()

class DoesNotExist(object):
    """The record does not exist."""
    @property
    def active(self):
        return getattr(settings, 'WAFFLE_SWITCH_DEFAULT', False)

def set_flag(request, flag_name, active=True, session_only=False):
    """Set a flag value on a request object."""
    if not hasattr(request, 'waffles'):
        request.waffles = {}
    request.waffles[flag_name] = [active, session_only]

def flag_is_active(request, flag_name):
    flag = cache.get(keyfmt(FLAG_CACHE_KEY, flag_name))
    if flag is None:
        try:
            flag = Flag.objects.get(name=flag_name)
            cache_flag(instance=flag)
        except Flag.DoesNotExist:
            return getattr(settings, 'WAFFLE_FLAG_DEFAULT', False)

    if getattr(settings, 'WAFFLE_OVERRIDE', False):
        if flag_name in request.GET:
            return request.GET[flag_name] == '1'

    if flag.everyone:
        return True
    elif flag.everyone is False:
        return False

    if flag.testing:  # Testing mode is on.
        tc = TEST_COOKIE_NAME % flag_name
        if tc in request.GET:
            on = request.GET[tc] == '1'
            if not hasattr(request, 'waffle_tests'):
                request.waffle_tests = {}
            request.waffle_tests[flag_name] = on
            return on
        if tc in request.COOKIES:
            return request.COOKIES[tc] == 'True'

    user = request.user

    if flag.authenticated and user.is_authenticated():
        return True

    if flag.staff and user.is_staff:
        return True

    if flag.superusers and user.is_superuser:
        return True

    if flag.languages:
        languages = flag.languages.split(',')
        if (hasattr(request, 'LANGUAGE_CODE') and
                request.LANGUAGE_CODE in languages):
            return True

    flag_users = cache.get(keyfmt(FLAG_USERS_CACHE_KEY, flag.name))
    if flag_users is None:
        flag_users = flag.users.all()
        cache_flag(instance=flag)
    if user in flag_users:
        return True

    flag_groups = cache.get(keyfmt(FLAG_GROUPS_CACHE_KEY, flag.name))
    if flag_groups is None:
        flag_groups = flag.groups.all()
        cache_flag(instance=flag)
    user_groups = user.groups.all()
    for group in flag_groups:
        if group in user_groups:
            return True

    if flag.percent and flag.percent > 0:
        if not hasattr(request, 'waffles'):
            request.waffles = {}
        elif flag_name in request.waffles:
            return request.waffles[flag_name][0]

        cookie = COOKIE_NAME % flag_name
        if cookie in request.COOKIES:
            flag_active = (request.COOKIES[cookie] == 'True')
            set_flag(request, flag_name, flag_active, flag.rollout)
            return flag_active

        if Decimal(str(random.uniform(0, 100))) <= flag.percent:
            set_flag(request, flag_name, True, flag.rollout)
            return True
        set_flag(request, flag_name, False, flag.rollout)

    return False

def switch_is_active(switch_name):
    switch = cache.get(keyfmt(SWITCH_CACHE_KEY, switch_name))
    if switch is None:
        try:
            switch = Switch.objects.get(name=switch_name)
            cache_switch(instance=switch)
        except Switch.DoesNotExist:
            switch = DoesNotExist()
            switch.name = switch_name
            cache_switch(instance=switch)
    return switch.active

def sample_is_active(sample_name):
    sample = cache.get(keyfmt(SAMPLE_CACHE_KEY, sample_name))
    if sample is None:
        try:
            sample = Sample.objects.get(name=sample_name)
            cache_sample(instance=sample)
        except Sample.DoesNotExist:
            return getattr(settings, 'WAFFLE_SAMPLE_DEFAULT', False)

    return Decimal(str(random.uniform(0, 100))) <= sample.percent

def cache_flag(**kwargs):
    action = kwargs.get('action', None)
    # action is included for m2m_changed signal. Only cache on the post_*.
    if not action or action in ['post_add', 'post_remove', 'post_clear']:
        f = kwargs.get('instance')
        cache.add(keyfmt(FLAG_CACHE_KEY, f.name), f)
        cache.add(keyfmt(FLAG_USERS_CACHE_KEY, f.name), f.users.all())
        cache.add(keyfmt(FLAG_GROUPS_CACHE_KEY, f.name), f.groups.all())

def uncache_flag(**kwargs):
    flag = kwargs.get('instance')
    data = {
        keyfmt(FLAG_CACHE_KEY, flag.name): None,
        keyfmt(FLAG_USERS_CACHE_KEY, flag.name): None,
        keyfmt(FLAG_GROUPS_CACHE_KEY, flag.name): None,
        keyfmt(FLAGS_ALL_CACHE_KEY): None
    }
    cache.set_many(data, 5)

post_save.connect(uncache_flag, sender=Flag, dispatch_uid='save_flag')
post_delete.connect(uncache_flag, sender=Flag, dispatch_uid='delete_flag')
m2m_changed.connect(uncache_flag, sender=Flag.users.through,
                    dispatch_uid='m2m_flag_users')
m2m_changed.connect(uncache_flag, sender=Flag.groups.through,
                    dispatch_uid='m2m_flag_groups')

def cache_sample(**kwargs):
    sample = kwargs.get('instance')
    cache.add(keyfmt(SAMPLE_CACHE_KEY, sample.name), sample)

def uncache_sample(**kwargs):
    sample = kwargs.get('instance')
    cache.set(keyfmt(SAMPLE_CACHE_KEY, sample.name), None, 5)
    cache.set(keyfmt(SAMPLES_ALL_CACHE_KEY), None, 5)

post_save.connect(uncache_sample, sender=Sample, dispatch_uid='save_sample')
post_delete.connect(uncache_sample, sender=Sample,
                    dispatch_uid='delete_sample')

def cache_switch(**kwargs):
    switch = kwargs.get('instance')
    cache.add(keyfmt(SWITCH_CACHE_KEY, switch.name), switch)

def uncache_switch(**kwargs):
    switch = kwargs.get('instance')
    cache.set(keyfmt(SWITCH_CACHE_KEY, switch.name), None, 5)
    cache.set(keyfmt(SWITCHES_ALL_CACHE_KEY), None, 5)

post_delete.connect(uncache_switch, sender=Switch,
                    dispatch_uid='delete_switch')
post_save.connect(uncache_switch, sender=Switch, dispatch_uid='save_switch')
<|endoftext|>