<commit_before>from base64 import b64decode
import datetime
import json
import httplib2
import logging
import sys
import time

import requests

from redash import settings
from redash.query_runner import *
from redash.utils import JSONEncoder

logger = logging.getLogger(__name__)

try:
    import apiclient.errors
    from apiclient.discovery import build
    from apiclient.errors import HttpError
    from oauth2client.client import SignedJwtAssertionCredentials
    from oauth2client import gce

    enabled = True
except ImportError:
    enabled = False

types_map = {
    'INTEGER': TYPE_INTEGER,
    'FLOAT': TYPE_FLOAT,
    'BOOLEAN': TYPE_BOOLEAN,
    'STRING': TYPE_STRING,
    'TIMESTAMP': TYPE_DATETIME,
}

def transform_row(row, fields):
    column_index = 0
    row_data = {}

    for cell in row["f"]:
        field = fields[column_index]
        cell_value = cell['v']

        if cell_value is None:
            pass
        # Otherwise just cast the value
        elif field['type'] == 'INTEGER':
            cell_value = int(cell_value)
        elif field['type'] == 'FLOAT':
            cell_value = float(cell_value)
        elif field['type'] == 'BOOLEAN':
            cell_value = cell_value.lower() == "true"
        elif field['type'] == 'TIMESTAMP':
            cell_value = datetime.datetime.fromtimestamp(float(cell_value))

        row_data[field["name"]] = cell_value
        column_index += 1

    return row_data

def _load_key(filename):
    f = file(filename, "rb")
    try:
        return f.read()
    finally:
        f.close()

def _get_query_results(jobs, project_id, job_id, start_index):
    query_reply = jobs.getQueryResults(projectId=project_id, jobId=job_id, startIndex=start_index).execute()
    logging.debug('query_reply %s', query_reply)
    if not query_reply['jobComplete']:
        time.sleep(10)
        return _get_query_results(jobs, project_id, job_id, start_index)

    return query_reply

class BigQuery(BaseQueryRunner):
    @classmethod
    def enabled(cls):
        return enabled

    @classmethod
    def configuration_schema(cls):
        return {
            'type': 'object',
            'properties': {
                'projectId': {
                    'type': 'string',
                    'title': 'Project ID'
                },
                'jsonKeyFile': {
                    "type": "string",
                    'title': 'JSON Key File'
                },
                'totalMBytesProcessedLimit': {
                    "type": "number",
                    'title': 'Total MByte Processed Limit'
                },
                'userDefinedFunctionResourceUri': {
                    "type": "string",
                    'title': 'UDF Source URIs (i.e. gs://bucket/date_utils.js, gs://bucket/string_utils.js )'
                },
                'useStandardSql(Beta)': {
                    "type": "boolean",
                    'title': "use BigQuery's standard SQL: https://cloud.google.com/bigquery/sql-reference/",
                }
            },
            'required': ['jsonKeyFile', 'projectId'],
            'secret': ['jsonKeyFile']
        }

    def __init__(self, configuration):
        super(BigQuery, self).__init__(configuration)

    def _get_bigquery_service(self):
        scope = [
            "https://www.googleapis.com/auth/bigquery",
            ]

        key = json.loads(b64decode(self.configuration['jsonKeyFile']))

        credentials = SignedJwtAssertionCredentials(key['client_email'], key['private_key'], scope=scope)
        http = httplib2.Http(timeout=settings.BIGQUERY_HTTP_TIMEOUT)
        http = credentials.authorize(http)

        return build("bigquery", "v2", http=http)

    def _get_project_id(self):
        return self.configuration["projectId"]

    def _get_total_bytes_processed(self, jobs, query):
        job_data = {
            "query": query,
            "dryRun": True,
            "useLegacySql": not self.configuration.get('useStandardSql(Beta)', False),
        }
        response = jobs.query(projectId=self._get_project_id(), body=job_data).execute()
        return int(response["totalBytesProcessed"])

    def _get_query_result(self, jobs, query):
        project_id = self._get_project_id()
        job_data = {
            "configuration": {
                "query": {
                    "query": query,
                    "useLegacySql": not self.configuration.get('useStandardSql(Beta)', False),
                }
            }
        }

        if "userDefinedFunctionResourceUri" in self.configuration:
            resource_uris = self.configuration["userDefinedFunctionResourceUri"].split(',')
            job_data["configuration"]["query"]["userDefinedFunctionResources"] = map(
                lambda resource_uri: {"resourceUri": resource_uri}, resource_uris)

        insert_response = jobs.insert(projectId=project_id, body=job_data).execute()
        current_row = 0
        query_reply = _get_query_results(jobs, project_id=project_id,
                                         job_id=insert_response['jobReference']['jobId'], start_index=current_row)

        logger.debug("bigquery replied: %s", query_reply)

        rows = []

        while ("rows" in query_reply) and current_row < query_reply['totalRows']:
            for row in query_reply["rows"]:
                rows.append(transform_row(row, query_reply["schema"]["fields"]))

            current_row += len(query_reply['rows'])
            query_reply = jobs.getQueryResults(projectId=project_id, jobId=query_reply['jobReference']['jobId'],
                                               startIndex=current_row).execute()

        columns = [{'name': f["name"],
                    'friendly_name': f["name"],
                    'type': types_map.get(f['type'], "string")} for f in query_reply["schema"]["fields"]]

        data = {
            "columns": columns,
            "rows": rows
        }

        return data

    def run_query(self, query):
        logger.debug("BigQuery got query: %s", query)

        bigquery_service = self._get_bigquery_service()
        jobs = bigquery_service.jobs()

        try:
            if "totalMBytesProcessedLimit" in self.configuration:
                limitMB = self.configuration["totalMBytesProcessedLimit"]
                processedMB = self._get_total_bytes_processed(jobs, query) / 1000.0 / 1000.0
                if limitMB < processedMB:
                    return None, "Larger than %d MBytes will be processed (%f MBytes)" % (limitMB, processedMB)

            data = self._get_query_result(jobs, query)
            error = None

            json_data = json.dumps(data, cls=JSONEncoder)
        except apiclient.errors.HttpError, e:
            json_data = None
            if e.resp.status == 400:
                error = json.loads(e.content)['error']['message']
            else:
                error = e.content
        except KeyboardInterrupt:
            error = "Query cancelled by user."
            json_data = None
        except Exception:
            raise sys.exc_info()[1], None, sys.exc_info()[2]

        return json_data, error

class BigQueryGCE(BigQuery):
    @classmethod
    def type(cls):
        return "bigquery_gce"

    @classmethod
    def configuration_schema(cls):
        return {}

    def _get_project_id(self):
        return requests.get('http://metadata/computeMetadata/v1/project/project-id', headers={'Metadata-Flavor': 'Google'}).content

    def _get_bigquery_service(self):
        credentials = gce.AppAssertionCredentials(scope='https://www.googleapis.com/auth/bigquery')
        http = httplib2.Http()
        http = credentials.authorize(http)

        return build("bigquery", "v2", http=http)

register(BigQuery)
register(BigQueryGCE)
<commit_msg>fix key name and title<commit_after>from base64 import b64decode
import datetime
import json
import httplib2
import logging
import sys
import time

import requests

from redash import settings
from redash.query_runner import *
from redash.utils import JSONEncoder

logger = logging.getLogger(__name__)

try:
    import apiclient.errors
    from apiclient.discovery import build
    from apiclient.errors import HttpError
    from oauth2client.client import SignedJwtAssertionCredentials
    from oauth2client import gce

    enabled = True
except ImportError:
    enabled = False

types_map = {
    'INTEGER': TYPE_INTEGER,
    'FLOAT': TYPE_FLOAT,
    'BOOLEAN': TYPE_BOOLEAN,
    'STRING': TYPE_STRING,
    'TIMESTAMP': TYPE_DATETIME,
}

def transform_row(row, fields):
    column_index = 0
    row_data = {}

    for cell in row["f"]:
        field = fields[column_index]
        cell_value = cell['v']

        if cell_value is None:
            pass
        # Otherwise just cast the value
        elif field['type'] == 'INTEGER':
            cell_value = int(cell_value)
        elif field['type'] == 'FLOAT':
            cell_value = float(cell_value)
        elif field['type'] == 'BOOLEAN':
            cell_value = cell_value.lower() == "true"
        elif field['type'] == 'TIMESTAMP':
            cell_value = datetime.datetime.fromtimestamp(float(cell_value))

        row_data[field["name"]] = cell_value
        column_index += 1

    return row_data

def _load_key(filename):
    f = file(filename, "rb")
    try:
        return f.read()
    finally:
        f.close()

def _get_query_results(jobs, project_id, job_id, start_index):
    query_reply = jobs.getQueryResults(projectId=project_id, jobId=job_id, startIndex=start_index).execute()
    logging.debug('query_reply %s', query_reply)
    if not query_reply['jobComplete']:
        time.sleep(10)
        return _get_query_results(jobs, project_id, job_id, start_index)

    return query_reply

class BigQuery(BaseQueryRunner):
    @classmethod
    def enabled(cls):
        return enabled

    @classmethod
    def configuration_schema(cls):
        return {
            'type': 'object',
            'properties': {
                'projectId': {
                    'type': 'string',
                    'title': 'Project ID'
                },
                'jsonKeyFile': {
                    "type": "string",
                    'title': 'JSON Key File'
                },
                'totalMBytesProcessedLimit': {
                    "type": "number",
                    'title': 'Total MByte Processed Limit'
                },
                'userDefinedFunctionResourceUri': {
                    "type": "string",
                    'title': 'UDF Source URIs (i.e. gs://bucket/date_utils.js, gs://bucket/string_utils.js )'
                },
                'useStandardSql': {
                    "type": "boolean",
                    'title': "Use Standard SQL (Beta)",
                }
            },
            'required': ['jsonKeyFile', 'projectId'],
            'secret': ['jsonKeyFile']
        }

    def __init__(self, configuration):
        super(BigQuery, self).__init__(configuration)

    def _get_bigquery_service(self):
        scope = [
            "https://www.googleapis.com/auth/bigquery",
            ]

        key = json.loads(b64decode(self.configuration['jsonKeyFile']))

        credentials = SignedJwtAssertionCredentials(key['client_email'], key['private_key'], scope=scope)
        http = httplib2.Http(timeout=settings.BIGQUERY_HTTP_TIMEOUT)
        http = credentials.authorize(http)

        return build("bigquery", "v2", http=http)

    def _get_project_id(self):
        return self.configuration["projectId"]

    def _get_total_bytes_processed(self, jobs, query):
        job_data = {
            "query": query,
            "dryRun": True,
            "useLegacySql": not self.configuration.get('useStandardSql', False),
        }
        response = jobs.query(projectId=self._get_project_id(), body=job_data).execute()
        return int(response["totalBytesProcessed"])

    def _get_query_result(self, jobs, query):
        project_id = self._get_project_id()
        job_data = {
            "configuration": {
                "query": {
                    "query": query,
                    "useLegacySql": not self.configuration.get('useStandardSql', False),
                }
            }
        }

        if "userDefinedFunctionResourceUri" in self.configuration:
            resource_uris = self.configuration["userDefinedFunctionResourceUri"].split(',')
            job_data["configuration"]["query"]["userDefinedFunctionResources"] = map(
                lambda resource_uri: {"resourceUri": resource_uri}, resource_uris)

        insert_response = jobs.insert(projectId=project_id, body=job_data).execute()
        current_row = 0
        query_reply = _get_query_results(jobs, project_id=project_id,
                                         job_id=insert_response['jobReference']['jobId'], start_index=current_row)

        logger.debug("bigquery replied: %s", query_reply)

        rows = []

        while ("rows" in query_reply) and current_row < query_reply['totalRows']:
            for row in query_reply["rows"]:
                rows.append(transform_row(row, query_reply["schema"]["fields"]))

            current_row += len(query_reply['rows'])
            query_reply = jobs.getQueryResults(projectId=project_id, jobId=query_reply['jobReference']['jobId'],
                                               startIndex=current_row).execute()

        columns = [{'name': f["name"],
                    'friendly_name': f["name"],
                    'type': types_map.get(f['type'], "string")} for f in query_reply["schema"]["fields"]]

        data = {
            "columns": columns,
            "rows": rows
        }

        return data

    def run_query(self, query):
        logger.debug("BigQuery got query: %s", query)

        bigquery_service = self._get_bigquery_service()
        jobs = bigquery_service.jobs()

        try:
            if "totalMBytesProcessedLimit" in self.configuration:
                limitMB = self.configuration["totalMBytesProcessedLimit"]
                processedMB = self._get_total_bytes_processed(jobs, query) / 1000.0 / 1000.0
                if limitMB < processedMB:
                    return None, "Larger than %d MBytes will be processed (%f MBytes)" % (limitMB, processedMB)

            data = self._get_query_result(jobs, query)
            error = None

            json_data = json.dumps(data, cls=JSONEncoder)
        except apiclient.errors.HttpError, e:
            json_data = None
            if e.resp.status == 400:
                error = json.loads(e.content)['error']['message']
            else:
                error = e.content
        except KeyboardInterrupt:
            error = "Query cancelled by user."
            json_data = None
        except Exception:
            raise sys.exc_info()[1], None, sys.exc_info()[2]

        return json_data, error

class BigQueryGCE(BigQuery):
    @classmethod
    def type(cls):
        return "bigquery_gce"

    @classmethod
    def configuration_schema(cls):
        return {}

    def _get_project_id(self):
        return requests.get('http://metadata/computeMetadata/v1/project/project-id', headers={'Metadata-Flavor': 'Google'}).content

    def _get_bigquery_service(self):
        credentials = gce.AppAssertionCredentials(scope='https://www.googleapis.com/auth/bigquery')
        http = httplib2.Http()
        http = credentials.authorize(http)

        return build("bigquery", "v2", http=http)

register(BigQuery)
register(BigQueryGCE)
<|endoftext|>


<commit_before>from sqlalchemy import create_engine
from sqlalchemy import Column, Index
from sqlalchemy import DateTime, Integer, LargeBinary, SmallInteger
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

_Model = declarative_base()

RADIO_TYPE = {
    'gsm': 0,
    'cdma': 1,
    'umts': 2,
    'lte': 3,
}
RADIO_TYPE_KEYS = list(RADIO_TYPE.keys())

class Cell(_Model):
    __tablename__ = 'cell'
    __table_args__ = (
        Index('cell_idx', 'radio', 'mcc', 'mnc', 'lac', 'cid'),
        {
            'mysql_engine': 'InnoDB',
            'mysql_charset': 'utf8',
        }
    )

    id = Column(Integer, primary_key=True)
    # lat/lon * decimaljson.FACTOR
    lat = Column(Integer)
    lon = Column(Integer)
    # mapped via RADIO_TYPE
    radio = Column(SmallInteger)
    # int in the range 0-1000
    mcc = Column(SmallInteger)
    # int in the range 0-1000 for gsm
    # int in the range 0-32767 for cdma (system id)
    mnc = Column(SmallInteger)
    lac = Column(Integer)
    cid = Column(Integer)
    # int in the range 0-511
    psc = Column(SmallInteger)
    range = Column(Integer)

cell_table = Cell.__table__

class Measure(_Model):
    __tablename__ = 'measure'
    __table_args__ = {
        'mysql_engine': 'InnoDB',
        'mysql_charset': 'utf8',
        'mysql_row_format': 'compressed',
        'mysql_key_block_size': '4',
    }

    id = Column(Integer, primary_key=True, autoincrement=True)
    # lat/lon * decimaljson.FACTOR
    lat = Column(Integer)
    lon = Column(Integer)
    time = Column(DateTime)
    accuracy = Column(SmallInteger)
    altitude = Column(SmallInteger)
    altitude_accuracy = Column(SmallInteger)
    radio = Column(SmallInteger)  # mapped via RADIO_TYPE
    # json blobs
    cell = Column(LargeBinary)
    wifi = Column(LargeBinary)

measure_table = Measure.__table__

class Database(object):

    def __init__(self, sqluri):
        options = dict(pool_recycle=3600, pool_size=10, pool_timeout=10)
        if sqluri.startswith('sqlite'):
            del options['pool_size']
            del options['pool_timeout']
        self.engine = create_engine(sqluri, **options)
        self.session_factory = sessionmaker(
            bind=self.engine, autocommit=False, autoflush=False)

        # bind and create tables
        cell_table.metadata.bind = self.engine
        cell_table.create(checkfirst=True)
        measure_table.metadata.bind = self.engine
        measure_table.create(checkfirst=True)

    def session(self):
        return self.session_factory()
<commit_msg>be a bit more permissive with some database fields (small -> regular int)<commit_after>from sqlalchemy import create_engine
from sqlalchemy import Column, Index
from sqlalchemy import DateTime, Integer, LargeBinary, SmallInteger
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

_Model = declarative_base()

RADIO_TYPE = {
    'gsm': 0,
    'cdma': 1,
    'umts': 2,
    'lte': 3,
}
RADIO_TYPE_KEYS = list(RADIO_TYPE.keys())

class Cell(_Model):
    __tablename__ = 'cell'
    __table_args__ = (
        Index('cell_idx', 'radio', 'mcc', 'mnc', 'lac', 'cid'),
        {
            'mysql_engine': 'InnoDB',
            'mysql_charset': 'utf8',
        }
    )

    id = Column(Integer, primary_key=True)
    # lat/lon * decimaljson.FACTOR
    lat = Column(Integer)
    lon = Column(Integer)
    # mapped via RADIO_TYPE
    radio = Column(SmallInteger)
    # int in the range 0-1000
    mcc = Column(SmallInteger)
    # int in the range 0-1000 for gsm
    # int in the range 0-32767 for cdma (system id)
    mnc = Column(Integer)
    lac = Column(Integer)
    cid = Column(Integer)
    psc = Column(Integer)
    range = Column(Integer)

cell_table = Cell.__table__

class Measure(_Model):
    __tablename__ = 'measure'
    __table_args__ = {
        'mysql_engine': 'InnoDB',
        'mysql_charset': 'utf8',
        'mysql_row_format': 'compressed',
        'mysql_key_block_size': '4',
    }

    id = Column(Integer, primary_key=True, autoincrement=True)
    # lat/lon * decimaljson.FACTOR
    lat = Column(Integer)
    lon = Column(Integer)
    time = Column(DateTime)
    accuracy = Column(Integer)
    altitude = Column(Integer)
    altitude_accuracy = Column(Integer)
    radio = Column(SmallInteger)  # mapped via RADIO_TYPE
    # json blobs
    cell = Column(LargeBinary)
    wifi = Column(LargeBinary)

measure_table = Measure.__table__

class Database(object):

    def __init__(self, sqluri):
        options = dict(pool_recycle=3600, pool_size=10, pool_timeout=10)
        if sqluri.startswith('sqlite'):
            del options['pool_size']
            del options['pool_timeout']
        self.engine = create_engine(sqluri, **options)
        self.session_factory = sessionmaker(
            bind=self.engine, autocommit=False, autoflush=False)

        # bind and create tables
        cell_table.metadata.bind = self.engine
        cell_table.create(checkfirst=True)
        measure_table.metadata.bind = self.engine
        measure_table.create(checkfirst=True)

    def session(self):
        return self.session_factory()
<|endoftext|>


<commit_before>"""
=====================================
Create a minimalistic user interface
=====================================

DIPY allows to create a minimalistic interface using widgets.

In this example we will create: a) two parallel steamtubes, b) add some buttons
which will change the opacity of these tubes and c) move the streamtubes using
a slider.
"""

import numpy as np
from dipy.viz import window, actor, widget
from dipy.data import fetch_viz_icons, read_viz_icons

"""
First, we add a couple of streamtubes to the Renderer
"""

renderer = window.Renderer()

lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]),
         np.array([[-1, 1, 0.], [1, 1, 0.]])]
colors = np.array([[1., 0., 0.], [0., .5, 0.]])
stream_actor = actor.streamtube(lines, colors, linewidth=0.3, lod=False)
renderer.add(stream_actor)

"""
The ``ShowManager`` allows to break the visualization process in steps so that
the widgets can be added and updated properly.
"""

show_manager = window.ShowManager(renderer, size=(800, 800),
                                  order_transparent=True)

"""
Next we add the widgets and their callbacks.
"""

def button_plus_callback(obj, event):
    print('+ pressed')
    opacity = stream_actor.GetProperty().GetOpacity()
    if opacity < 1:
        stream_actor.GetProperty().SetOpacity(opacity + 0.1)

def button_minus_callback(obj, event):
    print('- pressed')

    opacity = stream_actor.GetProperty().GetOpacity()
    if opacity > 0:
        stream_actor.GetProperty().SetOpacity(opacity - 0.1)

"""
We need to download some icons to create a face for our buttons. We provide
some simple icons in this tutorial. But you of course you can use any PNG icon
you may want.
"""

fetch_viz_icons()
button_png_plus = read_viz_icons(fname='plus.png')

button_plus = widget.button(show_manager.iren,
                            show_manager.ren,
                            button_plus_callback,
                            button_png_plus, (.98, .9), (120, 50))

button_png_minus = read_viz_icons(fname='minus.png')
button_minus = widget.button(show_manager.iren,
                             show_manager.ren,
                             button_minus_callback,
                             button_png_minus, (.98, .9), (50, 50))

def move_lines(obj, event):
    stream_actor.SetPosition((obj.get_value(), 0, 0))

"""
Then we create the slider.
"""

slider = widget.slider(show_manager.iren, show_manager.ren,
                       callback=move_lines,
                       min_value=-1,
                       max_value=1,
                       value=0.,
                       label="X",
                       right_normalized_pos=(.98, 0.7),
                       size=(120, 0), label_format="%0.2lf",
                       color=(0.4, 0.4, 0.4),
                       selected_color=(0.2, 0.2, 0.2))

"""
And we add a simple clickable text overlay at the bottom left corner.
"""

def text_clicked(obj, event):
    print "Awesome!"

text = widget.text(show_manager.iren, show_manager.ren,
                   message="Powered by DIPY",
                   callback=text_clicked,
                   color=(1., .5, .0),
                   left_down_pos=(10, 5),
                   right_top_pos=(200, 35))

"""
Position the camera.
"""

renderer.zoom(0.7)
renderer.roll(10.)

"""
Uncomment the following lines to start the interaction.
"""

show_manager.initialize()
show_manager.render()
show_manager.start()

renderer.reset_clipping_range()

window.record(renderer, out_path='mini_ui.png', size=(800, 800),
              reset_camera=False)

del show_manager

"""
.. figure:: mini_ui.png
   :align: center

   **A minimalistic user interface**.
"""
<commit_msg>DOC: Commented updated example<commit_after>"""
=====================================
Create a minimalistic user interface
=====================================

DIPY allows to create a minimalistic interface using widgets.

In this example we will create: a) two parallel steamtubes, b) add some buttons
which will change the opacity of these tubes and c) move the streamtubes using
a slider.
"""

import numpy as np
from dipy.viz import window, actor, widget
from dipy.data import fetch_viz_icons, read_viz_icons

"""
First, we add a couple of streamtubes to the Renderer
"""

renderer = window.Renderer()

lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]),
         np.array([[-1, 1, 0.], [1, 1, 0.]])]
colors = np.array([[1., 0., 0.], [0., .5, 0.]])
stream_actor = actor.streamtube(lines, colors, linewidth=0.3, lod=False)
renderer.add(stream_actor)

"""
The ``ShowManager`` allows to break the visualization process in steps so that
the widgets can be added and updated properly.
"""

show_manager = window.ShowManager(renderer, size=(800, 800),
                                  order_transparent=True)

"""
Next we add the widgets and their callbacks.
"""

def button_plus_callback(obj, event):
    print('+ pressed')
    opacity = stream_actor.GetProperty().GetOpacity()
    if opacity < 1:
        stream_actor.GetProperty().SetOpacity(opacity + 0.1)

def button_minus_callback(obj, event):
    print('- pressed')

    opacity = stream_actor.GetProperty().GetOpacity()
    if opacity > 0:
        stream_actor.GetProperty().SetOpacity(opacity - 0.1)

"""
We need to download some icons to create a face for our buttons. We provide
some simple icons in this tutorial. But you of course you can use any PNG icon
you may want.
"""

fetch_viz_icons()
button_png_plus = read_viz_icons(fname='plus.png')

button_plus = widget.button(show_manager.iren,
                            show_manager.ren,
                            button_plus_callback,
                            button_png_plus, (.98, .9), (120, 50))

button_png_minus = read_viz_icons(fname='minus.png')
button_minus = widget.button(show_manager.iren,
                             show_manager.ren,
                             button_minus_callback,
                             button_png_minus, (.98, .9), (50, 50))

def move_lines(obj, event):
    stream_actor.SetPosition((obj.get_value(), 0, 0))

"""
Then we create the slider.
"""

slider = widget.slider(show_manager.iren, show_manager.ren,
                       callback=move_lines,
                       min_value=-1,
                       max_value=1,
                       value=0.,
                       label="X",
                       right_normalized_pos=(.98, 0.7),
                       size=(120, 0), label_format="%0.2lf",
                       color=(0.4, 0.4, 0.4),
                       selected_color=(0.2, 0.2, 0.2))

"""
And we add a simple clickable text overlay at the bottom left corner.
"""

def text_clicked(obj, event):
    print "Awesome!"

text = widget.text(show_manager.iren, show_manager.ren,
                   message="Powered by DIPY",
                   callback=text_clicked,
                   color=(1., .5, .0),
                   left_down_pos=(10, 5),
                   right_top_pos=(200, 35))

"""
Position the camera.
"""

renderer.zoom(0.7)
renderer.roll(10.)
renderer.reset_clipping_range()

"""
Uncomment the following lines to start the interaction.
"""

# show_manager.initialize()
# show_manager.render()
# show_manager.start()

window.record(renderer, out_path='mini_ui.png', size=(800, 800),
              reset_camera=False)

del show_manager

"""
.. figure:: mini_ui.png
   :align: center

   **A minimalistic user interface**.
"""
<|endoftext|>


<commit_before># Copyright (c) 2007-2011 gocept gmbh & co. kg
# See also LICENSE.txt

from zope.testing import doctest
import BaseHTTPServer
import __future__
import contextlib
import copy
import gocept.selenium.ztk
import inspect
import logging
import mock
import pkg_resources
import random
import re
import string
import sys
import threading
import time
import transaction
import unittest2
import urllib2
import xml.sax.saxutils
import zeit.connector.interfaces
import zope.app.appsetup.product
import zope.app.testing.functional
import zope.component
import zope.publisher.browser
import zope.security.management
import zope.security.testing
import zope.site.hooks
import zope.testbrowser.testing
import zope.testing.renormalizing

def ZCMLLayer(
    config_file, module=None, name=None, allow_teardown=True,
    product_config=None):
    if module is None:
        module = stack = inspect.stack()[1][0].f_globals['__name__']
    if name is None:
        name = 'ZCMLLayer(%s)' % config_file
    if not config_file.startswith('/'):
        config_file = pkg_resources.resource_filename(module, config_file)
    if product_config is True:
        product_config = cms_product_config
    def setUp(cls):
        cls.setup = zope.app.testing.functional.FunctionalTestSetup(
            config_file, product_config=product_config)

    def tearDown(cls):
        cls.setup.tearDownCompletely()
        if not allow_teardown:
            raise NotImplementedError

    layer = type(name, (object,), dict(
        __module__=module,
        setUp=classmethod(setUp),
        tearDown=classmethod(tearDown),
    ))
    return layer

class HTTPServer(BaseHTTPServer.HTTPServer):
    # shutdown mechanism borrowed from gocept.selenium.static.HTTPServer

    _continue = True

    def __init__(self, *args):
        BaseHTTPServer.HTTPServer.__init__(self, *args)
        self.errors = []

    def handle_error(self, request, client_address):
        self.errors.append((request, client_address))

    def serve_until_shutdown(self):
        while self._continue:
            self.handle_request()

    def shutdown(self):
        self._continue = False
        # We fire a last request at the server in order to take it out of the
        # while loop in `self.serve_until_shutdown`.
        try:
            urllib2.urlopen(
                'http://%s:%s/die' % (self.server_name, self.server_port),
                timeout=1)
        except urllib2.URLError:
            # If the server is already shut down, we receive a socket error,
            # which we ignore.
            pass
        self.server_close()

def HTTPServerLayer(request_handler):
    """Factory for a layer which opens a HTTP port."""
    module = inspect.stack()[1][0].f_globals['__name__']
    port = random.randint(30000, 40000)

    def setUp(cls):
        server_address = ('localhost', port)
        cls.httpd = HTTPServer(server_address, request_handler)
        cls.thread = threading.Thread(target=cls.httpd.serve_until_shutdown)
        cls.thread.daemon = True
        cls.thread.start()
        # Wait as it sometimes takes a while to get the server started.
        # XXX this is a little kludgy
        time.sleep(0.001)

    def tearDown(cls):
        cls.httpd.shutdown()
        cls.thread.join()

    def testTearDown(cls):
        cls.httpd.errors[:] = []
        request_handler.tearDown()

    layer = type('HTTPLayer(%s)' % port, (object,), dict(
        __module__=module,
        setUp=classmethod(setUp),
        tearDown=classmethod(tearDown),
        testTearDown=classmethod(testTearDown),
    ))
    return layer, port

class BaseHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    """Handler for testing which does not log to STDOUT."""

    def log_message(self, format, *args):
        pass

    @classmethod
    def tearDown(cls):
        pass

cms_product_config = string.Template("""\
<product-config zeit.cms>
  source-serie file://${base}/content/serie.xml
  source-navigation file://${base}/content/navigation.xml
  source-print-ressort file://${base}/content/print-ressort.xml
  source-keyword file://${base}/content/zeit-ontologie-prism.xml
  source-products file://${base}/content/products.xml
  source-badges file://${base}/asset/badges.xml

  preview-prefix http://localhost/preview-prefix
  live-prefix http://localhost/live-prefix
  development-preview-prefix http://localhost/development-preview-prefix

  suggest-keyword-email-address none@testing
  suggest-keyword-real-name Dr. No
</product-config>
""").substitute(
    base=pkg_resources.resource_filename(__name__, ''))

cms_layer = ZCMLLayer('ftesting.zcml', product_config=True)
selenium_layer = gocept.selenium.ztk.Layer(cms_layer)

checker = zope.testing.renormalizing.RENormalizing([
    (re.compile(r'\d{4} \d{1,2} \d{1,2}  \d\d:\d\d:\d\d'), '<FORMATTED DATE>'),
    (re.compile('0x[0-9a-f]+'), "0x..."),
    (re.compile(r'/\+\+noop\+\+[0-9a-f]+'), ''),
    (re.compile('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'),
     "<GUID>"),
])

def setUpDoctests(test):
    test.old_product_config = copy.deepcopy(
        zope.app.appsetup.product.saveConfiguration())
    config = test.globs.get('product_config', {})
    __traceback_info__ = (config,)
    setup_product_config(config)

def tearDown(test):
    zope.security.management.endInteraction()
    # only for functional tests
    if hasattr(test, 'globs'):
        old_site = test.globs.get('old_site')
        if old_site is not None:
            zope.site.hooks.setSite(old_site)
    connector = zope.component.getUtility(
        zeit.connector.interfaces.IConnector)
    connector._reset()
    old_config = getattr(test, 'old_product_config', None)
    if old_config is not None:
        zope.app.appsetup.product.restoreConfiguration(old_config)

def setup_product_config(product_config={}):
    zope.app.appsetup.product._configs.update(product_config)

optionflags = (doctest.REPORT_NDIFF +
               doctest.INTERPRET_FOOTNOTES +
               doctest.NORMALIZE_WHITESPACE +
               doctest.ELLIPSIS)

def DocFileSuite(*paths, **kw):
    kw['package'] = doctest._normalize_module(kw.get('package'))
    kw.setdefault('checker', checker)
    kw.setdefault('optionflags', optionflags)
    return doctest.DocFileSuite(*paths, **kw)

def FunctionalDocFileSuite(*paths, **kw):
    layer = kw.pop('layer', cms_layer)
    kw['package'] = doctest._normalize_module(kw.get('package'))
    kw['setUp'] = setUpDoctests
    kw['tearDown'] = tearDown
    kw.setdefault('globs', {})['product_config'] = kw.pop(
        'product_config', {})
    kw['globs']['with_statement'] = __future__.with_statement
    kw.setdefault('checker', checker)
    kw.setdefault('optionflags', optionflags)

    test = zope.app.testing.functional.FunctionalDocFileSuite(
        *paths, **kw)
    test.layer = layer

    return test

class RepositoryHelper(object):

    @property
    def repository(self):
        import zeit.cms.repository.interfaces
        with site(self.getRootFolder()):
            return zope.component.getUtility(
                zeit.cms.repository.interfaces.IRepository)

    @repository.setter
    def repository(self, value):
        self.__dict__['repository'] = value

class ZCAHelper(object):

    def patchUtility(self, interface, new=None, name=None, sm=None):
        self._ensure_storage()
        if sm is None:
            sm = zope.component.getSiteManager()
        if new is None:
            new = mock.Mock()
        orig = sm.queryUtility(interface)
        if orig is not None:
            self.utilities.append((sm, orig, interface, name))
        if name is None:
            sm.registerUtility(new, interface)
        else:
            sm.registerUtility(new, interface, name)
        return new

    def restoreUtilities(self):
        self._ensure_storage()
        for sm, orig, interface, name in self.utilities:
            if name is None:
                sm.registerUtility(orig, interface)
            else:
                sm.registerUtility(orig, interface, name)

    def _ensure_storage(self):
        if not hasattr(self, 'utilities'):
            self.utilities = []

class FunctionalTestCase(zope.app.testing.functional.FunctionalTestCase,
                         unittest2.TestCase,
                         RepositoryHelper,
                         ZCAHelper):

    layer = cms_layer
    product_config = {}

    def setUp(self):
        super(FunctionalTestCase, self).setUp()
        self.old_product_config = copy.deepcopy(
            zope.app.appsetup.product.saveConfiguration())
        setup_product_config(self.product_config)
        zope.site.hooks.setSite(self.getRootFolder())
        self.principal = zeit.cms.testing.create_interaction(u'zope.user')

    def tearDown(self):
        self.restoreUtilities()
        zeit.cms.testing.tearDown(self)
        zope.site.hooks.setSite(None)
        super(FunctionalTestCase, self).tearDown()

class SeleniumTestCase(gocept.selenium.ztk.TestCase,
                       unittest2.TestCase,
                       RepositoryHelper):

    layer = selenium_layer
    skin = 'cms'
    log_errors = False
    log_errors_ignore = ()
    level = 2

    def setUp(self):
        super(SeleniumTestCase, self).setUp()
        if self.log_errors:
            with site(self.getRootFolder()):
                error_log = zope.component.getUtility(
                    zope.error.interfaces.IErrorReportingUtility)
                error_log.copy_to_zlog = True
                error_log._ignored_exceptions = self.log_errors_ignore
            self.log_handler = logging.StreamHandler(sys.stdout)
            logging.root.addHandler(self.log_handler)
            self.old_log_level = logging.root.level
            logging.root.setLevel(logging.ERROR)
            transaction.commit()
        self.selenium.getEval('window.sessionStorage.clear()')

    def tearDown(self):
        zeit.cms.testing.tearDown(self)
        super(SeleniumTestCase, self).tearDown()
        if self.log_errors:
            logging.root.removeHandler(self.log_handler)
            logging.root.setLevel(self.old_log_level)

    def open(self, path, auth='user:userpw'):
        auth_sent = getattr(self.layer, 'auth_sent', None)
        if auth and auth != auth_sent:
            # Only set auth when it changed. Firefox will be confused
            # otherwise.
            self.layer.auth_sent = auth
            auth = auth + '@'
        else:
            auth = ''
        self.selenium.open(
            'http://%s%s/++skin++%s%s' % (
                auth, self.selenium.server, self.skin, path))

    def click_label(self, label):
        self.selenium.click('//label[contains(string(.), %s)]' %
                            xml.sax.saxutils.quoteattr(label))

def click_wo_redirect(browser, *args, **kwargs):
    browser.mech_browser.set_handle_redirect(False)
    try:
        try:
            browser.getLink(*args, **kwargs).click()
        except urllib2.HTTPError, e:
            print str(e)
            print e.hdrs.get('location')
    finally:
        browser.mech_browser.set_handle_redirect(True)

def set_site(site=None):
    """Encapsulation of the getSite/setSite-dance.

    Sets the given site, preserves the old site in the globs,
    where it will be reset by our FunctionalDocFileSuite's tearDown.
    """

    globs = sys._getframe(1).f_locals
    globs['old_site'] = zope.site.hooks.getSite()
    if site is None:
        site = globs['getRootFolder']()
    zope.site.hooks.setSite(site)

def create_interaction(name=u'zope.user'):
    principal = zope.security.testing.Principal(
        name, groups=['zope.Authenticated'], description=u'test@example.com')
    request = zope.publisher.browser.TestRequest()
    request.setPrincipal(principal)
    zope.security.management.newInteraction(request)
    return principal

@contextlib.contextmanager
def interaction(principal_id=u'zope.user'):
    principal = create_interaction(principal_id)
    yield principal
    zope.security.management.endInteraction()

@contextlib.contextmanager
def site(root):
    old_site = zope.site.hooks.getSite()
    zope.site.hooks.setSite(root)
    yield
    zope.site.hooks.setSite(old_site)

class BrowserAssertions(object):

    def assert_ellipsis(self, want, got=None):
        import difflib
        import doctest
        if got is None:
            got = self.browser.contents
        # normalize whitespace
        norm_want = ' '.join(want.split())
        norm_got = ' '.join(got.split())
        if doctest._ellipsis_match(norm_want, norm_got):
            return True
        # Report ndiff
        engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
        diff = list(engine.compare(want.splitlines(True),
                                   got.splitlines(True)))
        kind = 'ndiff with -expected +actual'
        diff = [line.rstrip() + '\n' for line in diff]
        self.fail('Differences (%s):\n' % kind + ''.join(diff))

    def assert_json(self, want, got=None):
        import simplejson
        if got is None:
            got = self.browser.contents
        data = simplejson.loads(got)
        self.assertEqual(want, data)
        return data

class BrowserTestCase(unittest2.TestCase,
                      BrowserAssertions,
                      RepositoryHelper):

    layer = cms_layer

    def setUp(self):
        self.browser = zope.testbrowser.testing.Browser()
        self.browser.addHeader('Authorization', 'Basic user:userpw')

    def getRootFolder(self):
        return self.layer.setup.getRootFolder()
<commit_msg>Base BrowserTestCase on FunctionalTestCase, it breaks in combination with other tests otherwise<commit_after># Copyright (c) 2007-2011 gocept gmbh & co. kg
# See also LICENSE.txt

from zope.testing import doctest
import BaseHTTPServer
import __future__
import contextlib
import copy
import gocept.selenium.ztk
import inspect
import logging
import mock
import pkg_resources
import random
import re
import string
import sys
import threading
import time
import transaction
import unittest2
import urllib2
import xml.sax.saxutils
import zeit.connector.interfaces
import zope.app.appsetup.product
import zope.app.testing.functional
import zope.component
import zope.publisher.browser
import zope.security.management
import zope.security.testing
import zope.site.hooks
import zope.testbrowser.testing
import zope.testing.renormalizing

def ZCMLLayer(
    config_file, module=None, name=None, allow_teardown=True,
    product_config=None):
    if module is None:
        module = stack = inspect.stack()[1][0].f_globals['__name__']
    if name is None:
        name = 'ZCMLLayer(%s)' % config_file
    if not config_file.startswith('/'):
        config_file = pkg_resources.resource_filename(module, config_file)
    if product_config is True:
        product_config = cms_product_config
    def setUp(cls):
        cls.setup = zope.app.testing.functional.FunctionalTestSetup(
            config_file, product_config=product_config)

    def tearDown(cls):
        cls.setup.tearDownCompletely()
        if not allow_teardown:
            raise NotImplementedError

    layer = type(name, (object,), dict(
        __module__=module,
        setUp=classmethod(setUp),
        tearDown=classmethod(tearDown),
    ))
    return layer

class HTTPServer(BaseHTTPServer.HTTPServer):
    # shutdown mechanism borrowed from gocept.selenium.static.HTTPServer

    _continue = True

    def __init__(self, *args):
        BaseHTTPServer.HTTPServer.__init__(self, *args)
        self.errors = []

    def handle_error(self, request, client_address):
        self.errors.append((request, client_address))

    def serve_until_shutdown(self):
        while self._continue:
            self.handle_request()

    def shutdown(self):
        self._continue = False
        # We fire a last request at the server in order to take it out of the
        # while loop in `self.serve_until_shutdown`.
        try:
            urllib2.urlopen(
                'http://%s:%s/die' % (self.server_name, self.server_port),
                timeout=1)
        except urllib2.URLError:
            # If the server is already shut down, we receive a socket error,
            # which we ignore.
            pass
        self.server_close()

def HTTPServerLayer(request_handler):
    """Factory for a layer which opens a HTTP port."""
    module = inspect.stack()[1][0].f_globals['__name__']
    port = random.randint(30000, 40000)

    def setUp(cls):
        server_address = ('localhost', port)
        cls.httpd = HTTPServer(server_address, request_handler)
        cls.thread = threading.Thread(target=cls.httpd.serve_until_shutdown)
        cls.thread.daemon = True
        cls.thread.start()
        # Wait as it sometimes takes a while to get the server started.
        # XXX this is a little kludgy
        time.sleep(0.001)

    def tearDown(cls):
        cls.httpd.shutdown()
        cls.thread.join()

    def testTearDown(cls):
        cls.httpd.errors[:] = []
        request_handler.tearDown()

    layer = type('HTTPLayer(%s)' % port, (object,), dict(
        __module__=module,
        setUp=classmethod(setUp),
        tearDown=classmethod(tearDown),
        testTearDown=classmethod(testTearDown),
    ))
    return layer, port

class BaseHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    """Handler for testing which does not log to STDOUT."""

    def log_message(self, format, *args):
        pass

    @classmethod
    def tearDown(cls):
        pass

cms_product_config = string.Template("""\
<product-config zeit.cms>
  source-serie file://${base}/content/serie.xml
  source-navigation file://${base}/content/navigation.xml
  source-print-ressort file://${base}/content/print-ressort.xml
  source-keyword file://${base}/content/zeit-ontologie-prism.xml
  source-products file://${base}/content/products.xml
  source-badges file://${base}/asset/badges.xml

  preview-prefix http://localhost/preview-prefix
  live-prefix http://localhost/live-prefix
  development-preview-prefix http://localhost/development-preview-prefix

  suggest-keyword-email-address none@testing
  suggest-keyword-real-name Dr. No
</product-config>
""").substitute(
    base=pkg_resources.resource_filename(__name__, ''))

cms_layer = ZCMLLayer('ftesting.zcml', product_config=True)
selenium_layer = gocept.selenium.ztk.Layer(cms_layer)

checker = zope.testing.renormalizing.RENormalizing([
    (re.compile(r'\d{4} \d{1,2} \d{1,2}  \d\d:\d\d:\d\d'), '<FORMATTED DATE>'),
    (re.compile('0x[0-9a-f]+'), "0x..."),
    (re.compile(r'/\+\+noop\+\+[0-9a-f]+'), ''),
    (re.compile('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'),
     "<GUID>"),
])

def setUpDoctests(test):
    test.old_product_config = copy.deepcopy(
        zope.app.appsetup.product.saveConfiguration())
    config = test.globs.get('product_config', {})
    __traceback_info__ = (config,)
    setup_product_config(config)

def tearDown(test):
    zope.security.management.endInteraction()
    # only for functional tests
    if hasattr(test, 'globs'):
        old_site = test.globs.get('old_site')
        if old_site is not None:
            zope.site.hooks.setSite(old_site)
    connector = zope.component.getUtility(
        zeit.connector.interfaces.IConnector)
    connector._reset()
    old_config = getattr(test, 'old_product_config', None)
    if old_config is not None:
        zope.app.appsetup.product.restoreConfiguration(old_config)

def setup_product_config(product_config={}):
    zope.app.appsetup.product._configs.update(product_config)

optionflags = (doctest.REPORT_NDIFF +
               doctest.INTERPRET_FOOTNOTES +
               doctest.NORMALIZE_WHITESPACE +
               doctest.ELLIPSIS)

def DocFileSuite(*paths, **kw):
    kw['package'] = doctest._normalize_module(kw.get('package'))
    kw.setdefault('checker', checker)
    kw.setdefault('optionflags', optionflags)
    return doctest.DocFileSuite(*paths, **kw)

def FunctionalDocFileSuite(*paths, **kw):
    layer = kw.pop('layer', cms_layer)
    kw['package'] = doctest._normalize_module(kw.get('package'))
    kw['setUp'] = setUpDoctests
    kw['tearDown'] = tearDown
    kw.setdefault('globs', {})['product_config'] = kw.pop(
        'product_config', {})
    kw['globs']['with_statement'] = __future__.with_statement
    kw.setdefault('checker', checker)
    kw.setdefault('optionflags', optionflags)

    test = zope.app.testing.functional.FunctionalDocFileSuite(
        *paths, **kw)
    test.layer = layer

    return test

class RepositoryHelper(object):

    @property
    def repository(self):
        import zeit.cms.repository.interfaces
        with site(self.getRootFolder()):
            return zope.component.getUtility(
                zeit.cms.repository.interfaces.IRepository)

    @repository.setter
    def repository(self, value):
        self.__dict__['repository'] = value

class ZCAHelper(object):

    def patchUtility(self, interface, new=None, name=None, sm=None):
        self._ensure_storage()
        if sm is None:
            sm = zope.component.getSiteManager()
        if new is None:
            new = mock.Mock()
        orig = sm.queryUtility(interface)
        if orig is not None:
            self.utilities.append((sm, orig, interface, name))
        if name is None:
            sm.registerUtility(new, interface)
        else:
            sm.registerUtility(new, interface, name)
        return new

    def restoreUtilities(self):
        self._ensure_storage()
        for sm, orig, interface, name in self.utilities:
            if name is None:
                sm.registerUtility(orig, interface)
            else:
                sm.registerUtility(orig, interface, name)

    def _ensure_storage(self):
        if not hasattr(self, 'utilities'):
            self.utilities = []

class FunctionalTestCase(zope.app.testing.functional.FunctionalTestCase,
                         unittest2.TestCase,
                         RepositoryHelper,
                         ZCAHelper):

    layer = cms_layer
    product_config = {}

    def setUp(self):
        super(FunctionalTestCase, self).setUp()
        self.old_product_config = copy.deepcopy(
            zope.app.appsetup.product.saveConfiguration())
        setup_product_config(self.product_config)
        zope.site.hooks.setSite(self.getRootFolder())
        self.principal = zeit.cms.testing.create_interaction(u'zope.user')

    def tearDown(self):
        self.restoreUtilities()
        zeit.cms.testing.tearDown(self)
        zope.site.hooks.setSite(None)
        super(FunctionalTestCase, self).tearDown()

class SeleniumTestCase(gocept.selenium.ztk.TestCase,
                       unittest2.TestCase,
                       RepositoryHelper):

    layer = selenium_layer
    skin = 'cms'
    log_errors = False
    log_errors_ignore = ()
    level = 2

    def setUp(self):
        super(SeleniumTestCase, self).setUp()
        if self.log_errors:
            with site(self.getRootFolder()):
                error_log = zope.component.getUtility(
                    zope.error.interfaces.IErrorReportingUtility)
                error_log.copy_to_zlog = True
                error_log._ignored_exceptions = self.log_errors_ignore
            self.log_handler = logging.StreamHandler(sys.stdout)
            logging.root.addHandler(self.log_handler)
            self.old_log_level = logging.root.level
            logging.root.setLevel(logging.ERROR)
            transaction.commit()
        self.selenium.getEval('window.sessionStorage.clear()')

    def tearDown(self):
        zeit.cms.testing.tearDown(self)
        super(SeleniumTestCase, self).tearDown()
        if self.log_errors:
            logging.root.removeHandler(self.log_handler)
            logging.root.setLevel(self.old_log_level)

    def open(self, path, auth='user:userpw'):
        auth_sent = getattr(self.layer, 'auth_sent', None)
        if auth and auth != auth_sent:
            # Only set auth when it changed. Firefox will be confused
            # otherwise.
            self.layer.auth_sent = auth
            auth = auth + '@'
        else:
            auth = ''
        self.selenium.open(
            'http://%s%s/++skin++%s%s' % (
                auth, self.selenium.server, self.skin, path))

    def click_label(self, label):
        self.selenium.click('//label[contains(string(.), %s)]' %
                            xml.sax.saxutils.quoteattr(label))

def click_wo_redirect(browser, *args, **kwargs):
    browser.mech_browser.set_handle_redirect(False)
    try:
        try:
            browser.getLink(*args, **kwargs).click()
        except urllib2.HTTPError, e:
            print str(e)
            print e.hdrs.get('location')
    finally:
        browser.mech_browser.set_handle_redirect(True)

def set_site(site=None):
    """Encapsulation of the getSite/setSite-dance.

    Sets the given site, preserves the old site in the globs,
    where it will be reset by our FunctionalDocFileSuite's tearDown.
    """

    globs = sys._getframe(1).f_locals
    globs['old_site'] = zope.site.hooks.getSite()
    if site is None:
        site = globs['getRootFolder']()
    zope.site.hooks.setSite(site)

def create_interaction(name=u'zope.user'):
    principal = zope.security.testing.Principal(
        name, groups=['zope.Authenticated'], description=u'test@example.com')
    request = zope.publisher.browser.TestRequest()
    request.setPrincipal(principal)
    zope.security.management.newInteraction(request)
    return principal

@contextlib.contextmanager
def interaction(principal_id=u'zope.user'):
    principal = create_interaction(principal_id)
    yield principal
    zope.security.management.endInteraction()

@contextlib.contextmanager
def site(root):
    old_site = zope.site.hooks.getSite()
    zope.site.hooks.setSite(root)
    yield
    zope.site.hooks.setSite(old_site)

class BrowserAssertions(object):

    def assert_ellipsis(self, want, got=None):
        import difflib
        import doctest
        if got is None:
            got = self.browser.contents
        # normalize whitespace
        norm_want = ' '.join(want.split())
        norm_got = ' '.join(got.split())
        if doctest._ellipsis_match(norm_want, norm_got):
            return True
        # Report ndiff
        engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
        diff = list(engine.compare(want.splitlines(True),
                                   got.splitlines(True)))
        kind = 'ndiff with -expected +actual'
        diff = [line.rstrip() + '\n' for line in diff]
        self.fail('Differences (%s):\n' % kind + ''.join(diff))

    def assert_json(self, want, got=None):
        import simplejson
        if got is None:
            got = self.browser.contents
        data = simplejson.loads(got)
        self.assertEqual(want, data)
        return data

class BrowserTestCase(FunctionalTestCase,
                      BrowserAssertions):

    def setUp(self):
        super(BrowserTestCase, self).setUp()
        # undo some setup that would break browser tests
        zope.security.management.endInteraction()
        zope.component.hooks.setSite(None)

        self.browser = zope.testbrowser.testing.Browser()
        self.browser.addHeader('Authorization', 'Basic user:userpw')
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# Streaming CEP documentation build configuration file, created by
# sphinx-quickstart on Thu Jan 15 16:21:58 2015.
#
# 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.

# 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 = ['rst2pdf.pdfbuilder']

# 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 = u'Streaming Connector'
copyright = u'2015 Stratio'

# The version info for the project you'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 = '${project.version}'
# The full version, including alpha/beta/rc tags.
release = version

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
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'
highlight_language = 'java'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False

# -- 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 = 'stratio'

# 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 = {
    'versions' : ['0.5.0'],
    'github' : 'https://github.com/Stratio/stratio-connector-streaming',
    'jira': 'https://github.com/Stratio/stratio-connector-streaming',
    'module_name' : 'connector_streaming'
}

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

# 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']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# 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

# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'

# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}

# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'

# Output file base name for HTML help builder.
htmlhelp_basename = 'connector-streaming-doc'

# -- 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': '',

    # Latex figure (float) alignment
    #'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
#latex_documents = [
#    ('about', 'Grammar', u'GettingStarted',
#     'Juanjo Lopez, Daniel Higuero, Miguel Angel Fernandez'),
#]

# 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 = [
    ('about', 'Grammar', u'GettingStarted',
     [u'Juanjo Lopez, Daniel Higuero, Migel Angel Fernandez'], 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 = [
    ('about', 'Grammar', u'GettingStarted',
     'Juanjo Lopez, Daniel Higuero, Miguel Angel Fernandez'),
]

# 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'

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

pdf_documents = [
    ('about', u'${project.name}', u'${project.name}', u'${project.name}'),
    ]

pdf_stylesheets = ['sphinx','kerning','a4']
pdf_toc_depth = 9999
pdf_use_numbered_links = False
pdf_fit_background_mode = 'scale'
<commit_msg>Update conf.py<commit_after># -*- coding: utf-8 -*-
#
# Streaming CEP documentation build configuration file, created by
# sphinx-quickstart on Thu Jan 15 16:21:58 2015.
#
# 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.

# 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 = ['rst2pdf.pdfbuilder']

# 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 = u'Streaming Connector'
copyright = u'2015 Stratio'

# The version info for the project you'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 = '${project.version}'
# The full version, including alpha/beta/rc tags.
release = version

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
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'
highlight_language = 'java'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False

# -- 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 = 'stratio'

# 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 = {
    'versions' : ['0.5.0'],
    'github' : 'https://github.com/Stratio/stratio-connector-streaming',
    'jira': 'https://github.com/Stratio/stratio-connector-streaming',
    'module_name' : 'connector_streaming'
}

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

# 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']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# 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

# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'

# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}

# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'

# Output file base name for HTML help builder.
htmlhelp_basename = 'connector-streaming-doc'

# -- 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': '',

    # Latex figure (float) alignment
    #'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
#latex_documents = [
#    ('about', 'Grammar', u'GettingStarted',
#     'Juanjo Lopez, Daniel Higuero, Miguel Angel Fernandez'),
#]

# 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 = [
    ('about', 'Grammar', u'GettingStarted',
     [u'Juanjo Lopez, Daniel Higuero, Migel Angel Fernandez'], 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 = [
    ('about', 'Grammar', u'GettingStarted',
     'Juanjo Lopez, Daniel Higuero, Miguel Angel Fernandez'),
]

# 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'

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

pdf_documents = [
    ('about', u'${project.name}', u'${project.name}', u'${project.name}'),
    ]

pdf_stylesheets = ['sphinx','kerning','a4']
pdf_toc_depth = 9999
pdf_use_numbered_links = False
pdf_fit_background_mode = 'scale'
<|endoftext|>


<commit_before>import json
from graphenebase.types import *
from graphenebase.objects import GrapheneObject, isArgsThisClass
from graphenebase.account import PublicKey, Address

#: Operation ids
operations = {}
operations["vote"] = 0
operations["comment"] = 1
operations["transfer"] = 2
operations["transfer_to_vesting"] = 3
operations["withdraw_vesting"] = 4
operations["limit_order_create"] = 5
operations["limit_order_cancel"] = 6
operations["feed_publish"] = 7
operations["convert"] = 8
operations["account_create"] = 9
operations["account_update"] = 10
operations["witness_update"] = 11
operations["account_witness_vote"] = 12
operations["account_witness_proxy"] = 13
operations["pow"] = 14
operations["custom"] = 15
operations["report_over_production"] = 16
operations["fill_convert_request"] = 17
operations["comment_reward"] = 18
operations["curate_reward"] = 19
operations["liquidity_reward"] = 20
operations["interest"] = 21
operations["fill_vesting_withdraw"] = 22
operations["fill_order"] = 23

prefix = "STM"
# prefix = "TST"

def getOperationNameForId(i) :
    """ Convert an operation id into the corresponding string
    """
    for key in operations :
        if int(operations[key]) is int(i) :
            return key
    return "Unknown Operation ID %d" % i

class Operation() :
    def __init__(self, op) :
        if isinstance(op, list) and len(op) == 2:
            self.opId = operations[op[0]]
            name = op[0]
            self.name = name[0].upper() + name[1:]
            try:
                klass = eval(self.name)
            except:
                raise NotImplementedError("Unimplemented Operation %s" % self.name)
            self.op = klass(op[1])
        else:
            self.op = op
            self.name = type(self.op).__name__.lower()  # also store name
            self.opId = operations[self.name]

    def __bytes__(self) :
        return bytes(Id(self.opId)) + bytes(self.op)

    def __str__(self) :
        return json.dumps([getOperationNameForId(self.opId), JsonObj(self.op)])

class Permission(GrapheneObject):
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]

            # Sort keys (FIXME: ideally, the sorting is part of Public
            # Key and not located here)
            kwargs["key_auths"] = sorted(
                kwargs["key_auths"],
                key=lambda x: repr(PublicKey(x[0], prefix=prefix)),
                reverse=False,
            )

            accountAuths = Map([
                [String(e[0]), Uint16(e[1])]
                for e in kwargs["account_auths"]
            ])
            keyAuths = Map([
                [PublicKey(e[0], prefix=prefix), Uint16(e[1])]
                for e in kwargs["key_auths"]
            ])
            super().__init__(OrderedDict([
                ('weight_threshold', Uint32(int(kwargs["weight_threshold"]))),
                ('account_auths'   , accountAuths),
                ('key_auths'       , keyAuths),
            ]))

class Memo(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]

            super().__init__(OrderedDict([
                ('from'      , PublicKey(kwargs["from"], prefix=prefix)),
                ('to'        , PublicKey(kwargs["to"], prefix=prefix)),
                ('nonce'     , Uint64(int(kwargs["nonce"]))),
                ('check'     , Uint32(int(kwargs["check"]))),
                ('encrypted' , Bytes(kwargs["encrypted"])),
            ]))

"""
    Actual Operations
"""

class Vote(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('voter'    , String(kwargs["voter"])),
                ('author'   , String(kwargs["author"])),
                ('permlink' , String(kwargs["permlink"])),
                ('weight'   , Int16(kwargs["weight"])),
            ]))

class Comment(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            meta = ""
            if "json_metadata" in kwargs and kwargs["json_metadata"]:
                if isinstance(kwargs["json_metadata"], dict):
                    meta = json.dumps(kwargs["json_metadata"])
                else:
                    meta = kwargs["json_metadata"]

            super().__init__(OrderedDict([
                ('parent_author'   , String(kwargs["parent_author"])),
                ('parent_permlink' , String(kwargs["parent_permlink"])),
                ('author'          , String(kwargs["author"])),
                ('permlink'        , String(kwargs["permlink"])),
                ('title'           , String(kwargs["title"])),
                ('body'            , String(kwargs["body"])),
                ('json_metadata'   , String(meta)),
            ]))

class Amount() :
    def __init__(self, d) :
        self.amount, self.asset = d.strip().split(" ")
        self.amount = float(self.amount)

        if self.asset == "STEEM":
            self.precision = 3
        elif self.asset == "VESTS":
            self.precision = 6
        elif self.asset == "SBD":
            self.precision = 3
        else:
            raise Exception("Asset unknown")

    def __bytes__(self) :
        # padding
        asset = self.asset + "\x00" * (7 - len(self.asset))
        amount = int(float(self.amount) * 10 ** self.precision)
        return struct.pack("<q", amount) + \
            struct.pack("<b", self.precision) + \
            bytes(asset, "ascii")

    def __str__(self) :
        return '{:.{}f} {}'.format(
            self.amount,
            self.precision,
            self.asset
        )

class Account_create(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]

            meta = ""
            if "json_metadata" in kwargs and kwargs["json_metadata"]:
                if isinstance(kwargs["json_metadata"], dict):
                    meta = json.dumps(kwargs["json_metadata"])
                else:
                    meta = kwargs["json_metadata"]
            super().__init__(OrderedDict([
                ('fee'              , Amount(kwargs["fee"])),
                ('creator'          , String(kwargs["creator"])),
                ('new_account_name' , String(kwargs["new_account_name"])),
                ('owner'            , Permission(kwargs["owner"])),
                ('active'           , Permission(kwargs["active"])),
                ('posting'          , Permission(kwargs["posting"])),
                ('memo_key'         , PublicKey(kwargs["memo_key"], prefix=prefix)),
                ('json_metadata'    , String(meta)),
            ]))

class Transfer(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            if "memo" not in kwargs:
                kwargs["memo"] = ""
            if kwargs["memo"] and kwargs["memo"][0] == "#":
                raise Exception(
                    "This library does not yet support encrypted memos!"
                )
            super().__init__(OrderedDict([
                ('from'          , String(kwargs["from"])),
                ('to'            , String(kwargs["to"])),
                ('amount'        , Amount(kwargs["amount"])),
                ('memo'          , String(kwargs["memo"])),
            ]))

class Transfer_to_vesting(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('from'          , String(kwargs["from"])),
                ('to'            , String(kwargs["to"])),
                ('amount'        , Amount(kwargs["amount"])),
            ]))

class Withdraw_vesting(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('account'          , String(kwargs["account"])),
                ('vesting_shares'   , Amount(kwargs["vesting_shares"])),
            ]))

class Limit_order_create(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('owner'          , String(kwargs["owner"])),
                ('orderid'        , Uint32(int(kwargs["orderid"]))),
                ('amount_to_sell' , Amount(kwargs["amount_to_sell"])),
                ('min_to_receive' , Amount(kwargs["min_to_receive"])),
                ('fill_or_kill'   , Bool(kwargs["fill_or_kill"])),
                ('expiration'     , PointInTime(kwargs["expiration"])),
            ]))

class Limit_order_cancel(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('owner'          , String(kwargs["owner"])),
                ('orderid'        , Uint32(int(kwargs["orderid"]))),
            ]))
<commit_msg>[transactions] allow transfer of encrypted memos<commit_after>import json
from graphenebase.types import *
from graphenebase.objects import GrapheneObject, isArgsThisClass
from graphenebase.account import PublicKey, Address

#: Operation ids
operations = {}
operations["vote"] = 0
operations["comment"] = 1
operations["transfer"] = 2
operations["transfer_to_vesting"] = 3
operations["withdraw_vesting"] = 4
operations["limit_order_create"] = 5
operations["limit_order_cancel"] = 6
operations["feed_publish"] = 7
operations["convert"] = 8
operations["account_create"] = 9
operations["account_update"] = 10
operations["witness_update"] = 11
operations["account_witness_vote"] = 12
operations["account_witness_proxy"] = 13
operations["pow"] = 14
operations["custom"] = 15
operations["report_over_production"] = 16
operations["fill_convert_request"] = 17
operations["comment_reward"] = 18
operations["curate_reward"] = 19
operations["liquidity_reward"] = 20
operations["interest"] = 21
operations["fill_vesting_withdraw"] = 22
operations["fill_order"] = 23

prefix = "STM"
# prefix = "TST"

def getOperationNameForId(i) :
    """ Convert an operation id into the corresponding string
    """
    for key in operations :
        if int(operations[key]) is int(i) :
            return key
    return "Unknown Operation ID %d" % i

class Operation() :
    def __init__(self, op) :
        if isinstance(op, list) and len(op) == 2:
            self.opId = operations[op[0]]
            name = op[0]
            self.name = name[0].upper() + name[1:]
            try:
                klass = eval(self.name)
            except:
                raise NotImplementedError("Unimplemented Operation %s" % self.name)
            self.op = klass(op[1])
        else:
            self.op = op
            self.name = type(self.op).__name__.lower()  # also store name
            self.opId = operations[self.name]

    def __bytes__(self) :
        return bytes(Id(self.opId)) + bytes(self.op)

    def __str__(self) :
        return json.dumps([getOperationNameForId(self.opId), JsonObj(self.op)])

class Permission(GrapheneObject):
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]

            # Sort keys (FIXME: ideally, the sorting is part of Public
            # Key and not located here)
            kwargs["key_auths"] = sorted(
                kwargs["key_auths"],
                key=lambda x: repr(PublicKey(x[0], prefix=prefix)),
                reverse=False,
            )

            accountAuths = Map([
                [String(e[0]), Uint16(e[1])]
                for e in kwargs["account_auths"]
            ])
            keyAuths = Map([
                [PublicKey(e[0], prefix=prefix), Uint16(e[1])]
                for e in kwargs["key_auths"]
            ])
            super().__init__(OrderedDict([
                ('weight_threshold', Uint32(int(kwargs["weight_threshold"]))),
                ('account_auths'   , accountAuths),
                ('key_auths'       , keyAuths),
            ]))

class Memo(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]

            super().__init__(OrderedDict([
                ('from'      , PublicKey(kwargs["from"], prefix=prefix)),
                ('to'        , PublicKey(kwargs["to"], prefix=prefix)),
                ('nonce'     , Uint64(int(kwargs["nonce"]))),
                ('check'     , Uint32(int(kwargs["check"]))),
                ('encrypted' , Bytes(kwargs["encrypted"])),
            ]))

"""
    Actual Operations
"""

class Vote(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('voter'    , String(kwargs["voter"])),
                ('author'   , String(kwargs["author"])),
                ('permlink' , String(kwargs["permlink"])),
                ('weight'   , Int16(kwargs["weight"])),
            ]))

class Comment(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            meta = ""
            if "json_metadata" in kwargs and kwargs["json_metadata"]:
                if isinstance(kwargs["json_metadata"], dict):
                    meta = json.dumps(kwargs["json_metadata"])
                else:
                    meta = kwargs["json_metadata"]

            super().__init__(OrderedDict([
                ('parent_author'   , String(kwargs["parent_author"])),
                ('parent_permlink' , String(kwargs["parent_permlink"])),
                ('author'          , String(kwargs["author"])),
                ('permlink'        , String(kwargs["permlink"])),
                ('title'           , String(kwargs["title"])),
                ('body'            , String(kwargs["body"])),
                ('json_metadata'   , String(meta)),
            ]))

class Amount() :
    def __init__(self, d) :
        self.amount, self.asset = d.strip().split(" ")
        self.amount = float(self.amount)

        if self.asset == "STEEM":
            self.precision = 3
        elif self.asset == "VESTS":
            self.precision = 6
        elif self.asset == "SBD":
            self.precision = 3
        else:
            raise Exception("Asset unknown")

    def __bytes__(self) :
        # padding
        asset = self.asset + "\x00" * (7 - len(self.asset))
        amount = int(float(self.amount) * 10 ** self.precision)
        return struct.pack("<q", amount) + \
            struct.pack("<b", self.precision) + \
            bytes(asset, "ascii")

    def __str__(self) :
        return '{:.{}f} {}'.format(
            self.amount,
            self.precision,
            self.asset
        )

class Account_create(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]

            meta = ""
            if "json_metadata" in kwargs and kwargs["json_metadata"]:
                if isinstance(kwargs["json_metadata"], dict):
                    meta = json.dumps(kwargs["json_metadata"])
                else:
                    meta = kwargs["json_metadata"]
            super().__init__(OrderedDict([
                ('fee'              , Amount(kwargs["fee"])),
                ('creator'          , String(kwargs["creator"])),
                ('new_account_name' , String(kwargs["new_account_name"])),
                ('owner'            , Permission(kwargs["owner"])),
                ('active'           , Permission(kwargs["active"])),
                ('posting'          , Permission(kwargs["posting"])),
                ('memo_key'         , PublicKey(kwargs["memo_key"], prefix=prefix)),
                ('json_metadata'    , String(meta)),
            ]))

class Transfer(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            if "memo" not in kwargs:
                kwargs["memo"] = ""
            super().__init__(OrderedDict([
                ('from'          , String(kwargs["from"])),
                ('to'            , String(kwargs["to"])),
                ('amount'        , Amount(kwargs["amount"])),
                ('memo'          , String(kwargs["memo"])),
            ]))

class Transfer_to_vesting(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('from'          , String(kwargs["from"])),
                ('to'            , String(kwargs["to"])),
                ('amount'        , Amount(kwargs["amount"])),
            ]))

class Withdraw_vesting(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('account'          , String(kwargs["account"])),
                ('vesting_shares'   , Amount(kwargs["vesting_shares"])),
            ]))

class Limit_order_create(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('owner'          , String(kwargs["owner"])),
                ('orderid'        , Uint32(int(kwargs["orderid"]))),
                ('amount_to_sell' , Amount(kwargs["amount_to_sell"])),
                ('min_to_receive' , Amount(kwargs["min_to_receive"])),
                ('fill_or_kill'   , Bool(kwargs["fill_or_kill"])),
                ('expiration'     , PointInTime(kwargs["expiration"])),
            ]))

class Limit_order_cancel(GrapheneObject) :
    def __init__(self, *args, **kwargs) :
        if isArgsThisClass(self, args):
                self.data = args[0].data
        else:
            if len(args) == 1 and len(kwargs) == 0:
                kwargs = args[0]
            super().__init__(OrderedDict([
                ('owner'          , String(kwargs["owner"])),
                ('orderid'        , Uint32(int(kwargs["orderid"]))),
            ]))
<|endoftext|>