<commit_before>import json
from enum import Enum
from typing import Dict, List

from eth_utils import decode_hex, to_canonical_address, to_checksum_address
from web3.contract import Contract
from web3.utils.abi import get_abi_input_types
from web3.utils.contracts import encode_transaction_data, find_matching_fn_abi

from raiden import constants
from raiden.constants import EthClient
from raiden.exceptions import (
    InsufficientFunds,
    ReplacementTransactionUnderpriced,
    TransactionAlreadyPending,
)
from raiden.utils import typing
from raiden.utils.filters import decode_event

class ClientErrorInspectResult(Enum):
    """Represents the action to follow after inspecting a client exception"""
    PROPAGATE_ERROR = 1
    INSUFFICIENT_FUNDS = 2
    TRANSACTION_UNDERPRICED = 3
    TRANSACTION_PENDING = 4
    ALWAYS_FAIL = 5
    TRANSACTION_ALREADY_IMPORTED = 7

def inspect_client_error(val_err: ValueError, eth_node: EthClient) -> ClientErrorInspectResult:
    # both clients return invalid json. They use single quotes while json needs double ones.
    # Also parity may return something like: 'data': 'Internal("Error message")' which needs
    # special processing
    json_response = str(val_err).replace("'", '"').replace('("', '(').replace('")', ')')
    try:
        error = json.loads(json_response)
    except json.JSONDecodeError:
        return ClientErrorInspectResult.PROPAGATE_ERROR

    if eth_node == EthClient.GETH:
        if error['code'] == -32000:
            if 'insufficient funds' in error['message']:
                return ClientErrorInspectResult.INSUFFICIENT_FUNDS
            elif 'always failing transaction' in error['message']:
                return ClientErrorInspectResult.ALWAYS_FAIL
            elif error['message'] == 'replacement transaction underpriced':
                return ClientErrorInspectResult.TRANSACTION_UNDERPRICED
            elif error['message'].startswith('known transaction:'):
                return ClientErrorInspectResult.TRANSACTION_PENDING

    elif eth_node == EthClient.PARITY:
        if error['code'] == -32010:
            if 'insufficient funds' in error['message']:
                return ClientErrorInspectResult.INSUFFICIENT_FUNDS
            elif 'another transaction with same nonce in the queue' in error['message']:
                return ClientErrorInspectResult.TRANSACTION_UNDERPRICED
            elif 'Transaction with the same hash was already imported' in error['message']:
                return ClientErrorInspectResult.TRANSACTION_ALREADY_IMPORTED
        elif error['code'] == -32015 and 'Transaction execution error' in error['message']:
            return ClientErrorInspectResult.ALWAYS_FAIL

    return ClientErrorInspectResult.PROPAGATE_ERROR

class ContractProxy:
    def __init__(
            self,
            jsonrpc_client,
            contract: Contract,
    ):
        if contract is None:
            raise ValueError('Contract must not be None')
        if jsonrpc_client is None:
            raise ValueError('JSONRPCClient must not be None')
        self.jsonrpc_client = jsonrpc_client
        self.contract = contract

    def transact(
            self,
            function_name: str,
            startgas: int,
            *args,
            **kargs,
    ) -> typing.TransactionHash:
        data = ContractProxy.get_transaction_data(self.contract.abi, function_name, args)

        try:
            txhash = self.jsonrpc_client.send_transaction(
                to=self.contract.address,
                startgas=startgas,
                value=kargs.pop('value', 0),
                data=decode_hex(data),
                **kargs,
            )
        except ValueError as e:
            action = inspect_client_error(e, self.jsonrpc_client.eth_node)
            if action == ClientErrorInspectResult.INSUFFICIENT_FUNDS:
                raise InsufficientFunds('Insufficient ETH for transaction')
            elif action == ClientErrorInspectResult.TRANSACTION_UNDERPRICED:
                raise ReplacementTransactionUnderpriced(
                    'Transaction was rejected. This is potentially '
                    'caused by the reuse of the previous transaction '
                    'nonce as well as paying an amount of gas less than or '
                    'equal to the previous transaction\'s gas amount',
                )
            elif action == ClientErrorInspectResult.TRANSACTION_PENDING:
                raise TransactionAlreadyPending(
                    'The transaction has already been submitted. Please '
                    'wait until is has been mined or increase the gas price.',
                )
            elif action == ClientErrorInspectResult.TRANSACTION_ALREADY_IMPORTED:
                # This is like TRANSACTION_PENDING is for geth but happens in parity
                # Unlike with geth this can also happen without multiple transactions
                # being sent via RPC -- due to probably some parity bug:
                # https://github.com/raiden-network/raiden/issues/3211
                # We will try to not crash by looking into the local parity
                # transaction pool to retrieve the transaction hash
                hex_address = to_checksum_address(self.jsonrpc_client.address)
                txhash = self.jsonrpc_client.parity_get_pending_transaction_hash_by_nonce(
                    address=hex_address,
                    nonce=self.jsonrpc_client._available_nonce,
                )
                if not txhash:
                    raise TransactionAlreadyPending(
                        'Transaction was submitted via parity but parity saw it as'
                        ' already pending. Could not find the transaction in the '
                        'local transaction pool. Bailing ...',
                    )
                return txhash

            raise e

        return txhash

    @staticmethod
    def sanitize_args(abi: Dict, args: List):
        """Prepare inputs to match the ABI"""
        inputs = get_abi_input_types(abi)
        output = []
        assert len(inputs) == len(args)
        for input_type, arg in zip(inputs, args):
            if input_type == 'address':
                output.append(to_checksum_address(arg))
            elif input_type == 'bytes' and isinstance(arg, str):
                output.append(arg.encode())
            else:
                output.append(arg)
        return output

    @staticmethod
    def get_transaction_data(abi: Dict, function_name: str, args: List = None):
        """Get encoded transaction data"""
        args = args or list()
        fn_abi = find_matching_fn_abi(
            abi,
            function_name,
            args,
        )
        args = ContractProxy.sanitize_args(fn_abi, args)
        return encode_transaction_data(
            None,
            function_name,
            contract_abi=abi,
            fn_abi=fn_abi,
            args=args,
        )

    def decode_transaction_input(self, transaction_hash: bytes) -> Dict:
        """Return inputs of a method call"""
        transaction = self.contract.web3.eth.getTransaction(
            transaction_hash,
        )

        return self.contract.decode_function_input(
            transaction['input'],
        )

    def decode_event(self, log: Dict):
        return decode_event(self.contract.abi, log)

    def encode_function_call(self, function: str, args: List = None):
        return self.get_transaction_data(self.contract.abi, function, args)

    def estimate_gas(self, block_identifier, function: str, *args) -> typing.Optional[int]:
        """Returns a gas estimate for the function with the given arguments or
        None if the function call will fail due to Insufficient funds or
        the logic in the called function."""
        msg = (
            'At the moment since geth only accepts pending block for estimateGas '
            'we enforce the same behaviour for all clients. Please use "pending".'
        )
        assert block_identifier == 'pending', msg
        fn = getattr(self.contract.functions, function)
        address = to_checksum_address(self.jsonrpc_client.address)
        if self.jsonrpc_client.eth_node == constants.EthClient.GETH:
            # Unfortunately geth does not follow the ethereum JSON-RPC spec and
            # does not accept a block identifier argument for eth_estimateGas
            # parity and py-evm (trinity) do.
            #
            # Geth only runs estimateGas on the pending block and that's why we
            # should also enforce parity, py-evm and others to do the same since
            # we can't customize geth.
            #
            # Spec: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas
            # Geth Issue: https://github.com/ethereum/go-ethereum/issues/2586
            # Relevant web3 PR: https://github.com/ethereum/web3.py/pull/1046
            block_identifier = None
        try:
            return fn(*args).estimateGas(
                transaction={'from': address},
                block_identifier=block_identifier,
            )
        except ValueError as err:
            action = inspect_client_error(err, self.jsonrpc_client.eth_node)
            will_fail = action in (
                ClientErrorInspectResult.INSUFFICIENT_FUNDS,
                ClientErrorInspectResult.ALWAYS_FAIL,
            )
            if will_fail:
                return None

            raise err

    @property
    def contract_address(self):
        return to_canonical_address(self.contract.address)
<commit_msg>Remove the pending block assertion in estimate_gas<commit_after>import json
from enum import Enum
from typing import Dict, List

from eth_utils import decode_hex, to_canonical_address, to_checksum_address
from web3.contract import Contract
from web3.utils.abi import get_abi_input_types
from web3.utils.contracts import encode_transaction_data, find_matching_fn_abi

from raiden import constants
from raiden.constants import EthClient
from raiden.exceptions import (
    InsufficientFunds,
    ReplacementTransactionUnderpriced,
    TransactionAlreadyPending,
)
from raiden.utils import typing
from raiden.utils.filters import decode_event

class ClientErrorInspectResult(Enum):
    """Represents the action to follow after inspecting a client exception"""
    PROPAGATE_ERROR = 1
    INSUFFICIENT_FUNDS = 2
    TRANSACTION_UNDERPRICED = 3
    TRANSACTION_PENDING = 4
    ALWAYS_FAIL = 5
    TRANSACTION_ALREADY_IMPORTED = 7

def inspect_client_error(val_err: ValueError, eth_node: EthClient) -> ClientErrorInspectResult:
    # both clients return invalid json. They use single quotes while json needs double ones.
    # Also parity may return something like: 'data': 'Internal("Error message")' which needs
    # special processing
    json_response = str(val_err).replace("'", '"').replace('("', '(').replace('")', ')')
    try:
        error = json.loads(json_response)
    except json.JSONDecodeError:
        return ClientErrorInspectResult.PROPAGATE_ERROR

    if eth_node == EthClient.GETH:
        if error['code'] == -32000:
            if 'insufficient funds' in error['message']:
                return ClientErrorInspectResult.INSUFFICIENT_FUNDS
            elif 'always failing transaction' in error['message']:
                return ClientErrorInspectResult.ALWAYS_FAIL
            elif error['message'] == 'replacement transaction underpriced':
                return ClientErrorInspectResult.TRANSACTION_UNDERPRICED
            elif error['message'].startswith('known transaction:'):
                return ClientErrorInspectResult.TRANSACTION_PENDING

    elif eth_node == EthClient.PARITY:
        if error['code'] == -32010:
            if 'insufficient funds' in error['message']:
                return ClientErrorInspectResult.INSUFFICIENT_FUNDS
            elif 'another transaction with same nonce in the queue' in error['message']:
                return ClientErrorInspectResult.TRANSACTION_UNDERPRICED
            elif 'Transaction with the same hash was already imported' in error['message']:
                return ClientErrorInspectResult.TRANSACTION_ALREADY_IMPORTED
        elif error['code'] == -32015 and 'Transaction execution error' in error['message']:
            return ClientErrorInspectResult.ALWAYS_FAIL

    return ClientErrorInspectResult.PROPAGATE_ERROR

class ContractProxy:
    def __init__(
            self,
            jsonrpc_client,
            contract: Contract,
    ):
        if contract is None:
            raise ValueError('Contract must not be None')
        if jsonrpc_client is None:
            raise ValueError('JSONRPCClient must not be None')
        self.jsonrpc_client = jsonrpc_client
        self.contract = contract

    def transact(
            self,
            function_name: str,
            startgas: int,
            *args,
            **kargs,
    ) -> typing.TransactionHash:
        data = ContractProxy.get_transaction_data(self.contract.abi, function_name, args)

        try:
            txhash = self.jsonrpc_client.send_transaction(
                to=self.contract.address,
                startgas=startgas,
                value=kargs.pop('value', 0),
                data=decode_hex(data),
                **kargs,
            )
        except ValueError as e:
            action = inspect_client_error(e, self.jsonrpc_client.eth_node)
            if action == ClientErrorInspectResult.INSUFFICIENT_FUNDS:
                raise InsufficientFunds('Insufficient ETH for transaction')
            elif action == ClientErrorInspectResult.TRANSACTION_UNDERPRICED:
                raise ReplacementTransactionUnderpriced(
                    'Transaction was rejected. This is potentially '
                    'caused by the reuse of the previous transaction '
                    'nonce as well as paying an amount of gas less than or '
                    'equal to the previous transaction\'s gas amount',
                )
            elif action == ClientErrorInspectResult.TRANSACTION_PENDING:
                raise TransactionAlreadyPending(
                    'The transaction has already been submitted. Please '
                    'wait until is has been mined or increase the gas price.',
                )
            elif action == ClientErrorInspectResult.TRANSACTION_ALREADY_IMPORTED:
                # This is like TRANSACTION_PENDING is for geth but happens in parity
                # Unlike with geth this can also happen without multiple transactions
                # being sent via RPC -- due to probably some parity bug:
                # https://github.com/raiden-network/raiden/issues/3211
                # We will try to not crash by looking into the local parity
                # transaction pool to retrieve the transaction hash
                hex_address = to_checksum_address(self.jsonrpc_client.address)
                txhash = self.jsonrpc_client.parity_get_pending_transaction_hash_by_nonce(
                    address=hex_address,
                    nonce=self.jsonrpc_client._available_nonce,
                )
                if not txhash:
                    raise TransactionAlreadyPending(
                        'Transaction was submitted via parity but parity saw it as'
                        ' already pending. Could not find the transaction in the '
                        'local transaction pool. Bailing ...',
                    )
                return txhash

            raise e

        return txhash

    @staticmethod
    def sanitize_args(abi: Dict, args: List):
        """Prepare inputs to match the ABI"""
        inputs = get_abi_input_types(abi)
        output = []
        assert len(inputs) == len(args)
        for input_type, arg in zip(inputs, args):
            if input_type == 'address':
                output.append(to_checksum_address(arg))
            elif input_type == 'bytes' and isinstance(arg, str):
                output.append(arg.encode())
            else:
                output.append(arg)
        return output

    @staticmethod
    def get_transaction_data(abi: Dict, function_name: str, args: List = None):
        """Get encoded transaction data"""
        args = args or list()
        fn_abi = find_matching_fn_abi(
            abi,
            function_name,
            args,
        )
        args = ContractProxy.sanitize_args(fn_abi, args)
        return encode_transaction_data(
            None,
            function_name,
            contract_abi=abi,
            fn_abi=fn_abi,
            args=args,
        )

    def decode_transaction_input(self, transaction_hash: bytes) -> Dict:
        """Return inputs of a method call"""
        transaction = self.contract.web3.eth.getTransaction(
            transaction_hash,
        )

        return self.contract.decode_function_input(
            transaction['input'],
        )

    def decode_event(self, log: Dict):
        return decode_event(self.contract.abi, log)

    def encode_function_call(self, function: str, args: List = None):
        return self.get_transaction_data(self.contract.abi, function, args)

    def estimate_gas(self, block_identifier, function: str, *args) -> typing.Optional[int]:
        """Returns a gas estimate for the function with the given arguments or
        None if the function call will fail due to Insufficient funds or
        the logic in the called function."""
        fn = getattr(self.contract.functions, function)
        address = to_checksum_address(self.jsonrpc_client.address)
        if self.jsonrpc_client.eth_node == constants.EthClient.GETH:
            # Unfortunately geth does not follow the ethereum JSON-RPC spec and
            # does not accept a block identifier argument for eth_estimateGas
            # parity and py-evm (trinity) do.
            #
            # Geth only runs estimateGas on the pending block and that's why we
            # should also enforce parity, py-evm and others to do the same since
            # we can't customize geth.
            #
            # Spec: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas
            # Geth Issue: https://github.com/ethereum/go-ethereum/issues/2586
            # Relevant web3 PR: https://github.com/ethereum/web3.py/pull/1046
            block_identifier = None
        try:
            return fn(*args).estimateGas(
                transaction={'from': address},
                block_identifier=block_identifier,
            )
        except ValueError as err:
            action = inspect_client_error(err, self.jsonrpc_client.eth_node)
            will_fail = action in (
                ClientErrorInspectResult.INSUFFICIENT_FUNDS,
                ClientErrorInspectResult.ALWAYS_FAIL,
            )
            if will_fail:
                return None

            raise err

    @property
    def contract_address(self):
        return to_canonical_address(self.contract.address)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2013, Bruno Gonzalez <stenyak@stenyak.com>. This software is licensed under the Affero General Public License version 3 or later.  See the LICENSE file.

import json
from functools import wraps
from flask import request, g, session, flash, url_for, abort
from flask_openid import OpenID

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import os, urllib, time
from flask import Flask, redirect, send_file, render_template
from gallery import Gallery
app = Flask(__name__)
app.config.update(
    DATABASE_URI = 'sqlite:///profiles.db',
    SECRET_KEY = 'development key',
    DEBUG = True
)
# setup flask-openid
oid = OpenID(app)
def init_db():
    Base.metadata.create_all(bind=engine)

# setup sqlalchemy
engine = create_engine(app.config['DATABASE_URI'])
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(60))
    email = Column(String(200))
    openid = Column(String(200))

    def __init__(self, name, email, openid):
        self.name = name
        self.email = email
        self.openid = openid

def render_time(fn):
    @wraps(fn)
    def inner(*args, **kwargs):
        start = time.time()
        result = fn(*args, **kwargs)
        end = time.time()
        try:
            return result.replace("TTTTIME", "%.4f" %(end-start))
        except AttributeError:
            return result
    return inner

@app.before_request
def before_request():
    g.user = None
    if 'openid' in session:
        g.user = User.query.filter_by(openid=session['openid']).first()

@app.after_request
def after_request(response):
    db_session.remove()
    return response

@app.route('/favicon.ico')
def favicon():
    return send_file("static/favicon.ico")

@app.route('/')
def index():
    return redirect("/gallery/data")

def get_openid_providers():
    class OpenIdProvider():
        def __init__(self, name, url, hidden=True):
            self.name = name
            self.url = url
            self.image = "openid/" + name.replace(" ", "").lower() + ".png"
            self.hidden = hidden
    return [
    OpenIdProvider("Google", "https://www.google.com/accounts/o8/id"),
    OpenIdProvider("Yahoo", "yahoo.com"),
    OpenIdProvider("WordPress", "Your WordPress blog url", False),
    OpenIdProvider("Flickr", "flickr.com"),
    OpenIdProvider("Stack Exchange", "https://openid.stackexchange.com"),
    OpenIdProvider("Blogger", "Your Blogger blog url", False),
    OpenIdProvider("LiveJournal", "Your LiveJournal blog url", False),
    OpenIdProvider("OpenID", "Your custom OpenID url", False)
    ]

@app.route('/login', methods=['GET', 'POST'])
@render_time
@oid.loginhandler
def login():
    """Does the login via OpenID.  Has to call into `oid.try_login` to start the OpenID machinery.  """
    # if we are already logged in, go back to were we came from
    if g.user is not None:
        return redirect(oid.get_next_url())
    if request.method == 'POST':
        openid = request.form.get('openid')
        if openid:
            return oid.try_login(openid, ask_for=['email', 'fullname', 'nickname'])
    return render_template('login.html', next=oid.get_next_url(), error=oid.fetch_error(), providers=get_openid_providers())

@oid.after_login
def create_or_login(resp):
    """This is called when login with OpenID succeeded and it's not necessary to figure out if this is the users's first login or not.  This function has to redirect otherwise the user will be presented with a terrible URL which we certainly don't want.  """
    session['openid'] = resp.identity_url
    user = User.query.filter_by(openid=resp.identity_url).first()
    if user is not None:
        flash(u'Successfully signed in')
        g.user = user
        return redirect(oid.get_next_url())
    return redirect(url_for('create_profile', next=oid.get_next_url(), name=resp.fullname or resp.nickname, email=resp.email))

def get_config():
    with open("config.json", "r") as f:
        return json.loads(f.read())

@app.route('/create-profile', methods=['GET', 'POST'])
@render_time
def create_profile():
    """If this is the user's first login, the create_or_login function
    will redirect here so that the user can set up his profile.
    """
    if g.user is not None or 'openid' not in session:
        return redirect(url_for('index'))
    if request.method == 'POST':
        name = request.form['name']
        email = request.form['email']
        if not name:
            flash(u'Error: you have to provide a name')
        elif '@' not in email:
            flash(u'Error: you have to enter a valid email address')
        else:
            flash(u'Profile successfully created')
            db_session.add(User(name, email, session['openid']))
            db_session.commit()
            return redirect(oid.get_next_url())
    return render_template('create_profile.html', next_url=oid.get_next_url(), config=get_config())

@app.route('/profile', methods=['GET', 'POST'])
@render_time
def edit_profile():
    """Updates a profile"""
    user = g.user
    if user is None:
        abort(401)
    form = dict(name=user.name, email=user.email)
    if request.method == 'POST':
        if 'delete' in request.form:
            db_session.delete(user)
            db_session.commit()
            session['openid'] = None
            flash(u'Profile deleted')
            return redirect(url_for('index'))
        form['name'] = request.form['name']
        form['email'] = request.form['email']
        if not form['name']:
            flash(u'Error: you have to provide a name')
        elif '@' not in form['email']:
            flash(u'Error: you have to enter a valid email address')
        else:
            flash(u'Profile successfully created')
            user.name = form['name']
            user.email = form['email']
            db_session.commit()
            return redirect(url_for('edit_profile', user=user))
    return render_template('edit_profile.html', form=form, user=user)

@app.route('/logout')
def logout():
    session.pop('openid', None)
    flash(u'You have been signed out')
    return redirect(oid.get_next_url())

@app.route('/gallery/<path:path>')
@render_time
def show_gallery(path):
    global g
    user = g.user
    path = urllib.unquote(path).encode("utf-8")
    check_jailed_path(path, "data")
    g = Gallery(path)
    if user is not None:
        g.populate()
    return render_template("gallery.html", path = g.path.decode("utf-8"), parents = g.get_parents(), basename = os.path.basename(g.path.decode("utf-8")), nfiles = len(g.files), galleries = g.get_galleries(), files = g.get_files(), user = user)

@app.route('/video/<path:path>')
@render_time
def show_video(path):
    global g
    user = g.user
    if user is None:
        abort(401)
    video_path = urllib.unquote(path).encode("utf-8")
    path = os.path.dirname(video_path)
    check_jailed_path(path, "data")
    return render_template("video.html", video_path = video_path, path = path, video_basename = os.path.basename(video_path), user = user)

def check_jailed_path(path, jail_path):
    if os.path.normpath(path) == jail_path:
        return
    if not os.path.normpath(path).startswith(jail_path + os.sep):
        raise Exception("Permission denied, '%s' is outside '%s'" %(path, jail_path))

@app.route('/data/<path:path>')
def show_data(path):
    global g
    user = g.user
    if user is None:
        abort(401)
    path = urllib.unquote(path).encode("utf-8")
    check_jailed_path(path, "data")
    return send_file(path)

@app.route('/static/<path:path>')
def show_static(path):
    path = os.path.join("static", urllib.unquote(path).encode("utf-8"))
    check_jailed_path(path, "static")
    return send_file(path)

if __name__ == '__main__':
    app.run(debug=True)
<commit_msg>Automatically create database if it doesn't exist.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2013, Bruno Gonzalez <stenyak@stenyak.com>. This software is licensed under the Affero General Public License version 3 or later.  See the LICENSE file.

import json
from functools import wraps
from flask import request, g, session, flash, url_for, abort
from flask_openid import OpenID

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import os, urllib, time
from flask import Flask, redirect, send_file, render_template
from gallery import Gallery
app = Flask(__name__)
app.config.update(
    DATABASE_URI = 'sqlite:///profiles.db',
    SECRET_KEY = 'development key',
    DEBUG = True
)
# setup flask-openid
oid = OpenID(app)
def init_db():
    Base.metadata.create_all(bind=engine)

# setup sqlalchemy
engine = create_engine(app.config['DATABASE_URI'])
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(60))
    email = Column(String(200))
    openid = Column(String(200))

    def __init__(self, name, email, openid):
        self.name = name
        self.email = email
        self.openid = openid

def db_created():
    try:
        User.query.filter_by(openid="foobar").first()
        return True
    except:
        return False

def db_required(fn):
    @wraps(fn)
    def inner(*args, **kwargs):
        if not db_created():
            init_db()
        return fn(*args, **kwargs)
    return inner

def render_time(fn):
    @wraps(fn)
    def inner(*args, **kwargs):
        start = time.time()
        result = fn(*args, **kwargs)
        end = time.time()
        try:
            return result.replace("TTTTIME", "%.4f" %(end-start))
        except AttributeError:
            return result
    return inner

@app.before_request
@db_required
def before_request():
    g.user = None
    if 'openid' in session:
        g.user = User.query.filter_by(openid=session['openid']).first()

@app.after_request
def after_request(response):
    db_session.remove()
    return response

@app.route('/favicon.ico')
def favicon():
    return send_file("static/favicon.ico")

@app.route('/')
def index():
    return redirect("/gallery/data")

def get_openid_providers():
    class OpenIdProvider():
        def __init__(self, name, url, hidden=True):
            self.name = name
            self.url = url
            self.image = "openid/" + name.replace(" ", "").lower() + ".png"
            self.hidden = hidden
    return [
    OpenIdProvider("Google", "https://www.google.com/accounts/o8/id"),
    OpenIdProvider("Yahoo", "yahoo.com"),
    OpenIdProvider("WordPress", "Your WordPress blog url", False),
    OpenIdProvider("Flickr", "flickr.com"),
    OpenIdProvider("Stack Exchange", "https://openid.stackexchange.com"),
    OpenIdProvider("Blogger", "Your Blogger blog url", False),
    OpenIdProvider("LiveJournal", "Your LiveJournal blog url", False),
    OpenIdProvider("OpenID", "Your custom OpenID url", False)
    ]

@app.route('/login', methods=['GET', 'POST'])
@render_time
@oid.loginhandler
def login():
    """Does the login via OpenID.  Has to call into `oid.try_login` to start the OpenID machinery.  """
    # if we are already logged in, go back to were we came from
    if g.user is not None:
        return redirect(oid.get_next_url())
    if request.method == 'POST':
        openid = request.form.get('openid')
        if openid:
            return oid.try_login(openid, ask_for=['email', 'fullname', 'nickname'])
    return render_template('login.html', next=oid.get_next_url(), error=oid.fetch_error(), providers=get_openid_providers())

@db_required
@oid.after_login
def create_or_login(resp):
    """This is called when login with OpenID succeeded and it's not necessary to figure out if this is the users's first login or not.  This function has to redirect otherwise the user will be presented with a terrible URL which we certainly don't want.  """
    session['openid'] = resp.identity_url
    user = User.query.filter_by(openid=resp.identity_url).first()
    if user is not None:
        flash(u'Successfully signed in')
        g.user = user
        return redirect(oid.get_next_url())
    return redirect(url_for('create_profile', next=oid.get_next_url(), name=resp.fullname or resp.nickname, email=resp.email))

def get_config():
    with open("config.json", "r") as f:
        return json.loads(f.read())

@app.route('/create-profile', methods=['GET', 'POST'])
@render_time
def create_profile():
    """If this is the user's first login, the create_or_login function
    will redirect here so that the user can set up his profile.
    """
    if g.user is not None or 'openid' not in session:
        return redirect(url_for('index'))
    if request.method == 'POST':
        name = request.form['name']
        email = request.form['email']
        if not name:
            flash(u'Error: you have to provide a name')
        elif '@' not in email:
            flash(u'Error: you have to enter a valid email address')
        else:
            flash(u'Profile successfully created')
            db_session.add(User(name, email, session['openid']))
            db_session.commit()
            return redirect(oid.get_next_url())
    return render_template('create_profile.html', next_url=oid.get_next_url(), config=get_config())

@app.route('/profile', methods=['GET', 'POST'])
@render_time
def edit_profile():
    """Updates a profile"""
    user = g.user
    if user is None:
        abort(401)
    form = dict(name=user.name, email=user.email)
    if request.method == 'POST':
        if 'delete' in request.form:
            db_session.delete(user)
            db_session.commit()
            session['openid'] = None
            flash(u'Profile deleted')
            return redirect(url_for('index'))
        form['name'] = request.form['name']
        form['email'] = request.form['email']
        if not form['name']:
            flash(u'Error: you have to provide a name')
        elif '@' not in form['email']:
            flash(u'Error: you have to enter a valid email address')
        else:
            flash(u'Profile successfully created')
            user.name = form['name']
            user.email = form['email']
            db_session.commit()
            return redirect(url_for('edit_profile', user=user))
    return render_template('edit_profile.html', form=form, user=user)

@app.route('/logout')
def logout():
    session.pop('openid', None)
    flash(u'You have been signed out')
    return redirect(oid.get_next_url())

@app.route('/gallery/<path:path>')
@render_time
def show_gallery(path):
    global g
    user = g.user
    path = urllib.unquote(path).encode("utf-8")
    check_jailed_path(path, "data")
    g = Gallery(path)
    if user is not None:
        g.populate()
    return render_template("gallery.html", path = g.path.decode("utf-8"), parents = g.get_parents(), basename = os.path.basename(g.path.decode("utf-8")), nfiles = len(g.files), galleries = g.get_galleries(), files = g.get_files(), user = user)

@app.route('/video/<path:path>')
@render_time
def show_video(path):
    global g
    user = g.user
    if user is None:
        abort(401)
    video_path = urllib.unquote(path).encode("utf-8")
    path = os.path.dirname(video_path)
    check_jailed_path(path, "data")
    return render_template("video.html", video_path = video_path, path = path, video_basename = os.path.basename(video_path), user = user)

def check_jailed_path(path, jail_path):
    if os.path.normpath(path) == jail_path:
        return
    if not os.path.normpath(path).startswith(jail_path + os.sep):
        raise Exception("Permission denied, '%s' is outside '%s'" %(path, jail_path))

@app.route('/data/<path:path>')
def show_data(path):
    global g
    user = g.user
    if user is None:
        abort(401)
    path = urllib.unquote(path).encode("utf-8")
    check_jailed_path(path, "data")
    return send_file(path)

@app.route('/static/<path:path>')
def show_static(path):
    path = os.path.join("static", urllib.unquote(path).encode("utf-8"))
    check_jailed_path(path, "static")
    return send_file(path)

if __name__ == '__main__':
    app.run(debug=True)
<|endoftext|>


<commit_before>import asyncio
from collections import namedtuple
from datetime import datetime

from discord import Embed, TextChannel
from discord.ext import commands, menus
from discord.ext.commands import Cog
from discord.ext.menus import MenuKeysetPages, PageDirection

from schema.remind import Reminder, Table
from utils.checks import is_owner_or
from utils.converters import Time
from utils.etc import reverse_insort_by_key

class ReminderSource(menus.KeysetPageSource):
    def __init__(self, db, user_id, guild_id):
        self.db = db
        self.user_id = user_id
        self.guild_id = guild_id

    def is_paginating(self):
        return True

    async def get_page(self, specifier):
        async with self.db.get_session() as s:
            query = (
                s.select(Reminder)
                .where(
                    (Reminder.user_id == self.user_id)
                    & (Reminder.guild_id == self.guild_id)
                )
                .limit(10)
            )

            if specifier.reference is not None:
                if specifier.direction is PageDirection.after:
                    query = query.where(Reminder.id > specifier.reference[-1]["id"])
                else:
                    query = query.where(Reminder.id < specifier.reference[0]["id"])

            sort_order = "asc" if specifier.direction is PageDirection.after else "desc"
            query = query.order_by(Reminder.id, sort_order=sort_order)

            results = [reminder async for reminder in await query.all()]

        if not results:
            raise ValueError
        if specifier.direction is PageDirection.before:
            results.reverse()

        return results

    async def format_page(self, menu, page):
        return Embed(
            description="\n".join(
                f'ID {row.id}: "{row.topic}" at {row.time}' for row in page
            )
        )

class Remind(Cog):
    def __init__(self, bot):
        self.queue = []
        self.loop = bot.loop
        self.db = bot.db
        self.bot = bot
        self.db.bind_tables(Table)
        self.timer = self.loop.create_task(asyncio.sleep(0))
        self.loop.create_task(self.__init())

    def cog_unload(self):
        self.timer.cancel()

    async def __init(self):
        await self.bot.wait_until_ready()
        await Reminder.create(if_not_exists=True)
        async with self.db.get_session() as s:
            query = s.select(Reminder).order_by(Reminder.time, sort_order="desc")
            self.queue = [reminder async for reminder in await query.all()]
        await self.start_timer()

    @commands.group(invoke_without_command=True)
    async def remind(self, ctx, time: Time, *, topic: commands.clean_content = None):
        """Commands for setting and managing reminders."""
        await self.set_reminder(ctx, time, topic=topic)

    @remind.error
    async def remind_error(self, ctx, e):
        if ctx.invoked_subcommand is None:
            await self.set_reminder_error(ctx, e)

    @remind.command(name="set")
    async def set_reminder(
        self, ctx, time: Time, *, topic: commands.clean_content = None
    ):
        """Have the bot remind you about something.
           First put time (in quotes if there are spaces), then topic"""
        await self.schedule_reminder(ctx, time, topic)
        await ctx.send("Okay, I'll remind you.")

    @set_reminder.error
    async def set_reminder_error(self, ctx, e):
        if isinstance(e, (commands.BadArgument, commands.ConversionError)):
            await ctx.send(
                "Bad input. Valid input examples:\n"
                "remind 10m pizza\n"
                'remind "two days" check progress'
            )
        else:
            await ctx.bot.handle_error(ctx, e)

    @remind.command(name="list")
    async def list_reminders(self, ctx):
        pages = MenuKeysetPages(
            source=ReminderSource(ctx.bot.db, ctx.author.id, ctx.guild.id),
            clear_reactions_after=True,
        )
        try:
            await pages.start(ctx)
        except ValueError:
            await ctx.send("No reminders to show.")

    @remind.command(name="delete", aliases=["remove", "del"])
    async def delete_reminder(self, ctx, reminder_id: int):
        async with ctx.bot.db.get_session() as s:
            query = s.select(Reminder).where(Reminder.id == reminder_id)
            reminder = await query.first()
            if reminder is None:
                await ctx.send("No such reminder.")
                return
            if reminder.user_id != ctx.author.id:
                await ctx.send("That reminder belongs to someone else.")
                return
            await s.remove(reminder)
            if self.queue[-1] == reminder:
                self.timer.cancel()
                self.queue.pop()
                await self.start_timer()
            else:
                self.queue.remove(reminder)

        await ctx.send("Reminder deleted.")

    @remind.command(name=["channel"])
    @is_owner_or(manage_guild=True)
    async def set_channel(self, ctx, channel: TextChannel = None):
        """Set the channel reminders will appear in. Invoke with no input to reset."""
        await ctx.bot.config.set_guild(
            ctx.guild.id, reminder_channel=channel and channel.id
        )
        if channel is None:
            destination = "the channel they were invoked in"
        else:
            destination = channel.mention
        await ctx.send(f"All reminders will be sent to {destination} from now on.")

    async def schedule_reminder(self, ctx, time, topic):
        async with self.db.get_session() as s:
            reminder = await s.add(
                Reminder(
                    guild_id=ctx.guild.id,
                    channel_id=ctx.channel.id,
                    user_id=ctx.author.id,
                    time=time,
                    topic=topic,
                )
            )
        if not self.queue or reminder.time < self.queue[-1].time:
            self.queue.append(reminder)
            self.timer.cancel()
            await self.start_timer()
        else:
            reverse_insort_by_key(
                self.queue, reminder, key=lambda r: r.time, hi=len(self.queue) - 1
            )

    async def send_reminder(self, reminder):
        if (
            (guild := self.bot.get_guild(reminder.guild_id))
            and (member := guild.get_member(reminder.user_id))
            and (
                channel := guild.get_channel(
                    (await self.bot.config.get_guild(guild.id)).get("reminder_channel")
                    or reminder.channel_id
                )
            )
        ):
            topic = reminder.topic or "something"
            message = f"{member.mention}\nYou asked to be reminded about {topic}."
            await channel.send(message)
        async with self.db.get_session() as s:
            query = s.select(Reminder).where(Reminder.id == reminder.id)
            reminder = await query.first()
            await s.remove(reminder)

    async def start_timer(self):
        self.timer = self.loop.create_task(self.sleep())

    async def sleep(self):
        while self.queue:
            delta = (self.queue[-1].time - datetime.now()).total_seconds()
            if delta <= 0:
                await self.send_reminder(self.queue.pop())
            else:
                await asyncio.sleep(min(delta, 3_000_000))

def setup(bot):
    bot.add_cog(Remind(bot))
<commit_msg>Dedent unrelated code<commit_after>import asyncio
from collections import namedtuple
from datetime import datetime

from discord import Embed, TextChannel
from discord.ext import commands, menus
from discord.ext.commands import Cog
from discord.ext.menus import MenuKeysetPages, PageDirection

from schema.remind import Reminder, Table
from utils.checks import is_owner_or
from utils.converters import Time
from utils.etc import reverse_insort_by_key

class ReminderSource(menus.KeysetPageSource):
    def __init__(self, db, user_id, guild_id):
        self.db = db
        self.user_id = user_id
        self.guild_id = guild_id

    def is_paginating(self):
        return True

    async def get_page(self, specifier):
        async with self.db.get_session() as s:
            query = (
                s.select(Reminder)
                .where(
                    (Reminder.user_id == self.user_id)
                    & (Reminder.guild_id == self.guild_id)
                )
                .limit(10)
            )

            if specifier.reference is not None:
                if specifier.direction is PageDirection.after:
                    query = query.where(Reminder.id > specifier.reference[-1]["id"])
                else:
                    query = query.where(Reminder.id < specifier.reference[0]["id"])

            sort_order = "asc" if specifier.direction is PageDirection.after else "desc"
            query = query.order_by(Reminder.id, sort_order=sort_order)

            results = [reminder async for reminder in await query.all()]

        if not results:
            raise ValueError
        if specifier.direction is PageDirection.before:
            results.reverse()

        return results

    async def format_page(self, menu, page):
        return Embed(
            description="\n".join(
                f'ID {row.id}: "{row.topic}" at {row.time}' for row in page
            )
        )

class Remind(Cog):
    def __init__(self, bot):
        self.queue = []
        self.loop = bot.loop
        self.db = bot.db
        self.bot = bot
        self.db.bind_tables(Table)
        self.timer = self.loop.create_task(asyncio.sleep(0))
        self.loop.create_task(self.__init())

    def cog_unload(self):
        self.timer.cancel()

    async def __init(self):
        await self.bot.wait_until_ready()
        await Reminder.create(if_not_exists=True)
        async with self.db.get_session() as s:
            query = s.select(Reminder).order_by(Reminder.time, sort_order="desc")
            self.queue = [reminder async for reminder in await query.all()]
        await self.start_timer()

    @commands.group(invoke_without_command=True)
    async def remind(self, ctx, time: Time, *, topic: commands.clean_content = None):
        """Commands for setting and managing reminders."""
        await self.set_reminder(ctx, time, topic=topic)

    @remind.error
    async def remind_error(self, ctx, e):
        if ctx.invoked_subcommand is None:
            await self.set_reminder_error(ctx, e)

    @remind.command(name="set")
    async def set_reminder(
        self, ctx, time: Time, *, topic: commands.clean_content = None
    ):
        """Have the bot remind you about something.
           First put time (in quotes if there are spaces), then topic"""
        await self.schedule_reminder(ctx, time, topic)
        await ctx.send("Okay, I'll remind you.")

    @set_reminder.error
    async def set_reminder_error(self, ctx, e):
        if isinstance(e, (commands.BadArgument, commands.ConversionError)):
            await ctx.send(
                "Bad input. Valid input examples:\n"
                "remind 10m pizza\n"
                'remind "two days" check progress'
            )
        else:
            await ctx.bot.handle_error(ctx, e)

    @remind.command(name="list")
    async def list_reminders(self, ctx):
        pages = MenuKeysetPages(
            source=ReminderSource(ctx.bot.db, ctx.author.id, ctx.guild.id),
            clear_reactions_after=True,
        )
        try:
            await pages.start(ctx)
        except ValueError:
            await ctx.send("No reminders to show.")

    @remind.command(name="delete", aliases=["remove", "del"])
    async def delete_reminder(self, ctx, reminder_id: int):
        async with ctx.bot.db.get_session() as s:
            query = s.select(Reminder).where(Reminder.id == reminder_id)
            reminder = await query.first()
            if reminder is None:
                await ctx.send("No such reminder.")
                return
            if reminder.user_id != ctx.author.id:
                await ctx.send("That reminder belongs to someone else.")
                return
            await s.remove(reminder)

        if self.queue[-1] == reminder:
            self.timer.cancel()
            self.queue.pop()
            await self.start_timer()
        else:
            self.queue.remove(reminder)

        await ctx.send("Reminder deleted.")

    @remind.command(name=["channel"])
    @is_owner_or(manage_guild=True)
    async def set_channel(self, ctx, channel: TextChannel = None):
        """Set the channel reminders will appear in. Invoke with no input to reset."""
        await ctx.bot.config.set_guild(
            ctx.guild.id, reminder_channel=channel and channel.id
        )
        if channel is None:
            destination = "the channel they were invoked in"
        else:
            destination = channel.mention
        await ctx.send(f"All reminders will be sent to {destination} from now on.")

    async def schedule_reminder(self, ctx, time, topic):
        async with self.db.get_session() as s:
            reminder = await s.add(
                Reminder(
                    guild_id=ctx.guild.id,
                    channel_id=ctx.channel.id,
                    user_id=ctx.author.id,
                    time=time,
                    topic=topic,
                )
            )
        if not self.queue or reminder.time < self.queue[-1].time:
            self.queue.append(reminder)
            self.timer.cancel()
            await self.start_timer()
        else:
            reverse_insort_by_key(
                self.queue, reminder, key=lambda r: r.time, hi=len(self.queue) - 1
            )

    async def send_reminder(self, reminder):
        if (
            (guild := self.bot.get_guild(reminder.guild_id))
            and (member := guild.get_member(reminder.user_id))
            and (
                channel := guild.get_channel(
                    (await self.bot.config.get_guild(guild.id)).get("reminder_channel")
                    or reminder.channel_id
                )
            )
        ):
            topic = reminder.topic or "something"
            message = f"{member.mention}\nYou asked to be reminded about {topic}."
            await channel.send(message)
        async with self.db.get_session() as s:
            query = s.select(Reminder).where(Reminder.id == reminder.id)
            reminder = await query.first()
            await s.remove(reminder)

    async def start_timer(self):
        self.timer = self.loop.create_task(self.sleep())

    async def sleep(self):
        while self.queue:
            delta = (self.queue[-1].time - datetime.now()).total_seconds()
            if delta <= 0:
                await self.send_reminder(self.queue.pop())
            else:
                await asyncio.sleep(min(delta, 3_000_000))

def setup(bot):
    bot.add_cog(Remind(bot))
<|endoftext|>


<commit_before># Copyright (C) 2013-2014  CEA/DEN, EDF R&D, OPEN CASCADE
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
#

import unittest

import os
import sys
import imp
from cStringIO import StringIO
import logging

logger = logging.getLogger("TestLauncherLogger")
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler())

class TestSessionArgs(unittest.TestCase):
  @classmethod
  def setUpClass(cls):
    # Initialize path to SALOME application
    path_to_launcher = os.getenv("SALOME_LAUNCHER")
    appli_dir = os.path.dirname(path_to_launcher)
    envd_dir = os.path.join(appli_dir, "env.d")

    # Configure session startup
    cls.SALOME = imp.load_source("SALOME", os.path.join(appli_dir,"salome"))
    cls.SALOME_args = ["shell", "--config="+envd_dir]

    cls.logFile = "log.txt"
    sys.stdout = StringIO()

    # Set some predefined command args and corresponding output messages
    cls.hello0 = ["hello.py", "args:outfile="+cls.logFile]
    cls.hello0Msg = "Hello!"
    cls.hello1 = ["hello.py", "args:you,outfile="+cls.logFile]
    cls.hello1Msg = "Hello to: you"
    cls.helloToAdd = ["hello.py", "args:add.py,1,2,3,outfile="+cls.logFile]
    cls.helloToAddMsg = "Hello to: add.py, 1, 2, 3"
    cls.add0 = ["add.py", "args:outfile="+cls.logFile]
    cls.add0Msg = "No args!"
    cls.add3 = ["add.py", "args:1,2,3,outfile="+cls.logFile]
    cls.add3Msg = "1+2+3 = 6"
    cls.lines0 = ["lines.py", "args:outfile="+cls.logFile]
    cls.lines0Msg = "No files given"
    cls.lines2 = ["lines.py", "args:hello.py,add.py,outfile="+cls.logFile]
    cls.lines2Msg = "hello.py is 16 lines longadd.py is 18 lines long"
    cls.linesUnreadable = ["lines.py", "args:hello.py,add.py,1,2,outfile="+cls.logFile]
    cls.linesUnreadableMsg = "hello.py is 16 lines longadd.py is 18 lines longFile '1' cannot be readFile '2' cannot be read"
  #
  @classmethod
  def tearDownClass(cls):
    pass
  #
  def setUp(self):
    self.removeLogFile()
  #
  def tearDown(self):
    self.removeLogFile()
  #
  def session(self, args=[]):
    self.SALOME.main(self.SALOME_args + args)
  #
  def removeLogFile(self):
    try:
      os.remove(self.logFile)
    except OSError:
      pass
  #
  def assertLogFileContentsEqual(self, message):
    with open(self.logFile, "r") as f:
      contents = f.read().replace('\n', '')

    #sys.stderr.write("Generated contents :%s\n"%contents)
    #sys.stderr.write("Expected contents :%s\n"%message)
    self.assertTrue(contents==message)
  #
  def testHello0(self):
    self.session(self.hello0)
    self.assertLogFileContentsEqual(self.hello0Msg)
  #
  def testPythonHello0(self):
    self.session(["python"]+self.hello0)
    self.assertLogFileContentsEqual(self.hello0Msg)
  #
  def testHello1(self):
    self.session(self.hello1)
    self.assertLogFileContentsEqual(self.hello1Msg)
  #
  def testAdd0(self):
    self.session(self.add0)
    self.assertLogFileContentsEqual(self.add0Msg)
  #
  def testAdd3(self):
    self.session(self.add3)
    self.assertLogFileContentsEqual(self.add3Msg)
  #
  def testHello0Add3(self):
    self.session(self.hello0+self.add3)
    self.assertLogFileContentsEqual(self.hello0Msg+self.add3Msg)
  #
  def testHello1Add3(self):
    self.session(self.hello1+self.add3)
    self.assertLogFileContentsEqual(self.hello1Msg+self.add3Msg)
  #
  def testHelloToAdd(self):
    self.session(self.helloToAdd)
    self.assertLogFileContentsEqual(self.helloToAddMsg)
  #
  def testLines0(self):
    self.session(self.lines0)
    self.assertLogFileContentsEqual(self.lines0Msg)
  #
  def testLines2(self):
    self.session(self.lines2)
    self.assertLogFileContentsEqual(self.lines2Msg)
  #
  def testLines2Add3(self):
    self.session(self.lines2+self.add3)
    self.assertLogFileContentsEqual(self.lines2Msg+self.add3Msg)
  #
  def testLinesUnreadable(self):
    self.session(self.linesUnreadable)
    self.assertLogFileContentsEqual(self.linesUnreadableMsg)
  #
  def testAddAddHello(self):
    self.session(self.add3+self.add3+self.hello1)
    self.assertLogFileContentsEqual(self.add3Msg+self.add3Msg+self.hello1Msg)
  #
  def testHello0Add3Hello0Add3Hello0(self):
    self.session(self.hello1+self.add3+self.hello0+self.add3+self.hello0)
    self.assertLogFileContentsEqual(self.hello1Msg+self.add3Msg+self.hello0Msg+self.add3Msg+self.hello0Msg)
  #
#

if __name__ == "__main__":
  path_to_launcher = os.getenv("SALOME_LAUNCHER")
  if not path_to_launcher:
    msg = "Error: please set SALOME_LAUNCHER variable to the salome command of your application folder."
    raise Exception(msg)

  unittest.main()
#
<commit_msg>fix bug in log file comparison<commit_after># Copyright (C) 2013-2014  CEA/DEN, EDF R&D, OPEN CASCADE
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
#

import unittest

import os
import sys
import imp
from cStringIO import StringIO
import logging

logger = logging.getLogger("TestLauncherLogger")
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler())

class TestSessionArgs(unittest.TestCase):
  # setUpClass appears in Python 2.7
  @classmethod
  def setUpClass(cls):
    # Initialize path to SALOME application
    path_to_launcher = os.getenv("SALOME_LAUNCHER")
    appli_dir = os.path.dirname(path_to_launcher)
    envd_dir = os.path.join(appli_dir, "env.d")

    # Configure session startup
    cls.SALOME = imp.load_source("SALOME", os.path.join(appli_dir,"salome"))
    cls.SALOME_args = ["shell", "--config="+envd_dir]

    cls.logFile = "log.txt"
    sys.stdout = StringIO()

    # Set some predefined command args and corresponding output messages
    cls.hello0 = ["hello.py", "args:outfile="+cls.logFile]
    cls.hello0Msg = "Hello!"
    cls.hello1 = ["hello.py", "args:you,outfile="+cls.logFile]
    cls.hello1Msg = "Hello to: you"
    cls.helloToAdd = ["hello.py", "args:add.py,1,2,3,outfile="+cls.logFile]
    cls.helloToAddMsg = "Hello to: add.py, 1, 2, 3"
    cls.add0 = ["add.py", "args:outfile="+cls.logFile]
    cls.add0Msg = "No args!"
    cls.add3 = ["add.py", "args:1,2,3,outfile="+cls.logFile]
    cls.add3Msg = "1+2+3 = 6"
    cls.lines0 = ["lines.py", "args:outfile="+cls.logFile]
    cls.lines0Msg = "No files given"
    cls.lines2 = ["lines.py", "args:hello.py,add.py,outfile="+cls.logFile]
    cls.lines2Msg = "hello.py is 35 lines longadd.py is 37 lines long"
    cls.linesUnreadable = ["lines.py", "args:hello.py,add.py,1,2,outfile="+cls.logFile]
    cls.linesUnreadableMsg = "hello.py is 35 lines longadd.py is 37 lines longFile '1' cannot be readFile '2' cannot be read"
  #
  @classmethod
  def tearDownClass(cls):
    pass
  #
  def setUp(self):
    self.removeLogFile()
  #
  def tearDown(self):
    self.removeLogFile()
  #
  def session(self, args=[]):
    self.SALOME.main(self.SALOME_args + args)
  #
  def removeLogFile(self):
    try:
      os.remove(self.logFile)
    except OSError:
      pass
  #
  def assertLogFileContentsEqual(self, message):
    with open(self.logFile, "r") as f:
      contents = f.read().replace('\n', '')

    self.assertTrue(contents==message, "Contents differ!\n\tGenerated contents: %s\n\tExpected contents: %s"%(contents, message))
  #
  def testHello0(self):
    self.session(self.hello0)
    self.assertLogFileContentsEqual(self.hello0Msg)
  #
  def testPythonHello0(self):
    self.session(["python"]+self.hello0)
    self.assertLogFileContentsEqual(self.hello0Msg)
  #
  def testHello1(self):
    self.session(self.hello1)
    self.assertLogFileContentsEqual(self.hello1Msg)
  #
  def testAdd0(self):
    self.session(self.add0)
    self.assertLogFileContentsEqual(self.add0Msg)
  #
  def testAdd3(self):
    self.session(self.add3)
    self.assertLogFileContentsEqual(self.add3Msg)
  #
  def testHello0Add3(self):
    self.session(self.hello0+self.add3)
    self.assertLogFileContentsEqual(self.hello0Msg+self.add3Msg)
  #
  def testHello1Add3(self):
    self.session(self.hello1+self.add3)
    self.assertLogFileContentsEqual(self.hello1Msg+self.add3Msg)
  #
  def testHelloToAdd(self):
    self.session(self.helloToAdd)
    self.assertLogFileContentsEqual(self.helloToAddMsg)
  #
  def testLines0(self):
    self.session(self.lines0)
    self.assertLogFileContentsEqual(self.lines0Msg)
  #
  def testLines2(self):
    self.session(self.lines2)
    self.assertLogFileContentsEqual(self.lines2Msg)
  #
  def testLines2Add3(self):
    self.session(self.lines2+self.add3)
    self.assertLogFileContentsEqual(self.lines2Msg+self.add3Msg)
  #
  def testLinesUnreadable(self):
    self.session(self.linesUnreadable)
    self.assertLogFileContentsEqual(self.linesUnreadableMsg)
  #
  def testAddAddHello(self):
    self.session(self.add3+self.add3+self.hello1)
    self.assertLogFileContentsEqual(self.add3Msg+self.add3Msg+self.hello1Msg)
  #
  def testHello0Add3Hello0Add3Hello0(self):
    self.session(self.hello1+self.add3+self.hello0+self.add3+self.hello0)
    self.assertLogFileContentsEqual(self.hello1Msg+self.add3Msg+self.hello0Msg+self.add3Msg+self.hello0Msg)
  #
#

if __name__ == "__main__":
  path_to_launcher = os.getenv("SALOME_LAUNCHER")
  if not path_to_launcher:
    msg = "Error: please set SALOME_LAUNCHER variable to the salome command of your application folder."
    raise Exception(msg)

  unittest.main()
#
<|endoftext|>


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

import os
from glob import glob

if os.environ.get('USE_SETUPTOOLS'):
  from setuptools import setup
  setup_kwargs = dict(zip_safe=0)

else:
  from distutils.core import setup
  setup_kwargs = dict()

storage_dirs = [ ('storage/whisper',[]), ('storage/lists',[]),
                 ('storage/log',[]), ('storage/rrd',[]) ]
conf_files = [ ('conf', glob('conf/*.example')) ]

setup(
  name='carbon',
  version='0.9.9-pre4',
  url='https://launchpad.net/graphite',
  author='Chris Davis',
  author_email='chrismd@gmail.com',
  license='Apache Software License 2.0',
  description='Backend data caching and persistence daemon for Graphite',
  packages=['carbon', 'carbon.aggregator', 'twisted.plugins'],
  package_dir={'' : 'lib'},
  scripts=glob('bin/*'),
  package_data={ 'carbon' : ['*.xml'] },
  data_files=storage_dirs + conf_files,
  install_requires=['twisted', 'txamqp'],
  **setup_kwargs
)
<commit_msg>bumping rev to pre5<commit_after>#!/usr/bin/env python

import os
from glob import glob

if os.environ.get('USE_SETUPTOOLS'):
  from setuptools import setup
  setup_kwargs = dict(zip_safe=0)

else:
  from distutils.core import setup
  setup_kwargs = dict()

storage_dirs = [ ('storage/whisper',[]), ('storage/lists',[]),
                 ('storage/log',[]), ('storage/rrd',[]) ]
conf_files = [ ('conf', glob('conf/*.example')) ]

setup(
  name='carbon',
  version='0.9.9-pre5',
  url='https://launchpad.net/graphite',
  author='Chris Davis',
  author_email='chrismd@gmail.com',
  license='Apache Software License 2.0',
  description='Backend data caching and persistence daemon for Graphite',
  packages=['carbon', 'carbon.aggregator', 'twisted.plugins'],
  package_dir={'' : 'lib'},
  scripts=glob('bin/*'),
  package_data={ 'carbon' : ['*.xml'] },
  data_files=storage_dirs + conf_files,
  install_requires=['twisted', 'txamqp'],
  **setup_kwargs
)
<|endoftext|>


<commit_before><commit_msg>calculate ratios for 2d histogram<commit_after><|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import, print_function
import os
import re
import time

# Import salt libs
import salt.config
import salt.payload
import salt.utils.dictupdate

# Import third party libs
from salt.ext.six.moves import range  # pylint: disable=import-error,redefined-builtin
try:
    import zmq
    HAS_ZMQ = True
except ImportError:
    HAS_ZMQ = False

class CacheDict(dict):
    '''
    Subclass of dict that will lazily delete items past ttl
    '''
    def __init__(self, ttl, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self._ttl = ttl
        self._key_cache_time = {}

    def _enforce_ttl_key(self, key):
        '''
        Enforce the TTL to a specific key, delete if its past TTL
        '''
        if key not in self._key_cache_time:
            return
        if time.time() - self._key_cache_time[key] > self._ttl:
            del self._key_cache_time[key]
            dict.__delitem__(self, key)

    def __getitem__(self, key):
        '''
        Check if the key is ttld out, then do the get
        '''
        self._enforce_ttl_key(key)
        return dict.__getitem__(self, key)

    def __setitem__(self, key, val):
        '''
        Make sure to update the key cache time
        '''
        self._key_cache_time[key] = time.time()
        dict.__setitem__(self, key, val)

    def __contains__(self, key):
        self._enforce_ttl_key(key)
        return dict.__contains__(self, key)

class CacheCli(object):
    '''
    Connection client for the ConCache. Should be used by all
    components that need the list of currently connected minions
    '''

    def __init__(self, opts):
        '''
        Sets up the zmq-connection to the ConCache
        '''
        super(CacheCli, self).__init__()
        self.opts = opts
        self.serial = salt.payload.Serial(self.opts.get('serial', ''))
        self.cache_sock = os.path.join(self.opts['sock_dir'], 'con_cache.ipc')
        self.cache_upd_sock = os.path.join(
            self.opts['sock_dir'], 'con_upd.ipc')

        context = zmq.Context()

        # the socket for talking to the cache
        self.creq_out = context.socket(zmq.REQ)
        self.creq_out.setsockopt(zmq.LINGER, 100)
        self.creq_out.connect('ipc://' + self.cache_sock)

        # the socket for sending updates to the cache
        self.cupd_out = context.socket(zmq.PUB)
        self.cupd_out.setsockopt(zmq.LINGER, 1)
        self.cupd_out.connect('ipc://' + self.cache_upd_sock)

    def put_cache(self, minions):
        '''
        published the given minions to the ConCache
        '''
        self.cupd_out.send(self.serial.dumps(minions))

    def get_cached(self):
        '''
        queries the ConCache for a list of currently connected minions
        '''
        msg = self.serial.dumps('minions')
        self.creq_out.send(msg)
        min_list = self.serial.loads(self.creq_out.recv())
        return min_list

class CacheRegex(object):
    '''
    Create a regular expression object cache for the most frequently
    used patterns to minimize compilation of the same patterns over
    and over again
    '''
    def __init__(self, prepend='', append='', size=1000,
                 keep_fraction=0.8, max_age=3600):
        self.prepend = prepend
        self.append = append
        self.size = size
        self.clear_size = int(size - size * (keep_fraction))
        if self.clear_size >= size:
            self.clear_size = int(size/2) + 1
            if self.clear_size > size:
                self.clear_size = size
        self.max_age = max_age
        self.cache = {}
        self.timestamp = time.time()

    def clear(self):
        '''
        Clear the cache
        '''
        self.cache.clear()

    def sweep(self):
        '''
        Sweep the cache and remove the outdated or least frequently
        used entries
        '''
        if self.max_age < time.time() - self.timestamp:
            self.clear()
            self.timestamp = time.time()
        else:
            paterns = list(self.cache.values())
            paterns.sort()
            for idx in range(self.clear_size):
                del self.cache[paterns[idx][2]]

    def get(self, pattern):
        '''
        Get a compiled regular expression object based on pattern and
        cache it when it is not in the cache already
        '''
        try:
            self.cache[pattern][0] += 1
            return self.cache[pattern][1]
        except KeyError:
            pass
        if len(self.cache) > self.size:
            self.sweep()
        regex = re.compile('{0}{1}{2}'.format(
            self.prepend, pattern, self.append))
        self.cache[pattern] = [1, regex, pattern, time.time()]
        return regex

class ContextCache(object):
    def __init__(self, opts, name):
        '''
        Create a context cache
        '''
        self.opts = opts
        self.cache_path = os.path.join(opts['cachedir'], 'context', '{0}.p'.format(name))
        self.serial = salt.payload.Serial(self.opts)

    def cache_context(self, context):
        '''
        Cache the given context to disk
        '''
        if not os.path.isdir(os.path.dirname(self.cache_path)):
            os.mkdir(os.path.dirname(self.cache_path))
        with salt.utils.fopen(self.cache_path, 'w+b') as cache:
            self.serial.dump(context, cache)

    def get_cache_context(self):
        '''
        Retrieve a context cache from disk
        '''
        with salt.utils.fopen(self.cache_path, 'rb') as cache:
            return self.serial.load(cache)

def context_cache(func):
    '''
    A decorator to be used module functions which need to cache their
    context.

    To evaluate a __context__ and re-hydrate it if a given key
    is empty or contains no items, pass a list of keys to evaulate.
    '''
    def context_cache_wrap(*args, **kwargs):
        func_context = func.__globals__['__context__']
        func_opts = func.__globals__['__opts__']
        func_name = func.__globals__['__name__']

        context_cache = ContextCache(func_opts, func_name)
        if not func_context and os.path.isfile(context_cache.cache_path):
            salt.utils.dictupdate.update(func_context, context_cache.get_cache_context())
        else:
            context_cache.cache_context(func_context)
        return func(*args, **kwargs)
    return context_cache_wrap

# test code for the CacheCli
if __name__ == '__main__':

    opts = salt.config.master_config('/etc/salt/master')

    ccli = CacheCli(opts)

    ccli.put_cache(['test1', 'test10', 'test34'])
    ccli.put_cache(['test12'])
    ccli.put_cache(['test18'])
    ccli.put_cache(['test21'])
    print('minions: {0}'.format(ccli.get_cached()))
<commit_msg>no need to call parent<commit_after># -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import, print_function
import os
import re
import time

# Import salt libs
import salt.config
import salt.payload
import salt.utils.dictupdate

# Import third party libs
from salt.ext.six.moves import range  # pylint: disable=import-error,redefined-builtin
try:
    import zmq
    HAS_ZMQ = True
except ImportError:
    HAS_ZMQ = False

class CacheDict(dict):
    '''
    Subclass of dict that will lazily delete items past ttl
    '''
    def __init__(self, ttl, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self._ttl = ttl
        self._key_cache_time = {}

    def _enforce_ttl_key(self, key):
        '''
        Enforce the TTL to a specific key, delete if its past TTL
        '''
        if key not in self._key_cache_time:
            return
        if time.time() - self._key_cache_time[key] > self._ttl:
            del self._key_cache_time[key]
            dict.__delitem__(self, key)

    def __getitem__(self, key):
        '''
        Check if the key is ttld out, then do the get
        '''
        self._enforce_ttl_key(key)
        return dict.__getitem__(self, key)

    def __setitem__(self, key, val):
        '''
        Make sure to update the key cache time
        '''
        self._key_cache_time[key] = time.time()
        dict.__setitem__(self, key, val)

    def __contains__(self, key):
        self._enforce_ttl_key(key)
        return dict.__contains__(self, key)

class CacheCli(object):
    '''
    Connection client for the ConCache. Should be used by all
    components that need the list of currently connected minions
    '''

    def __init__(self, opts):
        '''
        Sets up the zmq-connection to the ConCache
        '''
        self.opts = opts
        self.serial = salt.payload.Serial(self.opts.get('serial', ''))
        self.cache_sock = os.path.join(self.opts['sock_dir'], 'con_cache.ipc')
        self.cache_upd_sock = os.path.join(
            self.opts['sock_dir'], 'con_upd.ipc')

        context = zmq.Context()

        # the socket for talking to the cache
        self.creq_out = context.socket(zmq.REQ)
        self.creq_out.setsockopt(zmq.LINGER, 100)
        self.creq_out.connect('ipc://' + self.cache_sock)

        # the socket for sending updates to the cache
        self.cupd_out = context.socket(zmq.PUB)
        self.cupd_out.setsockopt(zmq.LINGER, 1)
        self.cupd_out.connect('ipc://' + self.cache_upd_sock)

    def put_cache(self, minions):
        '''
        published the given minions to the ConCache
        '''
        self.cupd_out.send(self.serial.dumps(minions))

    def get_cached(self):
        '''
        queries the ConCache for a list of currently connected minions
        '''
        msg = self.serial.dumps('minions')
        self.creq_out.send(msg)
        min_list = self.serial.loads(self.creq_out.recv())
        return min_list

class CacheRegex(object):
    '''
    Create a regular expression object cache for the most frequently
    used patterns to minimize compilation of the same patterns over
    and over again
    '''
    def __init__(self, prepend='', append='', size=1000,
                 keep_fraction=0.8, max_age=3600):
        self.prepend = prepend
        self.append = append
        self.size = size
        self.clear_size = int(size - size * (keep_fraction))
        if self.clear_size >= size:
            self.clear_size = int(size/2) + 1
            if self.clear_size > size:
                self.clear_size = size
        self.max_age = max_age
        self.cache = {}
        self.timestamp = time.time()

    def clear(self):
        '''
        Clear the cache
        '''
        self.cache.clear()

    def sweep(self):
        '''
        Sweep the cache and remove the outdated or least frequently
        used entries
        '''
        if self.max_age < time.time() - self.timestamp:
            self.clear()
            self.timestamp = time.time()
        else:
            paterns = list(self.cache.values())
            paterns.sort()
            for idx in range(self.clear_size):
                del self.cache[paterns[idx][2]]

    def get(self, pattern):
        '''
        Get a compiled regular expression object based on pattern and
        cache it when it is not in the cache already
        '''
        try:
            self.cache[pattern][0] += 1
            return self.cache[pattern][1]
        except KeyError:
            pass
        if len(self.cache) > self.size:
            self.sweep()
        regex = re.compile('{0}{1}{2}'.format(
            self.prepend, pattern, self.append))
        self.cache[pattern] = [1, regex, pattern, time.time()]
        return regex

class ContextCache(object):
    def __init__(self, opts, name):
        '''
        Create a context cache
        '''
        self.opts = opts
        self.cache_path = os.path.join(opts['cachedir'], 'context', '{0}.p'.format(name))
        self.serial = salt.payload.Serial(self.opts)

    def cache_context(self, context):
        '''
        Cache the given context to disk
        '''
        if not os.path.isdir(os.path.dirname(self.cache_path)):
            os.mkdir(os.path.dirname(self.cache_path))
        with salt.utils.fopen(self.cache_path, 'w+b') as cache:
            self.serial.dump(context, cache)

    def get_cache_context(self):
        '''
        Retrieve a context cache from disk
        '''
        with salt.utils.fopen(self.cache_path, 'rb') as cache:
            return self.serial.load(cache)

def context_cache(func):
    '''
    A decorator to be used module functions which need to cache their
    context.

    To evaluate a __context__ and re-hydrate it if a given key
    is empty or contains no items, pass a list of keys to evaulate.
    '''
    def context_cache_wrap(*args, **kwargs):
        func_context = func.__globals__['__context__']
        func_opts = func.__globals__['__opts__']
        func_name = func.__globals__['__name__']

        context_cache = ContextCache(func_opts, func_name)
        if not func_context and os.path.isfile(context_cache.cache_path):
            salt.utils.dictupdate.update(func_context, context_cache.get_cache_context())
        else:
            context_cache.cache_context(func_context)
        return func(*args, **kwargs)
    return context_cache_wrap

# test code for the CacheCli
if __name__ == '__main__':

    opts = salt.config.master_config('/etc/salt/master')

    ccli = CacheCli(opts)

    ccli.put_cache(['test1', 'test10', 'test34'])
    ccli.put_cache(['test12'])
    ccli.put_cache(['test18'])
    ccli.put_cache(['test21'])
    print('minions: {0}'.format(ccli.get_cached()))
<|endoftext|>


<commit_before>from flask import Flask, request, jsonify, make_response
import json, requests, logging, time, jsondict, gzip, shortuuid

URL = "http://b303.me:7456"
app = Flask(__name__)

USERS = jsondict.JsonDict("users.json.gz", compress=True, autosave=True)
PENDING = jsondict.JsonDict("pending.json.gz", compress=True, autosave=True)
VERIFY = jsondict.JsonDict("verify.json.gz", compress=True, autosave=True)

@app.errorhandler(Exception)
def error_handler(e):
    try:
        code = e.code
    except AttributeError:
        code = 500
    return jsonify(error=code, text=str(e)), code

def err_resp(json=True, **kwargs):
    response = jsonify(**kwargs) if json else make_response(**kwargs)
    response.status_code = kwargs["error"] if "error" in kwargs else 500
    return response

def airgram_check(email, id):
    resp = requests.post("https://api.airgramapp.com/1/send_as_guest", data={'email': email, 'msg': "Hi! You've been added to Question. Swipe here to verify", "url": URL + "/verify/" + id}, verify=False).json()
    return resp["status"] != "ok", resp

def airgram_send(**kwargs):
    resp = requests.post("https://api.airgramapp.com/1/send_as_guest", data=kwargs, verify=False).json()
    return resp["status"] == "ok", resp

@app.route("/verify/<id>")
def verify_id(id):
    global VERIFY
    global USERS
    if id in VERIFY and VERIFY[id] in USERS:
        USERS[VERIFY[id]]["verified"] = True
        del VERIFY[id]
        return make_response("
VERIFIED

Feel free to close this window now
")
    else:
        return err_resp(json=False, error=404, text="
NOT VERIFIED

ID not found. Maybe you've already verified?
")

@app.route("/send/<nick>")
def send_question(nick):
    global USERS
    global PENDING
    if nick and 'text' in request.args and 'from' in request.args:
        if not nick in USERS or not USERS.get(nick, {}).get('verified', False):
            return err_resp(error=404, text="Destination user not found or not yet verified")
        if not request.args['from'] in USERS or not USERS.get(request.args['from'], {}).get('verified', False):
            return err_resp(error=404, text="Source user not found or not yet verified")
        id = shortuuid.uuid()
        PENDING[id] = {'to': nick, 'from': request.args['from'], 'text': request.args['text'], 'ts': time.time()}
        first, _f = airgram_send(email=USERS[nick]["email"], msg="Question from {from} : Yes | {text}".format(**request.args), url=URL + "/yes/" + id)
        second, _s = airgram_send(email=USERS[nick]["email"], msg="Question from {from} : Yes | {text}".format(**request.args), url=URL + "/no/" + id)
        if first and second:
            return jsonify(status="ok")
        elif (first and not second) or (second and not first):
            _ = airgram_send(email=USERS[nick]["email"], msg="Oops! Can't send {} message. Please contact {} ASAP.".format("first" if second else "second", request.args['from']))
            return err_resp(error=504, text="{} message didn't send, please contact {} directly (they may be contacting you also)".format("First" if second else "Second", nick))
        else:
            return err_resp(error=504, text="Messages could not be sent, please notify blha303 at b3@blha303.com.au and contact {} directly at {}".format(nick, USERS[nick]["email"]))

@app.route("/add/<nick>")
def add_user(nick):
    global VERIFY
    global USERS
    if nick and nick in USERS:
        return err_resp(error=409, text="Username in use")
    if len(nick) > 20:
        return err_resp(error=400, text="Username is too long (>20)")
    elif 'email' in request.args:
        id = shortuuid.uuid()
        VERIFY[id] = nick
        if airgram_check(request.args['email'], id):
            USERS[nick] = {'email': request.args["email"], 'verified': False, 'reg': time.time()}
            return jsonify(status="ok")
        else:
            return err_resp(error=404, text="No Airgram account for specified email address, please create account at airgramapp.com")
    else:
        return err_resp(error=400, text="Invalid or missing email address")

@app.route("/reverify/<nick>")
def reverify(nick):
    id = shortuuid.uuid()
    VERIFY[id] = nick
    if airgram_check(USERS[nick]["email"], id):
        return jsonify(status="ok")
    else:
        return err_resp(error=404, text="An error occured while verifying your Airgram account.")

@app.route("/user/<nick>")
def user_lookup(nick):
    if nick and nick in USERS:
        return jsonify({nick: USERS[nick]})
    else:
        return err_resp(error=404, text="User not found")

if __name__ == "__main__":
    app.run(port=7456, host="0.0.0.0")
<commit_msg>All functionality in place, not tested fully<commit_after>from flask import Flask, request, jsonify, make_response
import json, requests, logging, time, jsondict, gzip, shortuuid

URL = "http://b303.me:7456"
app = Flask(__name__)

USERS = jsondict.JsonDict("users.json.gz", compress=True, autosave=True)
PENDING = jsondict.JsonDict("pending.json.gz", compress=True, autosave=True)
VERIFY = jsondict.JsonDict("verify.json.gz", compress=True, autosave=True)

@app.errorhandler(Exception)
def error_handler(e):
    try:
        code = e.code
    except AttributeError:
        code = 500
    return jsonify(error=code, text=str(e)), code

def gen_html(header, body=""):
    return "
{}

{}
".format(header, body)

def err_resp(json=True, **kwargs):
    response = jsonify(**kwargs) if json else make_response(**kwargs)
    response.status_code = kwargs["error"] if "error" in kwargs else 500
    return response

def airgram_check(email, id, msg="Hi! You've been added to Question. Swipe here to verify"):
    resp = requests.post("https://api.airgramapp.com/1/send_as_guest", data={'email': email, 'msg': msg, "url": URL + "/verify/" + id}, verify=False).json()
    return resp["status"] != "error", resp["error_msg"] if "error_msg" in resp else None

def airgram_send(**kwargs):
    resp = requests.post("https://api.airgramapp.com/1/send_as_guest", data=kwargs, verify=False).json()
    return resp["status"] != "error", resp["error_msg"] if "error_msg" in resp else None

@app.route("/verify/<id>")
def verify_id(id):
    global VERIFY
    global USERS
    if id in VERIFY and VERIFY[id] in USERS:
        USERS[VERIFY[id]]["verified"] = True
        del VERIFY[id]
        return gen_html("VERIFIED", "Feel free to close this page now :)")
    else:
        return err_resp(json=False, error=404, text=gen_html("NOT VERIFIED", "ID not found. Maybe you've already verified?"))

@app.route("/yes/<id>")
def yes(id):
    global PENDING
    global USERS
    if id in PENDING:
        airgram_send(email=USERS[PENDING[id]["from"]]["email"],
                     msg="{to} replied Yes to: {text}".format(**PENDING[id]))
        return gen_html("REPLY SENT")
    else:
        return err_resp(json=False, error=404, text=gen_html("ALREADY REPLIED"))

@app.route("/no/<id>")
def no(id):
    global PENDING
    global USERS
    if id in PENDING:
        airgram_send(email=USERS[PENDING[id]["from"]]["email"],
                     msg="{to} replied No to: {text}".format(**PENDING[id]))
        return gen_html("REPLY SENT")
    else:
        return err_resp(json=False, error=404, text=gen_html("ALREADY REPLIED"))

@app.route("/send/<nick>")
def send_question(nick):
    global USERS
    global PENDING
    if nick and 'text' in request.args and 'from' in request.args:
        if not nick in USERS or not USERS.get(nick, {}).get('verified', False):
            return err_resp(error=404, text="Destination user not found or not yet verified")
        if not request.args['from'] in USERS or not USERS.get(request.args['from'], {}).get('verified', False):
            reverify(request.args['from'])
            return err_resp(error=404, text="Source user not found or not yet verified (verification msg sent if exists)")
        id = shortuuid.uuid()
        PENDING[id] = {'to': nick, 'from': request.args['from'], 'text': request.args['text'], 'ts': time.time()}
        first, _f = airgram_send(email=USERS[nick]["email"], msg="Question from {} : No | {}".format(request.args["from"], request.args["text"]), url=URL + "/no/" + id)
        second, _s = airgram_send(email=USERS[nick]["email"], msg="Question from {} : Yes | {}".format(request.args["from"], request.args["text"]), url=URL + "/yes/" + id)
        if first and second:
            return jsonify(status="ok")
        elif (first and not second) or (second and not first):
            _ = airgram_send(email=USERS[nick]["email"], msg="Oops! Can't send {} message. Please contact {} ASAP.".format("NO" if second else "YES", request.args['from']))
            return err_resp(error=504, text="{} message didn't send, please contact {} directly (they may be contacting you also)".format("First" if second else "Second", nick))
        else:
            return err_resp(error=504, text="Messages could not be sent, please notify blha303 at b3@blha303.com.au and contact {} directly at {}".format(nick, USERS[nick]["email"]))

@app.route("/add/<nick>")
def add_user(nick):
    global VERIFY
    global USERS
    if nick and nick in USERS:
        return err_resp(error=409, text="Username in use")
    if len(nick) > 20:
        return err_resp(error=400, text="Username is too long (>20)")
    elif 'email' in request.args:
        id = shortuuid.uuid()
        VERIFY[id] = nick
        exists, err = airgram_check(request.args['email'], id)
        if exists:
            USERS[nick] = {'email': request.args["email"], 'verified': False, 'reg': time.time()}
            return jsonify(status="ok")
        else:
            return err_resp(error=404, text="{} airgramapp.com".format(err))
    else:
        return err_resp(error=400, text="Invalid or missing email address")

@app.route("/reverify/<nick>")
def reverify(nick):
    id = shortuuid.uuid()
    VERIFY[id] = nick
    if airgram_check(USERS[nick]["email"], id, msg="Please reverify your Airgram account for Question. Swipe here to verify"):
        return jsonify(status="ok")
    else:
        return err_resp(error=404, text="An error occured while verifying your Airgram account.")

@app.route("/user/<nick>")
def user_lookup(nick):
    if nick and nick in USERS:
        return jsonify({nick: USERS[nick]})
    else:
        return err_resp(error=404, text="User not found")

if __name__ == "__main__":
    app.run(port=7456, host="0.0.0.0")
<|endoftext|>


<commit_before><commit_msg>Better error messages for bad credentials<commit_after><|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from github3.models import GitHubCore
from github3.issues import Issue

class IssueSearchResult(GitHubCore):
    def __init__(self, data, session=None):
        result = data.copy()
        #: Score of the result
        self.score = result.pop('score')
        #: Text matches
        self.text_matches = result.pop('text_matches', [])
        #: Repository object
        self.repository = Issue(result, self)

    def __repr__(self):
        return '<IssueSearchResult [{0}]>'.format(self.repository)
<commit_msg>Refer to the right thing<commit_after># -*- coding: utf-8 -*-
from github3.models import GitHubCore
from github3.issues import Issue

class IssueSearchResult(GitHubCore):
    def __init__(self, data, session=None):
        result = data.copy()
        #: Score of the result
        self.score = result.pop('score')
        #: Text matches
        self.text_matches = result.pop('text_matches', [])
        #: Issue object
        self.issue = Issue(result, self)

    def __repr__(self):
        return '<IssueSearchResult [{0}]>'.format(self.repository)
<|endoftext|>


<commit_before>import datetime
import hashlib
import hmac
import logging
import urlparse

import geventwebsocket
import geventwebsocket.handler

LOG = logging.getLogger(__name__)

def is_valid_namespace(environ, mac_secret):
    namespace = environ.get("PATH_INFO", "")
    if not namespace:
        return False

    try:
        query_string = environ["QUERY_STRING"]
        params = urlparse.parse_qs(query_string, strict_parsing=True)
        mac = params["h"][0]
        expires = params["e"][0]
        expiration_time = datetime.datetime.utcfromtimestamp(int(expires))
    except (KeyError, IndexError, ValueError):
        return

    if expiration_time < datetime.datetime.utcnow():
        return

    expected_mac = hmac.new(mac_secret, expires + namespace,
                            hashlib.sha1).hexdigest()
    if not constant_time_compare(mac, expected_mac):
        return False

    return True

def constant_time_compare(actual, expected):
    """Return whether or not two strings match.

    The time taken is dependent on the number of characters provided instead of
    the number of characters that match which makes this function resistant to
    timing attacks.

    """
    actual_len = len(actual)
    expected_len = len(expected)
    result = actual_len ^ expected_len
    if expected_len > 0:
        for i in xrange(actual_len):
            result |= ord(actual[i]) ^ ord(expected[i % expected_len])
    return result == 0

class WebSocketHandler(geventwebsocket.handler.WebSocketHandler):
    def upgrade_connection(self):
        if not is_valid_namespace(self.environ, self.application.mac_secret):
            LOG.info("rejected connection from %s due to invalid namespace",
                     self.environ["REMOTE_ADDR"])
            self.application.metrics.counter("conn.rejected.bad_namespace").increment()
            self.start_response("403 Forbidden", [])
            return ["Forbidden"]

        return super(WebSocketHandler, self).upgrade_connection()

class SocketServer(object):
    def __init__(self, metrics, dispatcher, mac_secret, ping_interval):
        self.metrics = metrics
        self.dispatcher = dispatcher
        self.mac_secret = mac_secret
        self.ping_interval = ping_interval

    def __call__(self, environ, start_response):
        websocket = environ.get("wsgi.websocket")
        if not websocket:
            self.metrics.counter("conn.rejected.not_websocket").increment()
            start_response("400 Bad Request", [])
            return ["you are not a websocket"]

        namespace = environ["PATH_INFO"]
        try:
            self.metrics.counter("conn.connected").increment()
            for msg in self.dispatcher.listen(namespace,
                                              max_timeout=self.ping_interval):
                if msg is not None:
                    websocket.send(msg)
                else:
                    websocket.send_frame("", websocket.OPCODE_PONG)
        except geventwebsocket.WebSocketError as e:
            LOG.debug("socket failed: %r", e)
        finally:
            self.metrics.counter("conn.lost").increment()
<commit_msg>Use baseplate's message signature validation<commit_after>import logging
import urlparse

import geventwebsocket
import geventwebsocket.handler

from baseplate.crypto import MessageSigner, SignatureError

LOG = logging.getLogger(__name__)

class WebSocketHandler(geventwebsocket.handler.WebSocketHandler):
    def upgrade_connection(self):
        app = self.application

        try:
            namespace = self.environ["PATH_INFO"]
            query_string = self.environ["QUERY_STRING"]
            params = urlparse.parse_qs(query_string, strict_parsing=True)
            signature = params["m"][0]
            app.signer.validate_signature(namespace, signature)
        except (KeyError, IndexError, ValueError, SignatureError):
            app.metrics.counter("conn.rejected.bad_namespace").increment()
            self.start_response("403 Forbidden", [])
            return ["Forbidden"]

        self.environ["signature_validated"] = True
        return super(WebSocketHandler, self).upgrade_connection()

class SocketServer(object):
    def __init__(self, metrics, dispatcher, mac_secret, ping_interval):
        self.metrics = metrics
        self.dispatcher = dispatcher
        self.signer = MessageSigner(mac_secret)
        self.ping_interval = ping_interval

    def __call__(self, environ, start_response):
        websocket = environ.get("wsgi.websocket")
        if not websocket:
            self.metrics.counter("conn.rejected.not_websocket").increment()
            start_response("400 Bad Request", [])
            return ["you are not a websocket"]

        # ensure the application was properly configured to use the custom
        # handler subclass which validates namespace signatures
        assert environ["signature_validated"]

        namespace = environ["PATH_INFO"]
        try:
            self.metrics.counter("conn.connected").increment()
            for msg in self.dispatcher.listen(namespace,
                                              max_timeout=self.ping_interval):
                if msg is not None:
                    websocket.send(msg)
                else:
                    websocket.send_frame("", websocket.OPCODE_PONG)
        except geventwebsocket.WebSocketError as e:
            LOG.debug("socket failed: %r", e)
        finally:
            self.metrics.counter("conn.lost").increment()
<|endoftext|>


<commit_before>#-----------------------------------------------------------------------------
# Copyright (c) 2013--, scikit-bio development team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

from .correspondence_analysis import CA
from .redundancy_analysis import RDA
from .canonical_correspondence_analysis import CCA
from .principal_coordinate_analysis import PCoA

__all__ = ['CA', 'RDA', 'CCA', 'PCoA']
<commit_msg>DOC: add short module intro.<commit_after>r"""
Ordination methods (:mod:`skbio.maths.stats.ordination`)
========================================================

.. currentmodule:: skbio.maths.stats.ordination

This module contains several ordination methods, including Principal
Coordinate Analysis, Correspondence Analysis, Redundancy Analysis and
Canonical Correspondence Analysis.

Classes
-------

.. autosummary::
   :toctree: generated/

   PCoA
   CA
   RDA
   CCA

"""
#-----------------------------------------------------------------------------
# Copyright (c) 2013--, scikit-bio development team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

from .correspondence_analysis import CA
from .redundancy_analysis import RDA
from .canonical_correspondence_analysis import CCA
from .principal_coordinate_analysis import PCoA

__all__ = ['CA', 'RDA', 'CCA', 'PCoA']
<|endoftext|>