<commit_before>from httplib import HTTPSConnection
import json

import base
import tools
import secrets

class GmailApi(base.ApiBase):

    def __init__(self):
        base.ApiBase.__init__(self, "gmail")
        self.token = ""

    def icon_url(self):
        return "https://mail.google.com/favicon.ico"

    def oauth_link(self):
        url = "https://accounts.google.com/o/oauth2/auth"
        args = {
            "response_type":"code",
            "client_id":secrets.GMAIL_CLIENT_ID,
            "redirect_uri":secrets.BASE_REDIRECT_URL + "gmail",
            "scope":"https://mail.google.com/",
        }
        return url + "?" + tools.encode_params(args)

    def oauth_callback(self, params):

        if 'code' not in params:
            return None

        conn = HTTPSConnection("accounts.google.com")
        body = tools.encode_params({
            "grant_type":"authorization_code",
            "code":params['code'],
            "client_id":secrets.GMAIL_CLIENT_ID,
            "client_secret":secrets.GMAIL_CLIENT_SECRET,
            "redirect_uri":secrets.BASE_REDIRECT_URL + "gmail",
        })
        headers = {
            "Content-Type":"application/x-www-form-urlencoded",
        }
        conn.request("POST", "/o/oauth2/token", body, headers)

        resp = conn.getresponse()
        try:
            self.token = json.loads(resp.read())['access_token']
            self.is_auth = True
        except (KeyError, ValueError):
            return None

    def logout():
        self.is_auth = False
        self.token = ""

<commit_msg>GmailApi fetches user email.<commit_after>from httplib import HTTPSConnection
import json

import base
import tools
import secrets

class GmailApi(base.ApiBase):

    def __init__(self):
        base.ApiBase.__init__(self, "gmail")
        self.token = ""

    def icon_url(self):
        return "https://mail.google.com/favicon.ico"

    def oauth_link(self):
        url = "https://accounts.google.com/o/oauth2/auth"
        args = {
            "response_type":"code",
            "client_id":secrets.GMAIL_CLIENT_ID,
            "redirect_uri":secrets.BASE_REDIRECT_URL + "gmail",
            "scope":"https://mail.google.com/auth/gmail.readonly https://www.googleapis.com/auth/userinfo.email",
            "approval_prompt":"force",
        }
        return url + "?" + tools.encode_params(args)

    def oauth_callback(self, params):

        if 'code' not in params:
            return None

        conn = HTTPSConnection("accounts.google.com")
        body = tools.encode_params({
            "grant_type":"authorization_code",
            "code":params['code'],
            "client_id":secrets.GMAIL_CLIENT_ID,
            "client_secret":secrets.GMAIL_CLIENT_SECRET,
            "redirect_uri":secrets.BASE_REDIRECT_URL + "gmail",
        })
        headers = {
            "Content-Type":"application/x-www-form-urlencoded",
        }
        conn.request("POST", "/o/oauth2/token", body, headers)

        resp = conn.getresponse()
        try:
            self.token = json.loads(resp.read())['access_token']
            self.is_auth = True
        except (KeyError, ValueError):
            return None

        conn.close()

        conn = HTTPSConnection("www.googleapis.com")
        conn.request("GET","/oauth2/v1/tokeninfo?alt=json&access_token="+self.token,"",{})
        resp = conn.getresponse()
        self.username = json.loads(resp.read())['email']

    def logout(self):
        self.is_auth = False
        self.token = ""

<|endoftext|>


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

from __future__ import unicode_literals

import calendar
from datetime import timedelta

import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import (format_time, get_link_to_form, get_url_to_report,
	global_date_format, now, now_datetime, validate_email_address, today, add_to_date)
from frappe.utils.csvutils import to_csv
from frappe.utils.xlsxutils import make_xlsx

max_reports_per_user = frappe.local.conf.max_reports_per_user or 3

class AutoEmailReport(Document):
	def autoname(self):
		self.name = _(self.report)

	def validate(self):
		self.validate_report_count()
		self.validate_emails()
		self.validate_report_format()

	def validate_emails(self):
		'''Cleanup list of emails'''
		if ',' in self.email_to:
			self.email_to.replace(',', '\n')

		valid = []
		for email in self.email_to.split():
			if email:
				validate_email_address(email, True)
				valid.append(email)

		self.email_to = '\n'.join(valid)

	def validate_report_count(self):
		'''check that there are only 3 enabled reports per user'''
		count = frappe.db.sql('select count(*) from `tabAuto Email Report` where user=%s and enabled=1', self.user)[0][0]
		if count > max_reports_per_user + (-1 if self.flags.in_insert else 0):
			frappe.throw(_('Only {0} emailed reports are allowed per user').format(max_reports_per_user))

	def validate_report_format(self):
		""" check if user has select correct report format """
		valid_report_formats = ["HTML", "XLSX", "CSV"]
		if self.format not in valid_report_formats:
			frappe.throw(_("%s is not a valid report format. Report format should \
				one of the following %s"%(frappe.bold(self.format), frappe.bold(", ".join(valid_report_formats)))))

	def get_report_content(self):
		'''Returns file in for the report in given format'''
		report = frappe.get_doc('Report', self.report)

		self.filters = frappe.parse_json(self.filters) if self.filters else {}

		if self.report_type=='Report Builder' and self.data_modified_till:
			self.filters['modified'] = ('>', now_datetime() - timedelta(hours=self.data_modified_till))

		if self.report_type != 'Report Builder' and self.dynamic_date_filters_set():
			self.prepare_dynamic_filters()

		columns, data = report.get_data(limit=self.no_of_rows or 100, user = self.user,
			filters = self.filters, as_dict=True, ignore_prepared_report=True)

		# add serial numbers
		columns.insert(0, frappe._dict(fieldname='idx', label='', width='30px'))
		for i in range(len(data)):
			data[i]['idx'] = i+1

		if len(data)==0 and self.send_if_data:
			return None

		if self.format == 'HTML':
			columns, data = make_links(columns, data)

			return self.get_html_table(columns, data)

		elif self.format == 'XLSX':
			spreadsheet_data = self.get_spreadsheet_data(columns, data)
			xlsx_file = make_xlsx(spreadsheet_data, "Auto Email Report")
			return xlsx_file.getvalue()

		elif self.format == 'CSV':
			spreadsheet_data = self.get_spreadsheet_data(columns, data)
			return to_csv(spreadsheet_data)

		else:
			frappe.throw(_('Invalid Output Format'))

	def get_html_table(self, columns=None, data=None):

		date_time = global_date_format(now()) + ' ' + format_time(now())
		report_doctype = frappe.db.get_value('Report', self.report, 'ref_doctype')

		return frappe.render_template('frappe/templates/emails/auto_email_report.html', {
			'title': self.name,
			'description': self.description,
			'date_time': date_time,
			'columns': columns,
			'data': data,
			'report_url': get_url_to_report(self.report, self.report_type, report_doctype),
			'report_name': self.report,
			'edit_report_settings': get_link_to_form('Auto Email Report', self.name)
		})

	@staticmethod
	def get_spreadsheet_data(columns, data):
		out = [[_(df.label) for df in columns], ]
		for row in data:
			new_row = []
			out.append(new_row)
			for df in columns:
				if df.fieldname not in row: continue
				new_row.append(frappe.format(row[df.fieldname], df, row))

		return out

	def get_file_name(self):
		return "{0}.{1}".format(self.report.replace(" ", "-").replace("/", "-"), self.format.lower())

	def prepare_dynamic_filters(self):
		self.filters = frappe.parse_json(self.filters)

		to_date = today()
		from_date_value = {
			'Daily': ('days', -1),
			'Weekly': ('weeks', -1),
			'Monthly': ('months', -1),
			'Quarterly': ('months', -3),
			'Half Yearly': ('months', -6),
			'Yearly': ('years', -1)
		}[self.dynamic_date_period]

		from_date = add_to_date(to_date, **{from_date_value[0]: from_date_value[1]})

		self.filters[self.from_date_field] = from_date
		self.filters[self.to_date_field] = to_date

	def send(self):
		if self.filter_meta and not self.filters:
			frappe.throw(_("Please set filters value in Report Filter table."))

		data = self.get_report_content()
		if not data:
			return

		attachments = None
		if self.format == "HTML":
			message = data
		else:
			message = self.get_html_table()

		if not self.format=='HTML':
			attachments = [{
				'fname': self.get_file_name(),
				'fcontent': data
			}]

		frappe.sendmail(
			recipients = self.email_to.split(),
			subject = self.name,
			message = message,
			attachments = attachments,
			reference_doctype = self.doctype,
			reference_name = self.name
		)

	def dynamic_date_filters_set(self):
		return self.dynamic_date_period and self.from_date_field and self.to_date_field

@frappe.whitelist()
def download(name):
	'''Download report locally'''
	auto_email_report = frappe.get_doc('Auto Email Report', name)
	auto_email_report.check_permission()
	data = auto_email_report.get_report_content()

	if not data:
		frappe.msgprint(_('No Data'))
		return

	frappe.local.response.filecontent = data
	frappe.local.response.type = "download"
	frappe.local.response.filename = auto_email_report.get_file_name()

@frappe.whitelist()
def send_now(name):
	'''Send Auto Email report now'''
	auto_email_report = frappe.get_doc('Auto Email Report', name)
	auto_email_report.check_permission()
	auto_email_report.send()

def send_daily():
	'''Check reports to be sent daily'''

	current_day = calendar.day_name[now_datetime().weekday()]
	enabled_reports = frappe.get_all('Auto Email Report',
		filters={'enabled': 1, 'frequency': ('in', ('Daily', 'Weekdays', 'Weekly'))})

	for report in enabled_reports:
		auto_email_report = frappe.get_doc('Auto Email Report', report.name)

		# if not correct weekday, skip
		if auto_email_report.frequency == "Weekdays":
			if current_day in ("Saturday", "Sunday"):
				continue
		elif auto_email_report.frequency == 'Weekly':
			if auto_email_report.day_of_week != current_day:
				continue

		auto_email_report.send()

def send_monthly():
	'''Check reports to be sent monthly'''
	for report in frappe.get_all('Auto Email Report', {'enabled': 1, 'frequency': 'Monthly'}):
		frappe.get_doc('Auto Email Report', report.name).send()

def make_links(columns, data):
	for row in data:
		for col in columns:
			if col.fieldtype == "Link" and col.options != "Currency":
				if col.options and row.get(col.fieldname):
					row[col.fieldname] = get_link_to_form(col.options, row[col.fieldname])
			elif col.fieldtype == "Dynamic Link":
				if col.options and row.get(col.fieldname) and row.get(col.options):
					row[col.fieldname] = get_link_to_form(row[col.options], row[col.fieldname])

	return columns, data
<commit_msg>fix: Send other Auto Email Reports if one fails (bp #10570) (#10581)<commit_after># -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals

import calendar
from datetime import timedelta

import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import (format_time, get_link_to_form, get_url_to_report,
	global_date_format, now, now_datetime, validate_email_address, today, add_to_date)
from frappe.utils.csvutils import to_csv
from frappe.utils.xlsxutils import make_xlsx

max_reports_per_user = frappe.local.conf.max_reports_per_user or 3

class AutoEmailReport(Document):
	def autoname(self):
		self.name = _(self.report)

	def validate(self):
		self.validate_report_count()
		self.validate_emails()
		self.validate_report_format()

	def validate_emails(self):
		'''Cleanup list of emails'''
		if ',' in self.email_to:
			self.email_to.replace(',', '\n')

		valid = []
		for email in self.email_to.split():
			if email:
				validate_email_address(email, True)
				valid.append(email)

		self.email_to = '\n'.join(valid)

	def validate_report_count(self):
		'''check that there are only 3 enabled reports per user'''
		count = frappe.db.sql('select count(*) from `tabAuto Email Report` where user=%s and enabled=1', self.user)[0][0]
		if count > max_reports_per_user + (-1 if self.flags.in_insert else 0):
			frappe.throw(_('Only {0} emailed reports are allowed per user').format(max_reports_per_user))

	def validate_report_format(self):
		""" check if user has select correct report format """
		valid_report_formats = ["HTML", "XLSX", "CSV"]
		if self.format not in valid_report_formats:
			frappe.throw(_("%s is not a valid report format. Report format should \
				one of the following %s"%(frappe.bold(self.format), frappe.bold(", ".join(valid_report_formats)))))

	def get_report_content(self):
		'''Returns file in for the report in given format'''
		report = frappe.get_doc('Report', self.report)

		self.filters = frappe.parse_json(self.filters) if self.filters else {}

		if self.report_type=='Report Builder' and self.data_modified_till:
			self.filters['modified'] = ('>', now_datetime() - timedelta(hours=self.data_modified_till))

		if self.report_type != 'Report Builder' and self.dynamic_date_filters_set():
			self.prepare_dynamic_filters()

		columns, data = report.get_data(limit=self.no_of_rows or 100, user = self.user,
			filters = self.filters, as_dict=True, ignore_prepared_report=True)

		# add serial numbers
		columns.insert(0, frappe._dict(fieldname='idx', label='', width='30px'))
		for i in range(len(data)):
			data[i]['idx'] = i+1

		if len(data)==0 and self.send_if_data:
			return None

		if self.format == 'HTML':
			columns, data = make_links(columns, data)

			return self.get_html_table(columns, data)

		elif self.format == 'XLSX':
			spreadsheet_data = self.get_spreadsheet_data(columns, data)
			xlsx_file = make_xlsx(spreadsheet_data, "Auto Email Report")
			return xlsx_file.getvalue()

		elif self.format == 'CSV':
			spreadsheet_data = self.get_spreadsheet_data(columns, data)
			return to_csv(spreadsheet_data)

		else:
			frappe.throw(_('Invalid Output Format'))

	def get_html_table(self, columns=None, data=None):

		date_time = global_date_format(now()) + ' ' + format_time(now())
		report_doctype = frappe.db.get_value('Report', self.report, 'ref_doctype')

		return frappe.render_template('frappe/templates/emails/auto_email_report.html', {
			'title': self.name,
			'description': self.description,
			'date_time': date_time,
			'columns': columns,
			'data': data,
			'report_url': get_url_to_report(self.report, self.report_type, report_doctype),
			'report_name': self.report,
			'edit_report_settings': get_link_to_form('Auto Email Report', self.name)
		})

	@staticmethod
	def get_spreadsheet_data(columns, data):
		out = [[_(df.label) for df in columns], ]
		for row in data:
			new_row = []
			out.append(new_row)
			for df in columns:
				if df.fieldname not in row: continue
				new_row.append(frappe.format(row[df.fieldname], df, row))

		return out

	def get_file_name(self):
		return "{0}.{1}".format(self.report.replace(" ", "-").replace("/", "-"), self.format.lower())

	def prepare_dynamic_filters(self):
		self.filters = frappe.parse_json(self.filters)

		to_date = today()
		from_date_value = {
			'Daily': ('days', -1),
			'Weekly': ('weeks', -1),
			'Monthly': ('months', -1),
			'Quarterly': ('months', -3),
			'Half Yearly': ('months', -6),
			'Yearly': ('years', -1)
		}[self.dynamic_date_period]

		from_date = add_to_date(to_date, **{from_date_value[0]: from_date_value[1]})

		self.filters[self.from_date_field] = from_date
		self.filters[self.to_date_field] = to_date

	def send(self):
		if self.filter_meta and not self.filters:
			frappe.throw(_("Please set filters value in Report Filter table."))

		data = self.get_report_content()
		if not data:
			return

		attachments = None
		if self.format == "HTML":
			message = data
		else:
			message = self.get_html_table()

		if not self.format=='HTML':
			attachments = [{
				'fname': self.get_file_name(),
				'fcontent': data
			}]

		frappe.sendmail(
			recipients = self.email_to.split(),
			subject = self.name,
			message = message,
			attachments = attachments,
			reference_doctype = self.doctype,
			reference_name = self.name
		)

	def dynamic_date_filters_set(self):
		return self.dynamic_date_period and self.from_date_field and self.to_date_field

@frappe.whitelist()
def download(name):
	'''Download report locally'''
	auto_email_report = frappe.get_doc('Auto Email Report', name)
	auto_email_report.check_permission()
	data = auto_email_report.get_report_content()

	if not data:
		frappe.msgprint(_('No Data'))
		return

	frappe.local.response.filecontent = data
	frappe.local.response.type = "download"
	frappe.local.response.filename = auto_email_report.get_file_name()

@frappe.whitelist()
def send_now(name):
	'''Send Auto Email report now'''
	auto_email_report = frappe.get_doc('Auto Email Report', name)
	auto_email_report.check_permission()
	auto_email_report.send()

def send_daily():
	'''Check reports to be sent daily'''

	current_day = calendar.day_name[now_datetime().weekday()]
	enabled_reports = frappe.get_all('Auto Email Report',
		filters={'enabled': 1, 'frequency': ('in', ('Daily', 'Weekdays', 'Weekly'))})

	for report in enabled_reports:
		auto_email_report = frappe.get_doc('Auto Email Report', report.name)

		# if not correct weekday, skip
		if auto_email_report.frequency == "Weekdays":
			if current_day in ("Saturday", "Sunday"):
				continue
		elif auto_email_report.frequency == 'Weekly':
			if auto_email_report.day_of_week != current_day:
				continue
		try:
			auto_email_report.send()
		except Exception as e:
			frappe.log_error(e, _('Failed to send {0} Auto Email Report').format(auto_email_report.name))

def send_monthly():
	'''Check reports to be sent monthly'''
	for report in frappe.get_all('Auto Email Report', {'enabled': 1, 'frequency': 'Monthly'}):
		frappe.get_doc('Auto Email Report', report.name).send()

def make_links(columns, data):
	for row in data:
		for col in columns:
			if col.fieldtype == "Link" and col.options != "Currency":
				if col.options and row.get(col.fieldname):
					row[col.fieldname] = get_link_to_form(col.options, row[col.fieldname])
			elif col.fieldtype == "Dynamic Link":
				if col.options and row.get(col.fieldname) and row.get(col.options):
					row[col.fieldname] = get_link_to_form(row[col.options], row[col.fieldname])

	return columns, data
<|endoftext|>


<commit_before>##########################################################################
## Remco Boerma
## Sylvain Hellegouarch
##
## History:
## 1.0.6   : 2005-12-04 Fixed error handling problems
## 1.0.5   : 2005-11-04 Fixed Content-Length bug (http://www.cherrypy.org/ticket/384)
## 1.0.4   : 2005-08-28 Fixed issues on input types which are not strings
## 1.0.3   : 2005-01-28 Bugfix on content-length in 1.0.2 code fixed by
##           Gian Paolo Ciceri
## 1.0.2   : 2005-01-26 changed infile dox based on ticket #97
## 1.0.1   : 2005-01-26 Speedup due to generator usage in CP2.
##           The result is now converted to a list with length 1. So the complete
##           xmlrpc result is written at once, and not per character. Thanks to
##           Gian Paolo Ciceri for reporting the slowdown.
## 1.0.0   : 2004-12-29 Released with CP2
## 0.0.9   : 2004-12-23 made it CP2 #59 compatible (returns an iterable)
##           Please note: as the xmlrpc doesn't know what you would want to return
##           (and for the logic of marshalling) it will return Generator objects, as
##           it is.. So it'll brake on that one!!
##           NOTE: __don't try to return a Generator object to the caller__
##           You could of course handle the generator usage internally, before sending
##           the result. This breaks from the general cherrypy way of handling generators...
## 0.0.8   : 2004-12-23 cherrypy.request.paramList should now be a filter.
## 0.0.7   : 2004-12-07 inserted in the experimental branch (all remco boerma till here)
## 0.0.6   : 2004-12-02 Converted basefilter to baseinputfileter,baseoutputfilter
## 0.0.5   : 2004-11-22 "RPC2/" now changed to "/RPC2/" with the new mapping function
##           Gian paolo ciceri notified me with the lack of passing parameters.
##           Thanks Gian, it's now implemented against the latest trunk.
##           Gian also came up with the idea of lazy content-type checking: if it's sent
##           as a header, it should be 'text/xml', if not sent at all, it should be
##           accepted. (While this it not the xml/rpc standard, it's handy for those
##           xml-rpc client implementations wich don't send this header)
## 0.0.4   : 2004-11-20 in setting the path, the dot is replaces by a slash
##           therefore the regular CP2 routines knows how to handle things, as
##           dots are not allowed in object names, it's varely easily adopted.
##           Path + method handling. The default path is 'RPC2', this one is
##           stripped. In case of path 'someurl' it is used for 'someurl' + method
##           and 'someurl/someotherurl' is mapped to someurl.someotherurl + method.
##           this way python serverproxies initialised with an url other than
##           just the host are handled well. I don't hope any other service would map
##           it to 'RPC2/someurl/someotherurl', cause then it would break i think. .
## 0.0.3   : 2004-11-19 changed some examples (includes error checking
##           wich returns marshalled Fault objects if the request is an RPC call.
##           took testing code form afterRequestHeader and put it in
##           testValidityOfRequest to make things a little simpler.
##           simply log the requested function with parameters to stdout
## 0.0.2   : 2004-11-19 the required cgi.py patch is no longer needed
##           (thanks remi for noticing). Webbased calls to regular objects
##           are now possible again ;) so it's no longer a dedicated xmlrpc
##           server. The test script is also in a ready to run file named
##           testRPC.py along with the test server: filterExample.py
## 0.0.1   : 2004-11-19 informing the public, dropping loads of useless
##           tests and debugging
## 0.0.0   : 2004-11-19 initial alpha
##
##---------------------------------------------------------------------
##
## EXAMPLE CODE FOR THE SERVER:
##    import cherrypy
##
##    class Root:
##        def longString(self, s, times):
##            return s * times
##        longString.exposed = True
##
##    cherrypy.root = Root()
##    cherrypy.config.update({'xmlRpcFilter.on': True,
##                            'socketPort': 9001,
##                            'threadPool':0,
##                            'socketQueueSize':10 })
##    if __name__=='__main__':
##        cherrypy.server.start()
##
## EXAMPLE CODE FOR THE CLIENT:
## >>> import xmlrpclib
## >>> server = xmlrpclib.ServerProxy('http://localhost:9001')
## >>> assert server.longString('abc', 3) == 'abcabcabc'
## >>>
######################################################################

from basefilter import BaseFilter
import xmlrpclib

class XmlRpcFilter(BaseFilter):
    """Converts XMLRPC to CherryPy2 object system and vice-versa.

    PLEASE NOTE:

    beforeRequestBody:
        Unmarshalls the posted data to a methodname and parameters.
        - These are stored in cherrypy.request.rpcMethod and .rpcParams
        - The method is also stored in cherrypy.request.objectPath,
          so CP2 will find the right method to call for you,
          based on the root's position.
    beforeFinalize:
        Marshalls cherrypy.response.body to xmlrpc.
        - Until resolved: cherrypy.response.body must be a python source string;
          this string is 'eval'ed to return the results. This will be
          resolved in the future.
        - Content-Type and Content-Length are set according to the new
          (marshalled) data.
    """

    def testValidityOfRequest(self):
        # test if the content-length was sent
        result = False
        if cherrypy.request.headerMap.has_key('Content-Length'):
            length = cherrypy.request.headerMap.get('Content-Length', 0)
            if length is None or length == "": length = 0
            result = int(length) > 0
        ct = 'text/xml'
        if cherrypy.request.headerMap.has_key('Content-Type'):
            ct = cherrypy.request.headerMap.get('Content-Type', 'text/xml').lower()
            if ct is None or ct == "": ct = 'text/xml'
        result = result and ct in ['text/xml']
        return result

    def onStartResource(self):
        # We have to dynamically import cherrypy because Python can't handle
        #   circular module imports :-(
        global cherrypy
        import cherrypy

    def beforeRequestBody(self):
        """ Called after the request header has been read/parsed"""
        request = cherrypy.request

        request.xmlRpcFilterOn = cherrypy.config.get('xmlRpcFilter.on', False)
        if not request.xmlRpcFilterOn:
            return True

        request.isRPC = self.testValidityOfRequest()
        if not request.isRPC:
            # used for debugging or more info
            # print 'not a valid xmlrpc call'
            return # break this if it's not for this filter!!

        request.processRequestBody = False
        dataLength = int(request.headerMap.get('Content-Length', 0))
        data = request.rfile.read(dataLength)
        try:
            params, method = xmlrpclib.loads(data)
        except Exception:
            params, method = ('ERROR PARAMS', ), 'ERRORMETHOD'
        request.rpcMethod, request.rpcParams = method, params

        # patch the path. there are only a few options:
        # - 'RPC2' + method >> method
        # - 'someurl' + method >> someurl.method
        # - 'someurl/someother' + method >> someurl.someother.method
        if not request.objectPath.endswith('/'):
            request.objectPath += '/'
        if request.objectPath.startswith('/RPC2/'):
            # strip the first /rpc2
            request.objectPath = request.objectPath[5:]
        request.objectPath += str(method).replace('.', '/')
        request.paramList = list(params)

    def beforeMain(self):
        """This is a variation of main() from _cphttptools.

        The reason it is redone here is because we don't want
        cherrypy.response.body = iterable(body) - we want to use
        whatever real value the user returned from their callable
        to reach the xmlrpcfilter unchanged."""

        if not cherrypy.request.xmlRpcFilterOn:
            return

        path = cherrypy.request.objectPath
        page_handler, object_path, virtual_path = cherrypy.request.mapPathToObject(path)

        # Remove "root" from object_path and join it to get objectPath
        cherrypy.request.objectPath = '/' + '/'.join(object_path[1:])
        args = virtual_path + cherrypy.request.paramList
        body = page_handler(*args, **cherrypy.request.paramMap)
        cherrypy.response.body = body

    def beforeFinalize(self):
        """ Called before finalizing output """
        if (not cherrypy.request.xmlRpcFilterOn
            or not cherrypy.request.isRPC):
            return

        encoding = cherrypy.config.get('xmlRpcFilter.encoding', 'utf-8')

        # See xmlrpclib documentation
        # Python's None value cannot be used in standard XML-RPC;
        # to allow using it via an extension, provide a true value for allow_none.
        cherrypy.response.body = [xmlrpclib.dumps(
            (cherrypy.response.body,),
            methodresponse=1,
            encoding=encoding,
            allow_none=0)]
        cherrypy.response.headerMap['Content-Type'] = 'text/xml'
        cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0])

    def beforeErrorResponse(self):
        try:
            if not cherrypy.request.xmlRpcFilterOn:
                return
            import sys
            # Since we got here because of an exception, let's get its error message if any
            message = str(sys.exc_info()[1])
            cherrypy.response.headerMap['Content-Type'] = 'text/xml'
            cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0])
            body = ''.join([chunk for chunk in message])
            cherrypy.response.body = [xmlrpclib.dumps(xmlrpclib.Fault(1, body))]
            cherrypy.response.headerMap['Content-Type'] = 'text/xml'
            cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0])
        except:
            pass

    def afterErrorResponse(self):
        # The XML-RPC spec (http://www.xmlrpc.com/spec) says:
        # "Unless there's a lower-level error, always return 200 OK."
        # However if arrived here we do have a status set to 500 then
        # it means we got an error we didn't want to trap explicitely
        # so let's assume it's part of the "lower-level error" defined above.
        if cherrypy.response.status[:3] != '500':
            cherrypy.response.status = '200 OK'
<commit_msg>oops missed one little thing in the previous commit... duh!<commit_after>##########################################################################
## Remco Boerma
## Sylvain Hellegouarch
##
## History:
## 1.0.6   : 2005-12-04 Fixed error handling problems
## 1.0.5   : 2005-11-04 Fixed Content-Length bug (http://www.cherrypy.org/ticket/384)
## 1.0.4   : 2005-08-28 Fixed issues on input types which are not strings
## 1.0.3   : 2005-01-28 Bugfix on content-length in 1.0.2 code fixed by
##           Gian Paolo Ciceri
## 1.0.2   : 2005-01-26 changed infile dox based on ticket #97
## 1.0.1   : 2005-01-26 Speedup due to generator usage in CP2.
##           The result is now converted to a list with length 1. So the complete
##           xmlrpc result is written at once, and not per character. Thanks to
##           Gian Paolo Ciceri for reporting the slowdown.
## 1.0.0   : 2004-12-29 Released with CP2
## 0.0.9   : 2004-12-23 made it CP2 #59 compatible (returns an iterable)
##           Please note: as the xmlrpc doesn't know what you would want to return
##           (and for the logic of marshalling) it will return Generator objects, as
##           it is.. So it'll brake on that one!!
##           NOTE: __don't try to return a Generator object to the caller__
##           You could of course handle the generator usage internally, before sending
##           the result. This breaks from the general cherrypy way of handling generators...
## 0.0.8   : 2004-12-23 cherrypy.request.paramList should now be a filter.
## 0.0.7   : 2004-12-07 inserted in the experimental branch (all remco boerma till here)
## 0.0.6   : 2004-12-02 Converted basefilter to baseinputfileter,baseoutputfilter
## 0.0.5   : 2004-11-22 "RPC2/" now changed to "/RPC2/" with the new mapping function
##           Gian paolo ciceri notified me with the lack of passing parameters.
##           Thanks Gian, it's now implemented against the latest trunk.
##           Gian also came up with the idea of lazy content-type checking: if it's sent
##           as a header, it should be 'text/xml', if not sent at all, it should be
##           accepted. (While this it not the xml/rpc standard, it's handy for those
##           xml-rpc client implementations wich don't send this header)
## 0.0.4   : 2004-11-20 in setting the path, the dot is replaces by a slash
##           therefore the regular CP2 routines knows how to handle things, as
##           dots are not allowed in object names, it's varely easily adopted.
##           Path + method handling. The default path is 'RPC2', this one is
##           stripped. In case of path 'someurl' it is used for 'someurl' + method
##           and 'someurl/someotherurl' is mapped to someurl.someotherurl + method.
##           this way python serverproxies initialised with an url other than
##           just the host are handled well. I don't hope any other service would map
##           it to 'RPC2/someurl/someotherurl', cause then it would break i think. .
## 0.0.3   : 2004-11-19 changed some examples (includes error checking
##           wich returns marshalled Fault objects if the request is an RPC call.
##           took testing code form afterRequestHeader and put it in
##           testValidityOfRequest to make things a little simpler.
##           simply log the requested function with parameters to stdout
## 0.0.2   : 2004-11-19 the required cgi.py patch is no longer needed
##           (thanks remi for noticing). Webbased calls to regular objects
##           are now possible again ;) so it's no longer a dedicated xmlrpc
##           server. The test script is also in a ready to run file named
##           testRPC.py along with the test server: filterExample.py
## 0.0.1   : 2004-11-19 informing the public, dropping loads of useless
##           tests and debugging
## 0.0.0   : 2004-11-19 initial alpha
##
##---------------------------------------------------------------------
##
## EXAMPLE CODE FOR THE SERVER:
##    import cherrypy
##
##    class Root:
##        def longString(self, s, times):
##            return s * times
##        longString.exposed = True
##
##    cherrypy.root = Root()
##    cherrypy.config.update({'xmlRpcFilter.on': True,
##                            'socketPort': 9001,
##                            'threadPool':0,
##                            'socketQueueSize':10 })
##    if __name__=='__main__':
##        cherrypy.server.start()
##
## EXAMPLE CODE FOR THE CLIENT:
## >>> import xmlrpclib
## >>> server = xmlrpclib.ServerProxy('http://localhost:9001')
## >>> assert server.longString('abc', 3) == 'abcabcabc'
## >>>
######################################################################

from basefilter import BaseFilter
import xmlrpclib

class XmlRpcFilter(BaseFilter):
    """Converts XMLRPC to CherryPy2 object system and vice-versa.

    PLEASE NOTE:

    beforeRequestBody:
        Unmarshalls the posted data to a methodname and parameters.
        - These are stored in cherrypy.request.rpcMethod and .rpcParams
        - The method is also stored in cherrypy.request.objectPath,
          so CP2 will find the right method to call for you,
          based on the root's position.
    beforeFinalize:
        Marshalls cherrypy.response.body to xmlrpc.
        - Until resolved: cherrypy.response.body must be a python source string;
          this string is 'eval'ed to return the results. This will be
          resolved in the future.
        - Content-Type and Content-Length are set according to the new
          (marshalled) data.
    """

    def testValidityOfRequest(self):
        # test if the content-length was sent
        result = False
        if cherrypy.request.headerMap.has_key('Content-Length'):
            length = cherrypy.request.headerMap.get('Content-Length', 0)
            if length is None or length == "": length = 0
            result = int(length) > 0
        ct = 'text/xml'
        if cherrypy.request.headerMap.has_key('Content-Type'):
            ct = cherrypy.request.headerMap.get('Content-Type', 'text/xml').lower()
            if ct is None or ct == "": ct = 'text/xml'
        result = result and ct in ['text/xml']
        return result

    def onStartResource(self):
        # We have to dynamically import cherrypy because Python can't handle
        #   circular module imports :-(
        global cherrypy
        import cherrypy

    def beforeRequestBody(self):
        """ Called after the request header has been read/parsed"""
        request = cherrypy.request

        request.xmlRpcFilterOn = cherrypy.config.get('xmlRpcFilter.on', False)
        if not request.xmlRpcFilterOn:
            return True

        request.isRPC = self.testValidityOfRequest()
        if not request.isRPC:
            # used for debugging or more info
            # print 'not a valid xmlrpc call'
            return # break this if it's not for this filter!!

        request.processRequestBody = False
        dataLength = int(request.headerMap.get('Content-Length', 0))
        data = request.rfile.read(dataLength)
        try:
            params, method = xmlrpclib.loads(data)
        except Exception:
            params, method = ('ERROR PARAMS', ), 'ERRORMETHOD'
        request.rpcMethod, request.rpcParams = method, params

        # patch the path. there are only a few options:
        # - 'RPC2' + method >> method
        # - 'someurl' + method >> someurl.method
        # - 'someurl/someother' + method >> someurl.someother.method
        if not request.objectPath.endswith('/'):
            request.objectPath += '/'
        if request.objectPath.startswith('/RPC2/'):
            # strip the first /rpc2
            request.objectPath = request.objectPath[5:]
        request.objectPath += str(method).replace('.', '/')
        request.paramList = list(params)

    def beforeMain(self):
        """This is a variation of main() from _cphttptools.

        The reason it is redone here is because we don't want
        cherrypy.response.body = iterable(body) - we want to use
        whatever real value the user returned from their callable
        to reach the xmlrpcfilter unchanged."""

        if not cherrypy.request.xmlRpcFilterOn:
            return

        path = cherrypy.request.objectPath
        page_handler, object_path, virtual_path = cherrypy.request.mapPathToObject(path)

        # Remove "root" from object_path and join it to get objectPath
        cherrypy.request.objectPath = '/' + '/'.join(object_path[1:])
        args = virtual_path + cherrypy.request.paramList
        body = page_handler(*args, **cherrypy.request.paramMap)
        cherrypy.response.body = body

    def beforeFinalize(self):
        """ Called before finalizing output """
        if (not cherrypy.request.xmlRpcFilterOn
            or not cherrypy.request.isRPC):
            return

        encoding = cherrypy.config.get('xmlRpcFilter.encoding', 'utf-8')

        # See xmlrpclib documentation
        # Python's None value cannot be used in standard XML-RPC;
        # to allow using it via an extension, provide a true value for allow_none.
        cherrypy.response.body = [xmlrpclib.dumps(
            (cherrypy.response.body,),
            methodresponse=1,
            encoding=encoding,
            allow_none=0)]
        cherrypy.response.headerMap['Content-Type'] = 'text/xml'
        cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0])

    def beforeErrorResponse(self):
        try:
            if not cherrypy.request.xmlRpcFilterOn:
                return
            import sys
            # Since we got here because of an exception, let's get its error message if any
            message = str(sys.exc_info()[1])
            body = ''.join([chunk for chunk in message])
            cherrypy.response.body = [xmlrpclib.dumps(xmlrpclib.Fault(1, body))]
            cherrypy.response.headerMap['Content-Type'] = 'text/xml'
            cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0])
        except:
            pass

    def afterErrorResponse(self):
        # The XML-RPC spec (http://www.xmlrpc.com/spec) says:
        # "Unless there's a lower-level error, always return 200 OK."
        # However if arrived here we do have a status set to 500 then
        # it means we got an error we didn't want to trap explicitely
        # so let's assume it's part of the "lower-level error" defined above.
        if cherrypy.response.status[:3] != '500':
            cherrypy.response.status = '200 OK'
<|endoftext|>


<commit_before>"""Tests for the CherryPy configuration system."""

from cherrypy.test import test
test.prefer_parent_path()

import os, sys
localDir = os.path.join(os.getcwd(), os.path.dirname(__file__))
import socket
import StringIO
import time

import cherrypy

def setup_server():

    class Root:
        def index(self):
            return cherrypy.request.wsgi_environ['SERVER_PORT']
        index.exposed = True

        def upload(self, file):
            return "Size: %s" % len(file.file.read())
        upload.exposed = True

        def tinyupload(self, maxlen):
            cherrypy.request.rfile.maxlen = int(maxlen)
            cl = int(cherrypy.request.headers['Content-Length'])
            try:
                body = cherrypy.request.rfile.read(cl)
            except Exception, e:
                if e.__class__.__name__ == 'MaxSizeExceeded':
                    # Post data is too big
                    raise cherrypy.HTTPError(413)
                else:
                    raise
            return body
        tinyupload.exposed = True
        tinyupload._cp_config = {'request.process_request_body': False}

    cherrypy.tree.mount(Root())

    cherrypy.config.update({
        'server.socket_host': '0.0.0.0',
        'server.socket_port': 9876,
        'server.max_request_body_size': 200,
        'server.max_request_header_size': 500,
        'server.socket_timeout': 0.5,

        # Test explicit server.instance
        'server.2.instance': 'cherrypy._cpwsgi_server.CPWSGIServer',
        'server.2.socket_port': 9877,

        # Test non-numeric <servername>
        # Also test default server.instance = builtin server
        'server.yetanother.socket_port': 9878,
        })

#                             Client-side code                             #

from cherrypy.test import helper

class ServerConfigTests(helper.CPWebCase):

    PORT = 9876

    def testBasicConfig(self):
        self.getPage("/")
        self.assertBody(str(self.PORT))

    def testAdditionalServers(self):
        self.PORT = 9877
        self.getPage("/")
        self.assertBody(str(self.PORT))
        self.PORT = 9878
        self.getPage("/")
        self.assertBody(str(self.PORT))

    def testMaxRequestSizePerHandler(self):
        if getattr(cherrypy.server, "using_apache", False):
            print "skipped due to known Apache differences...",
            return

        self.getPage('/tinyupload?maxlen=100', method="POST", body="x" * 100)
        self.assertStatus(200)
        self.assertBody("x" * 100)
        self.getPage('/tinyupload?maxlen=100', method="POST", body="x" * 101)
        self.assertStatus(413)

    def testMaxRequestSize(self):
        if getattr(cherrypy.server, "using_apache", False):
            print "skipped due to known Apache differences...",
            return

        for size in (500, 5000, 50000):
            self.getPage("/", headers=[('From', "x" * 500)])
            self.assertStatus(413)

        # Test for http://www.cherrypy.org/ticket/421
        # (Incorrect border condition in readline of SizeCheckWrapper).
        # This hangs in rev 891 and earlier.
        lines256 = "x" * 248
        self.getPage("/",
                     headers=[('Host', '%s:%s' % (self.HOST, self.PORT)),
                              ('From', lines256)])

        # Test upload
        body = """--x
Content-Disposition: form-data; name="file"; filename="hello.txt"
Content-Type: text/plain

%s
--x--
"""
        b = body % ("x" * 96)
        h = [("Content-type", "multipart/form-data; boundary=x"),
             ("Content-Length", len(b))]
        self.getPage('/upload', h, "POST", b)
        self.assertBody('Size: 96')

        b = body % ("x" * 200)
        h = [("Content-type", "multipart/form-data; boundary=x"),
             ("Content-Length", len(b))]
        self.getPage('/upload', h, "POST", b)
        self.assertStatus(413)

    def test_socket_timeout(self):
        if cherrypy.server.protocol_version != "HTTP/1.1":
            print "skipped ",
            return

        self.PROTOCOL = "HTTP/1.1"

        # Put request 1
        self.persistent = True
        conn = self.HTTP_CONN
        conn.putrequest("GET", "/", skip_host=True)
        conn.putheader("Host", self.HOST)
        conn.endheaders()
        response = conn.response_class(conn.sock, method="GET")
        response.begin()
        body = response.read()
        self.assertEqual(response.status, 200)

        time.sleep(cherrypy.server.socket_timeout)

        # Put next request
        try:
            conn._output('GET /hello HTTP/1.1')
            conn._output("Host: %s" % self.HOST)
            conn._send_output()
            response = conn.response_class(conn.sock, method="GET")
            response.begin()
            body = response.read()
            self.assertEqual(response.status, 200)
        except socket.error:
            pass
        else:
            self.fail("Socket did not time out as it should have.")

        conn.close()

if __name__ == '__main__':
    helper.testmain()
<commit_msg>Backport of [2303], [2310], [2311] from python3 to trunk.<commit_after>"""Tests for the CherryPy configuration system."""

from cherrypy.test import test
test.prefer_parent_path()

import os, sys
localDir = os.path.join(os.getcwd(), os.path.dirname(__file__))
import socket
import StringIO
import time

import cherrypy

def setup_server():

    class Root:
        def index(self):
            return cherrypy.request.wsgi_environ['SERVER_PORT']
        index.exposed = True

        def upload(self, file):
            return "Size: %s" % len(file.file.read())
        upload.exposed = True

        def tinyupload(self, maxlen):
            cherrypy.request.rfile.maxlen = int(maxlen)
            cl = int(cherrypy.request.headers['Content-Length'])
            try:
                body = cherrypy.request.rfile.read(cl)
            except Exception, e:
                if e.__class__.__name__ == 'MaxSizeExceeded':
                    # Post data is too big
                    raise cherrypy.HTTPError(413)
                else:
                    raise
            return body
        tinyupload.exposed = True
        tinyupload._cp_config = {'request.process_request_body': False}

    cherrypy.tree.mount(Root())

    cherrypy.config.update({
        'server.socket_host': '0.0.0.0',
        'server.socket_port': 9876,
        'server.max_request_body_size': 200,
        'server.max_request_header_size': 500,
        'server.socket_timeout': 0.5,

        # Test explicit server.instance
        'server.2.instance': 'cherrypy._cpwsgi_server.CPWSGIServer',
        'server.2.socket_port': 9877,

        # Test non-numeric <servername>
        # Also test default server.instance = builtin server
        'server.yetanother.socket_port': 9878,
        })

#                             Client-side code                             #

from cherrypy.test import helper

class ServerConfigTests(helper.CPWebCase):

    PORT = 9876

    def testBasicConfig(self):
        self.getPage("/")
        self.assertBody(str(self.PORT))

    def testAdditionalServers(self):
        self.PORT = 9877
        self.getPage("/")
        self.assertBody(str(self.PORT))
        self.PORT = 9878
        self.getPage("/")
        self.assertBody(str(self.PORT))

    def testMaxRequestSizePerHandler(self):
        if getattr(cherrypy.server, "using_apache", False):
            print "skipped due to known Apache differences...",
            return

        self.getPage('/tinyupload?maxlen=100', method="POST", body="x" * 100)
        self.assertStatus(200)
        self.assertBody("x" * 100)
        self.getPage('/tinyupload?maxlen=100', method="POST", body="x" * 101)
        self.assertStatus(413)

    def testMaxRequestSize(self):
        if getattr(cherrypy.server, "using_apache", False):
            print "skipped due to known Apache differences...",
            return

        for size in (500, 5000, 50000):
            self.getPage("/", headers=[('From', "x" * 500)])
            self.assertStatus(413)

        # Test for http://www.cherrypy.org/ticket/421
        # (Incorrect border condition in readline of SizeCheckWrapper).
        # This hangs in rev 891 and earlier.
        lines256 = "x" * 248
        self.getPage("/",
                     headers=[('Host', '%s:%s' % (self.HOST, self.PORT)),
                              ('From', lines256)])

        # Test upload
        body = '\r\n'.join([
            '--x',
            'Content-Disposition: form-data; name="file"; filename="hello.txt"',
            'Content-Type: text/plain',
            '',
            '%s',
            '--x--'])
        partlen = 200 - len(body)
        b = body % ("x" * partlen)
        h = [("Content-type", "multipart/form-data; boundary=x"),
             ("Content-Length", len(b))]
        self.getPage('/upload', h, "POST", b)
        self.assertBody('Size: %d' % partlen)

        b = body % ("x" * 200)
        h = [("Content-type", "multipart/form-data; boundary=x"),
             ("Content-Length", len(b))]
        self.getPage('/upload', h, "POST", b)
        self.assertStatus(413)

if __name__ == '__main__':
    helper.testmain()
<|endoftext|>


<commit_before>import sys

import pytest

from cheroot._compat import ntob
from cheroot.test import helper

@pytest.mark.xfail(reason='issue 1')
class WSGIGraftTests(helper.CherootWebCase):

    @staticmethod
    def setup_server():
        import os
        curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))

        def test_app(environ, start_response):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            start_response(status, response_headers)
            output = ['Hello, world!\n',
                      'This is a wsgi app running within CherryPy!\n\n']
            keys = list(environ.keys())
            keys.sort()
            for k in keys:
                output.append('%s: %s\n' % (k, environ[k]))
            return [ntob(x, 'utf-8') for x in output]

        def test_empty_string_app(environ, start_response):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            start_response(status, response_headers)
            return [
                ntob('Hello'), ntob(''), ntob(' '), ntob(''), ntob('world')
            ]

        class WSGIResponse(object):

            def __init__(self, appresults):
                self.appresults = appresults
                self.iter = iter(appresults)

            def __iter__(self):
                return self

            if sys.version_info >= (3, 0):
                def __next__(self):
                    return next(self.iter)
            else:
                def next(self):
                    return self.iter.next()

            def close(self):
                if hasattr(self.appresults, 'close'):
                    self.appresults.close()

        class ReversingMiddleware(object):

            def __init__(self, app):
                self.app = app

            def __call__(self, environ, start_response):
                results = app(environ, start_response)

                class Reverser(WSGIResponse):

                    if sys.version_info >= (3, 0):
                        def __next__(this):
                            line = list(next(this.iter))
                            line.reverse()
                            return bytes(line)
                    else:
                        def next(this):
                            line = list(this.iter.next())
                            line.reverse()
                            return ''.join(line)

                return Reverser(results)

    wsgi_output = '''Hello, world!
This is a wsgi app running within CherryPy!'''

    def test_01_standard_app(self):
        self.getPage('/')
        self.assertBody("I'm a regular CherryPy page handler!")

    def test_04_pure_wsgi(self):
        self.getPage('/hosted/app1')
        self.assertHeader('Content-Type', 'text/plain')
        self.assertInBody(self.wsgi_output)

    def test_05_wrapped_cp_app(self):
        self.getPage('/hosted/app2/')
        body = list("I'm a regular CherryPy page handler!")
        body.reverse()
        body = ''.join(body)
        self.assertInBody(body)

    def test_06_empty_string_app(self):
        self.getPage('/hosted/app3')
        self.assertHeader('Content-Type', 'text/plain')
        self.assertInBody('Hello world')
<commit_msg>PEP8fy codebase: eliminated E303 flake8 error<commit_after>import sys

import pytest

from cheroot._compat import ntob
from cheroot.test import helper

@pytest.mark.xfail(reason='issue 1')
class WSGIGraftTests(helper.CherootWebCase):

    @staticmethod
    def setup_server():
        import os
        curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))

        def test_app(environ, start_response):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            start_response(status, response_headers)
            output = ['Hello, world!\n',
                      'This is a wsgi app running within CherryPy!\n\n']
            keys = list(environ.keys())
            keys.sort()
            for k in keys:
                output.append('%s: %s\n' % (k, environ[k]))
            return [ntob(x, 'utf-8') for x in output]

        def test_empty_string_app(environ, start_response):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            start_response(status, response_headers)
            return [
                ntob('Hello'), ntob(''), ntob(' '), ntob(''), ntob('world')
            ]

        class WSGIResponse(object):

            def __init__(self, appresults):
                self.appresults = appresults
                self.iter = iter(appresults)

            def __iter__(self):
                return self

            if sys.version_info >= (3, 0):
                def __next__(self):
                    return next(self.iter)
            else:
                def next(self):
                    return self.iter.next()

            def close(self):
                if hasattr(self.appresults, 'close'):
                    self.appresults.close()

        class ReversingMiddleware(object):

            def __init__(self, app):
                self.app = app

            def __call__(self, environ, start_response):
                results = app(environ, start_response)

                class Reverser(WSGIResponse):

                    if sys.version_info >= (3, 0):
                        def __next__(this):
                            line = list(next(this.iter))
                            line.reverse()
                            return bytes(line)
                    else:
                        def next(this):
                            line = list(this.iter.next())
                            line.reverse()
                            return ''.join(line)

                return Reverser(results)

    wsgi_output = '''Hello, world!
This is a wsgi app running within CherryPy!'''

    def test_01_standard_app(self):
        self.getPage('/')
        self.assertBody("I'm a regular CherryPy page handler!")

    def test_04_pure_wsgi(self):
        self.getPage('/hosted/app1')
        self.assertHeader('Content-Type', 'text/plain')
        self.assertInBody(self.wsgi_output)

    def test_05_wrapped_cp_app(self):
        self.getPage('/hosted/app2/')
        body = list("I'm a regular CherryPy page handler!")
        body.reverse()
        body = ''.join(body)
        self.assertInBody(body)

    def test_06_empty_string_app(self):
        self.getPage('/hosted/app3')
        self.assertHeader('Content-Type', 'text/plain')
        self.assertInBody('Hello world')
<|endoftext|>


<commit_before>"""
Copyright (c) 2011 Satvik Chauhan

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

from scrapy.selector import HtmlXPathSelector
from scrapy.http import HtmlResponse
import json,pdb,sys
import httplib
baseurl="http://www.google.com/movies?near="

def search(city,date):
    movielist=[]
    start=0

    conn = httplib.HTTPConnection("www.google.com")
    conn.request("GET", "/movies?near="+city+"&start="+str(start)+"&date="+str(date))
    r1=conn.getresponse()
    hxs=HtmlXPathSelector(HtmlResponse("www.google.com/movies?near="+city+"&date="+str(date)+"&start="+str(start),r1.status,r1.getheaders(),r1.read(),request=conn))
    st=hxs.extract()
    while("No showtimes were found" not in st):
        theater=hxs.select('//h2[contains(@class,"name")]/a[contains(@href,"movies")]/text()').extract()
        m=hxs.select('//div[contains(@class,"name")]/a[contains(@href,"movies")]/text()').extract()
        x=hxs.select('//div[contains(@class,"times")]/text()').extract()
        counter=0
        for i,j in zip(theater,theater[1:]):
            star=st.find(i)
            end=st.find(j)
            test=st.find(m[counter],star,end)
            while(test!=-1):
                temp=x[counter].split()
                try:
                    am=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("am"))
                    temp[am]=temp[am][:-2]
                except:
                    am=0
                try:
                    pm=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("pm"))
                    temp[pm]=temp[pm][:-2]
                    for temp3 in range(am+1,pm+1):
                        if int(temp[temp3].split(':')[0])<12:
                            temp[temp3]=str((int(temp[temp3].split(':')[0])+12)%24)+temp[temp3][temp[temp3].find(':'):]
                except:
                    pass
                movielist.append((i,m[counter],temp))

                star =test+len(m[counter])
                counter+=1
                test=st.find(m[counter],star,end)
        while(counter!=len(m)):
            temp=x[counter].split()
            try:
                am=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("am"))
                temp[am]=temp[am][:-2]
            except:
                am=0
            try:
                pm=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("pm"))
                temp[pm]=temp[pm][:-2]
                for temp3 in range(am+1,pm+1):
                    if int(temp[temp3].split(':')[0])<12:
                        temp[temp3]=str((int(temp[temp3].split(':')[0])+12)%24)+temp[temp3][temp[temp3].find(':'):]
            except:
                pass
            movielist.append((theater[-1],m[counter],temp))
            counter+=1
        #pdb.set_trace()
        conn.close()
        start+=10
        conn = httplib.HTTPConnection("www.google.com")
        conn.request("GET", "/movies?near="+city+"&start="+str(start)+"&date="+str(date))
        r1=conn.getresponse()
        hxs=HtmlXPathSelector(HtmlResponse("www.google.com/movies?near="+city+"&date="+str(date)+"&start="+str(start),r1.status,r1.getheaders(),r1.read(),request=conn))
        st=hxs.extract()
    #return json.JSONEncoder().encode(movielist)
    return json.dumps(movielist, sort_keys=True, indent=4)
if __name__ == "__main__":
    if len(sys.argv)>1:
        m=search(sys.argv[1],0)
    else:
        m=search('kanpur',0)
    print m

<commit_msg>bug fixed only pm time not converted<commit_after>"""
Copyright (c) 2011 Satvik Chauhan

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

from scrapy.selector import HtmlXPathSelector
from scrapy.http import HtmlResponse
import json,pdb,sys
import httplib
baseurl="http://www.google.com/movies?near="

def search(city,date):
    movielist=[]
    start=0

    conn = httplib.HTTPConnection("www.google.com")
    conn.request("GET", "/movies?near="+city+"&start="+str(start)+"&date="+str(date))
    r1=conn.getresponse()
    hxs=HtmlXPathSelector(HtmlResponse("www.google.com/movies?near="+city+"&date="+str(date)+"&start="+str(start),r1.status,r1.getheaders(),r1.read(),request=conn))
    st=hxs.extract()
    while("No showtimes were found" not in st):
        theater=hxs.select('//h2[contains(@class,"name")]/a[contains(@href,"movies")]/text()').extract()
        m=hxs.select('//div[contains(@class,"name")]/a[contains(@href,"movies")]/text()').extract()
        x=hxs.select('//div[contains(@class,"times")]/text()').extract()
        counter=0
        for i,j in zip(theater,theater[1:]):
            star=st.find(i)
            end=st.find(j)
            test=st.find(m[counter],star,end)
            while(test!=-1):
                temp=x[counter].split()
                try:
                    am=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("am"))
                    temp[am]=temp[am][:-2]
                except:
                    am=0
                try:
                    pm=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("pm"))
                    temp[pm]=temp[pm][:-2]
                    if int(temp[pm].split(':')[0])<12:
                        temp[pm]=str((int(temp[pm].split(':')[0])+12)%24)+temp[pm][temp[pm].find(':'):]
                    for temp3 in range(am+1,pm):
                        if int(temp[temp3].split(':')[0])<12:
                            temp[temp3]=str((int(temp[temp3].split(':')[0])+12)%24)+temp[temp3][temp[temp3].find(':'):]
                except:
                    pass
                movielist.append((i,m[counter],temp))

                star =test+len(m[counter])
                counter+=1
                test=st.find(m[counter],star,end)
        while(counter!=len(m)):
            temp=x[counter].split()
            try:
                am=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("am"))
                temp[am]=temp[am][:-2]
            except:
                am=0
            try:
                pm=next(temp1 for temp1,temp2 in enumerate(temp) if temp2.endswith("pm"))
                temp[pm]=temp[pm][:-2]
                for temp3 in range(am+1,pm+1):
                    if int(temp[temp3].split(':')[0])<12:
                        temp[temp3]=str((int(temp[temp3].split(':')[0])+12)%24)+temp[temp3][temp[temp3].find(':'):]
            except:
                pass
            movielist.append((theater[-1],m[counter],temp))
            counter+=1
        #pdb.set_trace()
        conn.close()
        start+=10
        conn = httplib.HTTPConnection("www.google.com")
        conn.request("GET", "/movies?near="+city+"&start="+str(start)+"&date="+str(date))
        r1=conn.getresponse()
        hxs=HtmlXPathSelector(HtmlResponse("www.google.com/movies?near="+city+"&date="+str(date)+"&start="+str(start),r1.status,r1.getheaders(),r1.read(),request=conn))
        st=hxs.extract()
    #return json.JSONEncoder().encode(movielist)
    return json.dumps(movielist, sort_keys=True, indent=4)
if __name__ == "__main__":
    if len(sys.argv)>1:
        m=search(sys.argv[1],0)
    else:
        m=search('kanpur',0)
    print m

<|endoftext|>


<commit_before>"""A thread-based worker pool.

.. spelling::

   joinable
"""

from __future__ import absolute_import, division, print_function
__metaclass__ = type

import collections
import threading
import time
import socket
import warnings

from six.moves import queue

from jaraco.functools import pass_none

__all__ = ('WorkerThread', 'ThreadPool')

class TrueyZero:
    """Object which equals and does math like the integer 0 but evals True."""

    def __add__(self, other):
        return other

    def __radd__(self, other):
        return other

trueyzero = TrueyZero()

_SHUTDOWNREQUEST = None

class WorkerThread(threading.Thread):
    """Thread which continuously polls a Queue for Connection objects.

    Due to the timing issues of polling a Queue, a WorkerThread does not
    check its own 'ready' flag after it has started. To stop the thread,
    it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
    (one for each running WorkerThread).
    """

    conn = None
    """The current connection pulled off the Queue, or None."""

    server = None
    """The HTTP Server which spawned this thread, and which owns the
    Queue and is placing active connections into it."""

    ready = False
    """A simple flag for the calling server to know when this thread
    has begun polling the Queue."""

    def __init__(self, server):
        """Initialize WorkerThread instance.

        Args:
            server (cheroot.server.HTTPServer): web server object
                receiving this request
        """
        self.ready = False
        self.server = server

        self.requests_seen = 0
        self.bytes_read = 0
        self.bytes_written = 0
        self.start_time = None
        self.work_time = 0
        self.stats = {
            'Requests': lambda s: self.requests_seen + (
                self.start_time is None
                and trueyzero
                or self.conn.requests_seen
            ),
            'Bytes Read': lambda s: self.bytes_read + (
                self.start_time is None
                and trueyzero
                or self.conn.rfile.bytes_read
            ),
            'Bytes Written': lambda s: self.bytes_written + (
                self.start_time is None
                and trueyzero
                or self.conn.wfile.bytes_written
            ),
            'Work Time': lambda s: self.work_time + (
                self.start_time is None
                and trueyzero
                or time.time() - self.start_time
            ),
            'Read Throughput': lambda s: s['Bytes Read'](s) / (
                s['Work Time'](s) or 1e-6
            ),
            'Write Throughput': lambda s: s['Bytes Written'](s) / (
                s['Work Time'](s) or 1e-6
            ),
        }
        threading.Thread.__init__(self)

    def run(self):
        """Process incoming HTTP connections.

        Retrieves incoming connections from thread pool.
        """
        self.server.stats['Worker Threads'][self.getName()] = self.stats
        try:
            self.ready = True
            while True:
                conn = self.server.requests.get()
                if conn is _SHUTDOWNREQUEST:
                    return

                self.conn = conn
                is_stats_enabled = self.server.stats['Enabled']
                if is_stats_enabled:
                    self.start_time = time.time()
                keep_conn_open = False
                try:
                    keep_conn_open = conn.communicate()
                finally:
                    if keep_conn_open:
                        self.server.put_conn(conn)
                    else:
                        conn.close()
                    if is_stats_enabled:
                        self.requests_seen += self.conn.requests_seen
                        self.bytes_read += self.conn.rfile.bytes_read
                        self.bytes_written += self.conn.wfile.bytes_written
                        self.work_time += time.time() - self.start_time
                        self.start_time = None
                    self.conn = None
        except (KeyboardInterrupt, SystemExit) as ex:
            self.server.interrupt = ex

class ThreadPool:
    """A Request Queue for an HTTPServer which pools threads.

    ThreadPool objects must provide min, get(), put(obj), start()
    and stop(timeout) attributes.
    """

    def __init__(
            self, server, min=10, max=-1, accepted_queue_size=-1,
            accepted_queue_timeout=10,
    ):
        """Initialize HTTP requests queue instance.

        Args:
            server (cheroot.server.HTTPServer): web server object
                receiving this request
            min (int): minimum number of worker threads
            max (int): maximum number of worker threads
            accepted_queue_size (int): maximum number of active
                requests in queue
            accepted_queue_timeout (int): timeout for putting request
                into queue
        """
        self.server = server
        self.min = min
        self.max = max
        self._threads = []
        self._queue = queue.Queue(maxsize=accepted_queue_size)
        self._queue_put_timeout = accepted_queue_timeout
        self.get = self._queue.get
        self._pending_shutdowns = collections.deque()

    def start(self):
        """Start the pool of threads."""
        for i in range(self.min):
            self._threads.append(WorkerThread(self.server))
        for worker in self._threads:
            worker.setName(
                'CP Server {worker_name!s}'.
                format(worker_name=worker.getName()),
            )
            worker.start()
        for worker in self._threads:
            while not worker.ready:
                time.sleep(.1)

    @property
    def idle(self):  # noqa: D401; irrelevant for properties
        """Number of worker threads which are idle. Read-only."""
        idles = len([t for t in self._threads if t.conn is None])
        return max(idles - len(self._pending_shutdowns), 0)

    def put(self, obj):
        """Put request into queue.

        Args:
            obj (:py:class:`~cheroot.server.HTTPConnection`): HTTP connection
                waiting to be processed
        """
        self._queue.put(obj, block=True, timeout=self._queue_put_timeout)

    def _clear_dead_threads(self):
        # Remove any dead threads from our list
        for t in [t for t in self._threads if not t.is_alive()]:
            self._threads.remove(t)
            try:
                self._pending_shutdowns.popleft()
            except IndexError:
                pass

    def grow(self, amount):
        """Spawn new worker threads (not above self.max)."""
        if self.max > 0:
            budget = max(self.max - len(self._threads), 0)
        else:
            # self.max <= 0 indicates no maximum
            budget = float('inf')

        n_new = min(amount, budget)

        workers = [self._spawn_worker() for i in range(n_new)]
        while not all(worker.ready for worker in workers):
            time.sleep(.1)
        self._threads.extend(workers)

    def _spawn_worker(self):
        worker = WorkerThread(self.server)
        worker.setName(
            'CP Server {worker_name!s}'.
            format(worker_name=worker.getName()),
        )
        worker.start()
        return worker

    def shrink(self, amount):
        """Kill off worker threads (not below self.min)."""
        # Grow/shrink the pool if necessary.
        # Remove any dead threads from our list
        amount -= len(self._pending_shutdowns)
        self._clear_dead_threads()
        if amount <= 0:
            return

        # calculate the number of threads above the minimum
        n_extra = max(len(self._threads) - self.min, 0)

        # don't remove more than amount
        n_to_remove = min(amount, n_extra)

        # put shutdown requests on the queue equal to the number of threads
        # to remove. As each request is processed by a worker, that worker
        # will terminate and be culled from the list.
        for n in range(n_to_remove):
            self._pending_shutdowns.append(None)
            self._queue.put(_SHUTDOWNREQUEST)

    def stop(self, timeout=5):
        """Terminate all worker threads.

        Args:
            timeout (int): time to wait for threads to stop gracefully
        """
        # for compatability, negative timeouts are treated like None
        # TODO: treat negative timeouts like already expired timeouts
        if timeout is not None and timeout < 0:
            timeout = None
            warnings.warning(
                'In the future, negative timeouts to Server.stop() '
                'will be equivalent to a timeout of zero.',
                stacklevel=2,
            )

        if timeout is not None:
            endtime = time.time() + timeout

        # Must shut down threads here so the code that calls
        # this method can know when all threads are stopped.
        for worker in self._threads:
            self._queue.put(_SHUTDOWNREQUEST)

        ignored_errors = (
            # TODO: explain this exception.
            AssertionError,
            # Ignore repeated Ctrl-C. See cherrypy#691.
            KeyboardInterrupt,
        )

        for worker in self._clear_threads():
            remaining_time = timeout and endtime - time.time()
            try:
                worker.join(remaining_time)
                if worker.is_alive():
                    # Timeout exhausted; forcibly shut down the socket.
                    self._force_close(worker.conn)
                    worker.join()
            except ignored_errors:
                pass

    @staticmethod
    @pass_none
    def _force_close(conn):
        if conn.rfile.closed:
            return
        try:
            try:
                conn.socket.shutdown(socket.SHUT_RD)
            except TypeError:
                # pyOpenSSL sockets don't take an arg
                conn.socket.shutdown()
        except OSError:
            # shutdown sometimes fails (race with 'closed' check?)
            # ref #238
            pass

    def _clear_threads(self):
        """Clear self._threads and yield all joinable threads."""
        # threads = pop_all(self._threads)
        threads, self._threads[:] = self._threads[:], []
        return (
            thread
            for thread in threads
            if thread is not threading.currentThread()
        )

    @property
    def qsize(self):
        """Return the queue size."""
        return self._queue.qsize()
<commit_msg>Use `current_thread()` to address Python 3.10 `DeprecationWarning` <commit_after>"""A thread-based worker pool.

.. spelling::

   joinable
"""

from __future__ import absolute_import, division, print_function
__metaclass__ = type

import collections
import threading
import time
import socket
import warnings

from six.moves import queue

from jaraco.functools import pass_none

__all__ = ('WorkerThread', 'ThreadPool')

class TrueyZero:
    """Object which equals and does math like the integer 0 but evals True."""

    def __add__(self, other):
        return other

    def __radd__(self, other):
        return other

trueyzero = TrueyZero()

_SHUTDOWNREQUEST = None

class WorkerThread(threading.Thread):
    """Thread which continuously polls a Queue for Connection objects.

    Due to the timing issues of polling a Queue, a WorkerThread does not
    check its own 'ready' flag after it has started. To stop the thread,
    it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
    (one for each running WorkerThread).
    """

    conn = None
    """The current connection pulled off the Queue, or None."""

    server = None
    """The HTTP Server which spawned this thread, and which owns the
    Queue and is placing active connections into it."""

    ready = False
    """A simple flag for the calling server to know when this thread
    has begun polling the Queue."""

    def __init__(self, server):
        """Initialize WorkerThread instance.

        Args:
            server (cheroot.server.HTTPServer): web server object
                receiving this request
        """
        self.ready = False
        self.server = server

        self.requests_seen = 0
        self.bytes_read = 0
        self.bytes_written = 0
        self.start_time = None
        self.work_time = 0
        self.stats = {
            'Requests': lambda s: self.requests_seen + (
                self.start_time is None
                and trueyzero
                or self.conn.requests_seen
            ),
            'Bytes Read': lambda s: self.bytes_read + (
                self.start_time is None
                and trueyzero
                or self.conn.rfile.bytes_read
            ),
            'Bytes Written': lambda s: self.bytes_written + (
                self.start_time is None
                and trueyzero
                or self.conn.wfile.bytes_written
            ),
            'Work Time': lambda s: self.work_time + (
                self.start_time is None
                and trueyzero
                or time.time() - self.start_time
            ),
            'Read Throughput': lambda s: s['Bytes Read'](s) / (
                s['Work Time'](s) or 1e-6
            ),
            'Write Throughput': lambda s: s['Bytes Written'](s) / (
                s['Work Time'](s) or 1e-6
            ),
        }
        threading.Thread.__init__(self)

    def run(self):
        """Process incoming HTTP connections.

        Retrieves incoming connections from thread pool.
        """
        self.server.stats['Worker Threads'][self.getName()] = self.stats
        try:
            self.ready = True
            while True:
                conn = self.server.requests.get()
                if conn is _SHUTDOWNREQUEST:
                    return

                self.conn = conn
                is_stats_enabled = self.server.stats['Enabled']
                if is_stats_enabled:
                    self.start_time = time.time()
                keep_conn_open = False
                try:
                    keep_conn_open = conn.communicate()
                finally:
                    if keep_conn_open:
                        self.server.put_conn(conn)
                    else:
                        conn.close()
                    if is_stats_enabled:
                        self.requests_seen += self.conn.requests_seen
                        self.bytes_read += self.conn.rfile.bytes_read
                        self.bytes_written += self.conn.wfile.bytes_written
                        self.work_time += time.time() - self.start_time
                        self.start_time = None
                    self.conn = None
        except (KeyboardInterrupt, SystemExit) as ex:
            self.server.interrupt = ex

class ThreadPool:
    """A Request Queue for an HTTPServer which pools threads.

    ThreadPool objects must provide min, get(), put(obj), start()
    and stop(timeout) attributes.
    """

    def __init__(
            self, server, min=10, max=-1, accepted_queue_size=-1,
            accepted_queue_timeout=10,
    ):
        """Initialize HTTP requests queue instance.

        Args:
            server (cheroot.server.HTTPServer): web server object
                receiving this request
            min (int): minimum number of worker threads
            max (int): maximum number of worker threads
            accepted_queue_size (int): maximum number of active
                requests in queue
            accepted_queue_timeout (int): timeout for putting request
                into queue
        """
        self.server = server
        self.min = min
        self.max = max
        self._threads = []
        self._queue = queue.Queue(maxsize=accepted_queue_size)
        self._queue_put_timeout = accepted_queue_timeout
        self.get = self._queue.get
        self._pending_shutdowns = collections.deque()

    def start(self):
        """Start the pool of threads."""
        for i in range(self.min):
            self._threads.append(WorkerThread(self.server))
        for worker in self._threads:
            worker.setName(
                'CP Server {worker_name!s}'.
                format(worker_name=worker.getName()),
            )
            worker.start()
        for worker in self._threads:
            while not worker.ready:
                time.sleep(.1)

    @property
    def idle(self):  # noqa: D401; irrelevant for properties
        """Number of worker threads which are idle. Read-only."""
        idles = len([t for t in self._threads if t.conn is None])
        return max(idles - len(self._pending_shutdowns), 0)

    def put(self, obj):
        """Put request into queue.

        Args:
            obj (:py:class:`~cheroot.server.HTTPConnection`): HTTP connection
                waiting to be processed
        """
        self._queue.put(obj, block=True, timeout=self._queue_put_timeout)

    def _clear_dead_threads(self):
        # Remove any dead threads from our list
        for t in [t for t in self._threads if not t.is_alive()]:
            self._threads.remove(t)
            try:
                self._pending_shutdowns.popleft()
            except IndexError:
                pass

    def grow(self, amount):
        """Spawn new worker threads (not above self.max)."""
        if self.max > 0:
            budget = max(self.max - len(self._threads), 0)
        else:
            # self.max <= 0 indicates no maximum
            budget = float('inf')

        n_new = min(amount, budget)

        workers = [self._spawn_worker() for i in range(n_new)]
        while not all(worker.ready for worker in workers):
            time.sleep(.1)
        self._threads.extend(workers)

    def _spawn_worker(self):
        worker = WorkerThread(self.server)
        worker.setName(
            'CP Server {worker_name!s}'.
            format(worker_name=worker.getName()),
        )
        worker.start()
        return worker

    def shrink(self, amount):
        """Kill off worker threads (not below self.min)."""
        # Grow/shrink the pool if necessary.
        # Remove any dead threads from our list
        amount -= len(self._pending_shutdowns)
        self._clear_dead_threads()
        if amount <= 0:
            return

        # calculate the number of threads above the minimum
        n_extra = max(len(self._threads) - self.min, 0)

        # don't remove more than amount
        n_to_remove = min(amount, n_extra)

        # put shutdown requests on the queue equal to the number of threads
        # to remove. As each request is processed by a worker, that worker
        # will terminate and be culled from the list.
        for n in range(n_to_remove):
            self._pending_shutdowns.append(None)
            self._queue.put(_SHUTDOWNREQUEST)

    def stop(self, timeout=5):
        """Terminate all worker threads.

        Args:
            timeout (int): time to wait for threads to stop gracefully
        """
        # for compatability, negative timeouts are treated like None
        # TODO: treat negative timeouts like already expired timeouts
        if timeout is not None and timeout < 0:
            timeout = None
            warnings.warning(
                'In the future, negative timeouts to Server.stop() '
                'will be equivalent to a timeout of zero.',
                stacklevel=2,
            )

        if timeout is not None:
            endtime = time.time() + timeout

        # Must shut down threads here so the code that calls
        # this method can know when all threads are stopped.
        for worker in self._threads:
            self._queue.put(_SHUTDOWNREQUEST)

        ignored_errors = (
            # TODO: explain this exception.
            AssertionError,
            # Ignore repeated Ctrl-C. See cherrypy#691.
            KeyboardInterrupt,
        )

        for worker in self._clear_threads():
            remaining_time = timeout and endtime - time.time()
            try:
                worker.join(remaining_time)
                if worker.is_alive():
                    # Timeout exhausted; forcibly shut down the socket.
                    self._force_close(worker.conn)
                    worker.join()
            except ignored_errors:
                pass

    @staticmethod
    @pass_none
    def _force_close(conn):
        if conn.rfile.closed:
            return
        try:
            try:
                conn.socket.shutdown(socket.SHUT_RD)
            except TypeError:
                # pyOpenSSL sockets don't take an arg
                conn.socket.shutdown()
        except OSError:
            # shutdown sometimes fails (race with 'closed' check?)
            # ref #238
            pass

    def _clear_threads(self):
        """Clear self._threads and yield all joinable threads."""
        # threads = pop_all(self._threads)
        threads, self._threads[:] = self._threads[:], []
        return (
            thread
            for thread in threads
            if thread is not threading.current_thread()
        )

    @property
    def qsize(self):
        """Return the queue size."""
        return self._queue.qsize()
<|endoftext|>


<commit_before>from flask import Flask
from flask import request
from rasa_nlu.config import RasaNLUConfig
from rasa_nlu.converters import load_data
from rasa_nlu.model import Trainer
from rasa_nlu.model import Metadata, Interpreter
from controllers import nlpController

util.load_src_dir_to_sys_path()
from postgresql_db import database

app = Flask(__name__)

db = database.connect(app, 'postgres', os.environ['POSTGRES_PASSWORD'], 'postgres')
ma = Marshmallow(app)

CORS(app)

##This is the RASA Trainer
training_data = load_data('rasa/data/Problem_identifier.json')  # Where to fish the data it is being trained
trainer = Trainer(RasaNLUConfig(
    "rasa/config/config_spacy.json"))  # Choosing the trainer (in this case spacy, not the default one from rasa)
trainer.train(training_data)  # Train the actual data
model_directory = trainer.persist('./projects/default/')  # Where the models are stored
interpreter = Interpreter.load(model_directory, RasaNLUConfig(
    "rasa/config/config_spacy.json"))  # to use the builder, pass it as an arg when loading the model

##interpreter will parse incoming text to the nlp_service and furnish it back in a Json Format:
'''
{'intent':
{'name': 'greet',
'confidence': 0.67869660247875474},
'entities': [],
'intent_ranking':
    [{'name': 'greet', 'confidence': 0.67869660247875474},
    {'name': 'goodbye', 'confidence': 0.14246669235938911},
    {'name': 'restaurant_search', 'confidence': 0.094058190578983264},
    {'name': 'affirm', 'confidence': 0.084778514582872916}],
'text': 'hello'}

'''

## Results from a simple text interpreter.parse(u"hello")
@app.route("/claim_category", methods=['POST'])
def classify_claim_category():
    input = request.get_json()
    return nlpController.classify_claim_category(input['conversation_id'], input['message'])

@app.route("/submit_message", methods=['POST'])
def submit_message():
    input = request.get_json()
    return nlpController.process_user_input(input['conversation_id'], input['message'])
<commit_msg>[#75] Missing util import in app.py of nlp service<commit_after>from flask import Flask
from flask import request
from rasa_nlu.config import RasaNLUConfig
from rasa_nlu.converters import load_data
from rasa_nlu.model import Trainer
from rasa_nlu.model import Metadata, Interpreter
from controllers import nlpController
import util

util.load_src_dir_to_sys_path()
from postgresql_db import database

app = Flask(__name__)

db = database.connect(app, 'postgres', os.environ['POSTGRES_PASSWORD'], 'postgres')
ma = Marshmallow(app)

CORS(app)

##This is the RASA Trainer
training_data = load_data('rasa/data/Problem_identifier.json')  # Where to fish the data it is being trained
trainer = Trainer(RasaNLUConfig(
    "rasa/config/config_spacy.json"))  # Choosing the trainer (in this case spacy, not the default one from rasa)
trainer.train(training_data)  # Train the actual data
model_directory = trainer.persist('./projects/default/')  # Where the models are stored
interpreter = Interpreter.load(model_directory, RasaNLUConfig(
    "rasa/config/config_spacy.json"))  # to use the builder, pass it as an arg when loading the model

##interpreter will parse incoming text to the nlp_service and furnish it back in a Json Format:
'''
{'intent':
{'name': 'greet',
'confidence': 0.67869660247875474},
'entities': [],
'intent_ranking':
    [{'name': 'greet', 'confidence': 0.67869660247875474},
    {'name': 'goodbye', 'confidence': 0.14246669235938911},
    {'name': 'restaurant_search', 'confidence': 0.094058190578983264},
    {'name': 'affirm', 'confidence': 0.084778514582872916}],
'text': 'hello'}

'''

## Results from a simple text interpreter.parse(u"hello")
@app.route("/claim_category", methods=['POST'])
def classify_claim_category():
    input = request.get_json()
    return nlpController.classify_claim_category(input['conversation_id'], input['message'])

@app.route("/submit_message", methods=['POST'])
def submit_message():
    input = request.get_json()
    return nlpController.process_user_input(input['conversation_id'], input['message'])
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import re

_REGEX = re.compile('^(?P<major>[0-9]+)'
                    '\.(?P<minor>[0-9]+)'
                    '\.(?P<patch>[0-9]+)'
                    '(\-(?P<prerelease>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?'
                    '(\+(?P<build>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?$')

def parse(version):
    """
    Parse version to major, minor, patch, pre-release, build parts.
    """
    match = _REGEX.match(version)
    if match is None:
        raise ValueError('%s is not valid SemVer string' % version)

    verinfo = match.groupdict()

    verinfo['major'] = int(verinfo['major'])
    verinfo['minor'] = int(verinfo['minor'])
    verinfo['patch'] = int(verinfo['patch'])

    return verinfo

def compare(ver1, ver2):
    def nat_cmp(a, b):
        a, b = a or '', b or ''
        convert = lambda text: text.isdigit() and int(text) or text.lower()
        alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
        return cmp(alphanum_key(a), alphanum_key(b))

    def compare_by_keys(d1, d2):
        for key in ['major', 'minor', 'patch']:
            v = cmp(d1.get(key), d2.get(key))
            if v:
                return v
        rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
        build1, build2 = d1.get('build'), d2.get('build')
        rccmp = nat_cmp(rc1, rc2)
        buildcmp = nat_cmp(build1, build2)
        if not (rc1 or rc2):
            return buildcmp
        elif not rc1:
            return 1
        elif not rc2:
            return -1
        return rccmp or buildcmp or 0

    v1, v2 = parse(ver1), parse(ver2)

    return compare_by_keys(v1, v2)

def match(version, match_expr):
    prefix = match_expr[:2]
    if prefix in ('>=', '<=', '=='):
        match_version = match_expr[2:]
    elif prefix and prefix[0] in ('>', '<', '='):
        prefix = prefix[0]
        match_version = match_expr[1:]
    else:
        raise ValueError("match_expr parameter should be in format <op><ver>, "
                         "where <op> is one of ['<', '>', '==', '<=', '>=']. "
                         "You provided: %r" % match_expr)

    possibilities_dict = {
        '>': (1,),
        '<': (-1,),
        '==': (0,),
        '>=': (0, 1),
        '<=': (-1, 0)
    }

    possibilities = possibilities_dict[prefix]
    cmp_res = compare(version, match_version)

    return cmp_res in possibilities
<commit_msg>Add support for Python 3.x<commit_after># -*- coding: utf-8 -*-

import re

_REGEX = re.compile('^(?P<major>[0-9]+)'
                    '\.(?P<minor>[0-9]+)'
                    '\.(?P<patch>[0-9]+)'
                    '(\-(?P<prerelease>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?'
                    '(\+(?P<build>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?$')

if 'cmp' not in __builtins__:
    cmp = lambda a,b: (a > b) - (a < b)

def parse(version):
    """
    Parse version to major, minor, patch, pre-release, build parts.
    """
    match = _REGEX.match(version)
    if match is None:
        raise ValueError('%s is not valid SemVer string' % version)

    verinfo = match.groupdict()

    verinfo['major'] = int(verinfo['major'])
    verinfo['minor'] = int(verinfo['minor'])
    verinfo['patch'] = int(verinfo['patch'])

    return verinfo

def compare(ver1, ver2):
    def nat_cmp(a, b):
        a, b = a or '', b or ''
        convert = lambda text: text.isdigit() and int(text) or text.lower()
        alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
        return cmp(alphanum_key(a), alphanum_key(b))

    def compare_by_keys(d1, d2):
        for key in ['major', 'minor', 'patch']:
            v = cmp(d1.get(key), d2.get(key))
            if v:
                return v
        rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
        build1, build2 = d1.get('build'), d2.get('build')
        rccmp = nat_cmp(rc1, rc2)
        buildcmp = nat_cmp(build1, build2)
        if not (rc1 or rc2):
            return buildcmp
        elif not rc1:
            return 1
        elif not rc2:
            return -1
        return rccmp or buildcmp or 0

    v1, v2 = parse(ver1), parse(ver2)

    return compare_by_keys(v1, v2)

def match(version, match_expr):
    prefix = match_expr[:2]
    if prefix in ('>=', '<=', '=='):
        match_version = match_expr[2:]
    elif prefix and prefix[0] in ('>', '<', '='):
        prefix = prefix[0]
        match_version = match_expr[1:]
    else:
        raise ValueError("match_expr parameter should be in format <op><ver>, "
                         "where <op> is one of ['<', '>', '==', '<=', '>=']. "
                         "You provided: %r" % match_expr)

    possibilities_dict = {
        '>': (1,),
        '<': (-1,),
        '==': (0,),
        '>=': (0, 1),
        '<=': (-1, 0)
    }

    possibilities = possibilities_dict[prefix]
    cmp_res = compare(version, match_version)

    return cmp_res in possibilities
<|endoftext|>