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

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

"""
Generic REST client
"""

import httplib2
import json

__version__   = "0.9"
__author__    = "Nigel Small <py2neo@nigelsmall.org>"
__copyright__ = "Copyright 2011 Nigel Small"
__license__   = "Apache License, Version 2.0"

class Resource(object):
	"""
	RESTful web service resource class, designed to work with a well-behaved
	hypermedia web service
	"""

	SUPPORTED_CONTENT_TYPES = ['application/json']

	def __init__(self, uri, content_type='application/json', http=None):
		"""
		Creates a representation of a RESTful web service resource identified by URI.

		@param uri:  the URI identifying this resource
		@param http: httplib2.Http object to use for requests (optional)

		"""
		if content_type not in self.SUPPORTED_CONTENT_TYPES:
			raise NotImplementedError("Content type %s not supported" % content_type)
		self._uri = unicode(uri)
		self._content_type = content_type
		self._http = http or httplib2.Http()
		self._index = None

	def __repr__(self):
		"""
		Returns a valid Python representation of this object.
		"""
		return '%s(%s)' % (self.__class__.__name__, repr(self._uri))

	def __eq__(self, other):
		"""
		Determines equality of two objects based on URI.
		"""
		return self._uri == other._uri

	def __ne__(self, other):
		"""
		Determines inequality of two objects based on URI.
		"""
		return self._uri != other._uri

	def __get_request_headers(self, *keys):
		return dict([
			(key, self._content_type)
			for key in keys
			if key in ['Accept', 'Content-Type']
		])

	def _request(self, method, uri, data=None):
		"""
		Issues an HTTP request.

		@param method: the HTTP method to use for this call
		@param uri: the URI of the resource to access
		@param data: unserialised object to be converted to JSON and passed in request payload (optional)
		@return: object created from returned content (200), C{Location} header value (201) or C{None} (204)
		@raise ValueError: when supplied data is not appropriate (400)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when a conflict occurs (409) or when an unexpected HTTP status is received

		"""
		if data is not None:
			headers = self.__get_request_headers('Accept', 'Content-Type')
		else:
			headers = self.__get_request_headers('Accept')
		try:
			self.__response, self.__content = self._http.request(
				uri, method, data, headers
			)
		except:
			raise IOError("Cannot send %s request" %s (method));
		if self.__response.status == 200:
			return json.loads(self.__content)
		elif self.__response.status == 201:
			return self.__response['location']
		elif self.__response.status == 204:
			return None
		elif self.__response.status == 400:
			raise ValueError(data)
		elif self.__response.status == 404:
			raise LookupError(uri)
		elif self.__response.status == 409:
			raise SystemError(uri)
		else:
			raise SystemError(self.__response)

	def _get(self, uri):
		"""
		Issues an HTTP GET request.

		@param uri: the URI of the resource to GET
		@return: object created from returned content (200) or C{None} (204)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('GET', uri)

	def _post(self, uri, data):
		"""
		Issues an HTTP POST request.

		@param uri: the URI of the resource to POST to
		@param data: unserialised object to be converted to JSON and passed in request payload
		@return: object created from returned content (200), C{Location} header value (201) or C{None} (204)
		@raise ValueError: when supplied data is not appropriate (400)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('POST', uri, json.dumps(data))

	def _put(self, uri, data):
		"""
		Issues an HTTP PUT request.

		@param uri: the URI of the resource to PUT
		@param data: unserialised object to be converted to JSON and passed in request payload
		@return: C{None} (204)
		@raise ValueError: when supplied data is not appropriate (400)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('PUT', uri, json.dumps(data))

	def _delete(self, uri):
		"""
		Issues an HTTP DELETE request.

		@param uri: the URI of the resource to PUT
		@return: C{None} (204)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('DELETE', uri)

	def _lookup(self, key):
		"""
		Looks up a value in the resource index by key; will lazily load
		resource index if required and auto-correct URI from Content-Location
		header.

		@param key: the key of the value to look up in the resource index

		"""
		if(self._index == None):
			self._index = self._get(self._uri)
			if self.__response and 'content-location' in self.__response:
				self._uri = self.__response['content-location']
		if key in self._index:
			return self._index[key]
		else:
			raise KeyError(key)

<commit_msg>Refactoring within rest.py<commit_after>#!/usr/bin/env python

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

"""
Generic REST client
"""

import httplib2
import json

__version__   = "0.9"
__author__    = "Nigel Small <py2neo@nigelsmall.org>"
__copyright__ = "Copyright 2011 Nigel Small"
__license__   = "Apache License, Version 2.0"

class Resource(object):
	"""
	RESTful web service resource class, designed to work with a well-behaved
	hypermedia web service
	"""

	SUPPORTED_CONTENT_TYPES = ['application/json']

	def __init__(self, uri, content_type='application/json', http=None):
		"""
		Creates a representation of a RESTful web service resource identified by URI.

		@param uri:  the URI identifying this resource
		@param http: httplib2.Http object to use for requests (optional)

		"""
		if content_type not in self.SUPPORTED_CONTENT_TYPES:
			raise NotImplementedError("Content type %s not supported" % content_type)
		self._uri = unicode(uri)
		self._content_type = content_type
		self._http = http or httplib2.Http()
		self._index = None

	def __repr__(self):
		"""
		Returns a valid Python representation of this object.
		"""
		return '%s(%s)' % (self.__class__.__name__, repr(self._uri))

	def __eq__(self, other):
		"""
		Determines equality of two objects based on URI.
		"""
		return self._uri == other._uri

	def __ne__(self, other):
		"""
		Determines inequality of two objects based on URI.
		"""
		return self._uri != other._uri

	def __get_request_headers(self, *keys):
		return dict([
			(key, self._content_type)
			for key in keys
			if key in ['Accept', 'Content-Type']
		])

	def _request(self, method, uri, data=None):
		"""
		Issues an HTTP request.

		@param method: the HTTP method to use for this call
		@param uri: the URI of the resource to access
		@param data: unserialised object to be converted to JSON and passed in request payload (optional)
		@return: object created from returned content (200), C{Location} header value (201) or C{None} (204)
		@raise ValueError: when supplied data is not appropriate (400)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when a conflict occurs (409) or when an unexpected HTTP status is received

		"""
		if data is not None:
			headers = self.__get_request_headers('Accept', 'Content-Type')
		else:
			headers = self.__get_request_headers('Accept')
		try:
			self.__response, self.__content = self._http.request(
				uri, method, data, headers
			)
		except:
			raise IOError("Cannot send %s request" % (method));
		if self.__response.status == 200:
			return json.loads(self.__content)
		elif self.__response.status == 201:
			return self.__response['location']
		elif self.__response.status == 204:
			return None
		elif self.__response.status == 400:
			raise ValueError(data)
		elif self.__response.status == 404:
			raise LookupError(uri)
		elif self.__response.status == 409:
			raise SystemError(uri)
		else:
			raise SystemError(self.__response)

	def _get(self, uri):
		"""
		Issues an HTTP GET request.

		@param uri: the URI of the resource to GET
		@return: object created from returned content (200) or C{None} (204)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('GET', uri)

	def _post(self, uri, data):
		"""
		Issues an HTTP POST request.

		@param uri: the URI of the resource to POST to
		@param data: unserialised object to be converted to JSON and passed in request payload
		@return: object created from returned content (200), C{Location} header value (201) or C{None} (204)
		@raise ValueError: when supplied data is not appropriate (400)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('POST', uri, json.dumps(data))

	def _put(self, uri, data):
		"""
		Issues an HTTP PUT request.

		@param uri: the URI of the resource to PUT
		@param data: unserialised object to be converted to JSON and passed in request payload
		@return: C{None} (204)
		@raise ValueError: when supplied data is not appropriate (400)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('PUT', uri, json.dumps(data))

	def _delete(self, uri):
		"""
		Issues an HTTP DELETE request.

		@param uri: the URI of the resource to PUT
		@return: C{None} (204)
		@raise KeyError: when URI is not found (404)
		@raise SystemError: when an unexpected HTTP status is received

		"""
		return self._request('DELETE', uri)

	def _lookup(self, key):
		"""
		Looks up a value in the resource index by key; will lazily load
		resource index if required and auto-correct URI from Content-Location
		header.

		@param key: the key of the value to look up in the resource index

		"""
		if(self._index == None):
			self._index = self._get(self._uri)
			if self.__response and 'content-location' in self.__response:
				self._uri = self.__response['content-location']
		if key in self._index:
			return self._index[key]
		else:
			raise KeyError(key)

<|endoftext|>


<commit_before># coding: utf-8
from language import StoryLanguage
import sys
import re

TEMPLATE_PATTERN = r'\$[a-zA-Z]\w*'
"""
TODO:
    prettify the output of defined steps (patterns), like:
    @When(r'I sum 1 \+ 1'), prettify this kind of pattern
"""

class Step(object):
    '''Step is a baseclass for step directives'''

    name = 'step'

    def __init__(self, message, *args):
        self._message = message
        self._args = args

    def _set_step_attrs(self, local_attrs):
        for private_step in ['_givens', '_whens', '_thens']:
            if not private_step in local_attrs:
                local_attrs[private_step] = []

    def __call__(self, method=None):
        frame = sys._getframe(1)
        step = self.__class__.name
        self._set_step_attrs(frame.f_locals)
        steps = frame.f_locals['_%ss' % step]
        steps.append((method, self._message, self._args))
        return method

class Given(Step):
    name = 'given'

class When(Step):
    name = 'when'

class Then(Step):
    name = 'then'

class DadoQue(Given):
    '''given in portuguese'''

class Quando(When):
    '''when in portuguese'''

class Entao(Then):
    '''then in portuguese'''

class Story(object):
    def __init__(self, title='',
                       as_a='',
                       i_want_to='',
                       so_that='',
                       language='en-us'):
        self._language = StoryLanguage(language)
        self._title = title or self._language['empty_story_title']
        self._as_a = as_a
        self._i_want_to = i_want_to
        self._so_that = so_that
        self._scenarios = []

    def _set_defined_steps(self, scenario):
        for step in ['_givens', '_whens', '_thens']:
            scenario_steps = getattr(scenario, step)
            for i in range(len(scenario_steps)):
                method, msg, args = scenario_steps[i]
                if method is None:
                    for scenario2 in self._scenarios:
                        ok = False
                        for meth2, msg2, args2 in getattr(scenario2, step):
                            msg_pattern = re.sub(TEMPLATE_PATTERN, r'(.*)', msg2)
                            regex = re.match(msg_pattern, msg)
                            if regex:
                                scenario_steps[i] = meth2, msg, regex.groups()
                                ok = True
                                break
                        if ok:
                            break

                    else:
                        def undefined_step(self):
                            raise Exception('%s -- %s' % (self._language['undefined_step'], msg))
                        scenario_steps[i] = undefined_step, msg, args

    def add_scenario(self, scenario):
        scenario.set_story(self)
        self._set_defined_steps(scenario)
        self._scenarios.append(scenario)
        return self

    def show_story_title(self):
        print '%s: %s' % (self._language['story'], self._title)

    def show_header(self):
        if not (self._as_a == self._i_want_to and self._so_that == ''):
            print self._language['as_a'], self._as_a
            print self._language['i_want_to'], self._i_want_to
            print self._language['so_that'], self._so_that

    def run(self):
        self.show_story_title()
        self.show_header()
        for scenario, number in zip(self._scenarios, range(1, len(self._scenarios)+1)):
            print '\n%s %d: %s' % (self._language['scenario'], number, scenario.title)
            scenario.run()

class Scenario(object):
    def __init__(self, title='', language='en-us'):
        self._language = StoryLanguage(language)
        self._title = title or self._language['empty_scenario_title']
        self._errors = []
        self._story = []

    @property
    def title(self):
        return self._title

    def set_story(self, story):
        self._story = story
        self._language = story._language

    def run(self):
        self.run_steps(self._givens, 'given')
        self.run_steps(self._whens, 'when')
        self.run_steps(self._thens, 'then')
        if self._errors:
            print '\n\n%ss:' % self._language['fail']
            for error in self._errors:
                if not error.args:
                    error = self._language['exception_thrown'] % str(error.__class__)
                print ' ', error

    def _replace_template(self, message, args):
        for arg in args:
            message = re.sub(TEMPLATE_PATTERN, str(arg), message, 1)
        return message

    def _run_step(self, step, step_name):
        method, message, args = step
        message = self._replace_template(message, args)
        try:
            method(self, *args)
            print '  %s %s   ... OK' % (self._language[step_name], message)
        except Exception, e:
            self._errors.append(e)
            print '  %s %s   ... %s' % (self._language[step_name],
                                    message,
                                    self._language['fail'].upper())
            self._errors.append(e)

    def run_steps(self, steps, step_name):
        if steps == []:
            return False

        self._run_step(steps[0], step_name)
        for step in steps[1:]:
            self._run_step(step, 'and_word')
<commit_msg>removed the need of () for defined steps<commit_after># coding: utf-8
from language import StoryLanguage
import sys
import re

TEMPLATE_PATTERN = r'\$[a-zA-Z]\w*'
"""
TODO:
    prettify the output of defined steps (patterns), like:
    @When(r'I sum 1 \+ 1'), prettify this kind of pattern
"""

class Step(object):
    '''Step is a baseclass for step directives'''

    name = 'step'

    def __init__(self, message, *args):
        self._message = message
        self._args = args
        self._context = sys._getframe(1)
        self._set_step_attrs(self._context.f_locals)
        step = self.__class__.name
        self._steps = self._context.f_locals['_%ss' % step]
        self._steps.append((None, self._message, self._args))

    def _set_step_attrs(self, local_attrs):
        for private_step in ['_givens', '_whens', '_thens']:
            if not private_step in local_attrs:
                local_attrs[private_step] = []

    def __call__(self, method=None):
        del self._steps[-1]
        self._steps.append((method, self._message, self._args))
        return method

class Given(Step):
    name = 'given'

class When(Step):
    name = 'when'

class Then(Step):
    name = 'then'

class DadoQue(Given):
    '''given in portuguese'''

class Quando(When):
    '''when in portuguese'''

class Entao(Then):
    '''then in portuguese'''

class Story(object):
    def __init__(self, title='',
                       as_a='',
                       i_want_to='',
                       so_that='',
                       language='en-us'):
        self._language = StoryLanguage(language)
        self._title = title or self._language['empty_story_title']
        self._as_a = as_a
        self._i_want_to = i_want_to
        self._so_that = so_that
        self._scenarios = []

    def _set_defined_steps(self, scenario):
        for step in ['_givens', '_whens', '_thens']:
            scenario_steps = getattr(scenario, step)
            for i in range(len(scenario_steps)):
                method, msg, args = scenario_steps[i]
                if method is None:
                    for scenario2 in self._scenarios:
                        ok = False
                        for meth2, msg2, args2 in getattr(scenario2, step):
                            msg_pattern = re.sub(TEMPLATE_PATTERN, r'(.*)', msg2)
                            regex = re.match(msg_pattern, msg)
                            if regex:
                                scenario_steps[i] = meth2, msg, regex.groups()
                                ok = True
                                break
                        if ok:
                            break

                    else:
                        def undefined_step(self):
                            raise Exception('%s -- %s' % (self._language['undefined_step'], msg))
                        scenario_steps[i] = undefined_step, msg, args

    def add_scenario(self, scenario):
        scenario.set_story(self)
        self._set_defined_steps(scenario)
        self._scenarios.append(scenario)
        return self

    def show_story_title(self):
        print '%s: %s' % (self._language['story'], self._title)

    def show_header(self):
        if not (self._as_a == self._i_want_to and self._so_that == ''):
            print self._language['as_a'], self._as_a
            print self._language['i_want_to'], self._i_want_to
            print self._language['so_that'], self._so_that

    def run(self):
        self.show_story_title()
        self.show_header()
        for scenario, number in zip(self._scenarios, range(1, len(self._scenarios)+1)):
            print '\n%s %d: %s' % (self._language['scenario'], number, scenario.title)
            scenario.run()

class Scenario(object):
    def __init__(self, title='', language='en-us'):
        self._language = StoryLanguage(language)
        self._title = title or self._language['empty_scenario_title']
        self._errors = []
        self._story = []

    @property
    def title(self):
        return self._title

    def set_story(self, story):
        self._story = story
        self._language = story._language

    def run(self):
        self.run_steps(self._givens, 'given')
        self.run_steps(self._whens, 'when')
        self.run_steps(self._thens, 'then')
        if self._errors:
            print '\n\n%ss:' % self._language['fail']
            for error in self._errors:
                if not error.args:
                    error = self._language['exception_thrown'] % str(error.__class__)
                print ' ', error

    def _replace_template(self, message, args):
        for arg in args:
            message = re.sub(TEMPLATE_PATTERN, str(arg), message, 1)
        return message

    def _run_step(self, step, step_name):
        method, message, args = step
        message = self._replace_template(message, args)
        try:
            method(self, *args)
            print '  %s %s   ... OK' % (self._language[step_name], message)
        except Exception, e:
            self._errors.append(e)
            print '  %s %s   ... %s' % (self._language[step_name],
                                    message,
                                    self._language['fail'].upper())
            self._errors.append(e)

    def run_steps(self, steps, step_name):
        if steps == []:
            return False

        self._run_step(steps[0], step_name)
        for step in steps[1:]:
            self._run_step(step, 'and_word')
<|endoftext|>


<commit_before>"""Mypy static type checker plugin for Pytest"""

import functools
import json
import os
from tempfile import NamedTemporaryFile

from filelock import FileLock  # type: ignore
import mypy.api
import pytest  # type: ignore

mypy_argv = []
nodeid_name = 'mypy'

def pytest_addoption(parser):
    """Add options for enabling and running mypy."""
    group = parser.getgroup('mypy')
    group.addoption(
        '--mypy', action='store_true',
        help='run mypy on .py files')
    group.addoption(
        '--mypy-ignore-missing-imports', action='store_true',
        help="suppresses error messages about imports that cannot be resolved")

def _is_master(config):
    """
    True if the code running the given pytest.config object is running in
    an xdist master node or not running xdist at all.
    """
    return not hasattr(config, 'slaveinput')

def pytest_configure(config):
    """
    Initialize the path used to cache mypy results,
    register a custom marker for MypyItems,
    and configure the plugin based on the CLI.
    """
    if _is_master(config):

        # Get the path to a temporary file and delete it.
        # The first MypyItem to run will see the file does not exist,
        # and it will run and parse mypy results to create it.
        # Subsequent MypyItems will see the file exists,
        # and they will read the parsed results.
        with NamedTemporaryFile(delete=True) as tmp_f:
            config._mypy_results_path = tmp_f.name

        # If xdist is enabled, then the results path should be exposed to
        # the slaves so that they know where to read parsed results from.
        if config.pluginmanager.getplugin('xdist'):
            class _MypyXdistPlugin:
                def pytest_configure_node(self, node):  # xdist hook
                    """Pass config._mypy_results_path to workers."""
                    node.slaveinput['_mypy_results_path'] = \
                        node.config._mypy_results_path
            config.pluginmanager.register(_MypyXdistPlugin())

    # pytest_terminal_summary cannot accept config before pytest 4.2.
    global _pytest_terminal_summary_config
    _pytest_terminal_summary_config = config

    config.addinivalue_line(
        'markers',
        '{marker}: mark tests to be checked by mypy.'.format(
            marker=MypyItem.MARKER,
        ),
    )
    if config.getoption('--mypy-ignore-missing-imports'):
        mypy_argv.append('--ignore-missing-imports')

def pytest_collect_file(path, parent):
    """Create a MypyFileItem for every file mypy should run on."""
    if path.ext == '.py' and any([
            parent.config.option.mypy,
            parent.config.option.mypy_ignore_missing_imports,
    ]):
        item = MypyFileItem(path, parent)
        if nodeid_name:
            item = MypyFileItem(
                path,
                parent,
                nodeid='::'.join([item.nodeid, nodeid_name]),
            )
        return item
    return None

@pytest.hookimpl(hookwrapper=True, trylast=True)
def pytest_collection_modifyitems(session, config, items):
    """
    Add a MypyStatusItem if any MypyFileItems were collected.

    Since mypy might check files that were not collected,
    pytest could pass even though mypy failed!
    To prevent that, add an explicit check for the mypy exit status.

    This should execute as late as possible to avoid missing any
    MypyFileItems injected by other pytest_collection_modifyitems
    implementations.
    """
    yield
    if any(isinstance(item, MypyFileItem) for item in items):
        items.append(MypyStatusItem(nodeid_name, session, config, session))

class MypyItem(pytest.Item):

    """A Mypy-related test Item."""

    MARKER = 'mypy'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.add_marker(self.MARKER)

    def repr_failure(self, excinfo):
        """
        Unwrap mypy errors so we get a clean error message without the
        full exception repr.
        """
        if excinfo.errisinstance(MypyError):
            return excinfo.value.args[0]
        return super().repr_failure(excinfo)

class MypyFileItem(MypyItem, pytest.File):

    """A File that Mypy Runs On."""

    def runtest(self):
        """Raise an exception if mypy found errors for this item."""
        results = _mypy_results(self.session)
        abspath = os.path.abspath(str(self.fspath))
        errors = results['abspath_errors'].get(abspath)
        if errors:
            raise MypyError('\n'.join(errors))

    def reportinfo(self):
        """Produce a heading for the test report."""
        return (
            self.fspath,
            None,
            self.config.invocation_dir.bestrelpath(self.fspath),
        )

class MypyStatusItem(MypyItem):

    """A check for a non-zero mypy exit status."""

    def runtest(self):
        """Raise a MypyError if mypy exited with a non-zero status."""
        results = _mypy_results(self.session)
        if results['status']:
            raise MypyError(
                'mypy exited with status {status}.'.format(
                    status=results['status'],
                ),
            )

def _mypy_results(session):
    """Get the cached mypy results for the session, or generate them."""
    return _cached_json_results(
        results_path=(
            session.config._mypy_results_path
            if _is_master(session.config) else
            session.config.slaveinput['_mypy_results_path']
        ),
        results_factory=functools.partial(
            _mypy_results_factory,
            abspaths=[
                os.path.abspath(str(item.fspath))
                for item in session.items
                if isinstance(item, MypyFileItem)
            ],
        )
    )

def _cached_json_results(results_path, results_factory=None):
    """
    Read results from results_path if it exists;
    otherwise, produce them with results_factory,
    and write them to results_path.
    """
    with FileLock(results_path + '.lock'):
        try:
            with open(results_path, mode='r') as results_f:
                results = json.load(results_f)
        except FileNotFoundError:
            if not results_factory:
                raise
            results = results_factory()
            with open(results_path, mode='w') as results_f:
                json.dump(results, results_f)
    return results

def _mypy_results_factory(abspaths):
    """Run mypy on abspaths and return the results as a JSON-able dict."""

    stdout, stderr, status = mypy.api.run(mypy_argv + abspaths)

    abspath_errors, unmatched_lines = {}, []
    for line in stdout.split('\n'):
        if not line:
            continue
        path, _, error = line.partition(':')
        abspath = os.path.abspath(path)
        if abspath in abspaths:
            abspath_errors[abspath] = abspath_errors.get(abspath, []) + [error]
        else:
            unmatched_lines.append(line)

    return {
        'stdout': stdout,
        'stderr': stderr,
        'status': status,
        'abspath_errors': abspath_errors,
        'unmatched_stdout': '\n'.join(unmatched_lines),
    }

class MypyError(Exception):
    """
    An error caught by mypy, e.g a type checker violation
    or a syntax error.
    """

def pytest_terminal_summary(terminalreporter):
    """Report stderr and unrecognized lines from stdout."""
    config = _pytest_terminal_summary_config
    try:
        results = _cached_json_results(config._mypy_results_path)
    except FileNotFoundError:
        # No MypyItems executed.
        return
    if results['unmatched_stdout'] or results['stderr']:
        terminalreporter.section('mypy')
        if results['unmatched_stdout']:
            color = {'red': True} if results['status'] else {'green': True}
            terminalreporter.write_line(results['unmatched_stdout'], **color)
        if results['stderr']:
            terminalreporter.write_line(results['stderr'], yellow=True)
    os.remove(config._mypy_results_path)
<commit_msg>Use Node.from_parent to instantiate MypyItems<commit_after>"""Mypy static type checker plugin for Pytest"""

import functools
import json
import os
from tempfile import NamedTemporaryFile

from filelock import FileLock  # type: ignore
import mypy.api
import pytest  # type: ignore

mypy_argv = []
nodeid_name = 'mypy'

def pytest_addoption(parser):
    """Add options for enabling and running mypy."""
    group = parser.getgroup('mypy')
    group.addoption(
        '--mypy', action='store_true',
        help='run mypy on .py files')
    group.addoption(
        '--mypy-ignore-missing-imports', action='store_true',
        help="suppresses error messages about imports that cannot be resolved")

def _is_master(config):
    """
    True if the code running the given pytest.config object is running in
    an xdist master node or not running xdist at all.
    """
    return not hasattr(config, 'slaveinput')

def pytest_configure(config):
    """
    Initialize the path used to cache mypy results,
    register a custom marker for MypyItems,
    and configure the plugin based on the CLI.
    """
    if _is_master(config):

        # Get the path to a temporary file and delete it.
        # The first MypyItem to run will see the file does not exist,
        # and it will run and parse mypy results to create it.
        # Subsequent MypyItems will see the file exists,
        # and they will read the parsed results.
        with NamedTemporaryFile(delete=True) as tmp_f:
            config._mypy_results_path = tmp_f.name

        # If xdist is enabled, then the results path should be exposed to
        # the slaves so that they know where to read parsed results from.
        if config.pluginmanager.getplugin('xdist'):
            class _MypyXdistPlugin:
                def pytest_configure_node(self, node):  # xdist hook
                    """Pass config._mypy_results_path to workers."""
                    node.slaveinput['_mypy_results_path'] = \
                        node.config._mypy_results_path
            config.pluginmanager.register(_MypyXdistPlugin())

    # pytest_terminal_summary cannot accept config before pytest 4.2.
    global _pytest_terminal_summary_config
    _pytest_terminal_summary_config = config

    config.addinivalue_line(
        'markers',
        '{marker}: mark tests to be checked by mypy.'.format(
            marker=MypyItem.MARKER,
        ),
    )
    if config.getoption('--mypy-ignore-missing-imports'):
        mypy_argv.append('--ignore-missing-imports')

def pytest_collect_file(path, parent):
    """Create a MypyFileItem for every file mypy should run on."""
    if path.ext == '.py' and any([
            parent.config.option.mypy,
            parent.config.option.mypy_ignore_missing_imports,
    ]):
        return MypyFile.from_parent(parent=parent, fspath=path)
    return None

class MypyFile(pytest.File):

    """A File that Mypy will run on."""

    @classmethod
    def from_parent(cls, *args, **kwargs):
        """Override from_parent for compatibility."""
        # pytest.File.from_parent did not exist before pytest 5.4.
        return getattr(super(), 'from_parent', cls)(*args, **kwargs)

    def collect(self):
        """Create a MypyFileItem for the File."""
        yield MypyFileItem.from_parent(parent=self, name=nodeid_name)

@pytest.hookimpl(hookwrapper=True, trylast=True)
def pytest_collection_modifyitems(session, config, items):
    """
    Add a MypyStatusItem if any MypyFileItems were collected.

    Since mypy might check files that were not collected,
    pytest could pass even though mypy failed!
    To prevent that, add an explicit check for the mypy exit status.

    This should execute as late as possible to avoid missing any
    MypyFileItems injected by other pytest_collection_modifyitems
    implementations.
    """
    yield
    if any(isinstance(item, MypyFileItem) for item in items):
        items.append(
            MypyStatusItem.from_parent(parent=session, name=nodeid_name),
        )

class MypyItem(pytest.Item):

    """A Mypy-related test Item."""

    MARKER = 'mypy'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.add_marker(self.MARKER)

    @classmethod
    def from_parent(cls, *args, **kwargs):
        """Override from_parent for compatibility."""
        # pytest.Item.from_parent did not exist before pytest 5.4.
        return getattr(super(), 'from_parent', cls)(*args, **kwargs)

    def repr_failure(self, excinfo):
        """
        Unwrap mypy errors so we get a clean error message without the
        full exception repr.
        """
        if excinfo.errisinstance(MypyError):
            return excinfo.value.args[0]
        return super().repr_failure(excinfo)

class MypyFileItem(MypyItem):

    """A check for Mypy errors in a File."""

    def runtest(self):
        """Raise an exception if mypy found errors for this item."""
        results = _mypy_results(self.session)
        abspath = os.path.abspath(str(self.fspath))
        errors = results['abspath_errors'].get(abspath)
        if errors:
            raise MypyError('\n'.join(errors))

    def reportinfo(self):
        """Produce a heading for the test report."""
        return (
            self.fspath,
            None,
            self.config.invocation_dir.bestrelpath(self.fspath),
        )

class MypyStatusItem(MypyItem):

    """A check for a non-zero mypy exit status."""

    def runtest(self):
        """Raise a MypyError if mypy exited with a non-zero status."""
        results = _mypy_results(self.session)
        if results['status']:
            raise MypyError(
                'mypy exited with status {status}.'.format(
                    status=results['status'],
                ),
            )

def _mypy_results(session):
    """Get the cached mypy results for the session, or generate them."""
    return _cached_json_results(
        results_path=(
            session.config._mypy_results_path
            if _is_master(session.config) else
            session.config.slaveinput['_mypy_results_path']
        ),
        results_factory=functools.partial(
            _mypy_results_factory,
            abspaths=[
                os.path.abspath(str(item.fspath))
                for item in session.items
                if isinstance(item, MypyFileItem)
            ],
        )
    )

def _cached_json_results(results_path, results_factory=None):
    """
    Read results from results_path if it exists;
    otherwise, produce them with results_factory,
    and write them to results_path.
    """
    with FileLock(results_path + '.lock'):
        try:
            with open(results_path, mode='r') as results_f:
                results = json.load(results_f)
        except FileNotFoundError:
            if not results_factory:
                raise
            results = results_factory()
            with open(results_path, mode='w') as results_f:
                json.dump(results, results_f)
    return results

def _mypy_results_factory(abspaths):
    """Run mypy on abspaths and return the results as a JSON-able dict."""

    stdout, stderr, status = mypy.api.run(mypy_argv + abspaths)

    abspath_errors, unmatched_lines = {}, []
    for line in stdout.split('\n'):
        if not line:
            continue
        path, _, error = line.partition(':')
        abspath = os.path.abspath(path)
        if abspath in abspaths:
            abspath_errors[abspath] = abspath_errors.get(abspath, []) + [error]
        else:
            unmatched_lines.append(line)

    return {
        'stdout': stdout,
        'stderr': stderr,
        'status': status,
        'abspath_errors': abspath_errors,
        'unmatched_stdout': '\n'.join(unmatched_lines),
    }

class MypyError(Exception):
    """
    An error caught by mypy, e.g a type checker violation
    or a syntax error.
    """

def pytest_terminal_summary(terminalreporter):
    """Report stderr and unrecognized lines from stdout."""
    config = _pytest_terminal_summary_config
    try:
        results = _cached_json_results(config._mypy_results_path)
    except FileNotFoundError:
        # No MypyItems executed.
        return
    if results['unmatched_stdout'] or results['stderr']:
        terminalreporter.section('mypy')
        if results['unmatched_stdout']:
            color = {'red': True} if results['status'] else {'green': True}
            terminalreporter.write_line(results['unmatched_stdout'], **color)
        if results['stderr']:
            terminalreporter.write_line(results['stderr'], yellow=True)
    os.remove(config._mypy_results_path)
<|endoftext|>


<commit_before># TODO:
# - loops
# - Folgen, Gruppen

class SimpleAnim:
    def __init__(self, node, attrName, duration, useInt, onStop):
        self.node = node
        self.attrName = attrName
        self.duration = duration
        self.startTime = g_Player.getFrameTime()
        self.onStop = onStop
        self.useInt = useInt

class LinearAnim(SimpleAnim):
    def __init__(self, node, attrName, duration, startValue, endValue, useInt, onStop):
        SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop)
        self.__stopTimeout = g_Player.setTimeout(duration, self.__stop)
        self.__interval = g_Player.setInterval(1, self.__step)
        self.__startValue = startValue
        self.__endValue = endValue
        self.__done = False
        self.__step()
    def __step(self):
        if not(self.__done):
            part = ((g_Player.getFrameTime()-self.startTime)/self.duration)
            if part > 1.0:
                part = 1.0
            curValue = self.__startValue+(self.__endValue-self.__startValue)*part
            if self.useInt:
                curValue = int(curValue+0.5)
            setattr(self.node, self.attrName, curValue)
    def __stop(self):
        setattr(self.node, self.attrName, self.__endValue)
        self.__done = True
        g_Player.clearInterval(self.__interval)
        if self.onStop != None:
            self.onStop()
    def abort(self):
        if not(self.__done):
            self.__done = True
            g_Player.clearInterval(self.__interval)
            g_Player.clearInterval(self.__stopTimeout)
    def isDone(self):
        return self.__done

class SplineAnim(SimpleAnim):
    def __init__(self, node, attrName, duration,
            startValue, startSpeed, endValue, endSpeed, useInt, onStop):
        SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop)
        g_Player.setTimeout(duration, self.__stop)
        self.interval = g_Player.setInterval(1, self.__step)
        self.__startValue = startValue+0.0
        self.__startSpeed = startSpeed
        self.__endValue = endValue
        self.__endSpeed = endSpeed
        self.__a = -2*(self.__endValue-self.__startValue)+self.__startSpeed+self.__endSpeed
        self.__b = 3*(self.__endValue-self.__startValue)-2*self.__startSpeed-self.__endSpeed
        self.__c = self.__startSpeed
        self.__d = self.__startValue
        self.__done = 0
        self.__step()
    def __step(self):
        if not(self.__done):
            part = ((g_Player.getFrameTime()-self.startTime)/self.duration)
            curValue = ((self.__a*part+self.__b)*part+self.__c)*part+self.__d
            if self.useInt:
                curValue = int(curValue+0.5)
            setattr(self.node, self.attrName, curValue)
    def __stop(self):
        setattr(self.node, self.attrName, self.__endValue)
        self.__done = 1
        g_Player.clearInterval(self.interval)
        if self.onStop != None:
            self.onStop()

def fadeOut(node, duration):
    curValue = getattr(node, "opacity")
    LinearAnim(node, "opacity", duration, curValue, 0, 0, None)

def fadeIn(node, duration, max):
    curValue = getattr(node, "opacity")
    LinearAnim(node, "opacity", duration, curValue, max, 0, None)

def init(Player):
    global g_Player
    g_Player = Player
<commit_msg>Fixed totally broken anim.py<commit_after># TODO:
# - loops
# - Folgen, Gruppen

class SimpleAnim:
    def __init__(self, node, attrName, duration, useInt, onStop):
        self.node = node
        self.attrName = attrName
        self.duration = duration
        self.startTime = g_Player.getFrameTime()
        self.onStop = onStop
        self.useInt = useInt

class LinearAnim(SimpleAnim):
    def __init__(self, node, attrName, duration, startValue, endValue, useInt, onStop):
        SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop)
        self.__stopTimeout = g_Player.setTimeout(duration, self.__stop)
        self.__interval = g_Player.setInterval(1, self.__step)
        self.__startValue = startValue
        self.__endValue = endValue
        self.__done = False
        self.__step()
    def __step(self):
        if not(self.__done):
            part = ((float(g_Player.getFrameTime())-self.startTime)/self.duration)
            if part > 1.0:
                part = 1.0
            curValue = self.__startValue+(self.__endValue-self.__startValue)*part
            if self.useInt:
                curValue = int(curValue+0.5)
            setattr(self.node, self.attrName, curValue)
    def __stop(self):
        setattr(self.node, self.attrName, self.__endValue)
        self.__done = True
        g_Player.clearInterval(self.__interval)
        if self.onStop != None:
            self.onStop()
    def abort(self):
        if not(self.__done):
            self.__done = True
            g_Player.clearInterval(self.__interval)
            g_Player.clearInterval(self.__stopTimeout)
    def isDone(self):
        return self.__done

class SplineAnim(SimpleAnim):
    def __init__(self, node, attrName, duration,
            startValue, startSpeed, endValue, endSpeed, useInt, onStop):
        SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop)
        g_Player.setTimeout(duration, self.__stop)
        self.interval = g_Player.setInterval(1, self.__step)
        self.__startValue = startValue+0.0
        self.__startSpeed = startSpeed
        self.__endValue = endValue
        self.__endSpeed = endSpeed
        self.__a = -2*(self.__endValue-self.__startValue)+self.__startSpeed+self.__endSpeed
        self.__b = 3*(self.__endValue-self.__startValue)-2*self.__startSpeed-self.__endSpeed
        self.__c = self.__startSpeed
        self.__d = self.__startValue
        self.__done = 0
        self.__step()
    def __step(self):
        if not(self.__done):
            part = ((float(g_Player.getFrameTime())-self.startTime)/self.duration)
            if part > 1.0:
                part = 1.0
            curValue = ((self.__a*part+self.__b)*part+self.__c)*part+self.__d
            if self.useInt:
                curValue = int(curValue+0.5)
            setattr(self.node, self.attrName, curValue)
    def __stop(self):
        setattr(self.node, self.attrName, self.__endValue)
        self.__done = 1
        g_Player.clearInterval(self.interval)
        if self.onStop != None:
            self.onStop()

def fadeOut(node, duration):
    curValue = getattr(node, "opacity")
    LinearAnim(node, "opacity", duration, curValue, 0, 0, None)

def fadeIn(node, duration, max):
    curValue = getattr(node, "opacity")
    LinearAnim(node, "opacity", duration, curValue, max, 0, None)

def init(Player):
    global g_Player
    g_Player = Player
<|endoftext|>


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

                   Kremlin Magical Everything System
               Glasnost Image Board and Boredom Inhibitor

"""
from __future__ import with_statement # python <2.7 support
from datetime import datetime
import hashlib

from flaskext.sqlalchemy import SQLAlchemy

from kremlin import app

# FIXME: temporary, for dev purposes. Move me to __init__.py
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////test.db'
db = SQLAlchemy(app)

# Tags helper table
# Since this is a many to many relationship, I'm using an actual table
# instead of a dynamic model. It is much more efficient in that
# scenario.
tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
)

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)

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

    def __repr__(self):
        return '<Tag %r>' % self.name

class User(db.Model):
    """ Declarative class for Users database table """
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

class Post(db.Model):
    """ Declarative class for Posts database table """
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80))
    note = db.Column(db.Text)
    pub_date = db.Column(db.DateTime)

    # Foreign key for image attached to post
    # :relationaldatabases:
    image_id = db.Column(db.Integer, db.ForeignKey('image.id'))
    image = db.relationship('Image',
        backref=db.backref('images', lazy='dynamic'))

    def __init__(self, image, title=None, note=None, pub_date=None):
        self.image = image
        self.title = title
        self.note = note
        if pub_date is None:
            pub_date = datetime.utcnow()
        self.pub_date = pub_date

    def __repr__(self):
        return '<Post %r>' % self.title

class Image(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    sha1sum = db.Column(db.String(40), unique=True) # 40 bytes SHA1

    def __init__(self, name, filedata):
        self.name = name

        h = hashlib.new('sha1')
        h.update(filedata)
        self.sha1sum = h.hexdigest()

    def __repr__(self):
        return '<Image with checksum %r>' % self.sha1sum

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    pub_date = db.Column(db.DateTime)

    # Foreign key relationship for users
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    user = db.relationship('User',
        backref=db.backref('users', lazy='dynamic'))

    # Foreign key for parent post
    parent_post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
    parent_post = db.relationship('Post',
        backref=db.backref('posts', lazy='dynamic'))

    def __init__(self, user, parent_post, body, pub_date=None):
        self.user = user
        self.parent_post = parent_post
        self.body = body
        if pub_date is None:
            pub_date = datetime.utcnow()
        self.pub_date = pub_date

    def __repr__(self):
        return '<Comment by %r>' % self.user
<commit_msg>Add fixme note for slight redesign later on<commit_after>#!/usr/bin/python
"""
               #   # ####  ##### #   # ##### #   # #   #
               #  #  #   # #     ## ##  #  # #  ## #   #
               ###   ####  ####  # # #  #  # # # # #####
               #  #  #     #     #   #  #  # ##  # #   #
               #   # #     ##### #   # #   # #   # #   #

                   Kremlin Magical Everything System
               Glasnost Image Board and Boredom Inhibitor

"""
from __future__ import with_statement # python <2.7 support
from datetime import datetime
import hashlib

from flaskext.sqlalchemy import SQLAlchemy

from kremlin import app

# FIXME: temporary, for dev purposes. Move me to __init__.py
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////test.db'
db = SQLAlchemy(app)

# Tags helper table
# Since this is a many to many relationship, I'm using an actual table
# instead of a dynamic model. It is much more efficient in that
# scenario.
tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
)

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)

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

    def __repr__(self):
        return '<Tag %r>' % self.name

class User(db.Model):
    """ Declarative class for Users database table """
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

class Post(db.Model):
    """ Declarative class for Posts database table """
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80))
    note = db.Column(db.Text)
    pub_date = db.Column(db.DateTime)

    # Foreign key for image attached to post
    # :relationaldatabases:
    image_id = db.Column(db.Integer, db.ForeignKey('image.id'))
    image = db.relationship('Image',
        backref=db.backref('images', lazy='dynamic'))

    def __init__(self, image, title=None, note=None, pub_date=None):
        self.image = image
        self.title = title
        self.note = note
        if pub_date is None:
            pub_date = datetime.utcnow()
        self.pub_date = pub_date

    def __repr__(self):
        return '<Post %r>' % self.title

class Image(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    sha1sum = db.Column(db.String(40), unique=True) # 40 bytes SHA1

    # FIXME: Consider moving SHA hash computation to controller.
    # It is really, really out of place here I just thought it was nice
    # to autogenerate it like the date field, but then again, I'm not
    # sure if this is just going to be the declarative ORM stuff, or  a
    # full fledged MVC model. Whatever seems more pythonic to me later
    # on. Also, passing the file data around seems awkward.

    def __init__(self, name, filedata):
        self.name = name

        h = hashlib.new('sha1')
        h.update(filedata)
        self.sha1sum = h.hexdigest()

    def __repr__(self):
        return '<Image with checksum %r>' % self.sha1sum

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    pub_date = db.Column(db.DateTime)

    # Foreign key relationship for users
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    user = db.relationship('User',
        backref=db.backref('users', lazy='dynamic'))

    # Foreign key for parent post
    parent_post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
    parent_post = db.relationship('Post',
        backref=db.backref('posts', lazy='dynamic'))

    def __init__(self, user, parent_post, body, pub_date=None):
        self.user = user
        self.parent_post = parent_post
        self.body = body
        if pub_date is None:
            pub_date = datetime.utcnow()
        self.pub_date = pub_date

    def __repr__(self):
        return '<Comment by %r>' % self.user
<|endoftext|>


<commit_before>from django.shortcuts import render
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import (login as auth_login, logout as
    auth_logout, password_change)
from django.contrib.auth.forms import SetPasswordForm
from social.apps.django_app.default.models import UserSocialAuth
from social.apps.django_app.utils import setting
from social.apps.django_app.views import disconnect as social_disconnect
from ksp_login import SOCIAL_AUTH_PARTIAL_PIPELINE_KEY
from ksp_login.context_processors import login_providers
from ksp_login.forms import (KspUserCreationForm, PasswordChangeForm,
    UserProfileForm)
from ksp_login.signals import user_form_requested

def login(request):
    if request.user.is_authenticated():
        next_page = request.REQUEST.get('next', 'account_settings')
        return redirect(next_page)
    return auth_login(request, template_name='ksp_login/login.html',
                      extra_context=login_providers(request))

def logout(request):
    response = auth_logout(request, next_page='/')
    messages.success(request, _("Logout successful"))
    return response

@login_required
def disconnect(request, backend, association_id):
    """
    If the user has at least one other social account association or a
    valid password, disconnects the given social account, otherwise asks
    the user to set up a password before proceeding.
    """
    associations = UserSocialAuth.get_social_auth_for_user(request.user)
    has_assoc = associations.exclude(id=association_id).count()
    has_pass = request.user.has_usable_password()
    if has_assoc or has_pass:
        return social_disconnect(request, backend, association_id)
    return render(request, 'ksp_login/invalid_disconnect.html')

@login_required
def password(request):
    """
    Sets, changes or removes the currently logged in user's passwords,
    depending on whether they have any social account associations.
    """
    has_assoc = UserSocialAuth.get_social_auth_for_user(request.user).count()
    if request.user.has_usable_password():
        def form(*args, **kwargs):
            return PasswordChangeForm(not has_assoc, *args, **kwargs)
    else:
        form = SetPasswordForm
    return password_change(request,
                           post_change_redirect=reverse('account_settings'),
                           password_change_form=form,
                           template_name='ksp_login/password.html')

def register(request, creation_form=KspUserCreationForm):
    """
    As the name suggests, registers a new user.

    Can replace the create_user function in the SOCIAL_AUTH pipeline
    (through ksp_login.pipeline.register_user, with the corresponding
    save_status_to_session, of course) to make it possible for the user to
    pick a username.

    Uses the user_form_requested signal to gather additional forms from
    other applications to present to the user.
    """
    if request.user.is_authenticated():
        return redirect('account_settings')
    try:
        pipeline_state = request.session[setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY',
                                                 SOCIAL_AUTH_PARTIAL_PIPELINE_KEY)]
        backend = pipeline_state['backend']
        pipeline_state = pipeline_state['kwargs']
        standalone = False
    except KeyError:
        standalone = True

    form_classes = [creation_form] + \
                   [form for receiver, form in
                    user_form_requested.send(sender=request, new_user=True)]

    if request.method == "POST":
        forms = [form(request.POST, request=request)
                 for form in form_classes]
        if all(form.is_valid() for form in forms):
            user = forms[0].save()
            for form in forms[1:]:
                form.set_user(user)
                form.save()
            if standalone:
                return redirect('account_login')
            pipeline_state['user'] = user
            request.session['ksp_login_dummy_key'] = True
            return redirect('social:complete', backend=backend)
    else:
        forms = [form(request=request) for form in form_classes]

    return render(request, "ksp_login/registration.html", {
        'forms': forms,
    })

@login_required
def settings(request, settings_form=UserProfileForm):
    """
    Presents the user a form with their settings, basically the register
    form minus username minus password.

    Uses the user_form_requested signal to gather additional forms from
    other applications to present to the user.
    """
    form_classes = [settings_form] + \
                   [form for receiver, form in
                    user_form_requested.send(sender=request, new_user=False)]

    if request.method == "POST":
        forms = [form(request.POST, user=request.user)
                 for form in form_classes]
        if all(form.is_valid() for form in forms):
            for form in forms:
                form.save()
            return redirect('account_settings')
    else:
        forms = [form(user=request.user) for form in form_classes]

    return render(request, 'ksp_login/settings.html', {
        'account_associations': UserSocialAuth.get_social_auth_for_user(request.user),
        'forms': forms,
    })
<commit_msg>Made the session hack in the register view more robust.<commit_after>from django.shortcuts import render
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import (login as auth_login, logout as
    auth_logout, password_change)
from django.contrib.auth.forms import SetPasswordForm
from social.apps.django_app.default.models import UserSocialAuth
from social.apps.django_app.utils import setting
from social.apps.django_app.views import disconnect as social_disconnect
from ksp_login import SOCIAL_AUTH_PARTIAL_PIPELINE_KEY
from ksp_login.context_processors import login_providers
from ksp_login.forms import (KspUserCreationForm, PasswordChangeForm,
    UserProfileForm)
from ksp_login.signals import user_form_requested

def login(request):
    if request.user.is_authenticated():
        next_page = request.REQUEST.get('next', 'account_settings')
        return redirect(next_page)
    return auth_login(request, template_name='ksp_login/login.html',
                      extra_context=login_providers(request))

def logout(request):
    response = auth_logout(request, next_page='/')
    messages.success(request, _("Logout successful"))
    return response

@login_required
def disconnect(request, backend, association_id):
    """
    If the user has at least one other social account association or a
    valid password, disconnects the given social account, otherwise asks
    the user to set up a password before proceeding.
    """
    associations = UserSocialAuth.get_social_auth_for_user(request.user)
    has_assoc = associations.exclude(id=association_id).count()
    has_pass = request.user.has_usable_password()
    if has_assoc or has_pass:
        return social_disconnect(request, backend, association_id)
    return render(request, 'ksp_login/invalid_disconnect.html')

@login_required
def password(request):
    """
    Sets, changes or removes the currently logged in user's passwords,
    depending on whether they have any social account associations.
    """
    has_assoc = UserSocialAuth.get_social_auth_for_user(request.user).count()
    if request.user.has_usable_password():
        def form(*args, **kwargs):
            return PasswordChangeForm(not has_assoc, *args, **kwargs)
    else:
        form = SetPasswordForm
    return password_change(request,
                           post_change_redirect=reverse('account_settings'),
                           password_change_form=form,
                           template_name='ksp_login/password.html')

def register(request, creation_form=KspUserCreationForm):
    """
    As the name suggests, registers a new user.

    Can replace the create_user function in the SOCIAL_AUTH pipeline
    (through ksp_login.pipeline.register_user, with the corresponding
    save_status_to_session, of course) to make it possible for the user to
    pick a username.

    Uses the user_form_requested signal to gather additional forms from
    other applications to present to the user.
    """
    if request.user.is_authenticated():
        return redirect('account_settings')
    try:
        pipeline_state = request.session[setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY',
                                                 SOCIAL_AUTH_PARTIAL_PIPELINE_KEY)]
        backend = pipeline_state['backend']
        pipeline_state = pipeline_state['kwargs']
        standalone = False
    except KeyError:
        standalone = True

    form_classes = [creation_form] + \
                   [form for receiver, form in
                    user_form_requested.send(sender=request, new_user=True)]

    if request.method == "POST":
        forms = [form(request.POST, request=request)
                 for form in form_classes]
        if all(form.is_valid() for form in forms):
            user = forms[0].save()
            for form in forms[1:]:
                form.set_user(user)
                form.save()
            if standalone:
                return redirect('account_login')
            pipeline_state['user'] = user
            # This ensures the top-level session dict changes, otherwise
            # our changes in pipeline_state might not get stored.
            request.session.setdefault('ksp_login_dummy_key', 0)
            request.session['ksp_login_dummy_key'] += 1
            return redirect('social:complete', backend=backend)
    else:
        forms = [form(request=request) for form in form_classes]

    return render(request, "ksp_login/registration.html", {
        'forms': forms,
    })

@login_required
def settings(request, settings_form=UserProfileForm):
    """
    Presents the user a form with their settings, basically the register
    form minus username minus password.

    Uses the user_form_requested signal to gather additional forms from
    other applications to present to the user.
    """
    form_classes = [settings_form] + \
                   [form for receiver, form in
                    user_form_requested.send(sender=request, new_user=False)]

    if request.method == "POST":
        forms = [form(request.POST, user=request.user)
                 for form in form_classes]
        if all(form.is_valid() for form in forms):
            for form in forms:
                form.save()
            return redirect('account_settings')
    else:
        forms = [form(user=request.user) for form in form_classes]

    return render(request, 'ksp_login/settings.html', {
        'account_associations': UserSocialAuth.get_social_auth_for_user(request.user),
        'forms': forms,
    })
<|endoftext|>


<commit_before>import logging
import logging.config
import optparse

from kuyruk import Kuyruk
from config import Config

logger = logging.getLogger(__name__)

def main():
    parser = optparse.OptionParser()
    parser.add_option('--config')
    parser.add_option('--logging-config')
    parser.add_option('--logging-level', default='INFO')
    # These options below override the options from config module
    parser.add_option('--queues')
    parser.add_option('--max-load', type='int')
    parser.add_option('--max-run-time', type='int')
    parser.add_option('--save-failed-tasks', action='store_true')
    options, args = parser.parse_args()

    if options.logging_config:
        logging.config.fileConfig(options.logging_config)
    else:
        logging.getLogger('pika').level = logging.WARNING
        level = getattr(logging, options.logging_level)
        logging.basicConfig(level=level)

    config = Config(options.config)

    if options.max_load is not None:
        config.MAX_LOAD = options.max_load

    if options.max_run_time is not None:
        config.MAX_RUN_TIME = options.max_run_time

    if options.save_failed_tasks:
        config.SAVE_FAILED_TASKS = options.save_failed_tasks

    kuyruk = Kuyruk()
    kuyruk.config = config
    kuyruk.run(options.queues)

if __name__ == '__main__':
    main()
<commit_msg>float<commit_after>import logging
import logging.config
import optparse

from kuyruk import Kuyruk
from config import Config

logger = logging.getLogger(__name__)

def main():
    parser = optparse.OptionParser()
    parser.add_option('--config')
    parser.add_option('--logging-config')
    parser.add_option('--logging-level', default='INFO')
    # These options below override the options from config module
    parser.add_option('--queues')
    parser.add_option('--max-load', type='float')
    parser.add_option('--max-run-time', type='float')
    parser.add_option('--save-failed-tasks', action='store_true')
    options, args = parser.parse_args()

    if options.logging_config:
        logging.config.fileConfig(options.logging_config)
    else:
        logging.getLogger('pika').level = logging.WARNING
        level = getattr(logging, options.logging_level)
        logging.basicConfig(level=level)

    config = Config(options.config)

    if options.max_load is not None:
        config.MAX_LOAD = options.max_load

    if options.max_run_time is not None:
        config.MAX_RUN_TIME = options.max_run_time

    if options.save_failed_tasks:
        config.SAVE_FAILED_TASKS = options.save_failed_tasks

    kuyruk = Kuyruk()
    kuyruk.config = config
    kuyruk.run(options.queues)

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


<commit_before>import discord
import logging
import json
import collections

import features.dice as dice
import features.cards as cards

logger = logging.getLogger('discord')
logger.setLevel(logging.INFO)
handler = logging.FileHandler(filename='l5r-bot.log', encoding='utf-8', mode='w')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
logger.addHandler(handler)

client = discord.Client()

role_numbers_per_server = {}

with open('role_numbers.json', 'w+') as json_data:
    try:
        role_numbers_per_server = json.load(json_data)
    except json.decoder.JSONDecodeError:
        role_numbers_per_server = {}
with open('default_roles.json', 'w+') as json_data:
    try:
        default_roles = json.load(json_data)
    except json.decoder.JSONDecodeError:
        default_roles = {}
with open('hidden_roles.json', 'w+') as json_data:
    try:
        hidden_roles = json.load(json_data)
    except json.decoder.JSONDecodeError:
        hidden_roles = {}

async def save_stats_to_file():
    with open('role_numbers.json', 'w') as outfile:
        json.dump(role_numbers_per_server, outfile)
        logger.info('Saved new role stats to file')

async def save_default_roles_to_file():
    with open('default_roles.json', 'w') as outfile:
        json.dump(default_roles, outfile)
        logger.info('Saved default roles to file')

async def save_hidden_roles_to_file():
    with open('hidden_roles.json', 'w') as outfile:
        json.dump(hidden_roles, outfile)
        logger.info('Saved hidden roles to file')

async def update_server_stats():
    for server in client.servers:
        stats = collections.Counter()
        for member in server.members:
            roles = [role.name for role in member.roles if role.name != '@everyone']
            stats.update(roles)
        role_numbers_per_server[server.name] = stats
        await save_stats_to_file()

async def reload_from_files():
    nonlocal role_numbers_per_server
    nonlocal default_roles
    nonlocal hidden_roles
    with open('role_numbers.json', 'w+') as json_data:
        try:
            role_numbers_per_server = json.load(json_data)
        except json.decoder.JSONDecodeError:
            role_numbers_per_server = {}
    with open('default_roles.json', 'w+') as json_data:
        try:
            default_roles = json.load(json_data)
        except json.decoder.JSONDecodeError:
            default_roles = {}
    with open('hidden_roles.json', 'w+') as json_data:
        try:
            hidden_roles = json.load(json_data)
        except json.decoder.JSONDecodeError:
            hidden_roles = {}

@client.event
async def on_ready():
    logger.info('Logged in as')
    logger.info(client.user.name)
    logger.info(client.user.id)
    logger.info('------')

    logger.info('Updating role statistics')
    await update_server_stats()
    await save_stats_to_file()

@client.event
async def on_member_join(new_member):
    logger.info('A new member joined')
    try:
        roles = default_roles[new_member.server]
    except KeyError:
        logger.info('But there are no default roles set up!')
        return None
    client.add_roles(new_member, roles)
    logger.info('Added new roles to ' + new_member.name)

    role_numbers_per_server[new_member.server.name].update(roles)
    await save_stats_to_file()

@client.event
async def on_message(message):
    if message.content.startswith('!help'):
        logger.debug(str(message.author) + " asked for help!")
        help_text = "The Miya Herald has the following Emperor-granted powers: \n" + \
                    "\n" + \
                    "!help informs you about what he may do.  \n" + \
                    "\n" + \
                    "!clan <rolename> lets you swear allegiance to or leave a given clan. \n" + \
                    "!clan <rolename> default lets the admins set default roles that to apply to new members. \n" + \
                    "!clan <rolename> hidden lets the admins hide roles from the output. \n \n" + \
                    "!clans tells you how many people are in each clan. \n \n" + \
                    "!roll is used to roll dice. \n" + \
                    "[] denotes optional elements, {} denotes 'pick one'. show_dice shows the individual dice " + \
                    "results. \n " + \
                    "The following formats are supported: \n \n" + \
                    "!roll XkY [{+-}Z} [TN##] [unskilled] [emphasis] [mastery] [show_dice] rolls X 10-sided " + \
                    "exploding dice and keeps the highest Y. \n" + \
                    "Unskilled can be set to prevent the dice from exploding, while Emphasis rerolls 1s. \n" + \
                    "Mastery allows the dice to explode on 9s and 10s. \n" + \
                    "Ex. !roll 6k3 TN20 or !roll 2k2 TN10 unskilled"
        await client.send_message(message.channel, help_text)

    if message.content.startswith('!clan') and message.content != '!clans':
        command = message.content.split(' ')[1:]
        if len(command) == 1:
            logger.info(message.author.name + ' wants to join or leave a clan!')
            logger.info('That clan is ' + command[0])
            role = discord.utils.find(lambda r: r.name == command[0], message.server.roles)
            if role is not None and role not in message.author.roles:
                try:
                    await client.add_roles(message.author, role)
                    role_numbers_per_server[message.server.name][role.name] += 1
                    await client.send_message(message.channel, 'Let it be known that ' + message.author.mention +
                                              ' joined the ' + role.name + ' clan!')
                except discord.errors.Forbidden:
                    logger.info("Got a FORBIDDEN error while adding to the clan")
                    await client.send_message(message.channel, 'How presumptuous! This is not a clan one can simply ' +
                                              "join! *AKA you're not permitted to join this role or I'm not allowed " +
                                              "to give it to you*")
            elif role is not None and role in message.author.roles:
                await client.remove_roles(message.author, role)
                role_numbers_per_server[message.server.name][role.name] -= 1
                if role_numbers_per_server[message.server.name][role.name] == 0:
                    del (role_numbers_per_server[message.server.name][role.name])
                await client.send_message(message.channel, 'Let it be known that ' + message.author.mention +
                                          ' left the ' + role.name + ' clan!')
            else:
                logger.info("The clan doesn't exist")
                await client.send_message(message.channel, 'Unfortunately, ' + message.author.mention +
                                          '-san, this clan is not listed in the Imperial Records...')
        elif len(command) == 2:
            if not message.author.server_permissions.manage_server:
                logger.warning(message.author.name + ' try to set default or roles without permission!')
                await client.send_message(message.channel, 'You do not have permission to modify the default or hidden roles.')
                return None
            logger.info(message.author.name + ' wants to manage default or hidden roles.')
            if command[1] == 'default':
                role = discord.utils.find(lambda r: r.name == command[0], message.server.roles)
                try:
                    default_roles[message.server.name]
                except KeyError:
                    default_roles[message.server.name] = []
                if role.name in default_roles[message.server.name]:
                    default_roles[message.server.name].remove(role.name)
                    await save_default_roles_to_file()
                    await client.send_message(message.channel, role.name +
                                              ' has been removed from the default roles list.')
                else:
                    default_roles[message.server.name].append(role.name)
                    await save_default_roles_to_file()
                    await client.send_message(message.channel, role.name + ' has been added to the default roles list.')
            if command[1] == 'hidden':
                role = discord.utils.find(lambda r: r.name == command[0], message.server.roles)
                try:
                    hidden_roles[message.server.name]
                except KeyError:
                    hidden_roles[message.server.name] = []
                if role.name in hidden_roles[message.server.name]:
                    hidden_roles[message.server.name].remove(role.name)
                    await save_hidden_roles_to_file()
                    await client.send_message(message.channel, role.name +
                                              ' has been removed from the hidden roles list.')
                else:
                    hidden_roles[message.server.name].append(role.name)
                    await save_hidden_roles_to_file()
                    await client.send_message(message.channel,
                                              role.name + ' has been added to the hidden roles list.')
            else:
                await client.send_message(message.channel, 'That is not a request I can fulfill. Perhaps you should ' +
                                          'ask for !help first.')
    if message.content.startswith('!clans'):
        roles = role_numbers_per_server[message.server.name]
        logger.info("Displaying clan numbers")
        try:
            hidden_roles[message.server.name]
        except KeyError:
            hidden_roles[message.server.name] = []
        response = "```"
        for role, count in roles.items():
            if role not in hidden_roles[message.server.name]:
                response += role + ": " + str(count) + "\n"
        response += "``` \n"
        await client.send_message(message.channel, response)
        await update_server_stats()
    if message.content.startswith('!roll'):
        command = message.content.split(' ')[1:]
        if len(command) < 1:
            await client.send_message(message.channel,
                                      "4. Chosen by fair dice roll as the random number. "
                                      "If you wanted something else, perhaps look at !help")
        elif "k" in command[0]:
            roll, success = dice.roll_and_keep(command)
            await client.send_message(message.channel,
                                      message.author.mention + " rolled **" + str(roll) + "**! \n" + success)
        else:
            await client.send_message(message.channel,
                                      "Sorry, samurai-san, I didn't understand your request. \n"
                                      "!help should be informative for you.")
    if message.content.startswith('!card'):
        command = message.content.split(' ')[1:]
        if len(command) < 1:
            await client.send_message(message.channel, "I can look cards up for you, honourable samurai-san.")
        else:
            await client.send_message(message.channel, cards.get_card_url(command))
    if message.content.startswith('!reload'):
        await reload_from_files()

client.run('MzE3MjAwMjk5ODQ2NjY0MTky.DAgYmg.L9GPRhrc9HbaFEv2tyS5aG54FOY')
<commit_msg>Finally commited some changes to guard against data loss<commit_after>import discord
import logging
import json
import collections

import features.dice as dice
import features.cards as cards

logger = logging.getLogger('discord')
logger.setLevel(logging.INFO)
handler = logging.FileHandler(filename='l5r-bot.log', encoding='utf-8', mode='w')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
logger.addHandler(handler)

client = discord.Client()

role_numbers_per_server = {}

with open('role_numbers.json', 'r') as json_data:
    try:
        role_numbers_per_server = json.load(json_data)
    except json.decoder.JSONDecodeError:
        role_numbers_per_server = {}
with open('default_roles.json', 'r') as json_data:
    try:
        default_roles = json.load(json_data)
    except json.decoder.JSONDecodeError:
        default_roles = {}
with open('hidden_roles.json', 'r') as json_data:
    try:
        hidden_roles = json.load(json_data)
    except json.decoder.JSONDecodeError:
        hidden_roles = {}

async def save_stats_to_file():
    with open('role_numbers.json', 'w') as outfile:
        json.dump(role_numbers_per_server, outfile)
        logger.info('Saved new role stats to file')

async def save_default_roles_to_file():
    with open('default_roles.json', 'w') as outfile:
        json.dump(default_roles, outfile)
        logger.info('Saved default roles to file')

async def save_hidden_roles_to_file():
    with open('hidden_roles.json', 'w') as outfile:
        json.dump(hidden_roles, outfile)
        logger.info('Saved hidden roles to file')

async def update_server_stats():
    for server in client.servers:
        stats = collections.Counter()
        for member in server.members:
            roles = [role.name for role in member.roles if role.name != '@everyone']
            stats.update(roles)
        role_numbers_per_server[server.name] = stats
        await save_stats_to_file()

async def reload_from_files():
    global role_numbers_per_server
    global default_roles
    global hidden_roles
    with open('role_numbers.json', 'r') as json_data:
        try:
            role_numbers_per_server = json.load(json_data)
        except json.decoder.JSONDecodeError:
            role_numbers_per_server = {}
    with open('default_roles.json', 'r') as json_data:
        try:
            default_roles = json.load(json_data)
        except json.decoder.JSONDecodeError:
            default_roles = {}
    with open('hidden_roles.json', 'r') as json_data:
        try:
            hidden_roles = json.load(json_data)
        except json.decoder.JSONDecodeError:
            hidden_roles = {}

@client.event
async def on_ready():
    logger.info('Logged in as')
    logger.info(client.user.name)
    logger.info(client.user.id)
    logger.info('------')

    logger.info('Updating role statistics')
    await update_server_stats()
    await save_stats_to_file()

@client.event
async def on_member_join(new_member):
    logger.info('A new member joined')
    try:
        roles = default_roles[new_member.server]
    except KeyError:
        logger.info('But there are no default roles set up!')
        return None
    client.add_roles(new_member, roles)
    logger.info('Added new roles to ' + new_member.name)

    role_numbers_per_server[new_member.server.name].update(roles)
    await save_stats_to_file()

@client.event
async def on_message(message):
    if message.content.startswith('!help'):
        logger.debug(str(message.author) + " asked for help!")
        help_text = "The Miya Herald has the following Emperor-granted powers: \n" + \
                    "\n" + \
                    "!help informs you about what he may do.  \n" + \
                    "\n" + \
                    "!clan <rolename> lets you swear allegiance to or leave a given clan. \n" + \
                    "!clan <rolename> default lets the admins set default roles that to apply to new members. \n" + \
                    "!clan <rolename> hidden lets the admins hide roles from the output. \n \n" + \
                    "!clans tells you how many people are in each clan. \n \n" + \
                    "!roll is used to roll dice. \n" + \
                    "[] denotes optional elements, {} denotes 'pick one'. show_dice shows the individual dice " + \
                    "results. \n " + \
                    "The following formats are supported: \n \n" + \
                    "!roll XkY [{+-}Z} [TN##] [unskilled] [emphasis] [mastery] [show_dice] rolls X 10-sided " + \
                    "exploding dice and keeps the highest Y. \n" + \
                    "Unskilled can be set to prevent the dice from exploding, while Emphasis rerolls 1s. \n" + \
                    "Mastery allows the dice to explode on 9s and 10s. \n" + \
                    "Ex. !roll 6k3 TN20 or !roll 2k2 TN10 unskilled"
        await client.send_message(message.channel, help_text)

    if message.content.startswith('!clan') and message.content != '!clans':
        command = message.content.split(' ')[1:]
        if len(command) == 1:
            logger.info(message.author.name + ' wants to join or leave a clan!')
            logger.info('That clan is ' + command[0])
            role = discord.utils.find(lambda r: r.name == command[0], message.server.roles)
            if role is not None and role not in message.author.roles:
                try:
                    await client.add_roles(message.author, role)
                    role_numbers_per_server[message.server.name][role.name] += 1
                    await client.send_message(message.channel, 'Let it be known that ' + message.author.mention +
                                              ' joined the ' + role.name + ' clan!')
                except discord.errors.Forbidden:
                    logger.info("Got a FORBIDDEN error while adding to the clan")
                    await client.send_message(message.channel, 'How presumptuous! This is not a clan one can simply ' +
                                              "join! *AKA you're not permitted to join this role or I'm not allowed " +
                                              "to give it to you*")
            elif role is not None and role in message.author.roles:
                await client.remove_roles(message.author, role)
                role_numbers_per_server[message.server.name][role.name] -= 1
                if role_numbers_per_server[message.server.name][role.name] == 0:
                    del (role_numbers_per_server[message.server.name][role.name])
                await client.send_message(message.channel, 'Let it be known that ' + message.author.mention +
                                          ' left the ' + role.name + ' clan!')
            else:
                logger.info("The clan doesn't exist")
                await client.send_message(message.channel, 'Unfortunately, ' + message.author.mention +
                                          '-san, this clan is not listed in the Imperial Records...')
        elif len(command) == 2:
            if not message.author.server_permissions.manage_server:
                logger.warning(message.author.name + ' try to set default or roles without permission!')
                await client.send_message(message.channel, 'You do not have permission to modify the default or hidden roles.')
                return None
            logger.info(message.author.name + ' wants to manage default or hidden roles.')
            if command[1] == 'default':
                role = discord.utils.find(lambda r: r.name == command[0], message.server.roles)
                try:
                    default_roles[message.server.name]
                except KeyError:
                    default_roles[message.server.name] = []
                if role.name in default_roles[message.server.name]:
                    default_roles[message.server.name].remove(role.name)
                    await save_default_roles_to_file()
                    await client.send_message(message.channel, role.name +
                                              ' has been removed from the default roles list.')
                else:
                    default_roles[message.server.name].append(role.name)
                    await save_default_roles_to_file()
                    await client.send_message(message.channel, role.name + ' has been added to the default roles list.')
            if command[1] == 'hidden':
                role = discord.utils.find(lambda r: r.name == command[0], message.server.roles)
                try:
                    hidden_roles[message.server.name]
                except KeyError:
                    hidden_roles[message.server.name] = []
                if role.name in hidden_roles[message.server.name]:
                    hidden_roles[message.server.name].remove(role.name)
                    await save_hidden_roles_to_file()
                    await client.send_message(message.channel, role.name +
                                              ' has been removed from the hidden roles list.')
                else:
                    hidden_roles[message.server.name].append(role.name)
                    await save_hidden_roles_to_file()
                    await client.send_message(message.channel,
                                              role.name + ' has been added to the hidden roles list.')
            else:
                await client.send_message(message.channel, 'That is not a request I can fulfill. Perhaps you should ' +
                                          'ask for !help first.')
    if message.content.startswith('!clans'):
        roles = role_numbers_per_server[message.server.name]
        logger.info("Displaying clan numbers")
        try:
            hidden_roles[message.server.name]
        except KeyError:
            hidden_roles[message.server.name] = []
        response = "```"
        for role, count in roles.items():
            if role not in hidden_roles[message.server.name]:
                response += role + ": " + str(count) + "\n"
        response += "``` \n"
        await client.send_message(message.channel, response)
        await update_server_stats()
    if message.content.startswith('!roll'):
        command = message.content.split(' ')[1:]
        if len(command) < 1:
            await client.send_message(message.channel,
                                      "4. Chosen by fair dice roll as the random number. "
                                      "If you wanted something else, perhaps look at !help")
        elif "k" in command[0]:
            roll, success = dice.roll_and_keep(command)
            await client.send_message(message.channel,
                                      message.author.mention + " rolled **" + str(roll) + "**! \n" + success)
        else:
            await client.send_message(message.channel,
                                      "Sorry, samurai-san, I didn't understand your request. \n"
                                      "!help should be informative for you.")
    if message.content.startswith('!card'):
        command = message.content.split(' ')[1:]
        if len(command) < 1:
            await client.send_message(message.channel, "I can look cards up for you, honourable samurai-san.")
        else:
            await client.send_message(message.channel, cards.get_card_url(command))
    if message.content.startswith('!reload'):
        await reload_from_files()

client.run('MzE3MjAwMjk5ODQ2NjY0MTky.DAgYmg.L9GPRhrc9HbaFEv2tyS5aG54FOY')
<|endoftext|>