<commit_before>import re

from django.utils.translation import ugettext as _

from eulxml.xpath import parse as parse_xpath
from eulxml.xpath.ast import (
    BinaryExpression,
    FunctionCall,
    Step,
    UnaryExpression,
    serialize,
)

from corehq.apps.case_search.exceptions import (
    CaseFilterError,
    TooManyRelatedCasesError,
    XPathFunctionException,
)
from corehq.apps.case_search.xpath_functions import (
    XPATH_QUERY_FUNCTIONS,
    XPATH_VALUE_FUNCTIONS,
)
from corehq.apps.es import filters
from corehq.apps.es.case_search import (
    CaseSearchES,
    case_property_query,
    case_property_range_query,
    reverse_index_case_query,
)

def print_ast(node):
    """Prints the AST provided by eulxml.xpath.parse

    Useful for debugging particular expressions
    """
    def visit(node, indent):
        print("\t" * indent, node)  # noqa

        if hasattr(node, 'left'):
            indent += 1
            visit(node.left, indent)

        if hasattr(node, 'op'):
            print("\t" * indent, "##### {} #####".format(node.op))  # noqa

        if hasattr(node, 'right'):
            visit(node.right, indent)
            indent -= 1

    visit(node, 0)

MAX_RELATED_CASES = 500000  # Limit each related case lookup to return 500,000 cases to prevent timeouts

OPERATOR_MAPPING = {
    'and': filters.AND,
    'not': filters.NOT,
    'or': filters.OR,
}
COMPARISON_MAPPING = {
    '>': 'gt',
    '>=': 'gte',
    '<': 'lt',
    '<=': 'lte',
}

EQ = "="
NEQ = "!="

ALL_OPERATORS = [EQ, NEQ] + list(OPERATOR_MAPPING.keys()) + list(COMPARISON_MAPPING.keys())

def build_filter_from_ast(domain, node, fuzzy=False):
    """Builds an ES filter from an AST provided by eulxml.xpath.parse

    If fuzzy is true, all equality operations will be treated as fuzzy.
    """

    def _walk_ancestor_cases(node):
        """Return a query that will fulfill the filter on the related case.

        :param node: a node returned from eulxml.xpath.parse of the form `parent/grandparent/property = 'value'`

        Since ES has no way of performing joins, we filter down in stages:
        1. Find the ids of all cases where the condition is met
        2. Walk down the case hierarchy, finding all related cases with the right identifier to the ids
        found in (1).
        3. Return the lowest of these ids as an related case query filter
        """

        # fetch the ids of the highest level cases that match the case_property
        # i.e. all the cases which have `property = 'value'`
        ids = _parent_property_lookup(node)

        # get the related case path we need to walk, i.e. `parent/grandparent/property`
        n = node.left
        while _is_ancestor_case_lookup(n):
            # This walks down the tree and finds case ids that match each identifier
            # This is basically performing multiple "joins" to find related cases since ES
            # doesn't have a way to relate models together

            # Get the path to the related case, e.g. `parent/grandparent`
            # On subsequent run throughs, it walks down the tree (e.g. n = [parent, /, grandparent])
            n = n.left
            identifier = serialize(n.right)  # the identifier at this step, e.g. `grandparent`

            # get the ids of the cases that point at the previous level's cases
            # this has the potential of being a very large list
            ids = _child_case_lookup(ids, identifier=identifier)
            if not ids:
                break

        # after walking the full tree, get the final level we are interested in, i.e. `parent`
        final_identifier = serialize(n.left)
        return reverse_index_case_query(ids, final_identifier)

    def _parent_property_lookup(node):
        """given a node of the form `parent/foo = 'thing'`, return all case_ids where `foo = thing`
        """
        if isinstance(node.right, Step):
            _raise_step_RHS(node)
        new_query = '{} {} "{}"'.format(serialize(node.left.right), node.op, node.right)

        es_query = CaseSearchES().domain(domain).xpath_query(domain, new_query, fuzzy=fuzzy)
        if es_query.count() > MAX_RELATED_CASES:
            raise TooManyRelatedCasesError(
                _("The related case lookup you are trying to perform would return too many cases"),
                new_query
            )

        return es_query.scroll_ids()

    def _child_case_lookup(case_ids, identifier):
        """returns a list of all case_ids who have parents `case_id` with the relationship `identifier`
        """
        return CaseSearchES().domain(domain).get_child_cases(case_ids, identifier).scroll_ids()

    def _is_ancestor_case_lookup(node):
        """Returns whether a particular AST node is an ancestory case lookup

        e.g. `parent/host/thing = 'foo'`
        """
        return hasattr(node, 'left') and hasattr(node.left, 'op') and node.left.op == '/'

    def _is_subcase_count(node):
        """Returns whether a particular AST node is a subcase lookup.
        This is needed for subcase-count since we need the full expression, not just the function."""
        if not isinstance(node, BinaryExpression):
            return False

        return isinstance(node.left, FunctionCall) and node.left.name == 'subcase-count'

    def _raise_step_RHS(node):
        raise CaseFilterError(
            _("You cannot reference a case property on the right side "
              "of a boolean operation. If \"{}\" is meant to be a value, please surround it with "
              "quotation marks").format(serialize(node.right)),
            serialize(node)
        )

    def _unwrap_function(node):
        """Returns the value of the node if it is wrapped in a function, otherwise just returns the node
        """
        if isinstance(node, UnaryExpression) and node.op == '-':
            return -1 * node.right
        if not isinstance(node, FunctionCall):
            return node
        try:
            return XPATH_VALUE_FUNCTIONS[node.name](node)
        except KeyError:
            raise CaseFilterError(
                _("We don't know what to do with the function \"{}\". Accepted functions are: {}").format(
                    node.name,
                    ", ".join(list(XPATH_VALUE_FUNCTIONS.keys())),
                ),
                serialize(node)
            )
        except XPathFunctionException as e:
            raise CaseFilterError(str(e), serialize(node))

    def _equality(node):
        """Returns the filter for an equality operation (=, !=)

        """
        acceptable_rhs_types = (int, str, float, FunctionCall, UnaryExpression)
        if isinstance(node.left, Step) and (
                isinstance(node.right, acceptable_rhs_types)):
            # This is a leaf node
            case_property_name = serialize(node.left)
            value = _unwrap_function(node.right)
            q = case_property_query(case_property_name, value, fuzzy=fuzzy)

            if node.op == '!=':
                return filters.NOT(q)

            return q

        if isinstance(node.right, Step):
            _raise_step_RHS(node)

        raise CaseFilterError(
            _("We didn't understand what you were trying to do with {}").format(serialize(node)),
            serialize(node)
        )

    def _comparison(node):
        """Returns the filter for a comparison operation (>, <, >=, <=)

        """
        try:
            case_property_name = serialize(node.left)
            value = _unwrap_function(node.right)
            return case_property_range_query(case_property_name, **{COMPARISON_MAPPING[node.op]: value})
        except (TypeError, ValueError):
            raise CaseFilterError(
                _("The right hand side of a comparison must be a number or date. "
                  "Dates must be surrounded in quotation marks"),
                serialize(node),
            )

    def visit(node):
        if isinstance(node, FunctionCall):
            try:
                return XPATH_QUERY_FUNCTIONS[node.name](domain, node, fuzzy)
            except KeyError:
                raise CaseFilterError(
                    _("Unsupported function '{name}')").format(name=node.name),
                    serialize(node)
                )

        if not hasattr(node, 'op'):
            # TODO: adjust this for subcase queries
            raise CaseFilterError(
                _("Your search query is required to have at least one boolean operator ({boolean_ops})").format(
                    boolean_ops=", ".join(list(COMPARISON_MAPPING.keys()) + [EQ, NEQ]),
                ),
                serialize(node)
            )

        if _is_ancestor_case_lookup(node):
            # this node represents a filter on a property for a related case
            return _walk_ancestor_cases(node)

        if _is_subcase_count(node):
            return XPATH_QUERY_FUNCTIONS['subcase-count'](domain, node, fuzzy)

        if node.op in [EQ, NEQ]:
            # This node is a leaf
            return _equality(node)

        if node.op in list(COMPARISON_MAPPING.keys()):
            # This node is a leaf
            return _comparison(node)

        if node.op in list(OPERATOR_MAPPING.keys()):
            # This is another branch in the tree
            return OPERATOR_MAPPING[node.op](visit(node.left), visit(node.right))

        raise CaseFilterError(
            _("We don't know what to do with operator '{}'. Please try reformatting your query.".format(node.op)),
            serialize(node)
        )

    return visit(node)

def build_filter_from_xpath(domain, xpath, fuzzy=False):
    """Given an xpath expression this function will generate an Elasticsearch
    filter"""
    error_message = _(
        "We didn't understand what you were trying to do with {}. "
        "Please try reformatting your query. "
        "The operators we accept are: {}"
    )
    try:
        return build_filter_from_ast(domain, parse_xpath(xpath), fuzzy=fuzzy)
    except TypeError as e:
        text_error = re.search(r"Unknown text '(.+)'", str(e))
        if text_error:
            # This often happens if there is a bad operator (e.g. a ~ b)
            bad_part = text_error.groups()[0]
            raise CaseFilterError(error_message.format(bad_part, ", ".join(ALL_OPERATORS)), bad_part)
        raise CaseFilterError(_("Malformed search query"), None)
    except RuntimeError as e:
        # eulxml passes us string errors from YACC
        lex_token_error = re.search(r"LexToken\((\w+),\w?'(.+)'", str(e))
        if lex_token_error:
            bad_part = lex_token_error.groups()[1]
            raise CaseFilterError(error_message.format(bad_part, ", ".join(ALL_OPERATORS)), bad_part)
        raise CaseFilterError(_("Malformed search query"), None)
<commit_msg>'not' is a function, not an operator<commit_after>import re

from django.utils.translation import ugettext as _

from eulxml.xpath import parse as parse_xpath
from eulxml.xpath.ast import (
    BinaryExpression,
    FunctionCall,
    Step,
    UnaryExpression,
    serialize,
)

from corehq.apps.case_search.exceptions import (
    CaseFilterError,
    TooManyRelatedCasesError,
    XPathFunctionException,
)
from corehq.apps.case_search.xpath_functions import (
    XPATH_QUERY_FUNCTIONS,
    XPATH_VALUE_FUNCTIONS,
)
from corehq.apps.es import filters
from corehq.apps.es.case_search import (
    CaseSearchES,
    case_property_query,
    case_property_range_query,
    reverse_index_case_query,
)

def print_ast(node):
    """Prints the AST provided by eulxml.xpath.parse

    Useful for debugging particular expressions
    """
    def visit(node, indent):
        print("\t" * indent, node)  # noqa

        if hasattr(node, 'left'):
            indent += 1
            visit(node.left, indent)

        if hasattr(node, 'op'):
            print("\t" * indent, "##### {} #####".format(node.op))  # noqa

        if hasattr(node, 'right'):
            visit(node.right, indent)
            indent -= 1

    visit(node, 0)

MAX_RELATED_CASES = 500000  # Limit each related case lookup to return 500,000 cases to prevent timeouts

OPERATOR_MAPPING = {
    'and': filters.AND,
    'or': filters.OR,
}
COMPARISON_MAPPING = {
    '>': 'gt',
    '>=': 'gte',
    '<': 'lt',
    '<=': 'lte',
}

EQ = "="
NEQ = "!="

ALL_OPERATORS = [EQ, NEQ] + list(OPERATOR_MAPPING.keys()) + list(COMPARISON_MAPPING.keys())

def build_filter_from_ast(domain, node, fuzzy=False):
    """Builds an ES filter from an AST provided by eulxml.xpath.parse

    If fuzzy is true, all equality operations will be treated as fuzzy.
    """

    def _walk_ancestor_cases(node):
        """Return a query that will fulfill the filter on the related case.

        :param node: a node returned from eulxml.xpath.parse of the form `parent/grandparent/property = 'value'`

        Since ES has no way of performing joins, we filter down in stages:
        1. Find the ids of all cases where the condition is met
        2. Walk down the case hierarchy, finding all related cases with the right identifier to the ids
        found in (1).
        3. Return the lowest of these ids as an related case query filter
        """

        # fetch the ids of the highest level cases that match the case_property
        # i.e. all the cases which have `property = 'value'`
        ids = _parent_property_lookup(node)

        # get the related case path we need to walk, i.e. `parent/grandparent/property`
        n = node.left
        while _is_ancestor_case_lookup(n):
            # This walks down the tree and finds case ids that match each identifier
            # This is basically performing multiple "joins" to find related cases since ES
            # doesn't have a way to relate models together

            # Get the path to the related case, e.g. `parent/grandparent`
            # On subsequent run throughs, it walks down the tree (e.g. n = [parent, /, grandparent])
            n = n.left
            identifier = serialize(n.right)  # the identifier at this step, e.g. `grandparent`

            # get the ids of the cases that point at the previous level's cases
            # this has the potential of being a very large list
            ids = _child_case_lookup(ids, identifier=identifier)
            if not ids:
                break

        # after walking the full tree, get the final level we are interested in, i.e. `parent`
        final_identifier = serialize(n.left)
        return reverse_index_case_query(ids, final_identifier)

    def _parent_property_lookup(node):
        """given a node of the form `parent/foo = 'thing'`, return all case_ids where `foo = thing`
        """
        if isinstance(node.right, Step):
            _raise_step_RHS(node)
        new_query = '{} {} "{}"'.format(serialize(node.left.right), node.op, node.right)

        es_query = CaseSearchES().domain(domain).xpath_query(domain, new_query, fuzzy=fuzzy)
        if es_query.count() > MAX_RELATED_CASES:
            raise TooManyRelatedCasesError(
                _("The related case lookup you are trying to perform would return too many cases"),
                new_query
            )

        return es_query.scroll_ids()

    def _child_case_lookup(case_ids, identifier):
        """returns a list of all case_ids who have parents `case_id` with the relationship `identifier`
        """
        return CaseSearchES().domain(domain).get_child_cases(case_ids, identifier).scroll_ids()

    def _is_ancestor_case_lookup(node):
        """Returns whether a particular AST node is an ancestory case lookup

        e.g. `parent/host/thing = 'foo'`
        """
        return hasattr(node, 'left') and hasattr(node.left, 'op') and node.left.op == '/'

    def _is_subcase_count(node):
        """Returns whether a particular AST node is a subcase lookup.
        This is needed for subcase-count since we need the full expression, not just the function."""
        if not isinstance(node, BinaryExpression):
            return False

        return isinstance(node.left, FunctionCall) and node.left.name == 'subcase-count'

    def _raise_step_RHS(node):
        raise CaseFilterError(
            _("You cannot reference a case property on the right side "
              "of a boolean operation. If \"{}\" is meant to be a value, please surround it with "
              "quotation marks").format(serialize(node.right)),
            serialize(node)
        )

    def _unwrap_function(node):
        """Returns the value of the node if it is wrapped in a function, otherwise just returns the node
        """
        if isinstance(node, UnaryExpression) and node.op == '-':
            return -1 * node.right
        if not isinstance(node, FunctionCall):
            return node
        try:
            return XPATH_VALUE_FUNCTIONS[node.name](node)
        except KeyError:
            raise CaseFilterError(
                _("We don't know what to do with the function \"{}\". Accepted functions are: {}").format(
                    node.name,
                    ", ".join(list(XPATH_VALUE_FUNCTIONS.keys())),
                ),
                serialize(node)
            )
        except XPathFunctionException as e:
            raise CaseFilterError(str(e), serialize(node))

    def _equality(node):
        """Returns the filter for an equality operation (=, !=)

        """
        acceptable_rhs_types = (int, str, float, FunctionCall, UnaryExpression)
        if isinstance(node.left, Step) and (
                isinstance(node.right, acceptable_rhs_types)):
            # This is a leaf node
            case_property_name = serialize(node.left)
            value = _unwrap_function(node.right)
            q = case_property_query(case_property_name, value, fuzzy=fuzzy)

            if node.op == '!=':
                return filters.NOT(q)

            return q

        if isinstance(node.right, Step):
            _raise_step_RHS(node)

        raise CaseFilterError(
            _("We didn't understand what you were trying to do with {}").format(serialize(node)),
            serialize(node)
        )

    def _comparison(node):
        """Returns the filter for a comparison operation (>, <, >=, <=)

        """
        try:
            case_property_name = serialize(node.left)
            value = _unwrap_function(node.right)
            return case_property_range_query(case_property_name, **{COMPARISON_MAPPING[node.op]: value})
        except (TypeError, ValueError):
            raise CaseFilterError(
                _("The right hand side of a comparison must be a number or date. "
                  "Dates must be surrounded in quotation marks"),
                serialize(node),
            )

    def visit(node):
        if isinstance(node, FunctionCall):
            try:
                return XPATH_QUERY_FUNCTIONS[node.name](domain, node, fuzzy)
            except KeyError:
                raise CaseFilterError(
                    _("Unsupported function '{name}')").format(name=node.name),
                    serialize(node)
                )

        if not hasattr(node, 'op'):
            # TODO: adjust this for subcase queries
            raise CaseFilterError(
                _("Your search query is required to have at least one boolean operator ({boolean_ops})").format(
                    boolean_ops=", ".join(list(COMPARISON_MAPPING.keys()) + [EQ, NEQ]),
                ),
                serialize(node)
            )

        if _is_ancestor_case_lookup(node):
            # this node represents a filter on a property for a related case
            return _walk_ancestor_cases(node)

        if _is_subcase_count(node):
            return XPATH_QUERY_FUNCTIONS['subcase-count'](domain, node, fuzzy)

        if node.op in [EQ, NEQ]:
            # This node is a leaf
            return _equality(node)

        if node.op in list(COMPARISON_MAPPING.keys()):
            # This node is a leaf
            return _comparison(node)

        if node.op in list(OPERATOR_MAPPING.keys()):
            # This is another branch in the tree
            return OPERATOR_MAPPING[node.op](visit(node.left), visit(node.right))

        raise CaseFilterError(
            _("We don't know what to do with operator '{}'. Please try reformatting your query.".format(node.op)),
            serialize(node)
        )

    return visit(node)

def build_filter_from_xpath(domain, xpath, fuzzy=False):
    """Given an xpath expression this function will generate an Elasticsearch
    filter"""
    error_message = _(
        "We didn't understand what you were trying to do with {}. "
        "Please try reformatting your query. "
        "The operators we accept are: {}"
    )
    try:
        return build_filter_from_ast(domain, parse_xpath(xpath), fuzzy=fuzzy)
    except TypeError as e:
        text_error = re.search(r"Unknown text '(.+)'", str(e))
        if text_error:
            # This often happens if there is a bad operator (e.g. a ~ b)
            bad_part = text_error.groups()[0]
            raise CaseFilterError(error_message.format(bad_part, ", ".join(ALL_OPERATORS)), bad_part)
        raise CaseFilterError(_("Malformed search query"), None)
    except RuntimeError as e:
        # eulxml passes us string errors from YACC
        lex_token_error = re.search(r"LexToken\((\w+),\w?'(.+)'", str(e))
        if lex_token_error:
            bad_part = lex_token_error.groups()[1]
            raise CaseFilterError(error_message.format(bad_part, ", ".join(ALL_OPERATORS)), bad_part)
        raise CaseFilterError(_("Malformed search query"), None)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

"""
# Integrating RazorPay

### Validate Currency

Example:

	from frappe.integrations.utils import get_payment_gateway_controller

	controller = get_payment_gateway_controller("Razorpay")
	controller().validate_transaction_currency(currency)

### 2. Redirect for payment

Example:

	payment_details = {
		"amount": 600,
		"title": "Payment for bill : 111",
		"description": "payment via cart",
		"reference_doctype": "Payment Request",
		"reference_docname": "PR0001",
		"payer_email": "NuranVerkleij@example.com",
		"payer_name": "Nuran Verkleij",
		"order_id": "111",
		"currency": "INR",
		"payment_gateway": "Razorpay",
		"subscription_details": {
			"plan_id": "plan_12313", # if Required
			"start_date": "2018-08-30",
			"billing_period": "Month" #(Day, Week, Month, Year),
			"billing_frequency": 1,
			"customer_notify": 1,
			"upfront_amount": 1000
		}
	}

	# Redirect the user to this url
	url = controller().get_payment_url(**payment_details)

### 3. On Completion of Payment

Write a method for `on_payment_authorized` in the reference doctype

Example:

	def on_payment_authorized(payment_status):
		# this method will be called when payment is complete

##### Notes:

payment_status - payment gateway will put payment status on callback.
For razorpay payment status is Authorized

"""

from __future__ import unicode_literals
import frappe
from frappe import _
import json
from six.moves.urllib.parse import urlencode
from frappe.model.document import Document
from frappe.utils import get_url, call_hook_method, cint, get_timestamp
from frappe.integrations.utils import (make_get_request, make_post_request, create_request_log,
	create_payment_gateway)

class RazorpaySettings(Document):
	supported_currencies = ["INR"]

	def validate(self):
		create_payment_gateway('Razorpay')
		call_hook_method('payment_gateway_enabled', gateway='Razorpay')
		if not self.flags.ignore_mandatory:
			self.validate_razorpay_credentails()

	def validate_razorpay_credentails(self):
		if self.api_key and self.api_secret:
			try:
				make_get_request(url="https://api.razorpay.com/v1/payments",
					auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)))
			except Exception:
				frappe.throw(_("Seems API Key or API Secret is wrong !!!"))

	def validate_transaction_currency(self, currency):
		if currency not in self.supported_currencies:
			frappe.throw(_("Please select another payment method. Razorpay does not support transactions in currency '{0}'").format(currency))

	def setup_addon(self, settings, **kwargs):
		"""
			Addon template:
			{
				"item": {
					"name": row.upgrade_type,
					"amount": row.amount,
					"currency": currency,
					"description": "add-on description"
				},
				"quantity": 1 (The total amount is calculated as item.amount * quantity)
			}
		"""
		url = "https://api.razorpay.com/v1/subscriptions/{0}/addons".format(kwargs.get('subscription_id'))

		try:
			if not frappe.conf.converted_rupee_to_paisa:
				convert_rupee_to_paisa(**kwargs)

			for addon in kwargs.get("addons"):
				resp = make_post_request(
					url,
					auth=(settings.api_key, settings.api_secret),
					data=json.dumps(addon),
					headers={
						"content-type": "application/json"
					}
				)
				if not resp.get('id'):
					frappe.log_error(str(resp), 'Razorpay Failed while creating subscription')
		except:
			frappe.log_error(frappe.get_traceback())
			# failed
			pass

	def setup_subscription(self, settings, **kwargs):
		start_date = get_timestamp(kwargs.get('subscription_details').get("start_date")) \
			if kwargs.get('subscription_details').get("start_date") else None

		subscription_details = {
			"plan_id": kwargs.get('subscription_details').get("plan_id"),
			"start_at": cint(start_date),
			"total_count": kwargs.get('subscription_details').get("billing_frequency"),
			"customer_notify": kwargs.get('subscription_details').get("customer_notify")
		}

		if kwargs.get('addons'):
			convert_rupee_to_paisa(**kwargs)
			subscription_details.update({
				"addons": kwargs.get('addons')
			})

		try:
			resp = make_post_request(
				"https://api.razorpay.com/v1/subscriptions",
				auth=(settings.api_key, settings.api_secret),
				data=json.dumps(subscription_details),
				headers={
					"content-type": "application/json"
				}
			)

			if resp.get('status') == 'created':
				kwargs['subscription_id'] = resp.get('id')
				frappe.flags.status = 'created'
				return kwargs
			else:
				frappe.log_error(str(resp), 'Razorpay Failed while creating subscription')

		except:
			frappe.log_error(frappe.get_traceback())
			# failed
			pass

	def prepare_subscription_details(self, settings, **kwargs):
		if not kwargs.get("subscription_id"):
			kwargs = self.setup_subscription(settings, **kwargs)

		if frappe.flags.status !='created':
			kwargs['subscription_id'] = None

		return kwargs

	def get_payment_url(self, **kwargs):
		integration_request = create_request_log(kwargs, "Host", "Razorpay")
		return get_url("./integrations/razorpay_checkout?token={0}".format(integration_request.name))

	def create_request(self, data):
		self.data = frappe._dict(data)

		try:
			self.integration_request = frappe.get_doc("Integration Request", self.data.token)
			self.integration_request.update_status(self.data, 'Queued')
			return self.authorize_payment()

		except Exception:
			frappe.log_error(frappe.get_traceback())
			return{
				"redirect_to": frappe.redirect_to_message(_('Server Error'), _("Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account.")),
				"status": 401
			}

	def authorize_payment(self):
		"""
		An authorization is performed when user’s payment details are successfully authenticated by the bank.
		The money is deducted from the customer’s account, but will not be transferred to the merchant’s account
		until it is explicitly captured by merchant.
		"""
		data = json.loads(self.integration_request.data)
		settings = self.get_settings(data)

		try:
			resp = make_get_request("https://api.razorpay.com/v1/payments/{0}"
				.format(self.data.razorpay_payment_id), auth=(settings.api_key,
					settings.api_secret))

			if resp.get("status") == "authorized":
				self.integration_request.update_status(data, 'Authorized')
				self.flags.status_changed_to = "Authorized"

			elif data.get('subscription_id'):
				if resp.get("status") == "refunded":
					# if subscription start date is in future then
					# razorpay refunds the amount after authorizing the card details
					# thus changing status to Verified

					self.integration_request.update_status(data, 'Completed')
					self.flags.status_changed_to = "Verified"

				if resp.get("status") == "captured":
					# if subscription starts immediately then
					# razorpay charge the actual amount
					# thus changing status to Completed

					self.integration_request.update_status(data, 'Completed')
					self.flags.status_changed_to = "Completed"

			else:
				frappe.log_error(str(resp), 'Razorpay Payment not authorized')

		except:
			frappe.log_error(frappe.get_traceback())
			# failed
			pass

		status = frappe.flags.integration_request.status_code

		redirect_to = data.get('notes', {}).get('redirect_to') or None
		redirect_message = data.get('notes', {}).get('redirect_message') or None

		if self.flags.status_changed_to in ("Authorized", "Verified", "Completed"):
			if self.data.reference_doctype and self.data.reference_docname:
				custom_redirect_to = None
				try:
					frappe.flags.data = data
					custom_redirect_to = frappe.get_doc(self.data.reference_doctype,
						self.data.reference_docname).run_method("on_payment_authorized", self.flags.status_changed_to)

				except Exception:
					frappe.log_error(frappe.get_traceback())

				if custom_redirect_to:
					redirect_to = custom_redirect_to

			redirect_url = 'payment-success?doctype={0}&docname={1}'.format(self.data.reference_doctype, self.data.reference_docname)
		else:
			redirect_url = 'payment-failed'

		if redirect_to:
			redirect_url += '&' + urlencode({'redirect_to': redirect_to})
		if redirect_message:
			redirect_url += '&' + urlencode({'redirect_message': redirect_message})

		return {
			"redirect_to": redirect_url,
			"status": status
		}

	def get_settings(self, data):
		settings = frappe._dict({
			"api_key": self.api_key,
			"api_secret": self.get_password(fieldname="api_secret", raise_exception=False)
		})

		if cint(data.get('notes', {}).get('use_sandbox')) or data.get("use_sandbox"):
			settings.update({
				"api_key": frappe.conf.sandbox_api_key,
				"api_secret": frappe.conf.sandbox_api_secret,
			})

		return settings

	def cancel_subscription(self, subscription_id):
		settings = self.get_settings({})

		try:
			resp = make_post_request("https://api.razorpay.com/v1/subscriptions/{0}/cancel"
				.format(subscription_id), auth=(settings.api_key,
					settings.api_secret))
		except Exception:
			frappe.log_error(frappe.get_traceback())

def capture_payment(is_sandbox=False, sanbox_response=None):
	"""
		Verifies the purchase as complete by the merchant.
		After capture, the amount is transferred to the merchant within T+3 days
		where T is the day on which payment is captured.

		Note: Attempting to capture a payment whose status is not authorized will produce an error.
	"""
	controller = frappe.get_doc("Razorpay Settings")

	for doc in frappe.get_all("Integration Request", filters={"status": "Authorized",
		"integration_request_service": "Razorpay"}, fields=["name", "data"]):
		try:
			if is_sandbox:
				resp = sanbox_response
			else:
				data = json.loads(doc.data)
				settings = controller.get_settings(data)

				resp = make_get_request("https://api.razorpay.com/v1/payments/{0}".format(data.get("razorpay_payment_id")),
					auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")})

				if resp.get('status') == "authorized":
					resp = make_post_request("https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")),
						auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")})

			if resp.get("status") == "captured":
				frappe.db.set_value("Integration Request", doc.name, "status", "Completed")

		except Exception:
			doc = frappe.get_doc("Integration Request", doc.name)
			doc.status = "Failed"
			doc.error = frappe.get_traceback()
			frappe.log_error(doc.error, '{0} Failed'.format(doc.name))

def convert_rupee_to_paisa(**kwargs):
	for addon in kwargs.get('addons'):
		addon['item']['amount'] *= 100

	frappe.conf.converted_rupee_to_paisa = True

@frappe.whitelist(allow_guest=True)
def razorpay_subscription_callback():
	try:
		data = frappe.local.form_dict

		validate_payment_callback(data)

		data.update({
			"payment_gateway": "Razorpay"
		})

		doc = frappe.get_doc({
			"data": json.dumps(frappe.local.form_dict),
			"doctype": "Integration Request",
			"integration_type": "Subscription Notification",
			"status": "Queued"
		}).insert(ignore_permissions=True)
		frappe.db.commit()

		frappe.enqueue(method='frappe.integrations.doctype.razorpay_settings.razorpay_settings.handle_subscription_notification',
			queue='long', timeout=600, is_async=True, **{"doctype": "Integration Request", "docname":  doc.name})

	except frappe.InvalidStatusError:
		pass
	except Exception as e:
		frappe.log(frappe.log_error(title=e))

def validate_payment_callback(data):
	def _throw():
		frappe.throw(_("Invalid Subscription"), exc=frappe.InvalidStatusError)

	subscription_id = data.get('payload').get("subscription").get("entity").get("id")

	if not(subscription_id):
		_throw()

	controller = frappe.get_doc("Razorpay Settings")

	settings = controller.get_settings(data)

	resp = make_get_request("https://api.razorpay.com/v1/subscriptions/{0}".format(subscription_id),
		auth=(settings.api_key, settings.api_secret))

	if resp.get("status") != "active":
		_throw()

def handle_subscription_notification(doctype, docname):
	call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname)<commit_msg>fix: if start date exist only then pass it while creating subscription<commit_after># -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

"""
# Integrating RazorPay

### Validate Currency

Example:

	from frappe.integrations.utils import get_payment_gateway_controller

	controller = get_payment_gateway_controller("Razorpay")
	controller().validate_transaction_currency(currency)

### 2. Redirect for payment

Example:

	payment_details = {
		"amount": 600,
		"title": "Payment for bill : 111",
		"description": "payment via cart",
		"reference_doctype": "Payment Request",
		"reference_docname": "PR0001",
		"payer_email": "NuranVerkleij@example.com",
		"payer_name": "Nuran Verkleij",
		"order_id": "111",
		"currency": "INR",
		"payment_gateway": "Razorpay",
		"subscription_details": {
			"plan_id": "plan_12313", # if Required
			"start_date": "2018-08-30",
			"billing_period": "Month" #(Day, Week, Month, Year),
			"billing_frequency": 1,
			"customer_notify": 1,
			"upfront_amount": 1000
		}
	}

	# Redirect the user to this url
	url = controller().get_payment_url(**payment_details)

### 3. On Completion of Payment

Write a method for `on_payment_authorized` in the reference doctype

Example:

	def on_payment_authorized(payment_status):
		# this method will be called when payment is complete

##### Notes:

payment_status - payment gateway will put payment status on callback.
For razorpay payment status is Authorized

"""

from __future__ import unicode_literals
import frappe
from frappe import _
import json
from six.moves.urllib.parse import urlencode
from frappe.model.document import Document
from frappe.utils import get_url, call_hook_method, cint, get_timestamp
from frappe.integrations.utils import (make_get_request, make_post_request, create_request_log,
	create_payment_gateway)

class RazorpaySettings(Document):
	supported_currencies = ["INR"]

	def validate(self):
		create_payment_gateway('Razorpay')
		call_hook_method('payment_gateway_enabled', gateway='Razorpay')
		if not self.flags.ignore_mandatory:
			self.validate_razorpay_credentails()

	def validate_razorpay_credentails(self):
		if self.api_key and self.api_secret:
			try:
				make_get_request(url="https://api.razorpay.com/v1/payments",
					auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)))
			except Exception:
				frappe.throw(_("Seems API Key or API Secret is wrong !!!"))

	def validate_transaction_currency(self, currency):
		if currency not in self.supported_currencies:
			frappe.throw(_("Please select another payment method. Razorpay does not support transactions in currency '{0}'").format(currency))

	def setup_addon(self, settings, **kwargs):
		"""
			Addon template:
			{
				"item": {
					"name": row.upgrade_type,
					"amount": row.amount,
					"currency": currency,
					"description": "add-on description"
				},
				"quantity": 1 (The total amount is calculated as item.amount * quantity)
			}
		"""
		url = "https://api.razorpay.com/v1/subscriptions/{0}/addons".format(kwargs.get('subscription_id'))

		try:
			if not frappe.conf.converted_rupee_to_paisa:
				convert_rupee_to_paisa(**kwargs)

			for addon in kwargs.get("addons"):
				resp = make_post_request(
					url,
					auth=(settings.api_key, settings.api_secret),
					data=json.dumps(addon),
					headers={
						"content-type": "application/json"
					}
				)
				if not resp.get('id'):
					frappe.log_error(str(resp), 'Razorpay Failed while creating subscription')
		except:
			frappe.log_error(frappe.get_traceback())
			# failed
			pass

	def setup_subscription(self, settings, **kwargs):
		start_date = get_timestamp(kwargs.get('subscription_details').get("start_date")) \
			if kwargs.get('subscription_details').get("start_date") else None

		subscription_details = {
			"plan_id": kwargs.get('subscription_details').get("plan_id"),
			"total_count": kwargs.get('subscription_details').get("billing_frequency"),
			"customer_notify": kwargs.get('subscription_details').get("customer_notify")
		}

		if start_date:
			subscription_details['start_at'] = cint(start_date)

		if kwargs.get('addons'):
			convert_rupee_to_paisa(**kwargs)
			subscription_details.update({
				"addons": kwargs.get('addons')
			})

		try:
			resp = make_post_request(
				"https://api.razorpay.com/v1/subscriptions",
				auth=(settings.api_key, settings.api_secret),
				data=json.dumps(subscription_details),
				headers={
					"content-type": "application/json"
				}
			)

			if resp.get('status') == 'created':
				kwargs['subscription_id'] = resp.get('id')
				frappe.flags.status = 'created'
				return kwargs
			else:
				frappe.log_error(str(resp), 'Razorpay Failed while creating subscription')

		except:
			frappe.log_error(frappe.get_traceback())
			# failed
			pass

	def prepare_subscription_details(self, settings, **kwargs):
		if not kwargs.get("subscription_id"):
			kwargs = self.setup_subscription(settings, **kwargs)

		if frappe.flags.status !='created':
			kwargs['subscription_id'] = None

		return kwargs

	def get_payment_url(self, **kwargs):
		integration_request = create_request_log(kwargs, "Host", "Razorpay")
		return get_url("./integrations/razorpay_checkout?token={0}".format(integration_request.name))

	def create_request(self, data):
		self.data = frappe._dict(data)

		try:
			self.integration_request = frappe.get_doc("Integration Request", self.data.token)
			self.integration_request.update_status(self.data, 'Queued')
			return self.authorize_payment()

		except Exception:
			frappe.log_error(frappe.get_traceback())
			return{
				"redirect_to": frappe.redirect_to_message(_('Server Error'), _("Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account.")),
				"status": 401
			}

	def authorize_payment(self):
		"""
		An authorization is performed when user’s payment details are successfully authenticated by the bank.
		The money is deducted from the customer’s account, but will not be transferred to the merchant’s account
		until it is explicitly captured by merchant.
		"""
		data = json.loads(self.integration_request.data)
		settings = self.get_settings(data)

		try:
			resp = make_get_request("https://api.razorpay.com/v1/payments/{0}"
				.format(self.data.razorpay_payment_id), auth=(settings.api_key,
					settings.api_secret))

			if resp.get("status") == "authorized":
				self.integration_request.update_status(data, 'Authorized')
				self.flags.status_changed_to = "Authorized"

			elif data.get('subscription_id'):
				if resp.get("status") == "refunded":
					# if subscription start date is in future then
					# razorpay refunds the amount after authorizing the card details
					# thus changing status to Verified

					self.integration_request.update_status(data, 'Completed')
					self.flags.status_changed_to = "Verified"

				if resp.get("status") == "captured":
					# if subscription starts immediately then
					# razorpay charge the actual amount
					# thus changing status to Completed

					self.integration_request.update_status(data, 'Completed')
					self.flags.status_changed_to = "Completed"

			else:
				frappe.log_error(str(resp), 'Razorpay Payment not authorized')

		except:
			frappe.log_error(frappe.get_traceback())
			# failed
			pass

		status = frappe.flags.integration_request.status_code

		redirect_to = data.get('notes', {}).get('redirect_to') or None
		redirect_message = data.get('notes', {}).get('redirect_message') or None

		if self.flags.status_changed_to in ("Authorized", "Verified", "Completed"):
			if self.data.reference_doctype and self.data.reference_docname:
				custom_redirect_to = None
				try:
					frappe.flags.data = data
					custom_redirect_to = frappe.get_doc(self.data.reference_doctype,
						self.data.reference_docname).run_method("on_payment_authorized", self.flags.status_changed_to)

				except Exception:
					frappe.log_error(frappe.get_traceback())

				if custom_redirect_to:
					redirect_to = custom_redirect_to

			redirect_url = 'payment-success?doctype={0}&docname={1}'.format(self.data.reference_doctype, self.data.reference_docname)
		else:
			redirect_url = 'payment-failed'

		if redirect_to:
			redirect_url += '&' + urlencode({'redirect_to': redirect_to})
		if redirect_message:
			redirect_url += '&' + urlencode({'redirect_message': redirect_message})

		return {
			"redirect_to": redirect_url,
			"status": status
		}

	def get_settings(self, data):
		settings = frappe._dict({
			"api_key": self.api_key,
			"api_secret": self.get_password(fieldname="api_secret", raise_exception=False)
		})

		if cint(data.get('notes', {}).get('use_sandbox')) or data.get("use_sandbox"):
			settings.update({
				"api_key": frappe.conf.sandbox_api_key,
				"api_secret": frappe.conf.sandbox_api_secret,
			})

		return settings

	def cancel_subscription(self, subscription_id):
		settings = self.get_settings({})

		try:
			resp = make_post_request("https://api.razorpay.com/v1/subscriptions/{0}/cancel"
				.format(subscription_id), auth=(settings.api_key,
					settings.api_secret))
		except Exception:
			frappe.log_error(frappe.get_traceback())

def capture_payment(is_sandbox=False, sanbox_response=None):
	"""
		Verifies the purchase as complete by the merchant.
		After capture, the amount is transferred to the merchant within T+3 days
		where T is the day on which payment is captured.

		Note: Attempting to capture a payment whose status is not authorized will produce an error.
	"""
	controller = frappe.get_doc("Razorpay Settings")

	for doc in frappe.get_all("Integration Request", filters={"status": "Authorized",
		"integration_request_service": "Razorpay"}, fields=["name", "data"]):
		try:
			if is_sandbox:
				resp = sanbox_response
			else:
				data = json.loads(doc.data)
				settings = controller.get_settings(data)

				resp = make_get_request("https://api.razorpay.com/v1/payments/{0}".format(data.get("razorpay_payment_id")),
					auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")})

				if resp.get('status') == "authorized":
					resp = make_post_request("https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")),
						auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")})

			if resp.get("status") == "captured":
				frappe.db.set_value("Integration Request", doc.name, "status", "Completed")

		except Exception:
			doc = frappe.get_doc("Integration Request", doc.name)
			doc.status = "Failed"
			doc.error = frappe.get_traceback()
			frappe.log_error(doc.error, '{0} Failed'.format(doc.name))

def convert_rupee_to_paisa(**kwargs):
	for addon in kwargs.get('addons'):
		addon['item']['amount'] *= 100

	frappe.conf.converted_rupee_to_paisa = True

@frappe.whitelist(allow_guest=True)
def razorpay_subscription_callback():
	try:
		data = frappe.local.form_dict

		validate_payment_callback(data)

		data.update({
			"payment_gateway": "Razorpay"
		})

		doc = frappe.get_doc({
			"data": json.dumps(frappe.local.form_dict),
			"doctype": "Integration Request",
			"integration_type": "Subscription Notification",
			"status": "Queued"
		}).insert(ignore_permissions=True)
		frappe.db.commit()

		frappe.enqueue(method='frappe.integrations.doctype.razorpay_settings.razorpay_settings.handle_subscription_notification',
			queue='long', timeout=600, is_async=True, **{"doctype": "Integration Request", "docname":  doc.name})

	except frappe.InvalidStatusError:
		pass
	except Exception as e:
		frappe.log(frappe.log_error(title=e))

def validate_payment_callback(data):
	def _throw():
		frappe.throw(_("Invalid Subscription"), exc=frappe.InvalidStatusError)

	subscription_id = data.get('payload').get("subscription").get("entity").get("id")

	if not(subscription_id):
		_throw()

	controller = frappe.get_doc("Razorpay Settings")

	settings = controller.get_settings(data)

	resp = make_get_request("https://api.razorpay.com/v1/subscriptions/{0}".format(subscription_id),
		auth=(settings.api_key, settings.api_secret))

	if resp.get("status") != "active":
		_throw()

def handle_subscription_notification(doctype, docname):
	call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname)<|endoftext|>


<commit_before>from irc3.plugins.command import command

from bytebot_config import BYTEBOT_PLUGIN_CONFIG
from irc3 import asyncio
import json
import aiohttp

from geopy.geocoders import Nominatim
from geopy.distance import vincenty

@command(permission="view")
@asyncio.coroutine
def fuel(bot, mask, target, args):
    """Show the current fuel for Erfurt

        %%fuel [<city> <value> <type>]...
    """
    config = BYTEBOT_PLUGIN_CONFIG['fuel']
    sort_type = 'all'
    sort_value = 'dist'
    lat = config['lat']
    lng = config['lng']
    fuel_types = ['e5', 'e10', 'diesel', 'all']

    if config['api_key'] == "your_apikey":
        return "I don't have your api key!"

    if '<city>' not in args or len(args['<city>']) < 1:
        bot.log.info('Fetching fuel info for Erfurt')
        lat = config['lat']
        lng = config['lng']

    else:
        if " ".join(args['<city>']) == 'sort':
            bot.log.info('Fetching fuel info for Erfurt')

            lat = config['lat']
            lng = config['lng']

            if '<value>' not in args or len(args['<value>']) < 1:
                sort_type = 'all'
                sort_value = 'dist'
            else:
                sort_type = " ".join(args['<value>'])
                sort_value = 'price'

        else:
            if " ".join(args['<city>']) == 'help':
                bot.log.info('Printing some Help')

                cmd = '!'
                bot.privmsg(target, '( ͡° ͜ʖ ͡°)')
                bot.privmsg(target, 'Example commands:')
                bot.privmsg(target, cmd + 'fuel')
                bot.privmsg(target, cmd + 'fuel help')
                bot.privmsg(target, cmd + 'fuel sort <fuel>')
                bot.privmsg(target, cmd + 'fuel <place>')
                bot.privmsg(target, cmd + 'fuel <place> sort <fuel>')

                return ""

            else:
                bot.log.info('Fetching fuel info for ' +
                             str(" ".join(args['<city>'])))

                geolocator = Nominatim()
                location = geolocator.geocode(" ".join(args['<city>']))
                lat = location.latitude
                lng = location.longitude

                if " ".join(args['<value>']) == 'sort':
                    if '<type>' not in args or len(args['<type>']) < 1:
                        sort_type = 'all'
                        sort_value = 'dist'
                    else:
                        sort_type = " ".join(args['<type>'])
                        sort_value = 'price'

    if sort_type not in fuel_types:
        return "Not supported fuel."

    try:
        url = "https://creativecommons.tankerkoenig.de/json/list.php?" + \
            "lat=" + str(lat) + \
            "&lng=" + str(lng) + \
            "&rad=" + str(config['rad']) + \
            "&sort=" + str(sort_value) + \
            "&type=" + str(sort_type) + \
            "&apikey=" + str(config['api_key'])

        with aiohttp.Timeout(10):
            with aiohttp.ClientSession(loop=bot.loop) as session:
                resp = yield from session.get(url)
                if resp.status != 200:
                    bot.privmsg(target, "Error while retrieving station list")
                    raise Exception()
                r = yield from resp.read()

        data = json.loads(r.decode('utf-8'))

        messages = []
        for x in range(len(data['stations'])):
            brand = data[u'stations'][x][u"brand"]
            station_id = data['stations'][x][u"id"]
            postCode = data['stations'][x][u"postCode"]

            bot.log.info('Fetching fuel info for Erfurt station ' +
                         str(station_id))
            url = \
                "https://creativecommons.tankerkoenig.de/json/detail.php?" + \
                "id=" + station_id + \
                "&apikey=" + str(config['api_key'])

            with aiohttp.Timeout(10):
                with aiohttp.ClientSession(loop=bot.loop) as session:
                    resp = yield from session.get(url)
                    if resp.status != 200:
                        bot.privmsg(target, "Error while retrieving fuel data")
                        raise Exception()
                    r = yield from resp.read()

            details = json.loads(r.decode('utf-8'))

            e5 = str(details['station']['e5'])
            e10 = str(details['station']['e10'])
            diesel = str(details['station']['diesel'])

            dist = u"{:0.2} km".format(vincenty((details['station']['lat'],
                                                 details['station']['lng']),
                                                (lat, lng)).meters / 1000)

            if brand == '':
                brand = 'GLOBUS'

            print_str = \
                u"   {:20}".format(brand + ', ' + str(postCode) + ': ') + \
                u"{:5}  ".format(e5) + \
                u"{:5}  ".format(e10) + \
                u"{:5}  ".format(diesel) + \
                u"{:5}  ".format(dist)

            messages.append(print_str)

        headline = u"{:23}".format('fuel prices:') + \
            u"{:6} ".format('e5') + \
            u"{:6} ".format('e10') + \
            u"{:6} ".format('diesel') + \
            u"{:6} ".format('dist')

        if len(messages) > 0:
            bot.privmsg(target, headline)
            for m in messages:
                bot.privmsg(target, m)
        else:
            return "No fuel data found!"

    except KeyError:
        bot.privmsg(target, "Error while retrieving fuel data")
        raise Exception()
<commit_msg>extending examples<commit_after>from irc3.plugins.command import command

from bytebot_config import BYTEBOT_PLUGIN_CONFIG
from irc3 import asyncio
import json
import aiohttp

from geopy.geocoders import Nominatim
from geopy.distance import vincenty

@command(permission="view")
@asyncio.coroutine
def fuel(bot, mask, target, args):
    """Show the current fuel for Erfurt

        %%fuel [<city> <value> <type>]...
    """
    config = BYTEBOT_PLUGIN_CONFIG['fuel']
    sort_type = 'all'
    sort_value = 'dist'
    lat = config['lat']
    lng = config['lng']
    fuel_types = ['e5', 'e10', 'diesel', 'all']

    if config['api_key'] == "your_apikey":
        return "I don't have your api key!"

    if '<city>' not in args or len(args['<city>']) < 1:
        bot.log.info('Fetching fuel info for Erfurt')
        lat = config['lat']
        lng = config['lng']

    else:
        if " ".join(args['<city>']) == 'sort':
            bot.log.info('Fetching fuel info for Erfurt')

            lat = config['lat']
            lng = config['lng']

            if '<value>' not in args or len(args['<value>']) < 1:
                sort_type = 'all'
                sort_value = 'dist'
            else:
                sort_type = " ".join(args['<value>'])
                sort_value = 'price'

        else:
            if " ".join(args['<city>']) == 'help':
                bot.log.info('Printing some Help')

                cmd = '!'
                bot.privmsg(target, '( ͡° ͜ʖ ͡°)')
                bot.privmsg(target, 'Example commands:')
                bot.privmsg(target, cmd + 'fuel')
                bot.privmsg(target, cmd + 'fuel help')
                bot.privmsg(target, cmd + 'fuel sort <fuel>')
                bot.privmsg(target, cmd + 'fuel sort e5')
                bot.privmsg(target, cmd + 'fuel sort e10')
                bot.privmsg(target, cmd + 'fuel sort diesel')
                bot.privmsg(target, cmd + 'fuel <place>')
                bot.privmsg(target, cmd + 'fuel erfurt')
                bot.privmsg(target, cmd + 'fuel <place> sort <fuel>')
                bot.privmsg(target, cmd + 'fuel erfurt sort e5')
                bot.privmsg(target, cmd + 'fuel bytespeicher sort e10')
                bot.privmsg(target, cmd + 'fuel krautspace sort diesel')

                return ""

            else:
                bot.log.info('Fetching fuel info for ' +
                             str(" ".join(args['<city>'])))

                geolocator = Nominatim()
                location = geolocator.geocode(" ".join(args['<city>']))
                lat = location.latitude
                lng = location.longitude

                if " ".join(args['<value>']) == 'sort':
                    if '<type>' not in args or len(args['<type>']) < 1:
                        sort_type = 'all'
                        sort_value = 'dist'
                    else:
                        sort_type = " ".join(args['<type>'])
                        sort_value = 'price'

    if sort_type not in fuel_types:
        return "Not supported fuel."

    try:
        url = "https://creativecommons.tankerkoenig.de/json/list.php?" + \
            "lat=" + str(lat) + \
            "&lng=" + str(lng) + \
            "&rad=" + str(config['rad']) + \
            "&sort=" + str(sort_value) + \
            "&type=" + str(sort_type) + \
            "&apikey=" + str(config['api_key'])

        with aiohttp.Timeout(10):
            with aiohttp.ClientSession(loop=bot.loop) as session:
                resp = yield from session.get(url)
                if resp.status != 200:
                    bot.privmsg(target, "Error while retrieving station list")
                    raise Exception()
                r = yield from resp.read()

        data = json.loads(r.decode('utf-8'))

        messages = []
        for x in range(len(data['stations'])):
            brand = data[u'stations'][x][u"brand"]
            station_id = data['stations'][x][u"id"]
            postCode = data['stations'][x][u"postCode"]

            bot.log.info('Fetching fuel info for Erfurt station ' +
                         str(station_id))
            url = \
                "https://creativecommons.tankerkoenig.de/json/detail.php?" + \
                "id=" + station_id + \
                "&apikey=" + str(config['api_key'])

            with aiohttp.Timeout(10):
                with aiohttp.ClientSession(loop=bot.loop) as session:
                    resp = yield from session.get(url)
                    if resp.status != 200:
                        bot.privmsg(target, "Error while retrieving fuel data")
                        raise Exception()
                    r = yield from resp.read()

            details = json.loads(r.decode('utf-8'))

            e5 = str(details['station']['e5'])
            e10 = str(details['station']['e10'])
            diesel = str(details['station']['diesel'])

            dist = u"{:0.2} km".format(vincenty((details['station']['lat'],
                                                 details['station']['lng']),
                                                (lat, lng)).meters / 1000)

            if brand == '':
                brand = 'GLOBUS'

            print_str = \
                u"   {:20}".format(brand + ', ' + str(postCode) + ': ') + \
                u"{:5}  ".format(e5) + \
                u"{:5}  ".format(e10) + \
                u"{:5}  ".format(diesel) + \
                u"{:5}  ".format(dist)

            messages.append(print_str)

        headline = u"{:23}".format('fuel prices:') + \
            u"{:6} ".format('e5') + \
            u"{:6} ".format('e10') + \
            u"{:6} ".format('diesel') + \
            u"{:6} ".format('dist')

        if len(messages) > 0:
            bot.privmsg(target, headline)
            for m in messages:
                bot.privmsg(target, m)
        else:
            return "No fuel data found!"

    except KeyError:
        bot.privmsg(target, "Error while retrieving fuel data")
        raise Exception()
<|endoftext|>


<commit_before>#!/usr/bin/python3

import os
import random
import binascii
import string

root_fldr = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) )

dat_fldr = root_fldr + os.sep + 'data'
names    = dat_fldr + os.sep + 'names.csv'  # http://www.cs.princeton.edu/introcs/data/names.csv
places   = dat_fldr + os.sep + 'countries.csv'
wordList = dat_fldr + os.sep + 'nouns.txt'

def TEST():
    print('generate.py')
    print('Creates random data and strings in various formats')
    s = StringGenerator()
    print('Random Strings....\n  ', s.random_hex_string(20), '\n  ', s.random_letters(50))
    print('Random Block ....')
    print(s.random_block(30,11))
    print('Data Table ....')
    colLabel = ['DATE', 'name', 'password', 'Born',  'Quote', 'Score']
    colTypes = ['DATE', 'PEOPLE', 'STRING', 'PLACE', 'WORD',  'INT']
    tbl = TableGenerator(5, colTypes, colLabel)
    print(tbl)
    #save_table(tbl, 'test123.csv')
    print('password generator = ', s.generate_password(10))

    n = NumberGenerator('fives')
    print('random_currency = ', n.random_currency(45, 88))
    amounts_paid = []
    for _ in range(1,20):
        amounts_paid.append(n.random_currency())

    # table with a custom list
    custom_list = ['Carved Statue', '1984 Volvo', '2 metre Ball of string']
    tbl = TableGenerator(8, ['PEOPLE', 'INT', custom_list, amounts_paid], ['Name', 'Age', 'Fav Possession', 'Transaction Cost'])
    print(tbl)

    # random equation generator, and maths calculations
    f = FunctionGenerator(mult_range=[-3,5], exp_range=[0,3], num_terms=3)
    print(f)
    for i in range(5):
        params = [n.random_int(i,i+5), n.random_int(i,i+5), n.random_int(i,i+5)]
        c = FunctionCalculator(f, params, i)
        print(c)

class Structure(object):
    """
    core container to manager data generation
    structures
    """
    pass

class NumberGenerator(Structure):
    """
    Creates a random currency value based on likely
    cent values
    """
    def __init__(self, cents='Normal'):
        """
        pass a random choice cent selection
        """
        if cents == 'Normal':
            self.cent_choices = ['00','00','00','00','10','50','95','95','95','98','99','99']
        elif cents == 'fives':
            self.cent_choices = ['{:0>2}'.format(c) for c in range(0,99,5)]
        else:
            self.cent_choices = ['{:0>2}'.format(c) for c in range(0,99)]

    def random_int(self, min_v=0, max_v=100):
        return random.randrange(min_v, max_v)

    def random_currency(self, start=9, end=499.9999979797):
        cents = random.choice(self.cent_choices)
        if end == 499.9999979797:
            end = 499
            sign = random.choice(['$','', '+$', '+'])
        else:
            sign = random.choice(['$', '+$', '-$', '-', '', '$ ', ''])
        dollars = random.randint(start,end)
        return sign + str(dollars) + '.' + cents

class StringGenerator(Structure):
    """
    generates random strings
    """
    def random_letters(self, sze=20):
        lst = [random.choice(string.ascii_letters + string.digits) for _ in range(sze)]
        return "".join(lst)

    def generate_password(self, sze=18):
        if sze < 8: sze = 8
        first_half = sze - 6
        n = NumberGenerator()
        return self.random_letters(first_half).lower() + str(n.random_int(10,99)) + self.random_letters(4).upper()

    def random_hex_string(self, sze=30):
        return binascii.b2a_hex(os.urandom(sze))

    def random_block(self, cols=40, rows=5):
        return ''.join([self.random_letters(cols) + '\n' for _ in range(0,rows)])

class FunctionGenerator(object):
    """
    generates a random polynomial function
    """
    def __init__(self, mult_range, exp_range, num_terms=3):
        if num_terms is None:
            num_terms = random.randint(2, 9)
        self.num_terms = num_terms
        self.equation = ''
        self.mult = [random.randint(mult_range[0], mult_range[1] ) for _ in range(self.num_terms + 1)]
        self.expt = [random.randint(exp_range[0], exp_range[1]) for _ in range(self.num_terms + 1)]

        for i in range(self.num_terms):
            letter = chr(97 + i)
            sign = ''
            if self.mult[i] >= 0:
                if i > 0:
                    sign = '+'
            self.equation += sign + str(self.mult[i]) + letter + '^' + str(self.expt[i])

    def __str__(self):
        return 'Equation   : ' + self.equation

class FunctionCalculator(object):
    """
    uses a FunctionGenerator object 'func' to
    run calculations over a set of parameters
    PARAMETERS:
        func    : FunctionGenerator() object
        params  : [3, 4, 1] # list with ONE value per term (x,y,z...)
        test_id : optional integer for naming when logging
    USAGE:
        f = FunctionGenerator(mult_range=[-9,9], exp_range=[0,5], num_terms=3)
        print(f)
        for i in range(5):
            c = FunctionCalculator(f, [n.random_int(), n.random_int(), n.random_int()], i)
            print(c)
    RETURNS:
        Equation   : 7x^5 -1x^4 -6x^1
        Parameters : 1,4,7 => answer     : -249.000000000
        Parameters : 8,8,0 => answer     : 225280.000000000
        Parameters : 4,3,5 => answer     : 7087.000000000
        Parameters : 1,8,2 => answer     : -4089.000000000
        Parameters : 7,3,8 => answer     : 117568.000000000
    """
    def __init__(self, func, params, test_id=1):
        self.test_id = 'math_test_' + str(test_id)
        if len(params) != func.num_terms:
            assert('Error first parameter not equal to number of terms of function')
        self.params = params
        ans = 0
        #for param_num, p in enumerate(self.params):
        for i in range(func.num_terms - 1):
            ans += func.mult[i] * params[i] ** func.expt[i]
        #self.answer = '%.9f' %ans
        self.answer = str(ans)

    def __str__(self):
        res = 'Parameters : '
        res += ','.join([chr(97 + i) + '=' + str(t) for i,t in enumerate(self.params)]) + ' => '
        res += 'answer     : ' + self.answer # + '\n'
        return res

class TableGenerator(Structure):
    """
    holds a table and manages the cleaning and
    creation of DQ issues
    """
    def __init__(self, tot_rows, col_types, col_label):
        self.tot_rows = tot_rows
        self.col_types = col_types
        col_label = col_label
        self.tbl = []
        s = StringGenerator()
        n = NumberGenerator()
        # verify the col_types required and assign defaults to empty sets
        cols = len(col_types)
        #colTypes = fill_colList_blanks(col_types, cols)
        colTypes = col_types

        #print('Generating columns - ', colTypes)
        wordLists = load_lists(colTypes)
        self.tbl.insert(0, col_label) # column headers
        for _ in range(0,tot_rows):
            thisRow = []
            txt = ''
            for c in range(0, cols):
                if colTypes[c] == 'INT':
                    txt = str(n.random_int())
                elif colTypes[c] == 'STRING':
                    txt = s.random_letters()
                elif colTypes[c] == 'CURRENCY':
                    txt = n.random_currency(9, 499)
                elif isinstance((colTypes[c]), (list, tuple)):
                    # getting random data from passed list
                    txt = get_rand_text_from_list(colTypes[c])
                else:
                    for lst in wordLists:
                        if lst['name'] != 'INT':
                            if lst['name'] == colTypes[c]:
                                txt = get_rand_text_from_list(lst['lst'])
                thisRow.append(txt)
            self.tbl.append(thisRow)

    def __str__(self):
        txt = '\n'.join(','.join([col if type(col) is str else str(col) for col in row]) for row in self.tbl)
        return txt

    def get_column(self, ndx):
        res = []
        for r in self.tbl:
            res.append(r[ndx])
        return res

    def save_table(self,  fname, delim=',', qu='"'):
        with open(fname, "wt") as f:
            f.write('\n'.join(delim.join([qu + col + qu if type(col) is str else qu + str(col) + qu for col in row]) for row in self.tbl))

def get_list_string(num = 40):
    s = StringGenerator()
    return [s.random_letters(num) for _ in range(0,100)]

def get_rand_text_from_list(lst):
    return lst[random.randrange(0, len(lst))]

def fill_colList_blanks(partialCols, numRequiredCols):
    """
    no idea why this function is here - probably at start
    when trying to autofill table, but it needs to go
    """
    colWord = []
    num = 0
    for _ in range(0, numRequiredCols):
        tpe = partialCols[num]
        if tpe == '':
            tpe = 'STRING'
        colWord.append(tpe)
        num = num + 1
    return colWord

def load_lists(lst):
    """
    loads a sample of data for each type in lst
        l =  PEOPLE
        l =  INT
        l =  ['Carved Statue', '1984 Volvo', '2 metre Ball of string']

    lists_to_load = {l for l in lst}	# get unique list of types so only loading them once each
    """
    results = []
    lists_to_load = []
    for l in lst:
        #print(' l = ', l)
        if isinstance(l, (list, tuple)):
            results.append({'name': 'LIST', 'lst': l})
        else:
            lists_to_load.append(l)

    for tpe in lists_to_load:
        if tpe == 'STRING2':
            results.append({'name': 'STRING', 'lst': get_list_string(40)})
        if tpe == 'STRING':
            results.append({'name': 'STRING', 'lst': get_list_string()})
        if tpe == 'WORD':
            results.append({'name': 'WORD', 'lst': get_list_words()})
        if tpe == 'DATE':
            results.append({'name': 'DATE', 'lst': get_list_dates()})
        if tpe == 'PLACE':
            results.append({'name': 'PLACE', 'lst': get_list_places()})
        if tpe == 'PEOPLE':
            results.append({'name': 'PEOPLE', 'lst': get_list_people()})
    return results

def get_list_from_file(fname, col_name):
    """
    reads a file and returns the list of values
    from the column col_name
    """
    col_ndx = 0
    lst = []
    with open(fname, 'r') as f:
        line = f.readline()
        hdrs = line.split(',')
        for num, c in enumerate(hdrs):
            if c = col_name:
                col_ndx = num

        # now read the rest
        for line in f:
            cols = line.split(',')
            lst.append(col[col_ndx])
    return lst

def get_list_words():
    """
    reads wordnet to get a unique list of nouns
    """
    with open(wordList) as f:
        return [line.strip().replace('_', ' ') for line in f if random.randrange(1,100) > 90]

def get_list_dates(start_date=1985, end_date=2015):
    """
    picks a random year
    """
    return [i for i in range(start_date, end_date)]

def get_list_places():
    """
    picks a random country
    """
    with open(places) as f:
        return [line.split(',')[2].strip().strip('"').title() for line in f]

def get_list_people():
    """
    chooses a random name from names.csv
    """
    with open(names) as f:
        return [line.split(',')[0].title() for line in f]

if __name__ == '__main__':
    TEST()

<commit_msg>bug fix, == not =<commit_after>#!/usr/bin/python3

import os
import random
import binascii
import string

root_fldr = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) )

dat_fldr = root_fldr + os.sep + 'data'
names    = dat_fldr + os.sep + 'names.csv'  # http://www.cs.princeton.edu/introcs/data/names.csv
places   = dat_fldr + os.sep + 'countries.csv'
wordList = dat_fldr + os.sep + 'nouns.txt'

def TEST():
    print('generate.py')
    print('Creates random data and strings in various formats')
    s = StringGenerator()
    print('Random Strings....\n  ', s.random_hex_string(20), '\n  ', s.random_letters(50))
    print('Random Block ....')
    print(s.random_block(30,11))
    print('Data Table ....')
    colLabel = ['DATE', 'name', 'password', 'Born',  'Quote', 'Score']
    colTypes = ['DATE', 'PEOPLE', 'STRING', 'PLACE', 'WORD',  'INT']
    tbl = TableGenerator(5, colTypes, colLabel)
    print(tbl)
    #save_table(tbl, 'test123.csv')
    print('password generator = ', s.generate_password(10))

    n = NumberGenerator('fives')
    print('random_currency = ', n.random_currency(45, 88))
    amounts_paid = []
    for _ in range(1,20):
        amounts_paid.append(n.random_currency())

    # table with a custom list
    custom_list = ['Carved Statue', '1984 Volvo', '2 metre Ball of string']
    tbl = TableGenerator(8, ['PEOPLE', 'INT', custom_list, amounts_paid], ['Name', 'Age', 'Fav Possession', 'Transaction Cost'])
    print(tbl)

    # random equation generator, and maths calculations
    f = FunctionGenerator(mult_range=[-3,5], exp_range=[0,3], num_terms=3)
    print(f)
    for i in range(5):
        params = [n.random_int(i,i+5), n.random_int(i,i+5), n.random_int(i,i+5)]
        c = FunctionCalculator(f, params, i)
        print(c)

class Structure(object):
    """
    core container to manager data generation
    structures
    """
    pass

class NumberGenerator(Structure):
    """
    Creates a random currency value based on likely
    cent values
    """
    def __init__(self, cents='Normal'):
        """
        pass a random choice cent selection
        """
        if cents == 'Normal':
            self.cent_choices = ['00','00','00','00','10','50','95','95','95','98','99','99']
        elif cents == 'fives':
            self.cent_choices = ['{:0>2}'.format(c) for c in range(0,99,5)]
        else:
            self.cent_choices = ['{:0>2}'.format(c) for c in range(0,99)]

    def random_int(self, min_v=0, max_v=100):
        return random.randrange(min_v, max_v)

    def random_currency(self, start=9, end=499.9999979797):
        cents = random.choice(self.cent_choices)
        if end == 499.9999979797:
            end = 499
            sign = random.choice(['$','', '+$', '+'])
        else:
            sign = random.choice(['$', '+$', '-$', '-', '', '$ ', ''])
        dollars = random.randint(start,end)
        return sign + str(dollars) + '.' + cents

class StringGenerator(Structure):
    """
    generates random strings
    """
    def random_letters(self, sze=20):
        lst = [random.choice(string.ascii_letters + string.digits) for _ in range(sze)]
        return "".join(lst)

    def generate_password(self, sze=18):
        if sze < 8: sze = 8
        first_half = sze - 6
        n = NumberGenerator()
        return self.random_letters(first_half).lower() + str(n.random_int(10,99)) + self.random_letters(4).upper()

    def random_hex_string(self, sze=30):
        return binascii.b2a_hex(os.urandom(sze))

    def random_block(self, cols=40, rows=5):
        return ''.join([self.random_letters(cols) + '\n' for _ in range(0,rows)])

class FunctionGenerator(object):
    """
    generates a random polynomial function
    """
    def __init__(self, mult_range, exp_range, num_terms=3):
        if num_terms is None:
            num_terms = random.randint(2, 9)
        self.num_terms = num_terms
        self.equation = ''
        self.mult = [random.randint(mult_range[0], mult_range[1] ) for _ in range(self.num_terms + 1)]
        self.expt = [random.randint(exp_range[0], exp_range[1]) for _ in range(self.num_terms + 1)]

        for i in range(self.num_terms):
            letter = chr(97 + i)
            sign = ''
            if self.mult[i] >= 0:
                if i > 0:
                    sign = '+'
            self.equation += sign + str(self.mult[i]) + letter + '^' + str(self.expt[i])

    def __str__(self):
        return 'Equation   : ' + self.equation

class FunctionCalculator(object):
    """
    uses a FunctionGenerator object 'func' to
    run calculations over a set of parameters
    PARAMETERS:
        func    : FunctionGenerator() object
        params  : [3, 4, 1] # list with ONE value per term (x,y,z...)
        test_id : optional integer for naming when logging
    USAGE:
        f = FunctionGenerator(mult_range=[-9,9], exp_range=[0,5], num_terms=3)
        print(f)
        for i in range(5):
            c = FunctionCalculator(f, [n.random_int(), n.random_int(), n.random_int()], i)
            print(c)
    RETURNS:
        Equation   : 7x^5 -1x^4 -6x^1
        Parameters : 1,4,7 => answer     : -249.000000000
        Parameters : 8,8,0 => answer     : 225280.000000000
        Parameters : 4,3,5 => answer     : 7087.000000000
        Parameters : 1,8,2 => answer     : -4089.000000000
        Parameters : 7,3,8 => answer     : 117568.000000000
    """
    def __init__(self, func, params, test_id=1):
        self.test_id = 'math_test_' + str(test_id)
        if len(params) != func.num_terms:
            assert('Error first parameter not equal to number of terms of function')
        self.params = params
        ans = 0
        #for param_num, p in enumerate(self.params):
        for i in range(func.num_terms - 1):
            ans += func.mult[i] * params[i] ** func.expt[i]
        #self.answer = '%.9f' %ans
        self.answer = str(ans)

    def __str__(self):
        res = 'Parameters : '
        res += ','.join([chr(97 + i) + '=' + str(t) for i,t in enumerate(self.params)]) + ' => '
        res += 'answer     : ' + self.answer # + '\n'
        return res

class TableGenerator(Structure):
    """
    holds a table and manages the cleaning and
    creation of DQ issues
    """
    def __init__(self, tot_rows, col_types, col_label):
        self.tot_rows = tot_rows
        self.col_types = col_types
        col_label = col_label
        self.tbl = []
        s = StringGenerator()
        n = NumberGenerator()
        # verify the col_types required and assign defaults to empty sets
        cols = len(col_types)
        #colTypes = fill_colList_blanks(col_types, cols)
        colTypes = col_types

        #print('Generating columns - ', colTypes)
        wordLists = load_lists(colTypes)
        self.tbl.insert(0, col_label) # column headers
        for _ in range(0,tot_rows):
            thisRow = []
            txt = ''
            for c in range(0, cols):
                if colTypes[c] == 'INT':
                    txt = str(n.random_int())
                elif colTypes[c] == 'STRING':
                    txt = s.random_letters()
                elif colTypes[c] == 'CURRENCY':
                    txt = n.random_currency(9, 499)
                elif isinstance((colTypes[c]), (list, tuple)):
                    # getting random data from passed list
                    txt = get_rand_text_from_list(colTypes[c])
                else:
                    for lst in wordLists:
                        if lst['name'] != 'INT':
                            if lst['name'] == colTypes[c]:
                                txt = get_rand_text_from_list(lst['lst'])
                thisRow.append(txt)
            self.tbl.append(thisRow)

    def __str__(self):
        txt = '\n'.join(','.join([col if type(col) is str else str(col) for col in row]) for row in self.tbl)
        return txt

    def get_column(self, ndx):
        res = []
        for r in self.tbl:
            res.append(r[ndx])
        return res

    def save_table(self,  fname, delim=',', qu='"'):
        with open(fname, "wt") as f:
            f.write('\n'.join(delim.join([qu + col + qu if type(col) is str else qu + str(col) + qu for col in row]) for row in self.tbl))

def get_list_string(num = 40):
    s = StringGenerator()
    return [s.random_letters(num) for _ in range(0,100)]

def get_rand_text_from_list(lst):
    return lst[random.randrange(0, len(lst))]

def fill_colList_blanks(partialCols, numRequiredCols):
    """
    no idea why this function is here - probably at start
    when trying to autofill table, but it needs to go
    """
    colWord = []
    num = 0
    for _ in range(0, numRequiredCols):
        tpe = partialCols[num]
        if tpe == '':
            tpe = 'STRING'
        colWord.append(tpe)
        num = num + 1
    return colWord

def load_lists(lst):
    """
    loads a sample of data for each type in lst
        l =  PEOPLE
        l =  INT
        l =  ['Carved Statue', '1984 Volvo', '2 metre Ball of string']

    lists_to_load = {l for l in lst}	# get unique list of types so only loading them once each
    """
    results = []
    lists_to_load = []
    for l in lst:
        #print(' l = ', l)
        if isinstance(l, (list, tuple)):
            results.append({'name': 'LIST', 'lst': l})
        else:
            lists_to_load.append(l)

    for tpe in lists_to_load:
        if tpe == 'STRING2':
            results.append({'name': 'STRING', 'lst': get_list_string(40)})
        if tpe == 'STRING':
            results.append({'name': 'STRING', 'lst': get_list_string()})
        if tpe == 'WORD':
            results.append({'name': 'WORD', 'lst': get_list_words()})
        if tpe == 'DATE':
            results.append({'name': 'DATE', 'lst': get_list_dates()})
        if tpe == 'PLACE':
            results.append({'name': 'PLACE', 'lst': get_list_places()})
        if tpe == 'PEOPLE':
            results.append({'name': 'PEOPLE', 'lst': get_list_people()})
    return results

def get_list_from_file(fname, col_name):
    """
    reads a file and returns the list of values
    from the column col_name
    """
    col_ndx = 0
    lst = []
    with open(fname, 'r') as f:
        line = f.readline()
        hdrs = line.split(',')
        for num, c in enumerate(hdrs):
            if c == col_name:
                col_ndx = num

        # now read the rest
        for line in f:
            cols = line.split(',')
            lst.append(col[col_ndx])
    return lst

def get_list_words():
    """
    reads wordnet to get a unique list of nouns
    """
    with open(wordList) as f:
        return [line.strip().replace('_', ' ') for line in f if random.randrange(1,100) > 90]

def get_list_dates(start_date=1985, end_date=2015):
    """
    picks a random year
    """
    return [i for i in range(start_date, end_date)]

def get_list_places():
    """
    picks a random country
    """
    with open(places) as f:
        return [line.split(',')[2].strip().strip('"').title() for line in f]

def get_list_people():
    """
    chooses a random name from names.csv
    """
    with open(names) as f:
        return [line.split(',')[0].title() for line in f]

if __name__ == '__main__':
    TEST()

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Created on Sat Apr 19 16:20:55 2014

@author: pacif_000
"""
import os
import simplejson
import logging
from bson.objectid import ObjectId
from twisted.web import server
from twisted.internet import reactor

from deffered_resource import DefferedResource
import monk.core.api as monkapi
import monk.core.constants as cons
import monk.core.configuration as Config

from monk.utils.utils import DateTimeEncoder

config = Config.Configuration("executor.yml", "executorREST", str(os.getpid()))
monkapi.initialize(config)
logger = logging.getLogger("monk.executor")

class MonkAPI(DefferedResource):
    def __del__(self):
        monkapi.exits()

class Recommend(DefferedResource):
    isLeaf = True
    def __init__(self, turtleId=None, delayTime=0.0):
        DefferedResource.__init__(self, delayTime)
        self.defaultTurtleId = turtleId
        self.defaultUserContext = {'userId' : cons.DEFAULT_USER}

    def _filter(self, ent, fields):
        if fields:
            return {field:getattr(ent, field, '') for field in fields}
        else:
            return ent.generic()

    def _recommend(self, args):
        try:
            if 'turtleId' in args:
                turtleId = ObjectId(args['turtleId'][0])
            else:
                turtleId = ObjectId(self.defaultTurtleId)
            if 'userContext' in args:
                userContext = simplejson.loads(args.get('userContext')[0])
            else:
                userContext = self.defaultUserContext
            userId = userContext['userId']
            if 'query' in args:
                query = simplejson.loads(args.get('query')[0])
            else:
                query = {}
            if 'num' in args:
                num = int(args.get('num')[0])
            else:
                num = 10
            if 'fields' in args:
                fields = args['fields'][0].split(',')
            else:
                fields = None
            if not monkapi.has_one(turtleId, userId):
                if not monkapi.has_one_in_store(turtleId, userId):
                    monkapi.add_one(turtleId, userId)
                else:
                    monkapi.load_one(turtleId, userId)
            entityCollectionName = monkapi.entity_collection(turtleId)
            ents = monkapi.load_entities(None, query, num * 10, entityCollectionName)
            # @todo: add user_context features
            results = [(monkapi.predict(turtleId, userId, ent), ent) for ent in ents]
            results.sort(reverse=True)
        except Exception as e:
            logger.error(e.message)
            logger.error('can not parse request {0}'.format(args))
            results = []
        return [self._filter(res[1], fields) for res in results]

    def _delayedRender_GET(self, request):
        logger.info('request {0}'.format(request.args))
        results = self._recommend(request.args)
        simplejson.dump(results, request, cls=DateTimeEncoder)
        request.finish()

    def _delayedRender_POST(self, request):
        logger.info('request {0}'.format(request.args))
        results = self._recommend(request.args)
        simplejson.dump(results, request, cls=DateTimeEncoder)
        request.finish()

root = MonkAPI()
root.putChild("recommend", Recommend())
root.putChild("recommendTags", Recommend("5338c7562524830c64a2d599"))

site = server.Site(root, "web.log")
reactor.listenTCP(8080, site)
reactor.run()
<commit_msg>change fields url format to json<commit_after># -*- coding: utf-8 -*-
"""
Created on Sat Apr 19 16:20:55 2014

@author: pacif_000
"""
import os
import simplejson
import logging
from bson.objectid import ObjectId
from twisted.web import server
from twisted.internet import reactor

from deffered_resource import DefferedResource
import monk.core.api as monkapi
import monk.core.constants as cons
import monk.core.configuration as Config

from monk.utils.utils import DateTimeEncoder

config = Config.Configuration("executor.yml", "executorREST", str(os.getpid()))
monkapi.initialize(config)
logger = logging.getLogger("monk.executor")

class MonkAPI(DefferedResource):
    def __del__(self):
        monkapi.exits()

class Recommend(DefferedResource):
    isLeaf = True
    def __init__(self, turtleId=None, delayTime=0.0):
        DefferedResource.__init__(self, delayTime)
        self.defaultTurtleId = turtleId
        self.defaultUserContext = {'userId' : cons.DEFAULT_USER}

    def _filter(self, ent, fields):
        if fields:
            return {field:getattr(ent, field, '') for field in fields}
        else:
            return ent.generic()

    def _recommend(self, args):
        try:
            if 'turtleId' in args:
                turtleId = ObjectId(args['turtleId'][0])
            else:
                turtleId = ObjectId(self.defaultTurtleId)
            if 'userContext' in args:
                userContext = simplejson.loads(args.get('userContext')[0])
            else:
                userContext = self.defaultUserContext
            userId = userContext['userId']
            if 'query' in args:
                query = simplejson.loads(args.get('query')[0])
            else:
                query = {}
            if 'num' in args:
                num = int(args.get('num')[0])
            else:
                num = 10
            if 'fields' in args:
                fields = simplejson.loads(args['fields'][0])
            else:
                fields = None
            if not monkapi.has_one(turtleId, userId):
                if not monkapi.has_one_in_store(turtleId, userId):
                    monkapi.add_one(turtleId, userId)
                else:
                    monkapi.load_one(turtleId, userId)
            entityCollectionName = monkapi.entity_collection(turtleId)
            ents = monkapi.load_entities(None, query, num * 10, entityCollectionName)
            # @todo: add user_context features
            results = [(monkapi.predict(turtleId, userId, ent), ent) for ent in ents]
            results.sort(reverse=True)
        except Exception as e:
            logger.error(e.message)
            logger.error('can not parse request {0}'.format(args))
            results = []
        return [self._filter(res[1], fields) for res in results]

    def _delayedRender_GET(self, request):
        logger.info('request {0}'.format(request.args))
        results = self._recommend(request.args)
        simplejson.dump(results, request, cls=DateTimeEncoder)
        request.finish()

    def _delayedRender_POST(self, request):
        logger.info('request {0}'.format(request.args))
        results = self._recommend(request.args)
        simplejson.dump(results, request, cls=DateTimeEncoder)
        request.finish()

root = MonkAPI()
root.putChild("recommend", Recommend())
root.putChild("recommendTags", Recommend("5338c7562524830c64a2d599"))

site = server.Site(root, "web.log")
reactor.listenTCP(8080, site)
reactor.run()
<|endoftext|>


<commit_before>from django.conf.urls import patterns, include, url
from django.contrib import admin
from imager import settings
from django.conf import settings as dcs
from django.conf.urls.static import static

urlpatterns = patterns('',
                       # Examples:
                       url(r'^$', 'imager.views.home', name='home'),
                       # url(r'^blog/', include('blog.urls')),
                       url(r'^admin/', include(admin.site.urls)),
                       )

if settings.DEBUG:
    urlpatterns += static(dcs.MEDIA_URL, document_root=dcs.MEDIA_ROOT)
<commit_msg>add url() for accounts and registration<commit_after>from django.conf.urls import patterns, include, url
from django.contrib import admin
from imager import settings
from django.conf import settings as dcs
from django.conf.urls.static import static

urlpatterns = patterns('',
                       # Examples:
                       url(r'^$', 'imager.views.home', name='home'),
                       # url(r'^blog/', include('blog.urls')),
                       url(r'^admin/', include(admin.site.urls)),
                       url(r'^accounts/', include(
                           'registration.backends.default.urls'))
                       )

if settings.DEBUG:
    urlpatterns += static(dcs.MEDIA_URL, document_root=dcs.MEDIA_ROOT)
<|endoftext|>


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

# Copyright 2014 Google, Inc.
# Routines for the battery_power_test
# Author: TaiWen Ko
# Date: 2015-1-13

import xpf6020
import bk8500
import argparse
import math
import os

from datetime import datetime
from time import sleep

# parser = argparse.ArgumentParser(description='MPPT Power Test Script')
# parser.add_argument('logfile',
#         help='CSV file to append new measurements')
# parser.add_argument('-v', '--verbose',
#         action='store_true',
#         help='Tee serial communications to the console')
# args = parser.parse_args()

# Make sure to use the correct serial-to-usb cable
#ps_path = '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A602FGGN-if00-port0'
ps_path = '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A5028CFJ-if00-port0'
chroma_path = '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A603QW14-if00-port0'

# Input
vin = 43
iin = 1.5

# Output (BK8500)
mppt_v = 46 # can't be greater than mppt_v_max
mppt_v_max = 50

print "Accessing the XPF6020 Power Supply"
ps = xpf6020.Xpf6020(ps_path)
ps.reset_ps()
ps.set_voltage(1,vin)
ps.set_currentlimit(1,iin)

print "Accessing the BK8500 Electronic Load"
bkload = bk8500.Bk8500()
bkload.remote_switch('on')
bkload.config_cv_mode(mppt_v, mppt_v_max)

# Write headers
# dt = datetime.now()
# dt = dt.replace(microsecond=0)
# logdir = '%smppt_power_test-%s.csv' % (args.logfile, dt)
# logfile = open(logdir, 'wt')
# try:
#     if logfile.tell() == 0:
#         raise IOError, 'Null Error'
# except IOError:
#     logfile.write('TIMESTAMP,')
#     logfile.write('CURRENT(A),')
#     logfile.write('VOLTAGE(V),')
#     logfile.write('TEMPERATURE(C),')
#     logfile.write('RESULT\n')
#     logfile.flush()

def bkload_measure_check(current,voltage):

  ts = datetime.now().isoformat()

  [r_mppt_v, r_mppt_i] = bkload.read()

  tolerance = 0.05
  current_max = current * (1 + tolerance)
  current_min = current * (1 - tolerance)
  voltage_max = voltage * (1 + tolerance)
  voltage_min = voltage * (1 - tolerance)

  if float(r_mppt_i) > float(current_max):
    result = 'FAILED'
  elif float(r_mppt_i) < float(current_min):
    result = 'FAILED'
  elif float(r_mppt_v) > float(voltage_max):
    result = 'FAILED'
  elif float(r_mppt_v) < float(voltage_min):
    result = 'FAILED'
  else:
    result = 'PASSED'
  print ('MPPT ' + result + ' @ ' + str(r_mppt_v) + 'V, ' + str(r_mppt_i) + 'A')
  # logfile.write('%s,' % ts)
  # logfile.write('%s,' % r_mppt_i)
  # logfile.write('%s,' % r_mppt_v)
  # logfile.write('%s\n' % result)

print " MPPT power test started"
bkload.load_switch('on')
ps.ind_output('1','on')
chroma.set_output('on')
sleep(10)
bkload_measure_check(2, 46)
sleep(5)
bkload_measure_check(2, 46)

#clean up
chroma.set_output('off')
ps.ind_output('1','off')
bkload.load_switch('off')

print ' MPPT power test completed'
<commit_msg>Delete mppt_test.py<commit_after><|endoftext|>