<commit_before># -*- coding: utf-8 -*-
#
#
# This file is execfile()d with the current directory set to its containing
# dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))

# -- General configuration ----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
# source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = 'IRMA frontend'
copyright = '2013-2014, Quarkslab'

# The version info for the project yo're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.1'
# The full version, including alpha/beta/rc tags.
release = '1.1.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []

# -- Options for HTML output --------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
html_theme_path = ["_themes", ]

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
# html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
# html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}

# If false, no module index is generated.
# html_domain_indices = True

# If false, no index is generated.
# html_use_index = True

# If true, the index is split into individual pages for each letter.
# html_split_index = False

# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'IRMAdoc'

# -- Options for LaTeX output -------------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    # 'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
    ('index',
     'IRMA.tex',
     'IRMA (frontend) Documentation',
     'Quarkslab',
     'manual'),
    ]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False

# If true, show page references after internal links.
# latex_show_pagerefs = False

# If true, show URL addresses after external links.
# latex_show_urls = False

# Documents to append as an appendix to all manuals.
# latex_appendices = []

# If false, no module index is generated.
# latex_domain_indices = True

# -- Options for manual page output -------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'IRMA', 'IRMA (frontend) Documentation',
     ['Quarkslab'], 1)
]

# If true, show URL addresses after external links.
# man_show_urls = False

# -- Options for Texinfo output -----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    ('index',
     'IRMA',
     'IRMA (frontend) Documentation',
     'Quarkslab',
     'IRMA',
     'One line description of project.',
     'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
# texinfo_appendices = []

# If false, no module index is generated.
# texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'

# -- Options for Epub output --------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = 'IRMA'
epub_author = 'Quarkslab'
epub_publisher = 'Quarkslab'
epub_copyright = '2013-2014, Quarkslab'

# The language of the text. It defaults to the language option
# or en if the language is not set.
# epub_language = ''

# The scheme of the identifier. Typical schemes are ISBN or URL.
# epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
# epub_identifier = ''

# A unique identification for the text.
# epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
# epub_cover = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
# epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
# epub_post_files = []

# A list of files that should not be packed into the epub file.
# epub_exclude_files = []

# The depth of the table of contents in toc.ncx.
# epub_tocdepth = 3

# Allow duplicate toc entries.
# epub_tocdup = True
<commit_msg>updated conf.py<commit_after># -*- coding: utf-8 -*-
#
#
# This file is execfile()d with the current directory set to its containing
# dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))

# -- General configuration ----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
# source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = 'IRMA'
copyright = '2013-2014, Quarkslab'

# The version info for the project yo're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.1'
# The full version, including alpha/beta/rc tags.
release = '1.1.1'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []

# -- Options for HTML output --------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
html_theme_path = ["_themes", ]

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
# html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
# html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}

# If false, no module index is generated.
# html_domain_indices = True

# If false, no index is generated.
# html_use_index = True

# If true, the index is split into individual pages for each letter.
# html_split_index = False

# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'IRMAdoc'

# -- Options for LaTeX output -------------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    # 'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
    ('index',
     'IRMA.tex',
     'IRMA Documentation',
     'Quarkslab',
     'manual'),
    ]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False

# If true, show page references after internal links.
# latex_show_pagerefs = False

# If true, show URL addresses after external links.
# latex_show_urls = False

# Documents to append as an appendix to all manuals.
# latex_appendices = []

# If false, no module index is generated.
# latex_domain_indices = True

# -- Options for manual page output -------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'IRMA', 'IRMA Documentation',
     ['Quarkslab'], 1)
]

# If true, show URL addresses after external links.
# man_show_urls = False

# -- Options for Texinfo output -----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    ('index',
     'IRMA',
     'IRMA Documentation',
     'Quarkslab',
     'IRMA',
     'Incident Response & Malware Analysis Platform.',
     'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
# texinfo_appendices = []

# If false, no module index is generated.
# texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'

# -- Options for Epub output --------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = 'IRMA'
epub_author = 'Quarkslab'
epub_publisher = 'Quarkslab'
epub_copyright = '2013-2014, Quarkslab'

# The language of the text. It defaults to the language option
# or en if the language is not set.
# epub_language = ''

# The scheme of the identifier. Typical schemes are ISBN or URL.
# epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
# epub_identifier = ''

# A unique identification for the text.
# epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
# epub_cover = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
# epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
# epub_post_files = []

# A list of files that should not be packed into the epub file.
# epub_exclude_files = []

# The depth of the table of contents in toc.ncx.
# epub_tocdepth = 3

# Allow duplicate toc entries.
# epub_tocdup = True
<|endoftext|>


<commit_before>from logging import debug, info

class Brain(object):
	ACTIONS = [
		Find,
		Duplicate,
		Rest,
		Turn,
		Forward
	]

	def __init__(self, body):
		self.body = body
		self.actions = [a(self.body) for a in self.ACTIONS]

	def tick(self):
		self.dna.next_choice(self.actions).tick()

class Action(object):
	def __init__(self, body):
		self.body = body

	def log(self):
		raise NotImplementedError

	def tick(self):
		raise NotImplementedError

class Move(Action):
	pass

class Find(Action):
	pass

class Duplicate(Action):
	pass

class Turn(Action):
	def log(self):
		debug("Body %s is turning", self.body.dna)

	def tick(self):
		speed = self.body.dna.next_float(0.6) - 0.3
		self.body.drain(amount)
		self.body.direction += speed
		while self.body.direction < 0:
			self.body.direction += 2 * pi
		while self.body.direction > 2 * pi:
			self.body.direction -= 2 * pi

class Forward(Action):
	def log(self):
		debug("Body %s is moving forward", self.body.dna)

	def tick(self):
		speed = self.body.dna.next_float(10) + 10
		self.body.drain(speed * 2)
		self.body.x += speed * cos(self.body.direction)
		self.body.y += speed * sin(self.body.direction)

class Rest(Action):
	pass
<commit_msg>add dupliaction in core classes<commit_after>from logging import debug, info

class Brain(object):
	ACTIONS = [
		Find,
		Duplicate,
		Rest,
		Turn,
		Forward
	]

	def __init__(self, body):
		self.body = body
		self.actions = [a(self.body) for a in self.ACTIONS]

	def tick(self):
		self.dna.next_choice(self.actions).tick()

class Action(object):
	def __init__(self, body):
		self.body = body

	def log(self):
		raise NotImplementedError

	def tick(self):
		raise NotImplementedError

class Move(Action):
	pass

class Find(Action):
	pass

class Duplicate(Action):
	def log(self):
		debug("Body %s duplicated", self.body.dna)

	def tick(self):
		if self.body.dna.next_float() < 0.99:
			return
		self.body.drain(
			1000 * self.body.dna.next_float() +
			self.body.energy / 2
		)
		if self.dead:
			return
		self.body.map.add(Body.copy(self.body))

class Turn(Action):
	def log(self):
		debug("Body %s is turning", self.body.dna)

	def tick(self):
		speed = self.body.dna.next_float(0.6) - 0.3
		self.body.drain(amount)
		self.body.direction += speed
		while self.body.direction < 0:
			self.body.direction += 2 * pi
		while self.body.direction > 2 * pi:
			self.body.direction -= 2 * pi

class Forward(Action):
	def log(self):
		debug("Body %s is moving forward", self.body.dna)

	def tick(self):
		speed = self.body.dna.next_float(10) + 10
		self.body.drain(speed * 2)
		self.body.x += speed * cos(self.body.direction)
		self.body.y += speed * sin(self.body.direction)

class Rest(Action):
	pass
<|endoftext|>


<commit_before>import json
import random
import datetime
import calendar
import time
import importlib
from optparse import OptionParser

import settings as settingsLib

import boto.swf

import provider.swfmeta as swfmetalib
import starter

"""
SWF cron
"""

def run_cron(ENV = "dev"):
  # Specify run environment settings
  settings = settingsLib.get_settings(ENV)

  current_time = time.gmtime()

  # Based on the minutes of the current time, run certain starters
  if(current_time.tm_min >= 0 and current_time.tm_min <= 29):
    # Jobs to start at the top of the hour
    #print "Top of the hour"

    workflow_conditional_start(
      ENV           = ENV,
      starter_name  = "starter_S3Monitor",
      workflow_id   = "S3Monitor",
      start_seconds = 60*60)

    pass

  elif(current_time.tm_min >= 30 and current_time.tm_min <= 59):
    # Jobs to start at the bottom of the hour
    #print "Bottom of the hour"

    workflow_conditional_start(
      ENV           = ENV,
      starter_name  = "cron_NewS3XML",
      workflow_id   = "cron_NewS3XML",
      start_seconds = 60*60)

    if(current_time.tm_min >= 45 and current_time.tm_min <= 59):
      # Bottom quarter of the hour

      workflow_conditional_start(
        ENV           = ENV,
        starter_name  = "starter_AdminEmail",
        workflow_id   = "AdminEmail",
        start_seconds = 60*60*4)

def workflow_conditional_start(ENV, starter_name, start_seconds, data = None, workflow_id = None, workflow_name = None, workflow_version = None):
  """
  Given workflow criteria, check the workflow completion history for the last time run
  If it last run more than start_seconds ago, start a new workflow
  """

  diff_seconds = None
  last_startTimestamp = None

  settings = settingsLib.get_settings(ENV)

  swfmeta = swfmetalib.SWFMeta(settings)
  swfmeta.connect()

  last_startTimestamp = swfmeta.get_last_completed_workflow_execution_startTimestamp(workflow_id = workflow_id, workflow_name = workflow_name, workflow_version = workflow_version)

  current_timestamp = calendar.timegm(time.gmtime())

  if(last_startTimestamp is not None):
    diff_seconds = current_timestamp - start_seconds - last_startTimestamp
    print diff_seconds

  if(diff_seconds >= 0 or last_startTimestamp is None):
    # Start a new workflow
    # Load the starter module
    module_name = "starter." + starter_name
    importlib.import_module(module_name)
    s = eval(module_name)

    # Customised start functions
    if(starter_name == "starter_S3Monitor"):
      s.start(ENV = ENV, workflow = "S3Monitor")
    elif(starter_name == "starter_AdminEmail"):
      s.start(ENV = ENV, workflow = "AdminEmail")
    elif(starter_name == "cron_NewS3XML"):
      s.start(ENV = ENV)

if __name__ == "__main__":

  # Add options
  parser = OptionParser()
  parser.add_option("-e", "--env", default="dev", action="store", type="string", dest="env", help="set the environment to run, either dev or live")
  (options, args) = parser.parse_args()
  if options.env:
    ENV = options.env

  run_cron(ENV)
<commit_msg>Tweak pseudo-cron starter timings.<commit_after>import json
import random
import datetime
import calendar
import time
import importlib
from optparse import OptionParser

import settings as settingsLib

import boto.swf

import provider.swfmeta as swfmetalib
import starter

"""
SWF cron
"""

def run_cron(ENV = "dev"):
  # Specify run environment settings
  settings = settingsLib.get_settings(ENV)

  current_time = time.gmtime()

  # Based on the minutes of the current time, run certain starters
  if(current_time.tm_min >= 0 and current_time.tm_min <= 29):
    # Jobs to start at the top of the hour
    #print "Top of the hour"

    workflow_conditional_start(
      ENV           = ENV,
      starter_name  = "starter_S3Monitor",
      workflow_id   = "S3Monitor",
      start_seconds = 60*31)

    pass

  elif(current_time.tm_min >= 30 and current_time.tm_min <= 59):
    # Jobs to start at the bottom of the hour
    #print "Bottom of the hour"

    workflow_conditional_start(
      ENV           = ENV,
      starter_name  = "cron_NewS3XML",
      workflow_id   = "cron_NewS3XML",
      start_seconds = 60*31)

    if(current_time.tm_min >= 45 and current_time.tm_min <= 59):
      # Bottom quarter of the hour

      workflow_conditional_start(
        ENV           = ENV,
        starter_name  = "starter_AdminEmail",
        workflow_id   = "AdminEmail",
        start_seconds = (60*60*4)-14)

def workflow_conditional_start(ENV, starter_name, start_seconds, data = None, workflow_id = None, workflow_name = None, workflow_version = None):
  """
  Given workflow criteria, check the workflow completion history for the last time run
  If it last run more than start_seconds ago, start a new workflow
  """

  diff_seconds = None
  last_startTimestamp = None

  settings = settingsLib.get_settings(ENV)

  swfmeta = swfmetalib.SWFMeta(settings)
  swfmeta.connect()

  last_startTimestamp = swfmeta.get_last_completed_workflow_execution_startTimestamp(workflow_id = workflow_id, workflow_name = workflow_name, workflow_version = workflow_version)

  current_timestamp = calendar.timegm(time.gmtime())

  if(last_startTimestamp is not None):
    diff_seconds = current_timestamp - start_seconds - last_startTimestamp
    print diff_seconds

  if(diff_seconds >= 0 or last_startTimestamp is None):
    # Start a new workflow
    # Load the starter module
    module_name = "starter." + starter_name
    importlib.import_module(module_name)
    s = eval(module_name)

    # Customised start functions
    if(starter_name == "starter_S3Monitor"):
      s.start(ENV = ENV, workflow = "S3Monitor")
    elif(starter_name == "starter_AdminEmail"):
      s.start(ENV = ENV, workflow = "AdminEmail")
    elif(starter_name == "cron_NewS3XML"):
      s.start(ENV = ENV)

if __name__ == "__main__":

  # Add options
  parser = OptionParser()
  parser.add_option("-e", "--env", default="dev", action="store", type="string", dest="env", help="set the environment to run, either dev or live")
  (options, args) = parser.parse_args()
  if options.env:
    ENV = options.env

  run_cron(ENV)
<|endoftext|>


<commit_before>
import numpy as np
from spectral_cube import SpectralCube
from astropy import units as u
from astropy.coordinates import Angle

hi_mass_conversion = 0.019 * (u.M_sun / u.pc ** 2) / (u.K * u.km / u.s)

def radial_profile(gal, header=None, cube=None,
                   dr=100 * u.pc, mom0=None,
                   max_rad=10 * u.kpc,
                   mass_conversion=hi_mass_conversion,
                   restfreq=1.414 * u.GHz,
                   pa_bounds=None, beam=None):
    '''
    Create a radial profile, optionally with limits on the angles used.

    Parameters
    ----------
    pa_bounds : list of 2 Angles, optional
        When specified, limits the angles used when calculating the profile.
        e.g. pa_bounds=Angle([0.0*u.rad, np.pi*u.rad]))
    '''

    mom0 = mom0.squeeze()

    if mom0.ndim != 2:
        raise ValueError("mom0 must be 2 dimensional.")

    if mom0 is None:
        if cube is None:
            raise ValueError("Must give cube when not given mom0")
        mom0 = cube.moment0()

    if header is None and cube is None:
        raise TypeError("Either a header or cube must be given.")

    if header is None:
        header = cube.header

    if beam is None:
        if cube is not None:
            beam = cube.beam

    if beam is not None:
        beam_pix =  beam.sr.to(u.deg**2) / (header["CDELT2"] * u.deg)**2

    radius = gal.radius(header=header).to(u.kpc).value
    if pa_bounds is not None:
        # Check if they are angles
        if len(pa_bounds) != 2:
            raise IndexError("pa_bounds must contain 2 angles.")
        if not isinstance(pa_bounds, Angle):
            raise TypeError("pa_bounds must be an Angle.")

        # Return the array of PAs in the galaxy frame
        pas = gal.position_angles(header=header)

        # If the start angle is greater than the end, we need to wrap about
        # the discontinuity
        if pa_bounds[0] > pa_bounds[1]:
            initial_start = pa_bounds[0].copy()
            pa_bounds = pa_bounds.wrap_at(initial_start)
            pas = pas.wrap_at(initial_start)

    if max_rad is not None:
        max_rad = max_rad.to(u.kpc).value
    else:
        max_rad = radius.max() - dr

    dr = dr.to(u.kpc).value

    nbins = np.int(np.floor(max_rad / dr))

    inneredge = np.linspace(0, max_rad, nbins)
    outeredge = np.linspace(0 + dr, max_rad + dr, nbins)
    sdprof = np.zeros(nbins)
    sdprof_sigma = np.zeros(nbins)
    radprof = np.zeros(nbins)

    if pa_bounds is not None:
        pa_idx = np.logical_and(pas >= pa_bounds[0], pas < pa_bounds[1])

    for ctr, (r0, r1) in enumerate(zip(inneredge,
                                       outeredge)):

        idx = np.logical_and(radius >= r0, radius < r1)
        if pa_bounds is not None:
            idx = np.logical_and(idx, pa_idx)
        sdprof[ctr] = np.nansum(mom0[idx].value) / \
            np.sum(np.isfinite(radius[idx]))
        sdprof_sigma[ctr] = \
            np.sqrt(np.nansum((mom0[idx].value - sdprof[ctr])**2.) /
                    np.sum(np.isfinite(radius[idx])))
        # Rescale the sigma based on the number of independent samples
        if beam is not None:
            sdprof_sigma[ctr] /= \
                np.sqrt(np.sum(np.isfinite(radius[idx])) / beam_pix)
        radprof[ctr] = np.nanmean(radius[idx])

    # Re-apply some units
    radprof = radprof * u.kpc
    sdprof = sdprof * mom0.unit  # / u.pc ** 2
    sdprof_sigma = sdprof_sigma * mom0.unit  # / u.pc ** 2

    # Correct for the los inclinations
    sdprof *= np.cos(gal.inclination)
    sdprof_sigma *= np.cos(gal.inclination)

    # If in Jy/bm, convert to K.
    if cube is not None:
        unit = cube.unit

    # if mom0 is not None:
    #     unit = mom0.unit

    if unit.is_equivalent(u.Jy):
        # The beam units are sort of implied
        sdprof = sdprof.to(u.Jy * u.km / u.s)
        sdprof_sigma = sdprof_sigma.to(u.Jy * u.km / u.s)
        # Now convert to K
        if restfreq is not None:
            sdprof = sdprof * mom0.meta["beam"].jtok(restfreq)
            sdprof_sigma = sdprof_sigma * mom0.meta["beam"].jtok(restfreq)
        else:
            sdprof = sdprof * mom0.meta["beam"].jtok(mom0.header["RESTFREQ"])
            sdprof_sigma = sdprof_sigma * \
                mom0.meta["beam"].jtok(mom0.header["RESTFREQ"])

        sdprof = sdprof / u.Jy
        sdprof_sigma = sdprof_sigma / u.Jy

    if mass_conversion is not None:
        sdprof = sdprof * mass_conversion
        sdprof_sigma = sdprof_sigma * mass_conversion

    return radprof, sdprof, sdprof_sigma

if __name__ == "__main__":
    from galaxies import Galaxy
    import matplotlib.pyplot as p
    import os

    direc = "/home/eric/MyRAID/M33/14B-088/HI/full_imaging/"
    # direc = "/home/eric/MyRAID/M33/14B-088/HI/combined_HI/"

    cube_file = os.path.join(direc,
                             "M33_14B-088_HI.clean.image.pbcov_gt_0.3_masked.fits")
    # cube_file = os.path.join(direc,
    #                          "M33_14B-088_AT0206_HI.clean.image.pbcov_gt_0.3_masked.fits")

    cube = \
        SpectralCube.read(cube_file)

    g = Galaxy("M33")

    cube = cube.with_mask(cube > 1.8e-3 * u.Jy)

    mom0 = cube.moment0()

    # Create a radial profile of HI
    rs, sd, sd_sigma = radial_profile(g, cube=cube, mom0=mom0)
    rs_n, sd_n, sd_sigma_n = \
        radial_profile(g, cube=cube, mom0=mom0,
                       pa_bounds=Angle([0.5 * np.pi * u.rad,
                                        -0.5 * np.pi * u.rad]))
    rs_s, sd_s, sd_sigma_s = \
        radial_profile(g, cube=cube, mom0=mom0,
                       pa_bounds=Angle([-0.5 * np.pi * u.rad,
                                        0.5 * np.pi * u.rad]))

    # There is a ~1.5 global scaling factor b/w Arecibo and VLA + Arecibo
    scale_factor = 1.451

    # Add in creating a radial profile of the archival and the Arecibo
    # Also CO? I guess these should be on the same grid/resolution...

    # Arecibo
    arecibo_path = "/media/eric/Data_3//M33/Arecibo/14B-088_items/"
    arecibo_cube = \
        SpectralCube.read(os.path.join(arecibo_path,
                                       "M33_14B-088_HI_model.fits"))
    # Cut down to extents of the other cube
    arecibo_cube = \
        arecibo_cube.subcube(xlo=cube.longitude_extrema[0],
                             xhi=cube.longitude_extrema[1],
                             yhi=cube.latitude_extrema[0],
                             ylo=cube.latitude_extrema[1])
    arecibo_mom0 = arecibo_cube.moment0()
    rs_arec, sd_arec, sd_sigma_arec = \
        radial_profile(g, cube=arecibo_cube, mom0=arecibo_mom0)

    p.ioff()

    # Show the total radial profile VLA and Arecibo
    p.errorbar(rs.value, sd.value / scale_factor,
               yerr=sd_sigma.value / scale_factor, fmt="-", color="b",
               label="VLA + Arecibo", drawstyle='steps-mid')
    p.plot(rs_arec.value, sd_arec.value, "g--", drawstyle='steps-mid',
           label="Arecibo")
    # p.errorbar(rs_arec.value, sd_arec.value, yerr=sd_sigma_arec.value,
    #            fmt="o--", color="g", label="Arecibo", drawstyle='steps-mid')
    p.ylabel(r"$\Sigma$ (M$_{\odot}$ pc$^{-2}$)")
    p.xlabel(r"R (kpc)")
    p.legend(loc='best')
    p.grid("on")
    p.show()

    # Show the north vs south profiles
    p.plot(rs.value, sd.value / scale_factor, "k-.",
           drawstyle='steps-mid', label="Total")
    p.plot(rs_n.value, sd_n.value / scale_factor, "b-", label="North",
           drawstyle='steps-mid')
    p.plot(rs_s.value, sd_s.value / scale_factor, "g--", label="South",
           drawstyle='steps-mid')
    # p.errorbar(rs_n.value, sd_n.value, yerr=sd_sigma_n.value, fmt="D-", color="b",
    #            label="North")
    # p.errorbar(rs_s.value, sd_s.value, yerr=sd_sigma_s.value, fmt="o-", color="g",
    #            label="South")
    p.ylabel(r"$\Sigma$ (M$_{\odot}$ pc$^{-2}$)")
    p.xlabel(r"R (kpc)")
    p.legend(loc='best')
    p.grid("on")
    p.show()

    p.ion()
<commit_msg>Optionally compute the mass-weighted profiled<commit_after>
import numpy as np
from spectral_cube import SpectralCube
from astropy import units as u
from astropy.coordinates import Angle

hi_mass_conversion = 0.019 * (u.M_sun / u.pc ** 2) / (u.K * u.km / u.s)

def radial_profile(gal, header=None, cube=None,
                   dr=100 * u.pc, mom0=None,
                   max_rad=10 * u.kpc,
                   weight_type="area",
                   mass_conversion=hi_mass_conversion,
                   restfreq=1.414 * u.GHz,
                   pa_bounds=None, beam=None):
    '''
    Create a radial profile, optionally with limits on the angles used.

    Parameters
    ----------
    weight_type : "area" or "mass"
        Return either the area weighted profile (Sum Sigma * dA / Sum dA) or
        the mass weighted profile (Sum Sigma^2 dA / Sum Sigma dA). See
        Leroy et al. (2013) for a thorough description.
    pa_bounds : list of 2 Angles, optional
        When specified, limits the angles used when calculating the profile.
        e.g. pa_bounds=Angle([0.0*u.rad, np.pi*u.rad]))
    '''

    mom0 = mom0.squeeze()

    if weight_type not in ["area", "mass"]:
        raise ValueError("weight_type must be 'area' or 'mass'.")

    if mom0.ndim != 2:
        raise ValueError("mom0 must be 2 dimensional.")

    if mom0 is None:
        if cube is None:
            raise ValueError("Must give cube when not given mom0")
        mom0 = cube.moment0()

    if header is None and cube is None:
        raise TypeError("Either a header or cube must be given.")

    if header is None:
        header = cube.header

    if beam is None:
        if cube is not None:
            beam = cube.beam

    if beam is not None:
        beam_pix =  beam.sr.to(u.deg**2) / (header["CDELT2"] * u.deg)**2

    radius = gal.radius(header=header).to(u.kpc).value
    if pa_bounds is not None:
        # Check if they are angles
        if len(pa_bounds) != 2:
            raise IndexError("pa_bounds must contain 2 angles.")
        if not isinstance(pa_bounds, Angle):
            raise TypeError("pa_bounds must be an Angle.")

        # Return the array of PAs in the galaxy frame
        pas = gal.position_angles(header=header)

        # If the start angle is greater than the end, we need to wrap about
        # the discontinuity
        if pa_bounds[0] > pa_bounds[1]:
            initial_start = pa_bounds[0].copy()
            pa_bounds = pa_bounds.wrap_at(initial_start)
            pas = pas.wrap_at(initial_start)

    if max_rad is not None:
        max_rad = max_rad.to(u.kpc).value
    else:
        max_rad = radius.max() - dr

    dr = dr.to(u.kpc).value

    nbins = np.int(np.floor(max_rad / dr))

    inneredge = np.linspace(0, max_rad, nbins)
    outeredge = np.linspace(0 + dr, max_rad + dr, nbins)
    sdprof = np.zeros(nbins)
    sdprof_sigma = np.zeros(nbins)
    radprof = np.zeros(nbins)

    if pa_bounds is not None:
        pa_idx = np.logical_and(pas >= pa_bounds[0], pas < pa_bounds[1])

    for ctr, (r0, r1) in enumerate(zip(inneredge,
                                       outeredge)):

        idx = np.logical_and(radius >= r0, radius < r1)
        if pa_bounds is not None:
            idx = np.logical_and(idx, pa_idx)

        if weight_type  == "area":
            sdprof[ctr] = np.nansum(mom0[idx].value) / \
                np.sum(np.isfinite(radius[idx]))
            sdprof_sigma[ctr] = \
                np.sqrt(np.nansum((mom0[idx].value - sdprof[ctr])**2.) /
                        np.sum(np.isfinite(radius[idx])))
        else:
            # Has to be 'mass' since this is checked at the beginning
            sdprof[ctr] = np.nansum(np.power(mom0[idx].value, 2)) / \
                np.nansum(mom0[idx].value)

            # Now the std has weights of Sigma * dA, which should be
            # normalized
            weights = mom0[idx].value / np.nansum(mom0[idx].value)

            # No denominator, since the weights were normalize to unity.
            sdprof_sigma[ctr] = np.sqrt(np.nansum(weights * (mom0[idx].value - sdprof[ctr])**2))

        # Rescale the sigma based on the number of independent samples
        if beam is not None:
            sdprof_sigma[ctr] /= \
                np.sqrt(np.sum(np.isfinite(radius[idx])) / beam_pix)
        radprof[ctr] = np.nanmean(radius[idx])

    # Re-apply some units
    radprof = radprof * u.kpc
    sdprof = sdprof * mom0.unit  # / u.pc ** 2
    sdprof_sigma = sdprof_sigma * mom0.unit  # / u.pc ** 2

    # Correct for the los inclinations
    sdprof *= np.cos(gal.inclination)
    sdprof_sigma *= np.cos(gal.inclination)

    # If in Jy/bm, convert to K.
    if cube is not None:
        unit = cube.unit

    # if mom0 is not None:
    #     unit = mom0.unit

    if unit.is_equivalent(u.Jy):
        # The beam units are sort of implied
        sdprof = sdprof.to(u.Jy * u.km / u.s)
        sdprof_sigma = sdprof_sigma.to(u.Jy * u.km / u.s)
        # Now convert to K
        if restfreq is not None:
            sdprof = sdprof * mom0.meta["beam"].jtok(restfreq)
            sdprof_sigma = sdprof_sigma * mom0.meta["beam"].jtok(restfreq)
        else:
            sdprof = sdprof * mom0.meta["beam"].jtok(mom0.header["RESTFREQ"])
            sdprof_sigma = sdprof_sigma * \
                mom0.meta["beam"].jtok(mom0.header["RESTFREQ"])

        sdprof = sdprof / u.Jy
        sdprof_sigma = sdprof_sigma / u.Jy

    if mass_conversion is not None:
        sdprof = sdprof * mass_conversion
        sdprof_sigma = sdprof_sigma * mass_conversion

    return radprof, sdprof, sdprof_sigma

if __name__ == "__main__":
    from galaxies import Galaxy
    import matplotlib.pyplot as p
    import os

    direc = "/home/eric/MyRAID/M33/14B-088/HI/full_imaging/"
    # direc = "/home/eric/MyRAID/M33/14B-088/HI/combined_HI/"

    cube_file = os.path.join(direc,
                             "M33_14B-088_HI.clean.image.pbcov_gt_0.3_masked.fits")
    # cube_file = os.path.join(direc,
    #                          "M33_14B-088_AT0206_HI.clean.image.pbcov_gt_0.3_masked.fits")

    cube = \
        SpectralCube.read(cube_file)

    g = Galaxy("M33")

    cube = cube.with_mask(cube > 1.8e-3 * u.Jy)

    mom0 = cube.moment0()

    # Create a radial profile of HI
    rs, sd, sd_sigma = radial_profile(g, cube=cube, mom0=mom0)
    rs_n, sd_n, sd_sigma_n = \
        radial_profile(g, cube=cube, mom0=mom0,
                       pa_bounds=Angle([0.5 * np.pi * u.rad,
                                        -0.5 * np.pi * u.rad]))
    rs_s, sd_s, sd_sigma_s = \
        radial_profile(g, cube=cube, mom0=mom0,
                       pa_bounds=Angle([-0.5 * np.pi * u.rad,
                                        0.5 * np.pi * u.rad]))

    # There is a ~1.5 global scaling factor b/w Arecibo and VLA + Arecibo
    scale_factor = 1.451

    # Add in creating a radial profile of the archival and the Arecibo
    # Also CO? I guess these should be on the same grid/resolution...

    # Arecibo
    arecibo_path = "/media/eric/Data_3//M33/Arecibo/14B-088_items/"
    arecibo_cube = \
        SpectralCube.read(os.path.join(arecibo_path,
                                       "M33_14B-088_HI_model.fits"))
    # Cut down to extents of the other cube
    arecibo_cube = \
        arecibo_cube.subcube(xlo=cube.longitude_extrema[0],
                             xhi=cube.longitude_extrema[1],
                             yhi=cube.latitude_extrema[0],
                             ylo=cube.latitude_extrema[1])
    arecibo_mom0 = arecibo_cube.moment0()
    rs_arec, sd_arec, sd_sigma_arec = \
        radial_profile(g, cube=arecibo_cube, mom0=arecibo_mom0)

    p.ioff()

    # Show the total radial profile VLA and Arecibo
    p.errorbar(rs.value, sd.value / scale_factor,
               yerr=sd_sigma.value / scale_factor, fmt="-", color="b",
               label="VLA + Arecibo", drawstyle='steps-mid')
    p.plot(rs_arec.value, sd_arec.value, "g--", drawstyle='steps-mid',
           label="Arecibo")
    # p.errorbar(rs_arec.value, sd_arec.value, yerr=sd_sigma_arec.value,
    #            fmt="o--", color="g", label="Arecibo", drawstyle='steps-mid')
    p.ylabel(r"$\Sigma$ (M$_{\odot}$ pc$^{-2}$)")
    p.xlabel(r"R (kpc)")
    p.legend(loc='best')
    p.grid("on")
    p.show()

    # Show the north vs south profiles
    p.plot(rs.value, sd.value / scale_factor, "k-.",
           drawstyle='steps-mid', label="Total")
    p.plot(rs_n.value, sd_n.value / scale_factor, "b-", label="North",
           drawstyle='steps-mid')
    p.plot(rs_s.value, sd_s.value / scale_factor, "g--", label="South",
           drawstyle='steps-mid')
    # p.errorbar(rs_n.value, sd_n.value, yerr=sd_sigma_n.value, fmt="D-", color="b",
    #            label="North")
    # p.errorbar(rs_s.value, sd_s.value, yerr=sd_sigma_s.value, fmt="o-", color="g",
    #            label="South")
    p.ylabel(r"$\Sigma$ (M$_{\odot}$ pc$^{-2}$)")
    p.xlabel(r"R (kpc)")
    p.legend(loc='best')
    p.grid("on")
    p.show()

    p.ion()
<|endoftext|>


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

CONFIG      = 'config.xml'
ICON        = 'icon.ico'
APP_KEY     = '***REMOVED***'
APP_SECRET  = '***REMOVED***'

import Tkinter, xml.etree.ElementTree as xml, time, os, webbrowser, tkMessageBox
from dropbox import client, rest, session
from pil import ImageGrab

configHandler = xml.parse(CONFIG)
configRoot = configHandler.getroot()

class reference():
    def __init__(self, var):
        """ Initializing the variable, when you define the class"""
        self.var = var

    def get(self):
        """ Get the value of the variable """
        return self.var

    def set(self, var):
        """ Set he value of the variable """
        self.var = var

class dropbox(session.DropboxSession):
    def link(self, token):
        """ Create a new link between Dropbox and JamCrop """
        self.obtain_access_token(token)
        configRoot.find('token').text = "|".join([self.token.key, self.token.secret])

    def auth(self):
        """ Get the verification link from Dropbox """
        token = self.obtain_request_token()
        webbrowser.open(self.build_authorize_url(token))
        return(token)

    def unlink(self):
        """ Unlink the JamCrop from Dropbox """
        configRoot.find('token').text = None
        session.DropboxSession.unlink(self)

    def load(self):
        """ Load the saved link from token """
        if(configRoot.find('token').text != None):
            try:
                self.set_token(*configRoot.find('token').text.split('|'))
                return(1)
            except: pass
        return(0)

class window():
    def entry(self, root, x, y, w, default, var = None, text = None):
        """ Create a new entry (@var: StringVar; @text: String;) """
        if(var != None): entry = Tkinter.Entry(root, textvariable = var, width = w)
        elif(text != None): entry = Tkinter.Entry(root, text = text, width = w)
        if(default != None): entry.insert(0, default)
        entry.place(x = x, y = y)
        return(entry)

    def label(self, root, x, y, text):
        """ Create a new label """
        label = Tkinter.Label(root, text = text)
        label.place(x = x, y = y)
        return(label)

    def button(self, root, x, y, w, var = None, text = None):
        """ Create a new button (@var: StringVar; @text: String;) """
        if(var != None): button = Tkinter.Button(root, textvariable = var, width = w)
        elif(text != None): button = Tkinter.Button(root, text = text, width = w)
        button.place(x = x, y = y)
        return(button)

    def menu(self, root, x, y, w, var, values):
        """ Create a new menu (@var: StringVar; @values: Array;) """
        menu = apply(Tkinter.OptionMenu, (root, var) + tuple(values))
        menu.config(width = w)
        menu.place(x = x, y = y)
        return(menu)

    def check(self, root, x, y, var, on, off):
        """ Create a new checkbox """
        check = Tkinter.Checkbutton(root, variable = var, offvalue = off, onvalue = on)
        check.place(x = x, y = y)
        return(check)

class configWindow(Tkinter.Toplevel, window):
    def __init__(self, parent, session, status = reference(0)):
        """ Initializing the config windows """
        Tkinter.Toplevel.__init__(self, parent, width = 195, height = 110)
        self.protocol('WM_DELETE_WINDOW', lambda: self.deleteEvent(status))
        self.resizable(width = 'false', height = 'false')
        self.attributes('-toolwindow', 1)
        self.wm_attributes("-topmost", 1)
        self.title(u"Configuration")
        self.wm_iconbitmap(ICON)

        # Create the automatic url copy checkbox
        self.label(self, 5, 5, "Automatic URL copy:")
        copyValue = Tkinter.StringVar()
        copyCheck = self.check(self, 172, 5, copyValue, 'true', 'false')
        copyValue.trace(mode = 'w', callback = lambda varName, elementName, mode: self.setCopy(varName, elementName, mode, copyValue))
        if(configRoot.find('copy').text == 'false'): copyCheck.deselect()

        # Create the browser behavor checkbox
        self.label(self, 5, 30, "Open in the browser:")
        shortValue = Tkinter.StringVar()
        shortCheck = self.check(self, 172, 30, shortValue, 'true', 'false')
        shortValue.trace(mode = 'w', callback = lambda varName, elementName, mode: self.setBrowser(varName, elementName, mode, shortValue))
        if(configRoot.find('browser').text == 'false'): shortCheck.deselect()

        # Create the list of image formats
        self.label(self, 5, 55, "Image format:")
        formatValue = Tkinter.StringVar()
        formatValue.set(configRoot.find('format').text)
        formatMenu = self.menu(self, 93, 50, 9, formatValue, ['jpg', 'png', 'gif'])
        formatValue.trace(mode = 'w', callback = lambda varName, elementName, mode: self.setFormat(varName, elementName, mode, formatValue))

        # Create the button for unlink the applcation
        button = self.button(self, 5, 80, 25, text = "Unlink JamCrop")
        button.bind("<Button-1>", lambda event: self.doUnlink(event, parent, session))

        status.set(1)

    def deleteEvent(self, status):
        """ Configuration window closing function """
        status.set(0)
        self.destroy()

    def setCopy(self, varName, elementName, mode, value):
        """ Set the url copy paramter """
        configRoot.find('copy').text = unicode(value.get())

    def setBrowser(self, varName, elementName, mode, value):
        """ Set the browser parameter """
        configRoot.find('browser').text = unicode(value.get())

    def setFormat(self, varName, elementName, mode, value):
        """ Change the format parameter """
        configRoot.find('format').text = unicode(value.get())

    def doUnlink(self, event, parent, session):
        """ Unlink JamCrop from Dropbox, and close the windows """
        session.unlink()
        parent.deleteEvent()

class grabWindow(Tkinter.Tk):
    disabled = reference(0)
    x, y, last = 0, 0, 0
    square, session = None, None

    def __init__(self):
        """ Initializing the grab windows of the application """
        Tkinter.Tk.__init__(self)
        self.protocol('WM_DELETE_WINDOW', self.deleteEvent)
        self.configure(background = 'white')
        self.wm_attributes("-topmost", 1)
        self.attributes('-fullscreen', 1)
        self.attributes('-alpha', 0.15)
        self.wm_iconbitmap(ICON)
        self.title(u"JamCrop")

        self.bind("<Button-1>", self.click)
        self.bind_all('<Key>', self.keyPress)
        self.square = Tkinter.Canvas(self, width = 0, height = 0, bg = 'black')

        self.session = dropbox(APP_KEY, APP_SECRET, access_type = 'app_folder')
        if(not self.session.load()):
            self.withdraw()

            token = self.session.auth()
            if(tkMessageBox.askokcancel(title = "JamCrop", message = "The JamCrop require a limited Dropbox access for itself. If you allowed the connection to the Dropbox, from the recently appeared browser window, please click on the OK button. After the grab windows have shown, you can open the configuration windows by pressing the F1 button.")):
                try: self.session.link(token)
                except: return
            else: return

            self.update()
            self.deiconify()

    def deleteEvent(self):
        """ Closing function for the grab window """
        configHandler.write(CONFIG)
        self.destroy()

    def autoFocus(self):
        """ Automatic focus for the grab window """
        if(self.disabled.get()):
            self.wm_attributes("-topmost", 0)
        else:
            self.wm_attributes("-topmost", 1)
            self.tkraise()
            self.focus()
        self.after(250, self.autoFocus)

    def keyPress(self, event):
        """ Parse the key presses """
        if(event.keysym == 'Escape'):
            self.deleteEvent()
        elif(event.keysym == 'F1' and not self.disabled.get()):
            config = configWindow(self, self.session, self.disabled)
            config.mainloop()

    def drawSquare(self, event):
        """ Draw the selecting square on to the grab window """
        if(self.x < event.x_root and self.y < event.y_root):
            self.square.config(width = event.x_root-self.x, height = event.y_root-self.y)
            self.square.place(x = self.x, y = self.y)
        elif(self.x > event.x_root and self.y > event.y_root):
            self.square.config(width = self.x-event.x_root, height = self.y-event.y_root)
            self.square.place(x = event.x_root, y = event.y_root)
        elif(self.x < event.x_root and self.y > event.y_root):
            self.square.config(width = event.x_root-self.x, height = self.y-event.y_root)
            self.square.place(x = self.x, y = event.y_root)
        elif(self.x > event.x_root and self.y < event.y_root):
            self.square.config(width = self.x-event.x_root, height = event.y_root-self.y)
            self.square.place(x = event.x_root, y = self.y)
        else:
            self.square.place_forget()

    def click(self, event):
        """ Set the coordinates of the screenshot """
        if(not self.disabled.get() and not self.last):
            self.bind("<Motion>", self.drawSquare)
            self.x = event.x_root
            self.y = event.y_root
            self.last = 1;
        elif(not self.disabled.get()):
            if(self.x < event.x_root and self.y < event.y_root):
                self.grab(self.x, self.y, event.x_root, event.y_root)
            elif(self.x > event.x_root and self.y > event.y_root):
                self.grab(event.x_root, event.y_root, self.x, self.y)
            elif(self.x < event.x_root and self.y > event.y_root):
                self.grab(self.x, event.y_root, event.x_root, self.y)
            elif(self.x > event.x_root and self.y < event.y_root):
                self.grab(event.x_root, self.y, self.x, event.y_root)
            else:
                self.unbind("<Motion>")
                self.square.place_forget()
                self.last = 0;

    def grab(self, x1, y1, x2, y2):
        """ Create the screenshot from the coordinates """
        self.withdraw()
        connection = client.DropboxClient(self.session)

        fileName = time.strftime('%Y_%m_%d_%H_%M_%S') + '.' + configRoot.find('format').text;
        ImageGrab.grab((x1, y1, x2, y2)).save(fileName)
        connection.put_file(fileName, open(os.path.expanduser(fileName), "rb"))
        os.unlink(fileName)
        result = connection.share(fileName)

        if(configRoot.find('browser').text == 'true'):
			webbrowser.open(result['url'])
        if(configRoot.find('copy').text == 'true'):
            self.clipboard_clear()
            self.clipboard_append(result['url'])

        self.deleteEvent()

def main():
    crop = grabWindow()
    crop.autoFocus()
    crop.mainloop()

if(__name__ == '__main__'):
    main()<commit_msg>English translation, and small changes<commit_after>#!/usr/bin/env python
#-*- coding: utf-8 -*-

CONFIG      = 'config.xml'
ICON        = 'icon.ico'
APP_KEY     = '***REMOVED***'
APP_SECRET  = '***REMOVED***'

import Tkinter, xml.etree.ElementTree as xml, time, os, webbrowser, tkMessageBox
from dropbox import client, rest, session
from pil import ImageGrab

configHandler = xml.parse(CONFIG)
configRoot = configHandler.getroot()

class reference():
    def __init__(self, var):
        """ Initializing the variable, when you define the class"""
        self.var = var

    def get(self):
        """ Get the value of the variable """
        return self.var

    def set(self, var):
        """ Set he value of the variable """
        self.var = var

class dropbox(session.DropboxSession):
    def verify(self):
        """ Get the verification link and the token from Dropbox """
        token = self.obtain_request_token()
        webbrowser.open(self.build_authorize_url(token))
        return(token)

    def link(self, token):
        """ Create a new link between Dropbox and JamCrop """
        self.obtain_access_token(token)
        configRoot.find('token').text = "|".join([self.token.key, self.token.secret])

    def unlink(self):
        """ Unlink the JamCrop from Dropbox """
        configRoot.find('token').text = None
        session.DropboxSession.unlink(self)

    def load(self):
        """ Load the saved link from token """
        if(configRoot.find('token').text != None):
            try:
                self.set_token(*configRoot.find('token').text.split('|'))
                return(1)
            except: pass
        return(0)

class window():
    def entry(self, root, x, y, w, default, var = None, text = None):
        """ Create a new entry (@var: StringVar; @text: String;) """
        if(var != None): entry = Tkinter.Entry(root, textvariable = var, width = w)
        elif(text != None): entry = Tkinter.Entry(root, text = text, width = w)
        if(default != None): entry.insert(0, default)
        entry.place(x = x, y = y)
        return(entry)

    def label(self, root, x, y, text):
        """ Create a new label """
        label = Tkinter.Label(root, text = text)
        label.place(x = x, y = y)
        return(label)

    def button(self, root, x, y, w, var = None, text = None):
        """ Create a new button (@var: StringVar; @text: String;) """
        if(var != None): button = Tkinter.Button(root, textvariable = var, width = w)
        elif(text != None): button = Tkinter.Button(root, text = text, width = w)
        button.place(x = x, y = y)
        return(button)

    def menu(self, root, x, y, w, var, values):
        """ Create a new menu (@var: StringVar; @values: Array;) """
        menu = apply(Tkinter.OptionMenu, (root, var) + tuple(values))
        menu.config(width = w)
        menu.place(x = x, y = y)
        return(menu)

    def check(self, root, x, y, var, on, off):
        """ Create a new checkbox """
        check = Tkinter.Checkbutton(root, variable = var, offvalue = off, onvalue = on)
        check.place(x = x, y = y)
        return(check)

class configWindow(Tkinter.Toplevel, window):
    def __init__(self, parent, session, status = reference(0)):
        """ Initializing the config windows """
        Tkinter.Toplevel.__init__(self, parent, width = 195, height = 110)
        self.protocol('WM_DELETE_WINDOW', lambda: self.deleteEvent(status))
        self.resizable(width = 'false', height = 'false')
        self.attributes('-toolwindow', 1)
        self.wm_attributes("-topmost", 1)
        self.title(u"Configuration")
        self.wm_iconbitmap(ICON)

        # Create the automatic url copy checkbox
        self.label(self, 5, 5, "Automatic URL copy:")
        copyValue = Tkinter.StringVar()
        copyCheck = self.check(self, 172, 5, copyValue, 'true', 'false')
        copyValue.trace(mode = 'w', callback = lambda varName, elementName, mode: self.setCopy(varName, elementName, mode, copyValue))
        if(configRoot.find('copy').text == 'false'): copyCheck.deselect()

        # Create the browser behavor checkbox
        self.label(self, 5, 30, "Open in the browser:")
        shortValue = Tkinter.StringVar()
        shortCheck = self.check(self, 172, 30, shortValue, 'true', 'false')
        shortValue.trace(mode = 'w', callback = lambda varName, elementName, mode: self.setBrowser(varName, elementName, mode, shortValue))
        if(configRoot.find('browser').text == 'false'): shortCheck.deselect()

        # Create the list of image formats
        self.label(self, 5, 55, "Image format:")
        formatValue = Tkinter.StringVar()
        formatValue.set(configRoot.find('format').text)
        formatMenu = self.menu(self, 93, 50, 9, formatValue, ['jpg', 'png', 'gif'])
        formatValue.trace(mode = 'w', callback = lambda varName, elementName, mode: self.setFormat(varName, elementName, mode, formatValue))

        # Create the button for unlink the applcation
        button = self.button(self, 5, 80, 25, text = "Unlink JamCrop")
        button.bind("<Button-1>", lambda event: self.doUnlink(event, parent, session))

        status.set(1)

    def deleteEvent(self, status):
        """ Configuration window closing function """
        status.set(0)
        self.destroy()

    def setCopy(self, varName, elementName, mode, value):
        """ Set the url copy paramter """
        configRoot.find('copy').text = unicode(value.get())

    def setBrowser(self, varName, elementName, mode, value):
        """ Set the browser parameter """
        configRoot.find('browser').text = unicode(value.get())

    def setFormat(self, varName, elementName, mode, value):
        """ Change the format parameter """
        configRoot.find('format').text = unicode(value.get())

    def doUnlink(self, event, parent, session):
        """ Unlink JamCrop from Dropbox, and close the windows """
        session.unlink()
        parent.deleteEvent()

class grabWindow(Tkinter.Tk):
    disabled = reference(0)
    x, y, last = 0, 0, 0
    square, session = None, None

    def __init__(self):
        """ Initializing the grab windows of the application """
        Tkinter.Tk.__init__(self)
        self.protocol('WM_DELETE_WINDOW', self.deleteEvent)
        self.configure(background = 'white')
        self.wm_attributes("-topmost", 1)
        self.attributes('-fullscreen', 1)
        self.attributes('-alpha', 0.15)
        self.wm_iconbitmap(ICON)
        self.title(u"JamCrop")

        self.bind("<Button-1>", self.click)
        self.bind_all('<Key>', self.keyPress)
        self.square = Tkinter.Canvas(self, width = 0, height = 0, bg = 'black')

        self.session = dropbox(APP_KEY, APP_SECRET, access_type = 'app_folder')
        if(not self.session.load()):
            self.withdraw()

            token = self.session.verify()
            if(tkMessageBox.askokcancel(title = "JamCrop", message = "The JamCrop require a limited Dropbox access for itself. If you allowed the connection to the Dropbox, from the recently appeared browser window, please click on the OK button. After the grab windows have shown, you can open the configuration windows by pressing the F1 button.")):
                try: self.session.link(token)
                except: return
            else: return

            self.update()
            self.deiconify()

    def deleteEvent(self):
        """ Closing function for the grab window """
        configHandler.write(CONFIG)
        self.destroy()

    def autoFocus(self):
        """ Automatic focus for the grab window """
        if(self.disabled.get()):
            self.wm_attributes("-topmost", 0)
        else:
            self.wm_attributes("-topmost", 1)
            self.tkraise()
            self.focus()
        self.after(250, self.autoFocus)

    def keyPress(self, event):
        """ Parse the key presses """
        if(event.keysym == 'Escape'):
            self.deleteEvent()
        elif(event.keysym == 'F1' and not self.disabled.get()):
            config = configWindow(self, self.session, self.disabled)
            config.mainloop()

    def drawSquare(self, event):
        """ Draw the selecting square on to the grab window """
        if(self.x < event.x_root and self.y < event.y_root):
            self.square.config(width = event.x_root-self.x, height = event.y_root-self.y)
            self.square.place(x = self.x, y = self.y)
        elif(self.x > event.x_root and self.y > event.y_root):
            self.square.config(width = self.x-event.x_root, height = self.y-event.y_root)
            self.square.place(x = event.x_root, y = event.y_root)
        elif(self.x < event.x_root and self.y > event.y_root):
            self.square.config(width = event.x_root-self.x, height = self.y-event.y_root)
            self.square.place(x = self.x, y = event.y_root)
        elif(self.x > event.x_root and self.y < event.y_root):
            self.square.config(width = self.x-event.x_root, height = event.y_root-self.y)
            self.square.place(x = event.x_root, y = self.y)
        else:
            self.square.place_forget()

    def click(self, event):
        """ Set the coordinates of the screenshot """
        if(not self.disabled.get() and not self.last):
            self.bind("<Motion>", self.drawSquare)
            self.x = event.x_root
            self.y = event.y_root
            self.last = 1;
        elif(not self.disabled.get()):
            if(self.x < event.x_root and self.y < event.y_root):
                self.grab(self.x, self.y, event.x_root, event.y_root)
            elif(self.x > event.x_root and self.y > event.y_root):
                self.grab(event.x_root, event.y_root, self.x, self.y)
            elif(self.x < event.x_root and self.y > event.y_root):
                self.grab(self.x, event.y_root, event.x_root, self.y)
            elif(self.x > event.x_root and self.y < event.y_root):
                self.grab(event.x_root, self.y, self.x, event.y_root)
            else:
                self.unbind("<Motion>")
                self.square.place_forget()
                self.last = 0;

    def grab(self, x1, y1, x2, y2):
        """ Create the screenshot from the coordinates """
        self.withdraw()
        connection = client.DropboxClient(self.session)

        fileName = time.strftime('%Y_%m_%d_%H_%M_%S') + '.' + configRoot.find('format').text;
        ImageGrab.grab((x1, y1, x2, y2)).save(fileName)
        connection.put_file(fileName, open(os.path.expanduser(fileName), "rb"))
        os.unlink(fileName)
        result = connection.share(fileName)

        if(configRoot.find('browser').text == 'true'):
			webbrowser.open(result['url'])
        if(configRoot.find('copy').text == 'true'):
            self.clipboard_clear()
            self.clipboard_append(result['url'])

        self.deleteEvent()

def main():
    crop = grabWindow()
    crop.autoFocus()
    crop.mainloop()

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


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

import functools

from oslo_serialization import jsonutils as json
import six
from six.moves.urllib import parse as urllib

from tempest.common import service_client

def handle_errors(f):
    """A decorator that allows to ignore certain types of errors."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        param_name = 'ignore_errors'
        ignored_errors = kwargs.get(param_name, tuple())

        if param_name in kwargs:
            del kwargs[param_name]

        try:
            return f(*args, **kwargs)
        except ignored_errors:
            # Silently ignore errors
            pass

    return wrapper

class BaremetalClient(service_client.ServiceClient):
    """Base Tempest REST client for Ironic API."""

    uri_prefix = ''

    def serialize(self, object_dict):
        """Serialize an Ironic object."""

        return json.dumps(object_dict)

    def deserialize(self, object_str):
        """Deserialize an Ironic object."""

        return json.loads(object_str)

    def _get_uri(self, resource_name, uuid=None, permanent=False):
        """Get URI for a specific resource or object.

        :param resource_name: The name of the REST resource, e.g., 'nodes'.
        :param uuid: The unique identifier of an object in UUID format.
        :return: Relative URI for the resource or object.

        """
        prefix = self.uri_prefix if not permanent else ''

        return '{pref}/{res}{uuid}'.format(pref=prefix,
                                           res=resource_name,
                                           uuid='/%s' % uuid if uuid else '')

    def _make_patch(self, allowed_attributes, **kw):
        """Create a JSON patch according to RFC 6902.

        :param allowed_attributes: An iterable object that contains a set of
            allowed attributes for an object.
        :param **kw: Attributes and new values for them.
        :return: A JSON path that sets values of the specified attributes to
            the new ones.

        """
        def get_change(kw, path='/'):
            for name, value in six.iteritems(kw):
                if isinstance(value, dict):
                    for ch in get_change(value, path + '%s/' % name):
                        yield ch
                else:
                    if value is None:
                        yield {'path': path + name,
                               'op': 'remove'}
                    else:
                        yield {'path': path + name,
                               'value': value,
                               'op': 'replace'}

        patch = [ch for ch in get_change(kw)
                 if ch['path'].lstrip('/') in allowed_attributes]

        return patch

    def _list_request(self, resource, permanent=False, **kwargs):
        """Get the list of objects of the specified type.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        "param **kw: Parameters for the request.
        :return: A tuple with the server response and deserialized JSON list
                 of objects

        """
        uri = self._get_uri(resource, permanent=permanent)
        if kwargs:
            uri += "?%s" % urllib.urlencode(kwargs)

        resp, body = self.get(uri)
        self.expected_success(200, resp['status'])

        return resp, self.deserialize(body)

    def _show_request(self, resource, uuid, permanent=False, **kwargs):
        """Gets a specific object of the specified type.

        :param uuid: Unique identifier of the object in UUID format.
        :return: Serialized object as a dictionary.

        """
        if 'uri' in kwargs:
            uri = kwargs['uri']
        else:
            uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
        resp, body = self.get(uri)
        self.expected_success(200, resp['status'])

        return resp, self.deserialize(body)

    def _create_request(self, resource, object_dict):
        """Create an object of the specified type.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param object_dict: A Python dict that represents an object of the
                            specified type.
        :return: A tuple with the server response and the deserialized created
                 object.

        """
        body = self.serialize(object_dict)
        uri = self._get_uri(resource)

        resp, body = self.post(uri, body=body)
        self.expected_success(201, resp['status'])

        return resp, self.deserialize(body)

    def _delete_request(self, resource, uuid):
        """Delete specified object.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param uuid: The unique identifier of an object in UUID format.
        :return: A tuple with the server response and the response body.

        """
        uri = self._get_uri(resource, uuid)

        resp, body = self.delete(uri)
        self.expected_success(204, resp['status'])
        return resp, body

    def _patch_request(self, resource, uuid, patch_object):
        """Update specified object with JSON-patch.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param uuid: The unique identifier of an object in UUID format.
        :return: A tuple with the server response and the serialized patched
                 object.

        """
        uri = self._get_uri(resource, uuid)
        patch_body = json.dumps(patch_object)

        resp, body = self.patch(uri, body=patch_body)
        self.expected_success(200, resp['status'])
        return resp, self.deserialize(body)

    @handle_errors
    def get_api_description(self):
        """Retrieves all versions of the Ironic API."""

        return self._list_request('', permanent=True)

    @handle_errors
    def get_version_description(self, version='v1'):
        """Retrieves the desctription of the API.

        :param version: The version of the API. Default: 'v1'.
        :return: Serialized description of API resources.

        """
        return self._list_request(version, permanent=True)

    def _put_request(self, resource, put_object):
        """Update specified object with JSON-patch."""
        uri = self._get_uri(resource)
        put_body = json.dumps(put_object)

        resp, body = self.put(uri, body=put_body)
        self.expected_success(202, resp['status'])
        return resp, body
<commit_msg>Fix some Type in docstrings<commit_after>#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import functools

from oslo_serialization import jsonutils as json
import six
from six.moves.urllib import parse as urllib

from tempest.common import service_client

def handle_errors(f):
    """A decorator that allows to ignore certain types of errors."""

    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        param_name = 'ignore_errors'
        ignored_errors = kwargs.get(param_name, tuple())

        if param_name in kwargs:
            del kwargs[param_name]

        try:
            return f(*args, **kwargs)
        except ignored_errors:
            # Silently ignore errors
            pass

    return wrapper

class BaremetalClient(service_client.ServiceClient):
    """Base Tempest REST client for Ironic API."""

    uri_prefix = ''

    def serialize(self, object_dict):
        """Serialize an Ironic object."""

        return json.dumps(object_dict)

    def deserialize(self, object_str):
        """Deserialize an Ironic object."""

        return json.loads(object_str)

    def _get_uri(self, resource_name, uuid=None, permanent=False):
        """Get URI for a specific resource or object.

        :param resource_name: The name of the REST resource, e.g., 'nodes'.
        :param uuid: The unique identifier of an object in UUID format.
        :returns: Relative URI for the resource or object.

        """
        prefix = self.uri_prefix if not permanent else ''

        return '{pref}/{res}{uuid}'.format(pref=prefix,
                                           res=resource_name,
                                           uuid='/%s' % uuid if uuid else '')

    def _make_patch(self, allowed_attributes, **kwargs):
        """Create a JSON patch according to RFC 6902.

        :param allowed_attributes: An iterable object that contains a set of
            allowed attributes for an object.
        :param **kwargs: Attributes and new values for them.
        :returns: A JSON path that sets values of the specified attributes to
            the new ones.

        """
        def get_change(kwargs, path='/'):
            for name, value in six.iteritems(kwargs):
                if isinstance(value, dict):
                    for ch in get_change(value, path + '%s/' % name):
                        yield ch
                else:
                    if value is None:
                        yield {'path': path + name,
                               'op': 'remove'}
                    else:
                        yield {'path': path + name,
                               'value': value,
                               'op': 'replace'}

        patch = [ch for ch in get_change(kwargs)
                 if ch['path'].lstrip('/') in allowed_attributes]

        return patch

    def _list_request(self, resource, permanent=False, **kwargs):
        """Get the list of objects of the specified type.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param **kwargs: Parameters for the request.
        :returns: A tuple with the server response and deserialized JSON list
                 of objects

        """
        uri = self._get_uri(resource, permanent=permanent)
        if kwargs:
            uri += "?%s" % urllib.urlencode(kwargs)

        resp, body = self.get(uri)
        self.expected_success(200, resp['status'])

        return resp, self.deserialize(body)

    def _show_request(self, resource, uuid, permanent=False, **kwargs):
        """Gets a specific object of the specified type.

        :param uuid: Unique identifier of the object in UUID format.
        :returns: Serialized object as a dictionary.

        """
        if 'uri' in kwargs:
            uri = kwargs['uri']
        else:
            uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
        resp, body = self.get(uri)
        self.expected_success(200, resp['status'])

        return resp, self.deserialize(body)

    def _create_request(self, resource, object_dict):
        """Create an object of the specified type.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param object_dict: A Python dict that represents an object of the
                            specified type.
        :returns: A tuple with the server response and the deserialized created
                 object.

        """
        body = self.serialize(object_dict)
        uri = self._get_uri(resource)

        resp, body = self.post(uri, body=body)
        self.expected_success(201, resp['status'])

        return resp, self.deserialize(body)

    def _delete_request(self, resource, uuid):
        """Delete specified object.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param uuid: The unique identifier of an object in UUID format.
        :returns: A tuple with the server response and the response body.

        """
        uri = self._get_uri(resource, uuid)

        resp, body = self.delete(uri)
        self.expected_success(204, resp['status'])
        return resp, body

    def _patch_request(self, resource, uuid, patch_object):
        """Update specified object with JSON-patch.

        :param resource: The name of the REST resource, e.g., 'nodes'.
        :param uuid: The unique identifier of an object in UUID format.
        :returns: A tuple with the server response and the serialized patched
                 object.

        """
        uri = self._get_uri(resource, uuid)
        patch_body = json.dumps(patch_object)

        resp, body = self.patch(uri, body=patch_body)
        self.expected_success(200, resp['status'])
        return resp, self.deserialize(body)

    @handle_errors
    def get_api_description(self):
        """Retrieves all versions of the Ironic API."""

        return self._list_request('', permanent=True)

    @handle_errors
    def get_version_description(self, version='v1'):
        """Retrieves the desctription of the API.

        :param version: The version of the API. Default: 'v1'.
        :returns: Serialized description of API resources.

        """
        return self._list_request(version, permanent=True)

    def _put_request(self, resource, put_object):
        """Update specified object with JSON-patch."""
        uri = self._get_uri(resource)
        put_body = json.dumps(put_object)

        resp, body = self.put(uri, body=put_body)
        self.expected_success(202, resp['status'])
        return resp, body
<|endoftext|>


<commit_before>import time
import rtmidi
from enum import Enum
from rtmidi.midiconstants import CONTROL_CHANGE
from collections import defaultdict

from devices import BCR2k, MidiLoop, Listener

class Target(object):
    """
    A mapping target. In the Interface, the IDs of the input
    device are mapped to targets.    """
    def __init__(self, name):
        self.name = name

    def act(self, value):
        """
        Their act method is then called
        with the value transmitted by the Control.
        """
        raise NotImplemented

class Parameter(Target):
    """
    A type of target that simply maps the incoming value to a
    Control Change midi signal on the configured (output) device.
    Button values are (for now) hardcoded to 0 for Off and 127 for On.
    """
    def __init__(self, name, device, cc, initial=0, is_button=False):
        self.name = name
        self.device = device
        self.cc = cc
        self.value = initial
        self.is_button = is_button

    def act(self, value):
        """
        Forwards the value to the configured (output) Device with
        the transmitted value.
        """
        if self.is_button:
            if value:
                value = 127
            else:
                value = 0
        self.value = value
        self.device.send(self.cc, self.value)

class Exhausted(Exception):
    pass

class ParameterMaker(object):
    """
    Produces Targets of the type Parameter. Everytime a new target is
    requested it assigns that target the next available CC.
    """
    def __init__(self, output_device, channel, prefix="CC", first_cc=1, expand=True):
        self.device = output_device
        self.channel = channel
        self.next_cc = first_cc
        self.prefix = prefix
        self.expand = expand

        self.exhausted = False

    def make(self, is_button=False):
        if self.exhausted:
            raise Exhausted

        name = "%s_%i" % (self.prefix, self.next_cc)
        t = Parameter(name, self.device, self.next_cc, is_button=is_button)
        self.next_cc += 1
        if self.next_cc > 128:
            if self.expand and self.channel < 16:
                self.next_cc = 1
                self.channel += 1
            else:
                self.exhausted = True
        return t

class View(object):
    """
    A View is made up of two components:
    - A configuration: How the buttons and dials on the input device should behave
    - A Map: Connects the input device's controls (by their ID) to Targets like
             Parameters, Commands etc. from which their current values can also
             be infered.
    When activating a View, the input Device needs to be reconfigured and the
    values of each mapped target transmitted to that device for it to show those
    values on the hardware.
    """
    def __init__(self):
        # Map IDs of a device's controls to configurations like
        # - Buttons: toggle vs momentary
        # - Maxvals / Minvals
        self.configuration = {}

        # Map IDs of a device's controls to Parameters
        self.map = defaultdict(list)

class Interface(Listener):
    """
    The Interface connects an input device with an output device by tunneling
    transmitted values from the input through its currently active View.
    This view can transform CC messages, issue commands like switching to a
    different View or other meta functions. For a simple mapped CC parameter,
    the - possibly modified - value is sent to the Interface's output device.

    Changes communicated from the output device (e.g. automation in Ableton Live
    needs to be reflected on the hardware) is sent back to the input device,
    depending on if any of its controls are currently mapped to the changed Parameter.
    """
    def __init__(self, devin, devout, initview=None):
        """
        Initialize the Interface with the provided input and output device
        and a View. If no View is provided and empty View will be produced.

        The Interface attaches itself as a listener to both input and output
        devices.
        """
        self.input = devin
        self.output = devout
        self.targets = {}
        self.view = initview if initview else View()
        self.views = [self.view]

        self.input.listeners.append(self)
        self.output.listeners.append(self)

        self.maker = ParameterMaker(self.output, 1)

    def set_value(self, target, value, input_only=False):
        """
        Sets the value of a Target. The value is typically communicated
        to both input and output device. This makes it possible to automate
        values from within the interface and having that reflect on both
        the input device (hardware) and the output device (DAW).

        We a value change was communicated from the output device (e.g.
        DAW automation) we only want to inform the input device about the
        new value. In that case, use the input_only flag. If you don't, a
        feedback loop might occur.
        """
        # Find a Control on the input device that is mapped to the
        # provided target and set it to the current value
        for ID, vtargets in self.view.map.items():
            for target in vtargets:
                if target == vtarget:
                    self.input.send(ID, value)

        # Prevent feedback loop, for example if the source of the
        # new value was the output device itself
        if input_only:
            # We still need to reflect the value change in the target
            # but without performing the associated action
            target.value = value
        else:
            target.act(value)

    def switch_to_view(self, view):
        """
        Switches to the provided view. If this is a new view it will
        be added to the Interface's view catalog and all targets of
        that view will be added to the total list of targets.
        """
        self.view = view
        if view not in self.views:
            self.views.append(view)
            for ID, target in view.map:
                self.add_target(target)

    def add_target(self, target):
        """
        Add a configured target. This method checks for duplicates and
        ignores them if detected.
        """
        if target.name in self.targets:
            print("Target with same name already exists! Ignoring...")
            return
        self.targets[target.name] = target

    def quick_parameter(self, ID):
        """
        Quickly map the provided ID to a Parameter by creating a new
        Parameter target using the class's own maker
        """
        t = self.maker.make(is_button=False)
        self.add_target(t)
        self.view.map[ID].append(t)

    def inform(self, sender, ID, value):
        """
        Callback method whenever the input or output devices produce
        messages to consume (input -> hardware -> controls, output ->
        daw -> automation).
        """
        try:
            targets = self.view.map[ID]
        except KeyError:
            print("No target configured for ID %i" % ID)
            return

        for target in targets:
            if sender == self.input:
                # Perform the action of the target. This might send a
                # message to the output device but could also be a meta
                # command like switching views
                target.act(value)
            elif sender == self.output:
                # Just reflect the value in both target and on the input device
                self.set_value(target, value, input_only=True)

    def __repr__(self):
        return "Interface"

    def __str__(self):
        return self.__repr__()

##################################

def test(i):
    i.quick_parameter(81)
    i.quick_parameter(82)
    i.quick_parameter(83)
    i.quick_parameter(84)

    i.quick_parameter(81)
    i.quick_parameter(82)
    i.quick_parameter(83)
    i.quick_parameter(84)
    while True:
        bcr.update(time.time())

def fun(bcr):
    x = 0
    import math
    import time
    while True:
        time.sleep(0.05)
        for i in range(81, 104 + 1):
            v = min(math.sin(x - (i-81)*0.1) * 64 + 64, 127)
            bcr.send(i, v)
        x += 0.2

if __name__ == "__main__":
    bcr = BCR2k()
    loop = MidiLoop()

    interface = Interface(bcr, loop)

#    fun(bcr)
    test(interface)
<commit_msg>Multiple controls mapped to the same target behave the same way<commit_after>import time
import rtmidi
from enum import Enum
from rtmidi.midiconstants import CONTROL_CHANGE
from collections import defaultdict

from devices import BCR2k, MidiLoop, Listener

class Target(object):
    """
    A mapping target. In the Interface, the IDs of the input
    device are mapped to targets.    """
    def __init__(self, name):
        self.name = name

    def act(self, value):
        """
        Their act method is then called
        with the value transmitted by the Control.
        """
        raise NotImplemented

class Parameter(Target):
    """
    A type of target that simply maps the incoming value to a
    Control Change midi signal on the configured (output) device.
    Button values are (for now) hardcoded to 0 for Off and 127 for On.
    """
    def __init__(self, name, device, cc, initial=0, is_button=False):
        self.name = name
        self.device = device
        self.cc = cc
        self.value = initial
        self.is_button = is_button

    def act(self, value):
        """
        Forwards the value to the configured (output) Device with
        the transmitted value.
        """
        if self.is_button:
            if value:
                value = 127
            else:
                value = 0
        self.value = value
        self.device.send(self.cc, self.value)

class Exhausted(Exception):
    pass

class ParameterMaker(object):
    """
    Produces Targets of the type Parameter. Everytime a new target is
    requested it assigns that target the next available CC.
    """
    def __init__(self, output_device, channel, prefix="CC", first_cc=1, expand=True):
        self.device = output_device
        self.channel = channel
        self.next_cc = first_cc
        self.prefix = prefix
        self.expand = expand

        self.exhausted = False

    def make(self, is_button=False):
        if self.exhausted:
            raise Exhausted

        name = "%s_%i" % (self.prefix, self.next_cc)
        t = Parameter(name, self.device, self.next_cc, is_button=is_button)
        self.next_cc += 1
        if self.next_cc > 128:
            if self.expand and self.channel < 16:
                self.next_cc = 1
                self.channel += 1
            else:
                self.exhausted = True
        return t

class View(object):
    """
    A View is made up of two components:
    - A configuration: How the buttons and dials on the input device should behave
    - A Map: Connects the input device's controls (by their ID) to Targets like
             Parameters, Commands etc. from which their current values can also
             be infered.
    When activating a View, the input Device needs to be reconfigured and the
    values of each mapped target transmitted to that device for it to show those
    values on the hardware.
    """
    def __init__(self):
        # Map IDs of a device's controls to configurations like
        # - Buttons: toggle vs momentary
        # - Maxvals / Minvals
        self.configuration = {}

        # Map IDs of a device's controls to Parameters
        self.map = defaultdict(list)

    def find_IDs_by_target(self, vtarget):
        """
        Make a list of IDs on this view mapped to the provided target.
        """
        IDs = []
        for ID, vtargets in self.map.items():
            for target in vtargets:
                if target == vtarget:
                    IDs.append(ID)
        return IDs

    def map_this(self, ID, t):
        """
        Add a mapping from the ID to the target
        """
        self.map[ID].append(t)

class Interface(Listener):
    """
    The Interface connects an input device with an output device by tunneling
    transmitted values from the input through its currently active View.
    This view can transform CC messages, issue commands like switching to a
    different View or other meta functions. For a simple mapped CC parameter,
    the - possibly modified - value is sent to the Interface's output device.

    Changes communicated from the output device (e.g. automation in Ableton Live
    needs to be reflected on the hardware) is sent back to the input device,
    depending on if any of its controls are currently mapped to the changed Parameter.
    """
    def __init__(self, devin, devout, initview=None):
        """
        Initialize the Interface with the provided input and output device
        and a View. If no View is provided and empty View will be produced.

        The Interface attaches itself as a listener to both input and output
        devices.
        """
        self.input = devin
        self.output = devout
        self.targets = {}
        self.view = initview if initview else View()
        self.views = [self.view]

        self.input.listeners.append(self)
        self.output.listeners.append(self)

        self.maker = ParameterMaker(self.output, 1)

    def set_value(self, target, value, input_only=False, exclude_IDs=None):
        """
        Sets the value of a Target. The value is typically communicated
        to both input and output device. This makes it possible to automate
        values from within the interface and having that reflect on both
        the input device (hardware) and the output device (DAW).

        We a value change was communicated from the output device (e.g.
        DAW automation) we only want to inform the input device about the
        new value. In that case, use the input_only flag. If you don't, a
        feedback loop might occur.

        Should not be called because a value directly on the input changed.
        That's what target.act() is for.
        """
        # Inform input controls mapped to this target about the change
        for ID in self.view.find_IDs_by_target(target):
            if not exclude_IDs or ID not in exclude_IDs:
                self.input.send(ID, value)

        # Prevent feedback loop, for example if the source of the
        # new value was the output device itself
        if input_only:
            # We still need to reflect the value change in the target
            # but without performing the associated action
            target.value = value
        else:
            target.act(value)

    def switch_to_view(self, view):
        """
        Switches to the provided view. If this is a new view it will
        be added to the Interface's view catalog and all targets of
        that view will be added to the total list of targets.
        """
        self.view = view
        if view not in self.views:
            self.views.append(view)
            for ID, target in view.map:
                self.add_target(target)

    def add_target(self, target):
        """
        Add a configured target. This method checks for duplicates and
        ignores them if detected.
        """
        if target.name in self.targets:
            print("Target with same name already exists! Ignoring...")
            return
        self.targets[target.name] = target

    def quick_parameter(self, ID):
        """
        Quickly map the provided ID to a Parameter by creating a new
        Parameter target using the class's own maker
        """
        t = self.maker.make(is_button=False)
        self.add_target(t)
        self.view.map_this(ID, t)
        return t

    def inform(self, sender, ID, value):
        """
        Callback method whenever the input or output devices produce
        messages to consume (input -> hardware -> controls, output ->
        daw -> automation).
        """
        try:
            targets = self.view.map[ID]
        except KeyError:
            print("No target configured for ID %i" % ID)
            return

        for target in targets:
            if sender == self.input:
                # Perform the action of the target. This might send a
                # message to the output device but could also be a meta
                # command like switching views
                target.act(value)
                # Multiple input controls might be mapped to this
                # so let's call set_value on the input_only but exclude the
                # ID that issued the value change
                self.set_value(target, value, input_only=True, exclude_IDs=[ID])
            elif sender == self.output:
                # Just reflect the value in both target and on the input device
                self.set_value(target, value, input_only=True)

    def __repr__(self):
        return "Interface"

    def __str__(self):
        return self.__repr__()

##################################

def test(i):
    i.quick_parameter(81)
    i.quick_parameter(82)
    i.quick_parameter(83)
    i.quick_parameter(84)

    i.quick_parameter(81)
    i.quick_parameter(82)
    i.quick_parameter(83)
    t = i.quick_parameter(84)
    i.view.map_this(85, t)

    i.set_value(t, 127)
    while True:
        bcr.update(time.time())

def fun(bcr):
    x = 0
    import math
    import time
    while True:
        time.sleep(0.05)
        for i in range(81, 104 + 1):
            v = min(math.sin(x - (i-81)*0.1) * 64 + 64, 127)
            bcr.send(i, v)
        x += 0.2

if __name__ == "__main__":
    bcr = BCR2k()
    loop = MidiLoop()

    interface = Interface(bcr, loop)

#    fun(bcr)
    test(interface)
<|endoftext|>