<commit_before># Copyright 2015-2016 Yelp Inc.
#
# 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.
import re
import time
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from typing import Set
from typing import Type
from typing import TypeVar

import aiohttp
from mypy_extensions import TypedDict

from paasta_tools.utils import get_user_agent

_drain_methods: Dict[str, Type["DrainMethod"]] = {}
HACHECK_CONN_TIMEOUT = 3
HACHECK_READ_TIMEOUT = 1

_RegisterDrainMethod_T = TypeVar('_RegisterDrainMethod_T', bound=Type["DrainMethod"])

def register_drain_method(name: str) -> Callable[[_RegisterDrainMethod_T], _RegisterDrainMethod_T]:
    """Returns a decorator that registers a DrainMethod subclass at a given name
    so get_drain_method/list_drain_methods can find it."""
    def outer(drain_method: _RegisterDrainMethod_T) -> _RegisterDrainMethod_T:
        _drain_methods[name] = drain_method
        return drain_method
    return outer

def get_drain_method(
    name: str,
    service: str,
    instance: str,
    nerve_ns: str,
    drain_method_params: Optional[Dict]=None,
) -> "DrainMethod":
    return _drain_methods[name](service, instance, nerve_ns, **(drain_method_params or {}))

def list_drain_methods() -> List[str]:
    return sorted(_drain_methods.keys())

DrainTask = TypeVar('DrainTask', bound=Any)

class DrainMethod(object):
    """A drain method is a way of stopping new traffic to tasks without killing them. For example, you might take a task
    out of a load balancer by causing its healthchecks to fail.

    A drain method must have the following methods:
     - drain(task): Begin draining traffic from a task. This should be idempotent.
     - stop_draining(task): Stop draining traffic from a task. This should be idempotent.
     - is_draining(task): Whether a task has already been marked as downed. Note that this state should be stored out of
                          process, because a bounce may take multiple runs of setup_marathon_job to complete.
     - is_safe_to_kill(task): Return True if this task is safe to kill, False otherwise.

    When implementing a drain method, be sure to decorate with @register_drain_method(name).
    """

    def __init__(self, service: str, instance: str, nerve_ns: str, **kwargs: Dict) -> None:
        self.service = service
        self.instance = instance
        self.nerve_ns = nerve_ns

    async def drain(self, task: DrainTask) -> None:
        """Make a task stop receiving new traffic."""
        raise NotImplementedError()

    async def stop_draining(self, task: DrainTask) -> None:
        """Make a task that has previously been downed start receiving traffic again."""
        raise NotImplementedError()

    async def is_draining(self, task: DrainTask) -> bool:
        """Return whether a task is being drained."""
        raise NotImplementedError()

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        """Return True if a task is drained and ready to be killed, or False if we should wait."""
        raise NotImplementedError()

@register_drain_method('noop')
class NoopDrainMethod(DrainMethod):
    """This drain policy does nothing and assumes every task is safe to kill."""

    async def drain(self, task: DrainTask) -> None:
        pass

    async def stop_draining(self, task: DrainTask) -> None:
        pass

    async def is_draining(self, task: DrainTask) -> bool:
        return False

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        return True

@register_drain_method('test')
class TestDrainMethod(DrainMethod):
    """This drain policy is meant for integration testing. Do not use."""

    # These are variables on the class for ease of use in testing.
    downed_task_ids: Set[str] = set()
    safe_to_kill_task_ids: Set[str] = set()

    async def drain(self, task: DrainTask) -> None:
        if task.id not in self.safe_to_kill_task_ids:
            self.downed_task_ids.add(task.id)

    async def stop_draining(self, task: DrainTask) -> None:
        self.downed_task_ids -= {task.id}
        self.safe_to_kill_task_ids -= {task.id}

    async def is_draining(self, task: DrainTask) -> bool:
        return task.id in (self.downed_task_ids | self.safe_to_kill_task_ids)

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        return task.id in self.safe_to_kill_task_ids

    @classmethod
    def mark_arbitrary_task_as_safe_to_kill(cls) -> None:
        cls.safe_to_kill_task_ids.add(cls.downed_task_ids.pop())

@register_drain_method('crashy_drain')
class CrashyDrainDrainMethod(NoopDrainMethod):
    async def drain(self, task: DrainTask) -> None:
        raise Exception("Intentionally crashing for testing purposes")

@register_drain_method('crashy_is_safe_to_kill')
class CrashySafeToKillDrainMethod(NoopDrainMethod):
    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        raise Exception("Intentionally crashing for testing purposes")

SpoolInfo = TypedDict(
    'SpoolInfo',
    {
        'service': str,
        'state': str,
        'since': float,
        'until': float,
        'reason': str,
    },
    total=False,
)

@register_drain_method('hacheck')
class HacheckDrainMethod(DrainMethod):
    """This drain policy issues a POST to hacheck's /spool/{service}/{port}/status endpoint to cause healthchecks to
    fail. It considers tasks safe to kill if they've been down in hacheck for more than a specified delay."""

    def __init__(
        self,
        service: str,
        instance: str,
        nerve_ns: str,
        delay: float=120,
        hacheck_port: int=6666,
        expiration: float=0,
        **kwargs: Dict,
    ) -> None:
        super(HacheckDrainMethod, self).__init__(service, instance, nerve_ns)
        self.delay = float(delay)
        self.hacheck_port = hacheck_port
        self.expiration = float(expiration) or float(delay) * 10

    def spool_url(self, task: DrainTask) -> str:
        if task.ports == []:
            return None
        else:
            return 'http://%(task_host)s:%(hacheck_port)d/spool/%(service)s.%(nerve_ns)s/%(task_port)d/status' % {
                'task_host': task.host,
                'task_port': task.ports[0],
                'hacheck_port': self.hacheck_port,
                'service': self.service,
                'nerve_ns': self.nerve_ns,
            }

    async def post_spool(self, task: DrainTask, status: str) -> None:
        spool_url = self.spool_url(task)
        if spool_url is not None:
            data: Dict[str, str] = {'status': status}
            if status == 'down':
                data.update({
                    'expiration': str(time.time() + self.expiration),
                    'reason': 'Drained by Paasta',
                })
            async with aiohttp.ClientSession(
                conn_timeout=HACHECK_CONN_TIMEOUT,
                read_timeout=HACHECK_READ_TIMEOUT,
            ) as session:
                async with session.post(
                    self.spool_url(task),
                    data=data,
                    headers={'User-Agent': get_user_agent()},
                ) as resp:
                    resp.raise_for_status()

    async def get_spool(self, task: DrainTask) -> SpoolInfo:
        """Query hacheck for the state of a task, and parse the result into a dictionary."""
        spool_url = self.spool_url(task)
        if spool_url is None:
            return None

        # TODO: aiohttp says not to create a session per request. Fix this.
        async with aiohttp.ClientSession(
            conn_timeout=HACHECK_CONN_TIMEOUT,
            read_timeout=HACHECK_READ_TIMEOUT,
        ) as session:
            response = await session.get(
                self.spool_url(task),
                headers={'User-Agent': get_user_agent()},
            )
            if response.status == 200:
                return {
                    'state': 'up',
                }

            regex = ''.join([
                "^",
                r"Service (?P<service>.+)",
                r" in (?P<state>.+) state",
                r"(?: since (?P<since>[0-9.]+))?",
                r"(?: until (?P<until>[0-9.]+))?",
                r"(?:: (?P<reason>.*))?",
                "$",
            ])

            response_text = await response.text()
            match = re.match(regex, response_text)
            groupdict = match.groupdict()
            info: SpoolInfo = {}
            info['service'] = groupdict['service']
            info['state'] = groupdict['state']
            if 'since' in groupdict:
                info['since'] = float(groupdict['since'] or 0)
            if 'until' in groupdict:
                info['until'] = float(groupdict['until'] or 0)
            if 'reason' in groupdict:
                info['reason'] = groupdict['reason']
            return info

    async def drain(self, task: DrainTask) -> None:
        return await self.post_spool(task, 'down')

    async def stop_draining(self, task: DrainTask) -> None:
        return await self.post_spool(task, 'up')

    async def is_draining(self, task: DrainTask) -> bool:
        info = await self.get_spool(task)
        if info is None or info["state"] == "up":
            return False
        else:
            return True

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        info = await self.get_spool(task)
        if info is None or info["state"] == "up":
            return False
        else:
            return info.get("since", 0) < (time.time() - self.delay)

class StatusCodeNotAcceptableError(Exception):
    pass

UrlSpec = TypedDict(
    'UrlSpec',
    {
        'url_format': str,
        'method': str,
        'success_codes': str,
    },
    total=False,
)

@register_drain_method('http')
class HTTPDrainMethod(DrainMethod):
    """This drain policy issues arbitrary HTTP calls to arbitrary URLs specified by the parameters. The URLs are
    specified as format strings, and will have variables such as {host}, {port}, etc. filled in."""

    def __init__(
        self,
        service: str,
        instance: str,
        nerve_ns: str,
        drain: UrlSpec,
        stop_draining: UrlSpec,
        is_draining: UrlSpec,
        is_safe_to_kill: UrlSpec,
    ) -> None:
        super(HTTPDrainMethod, self).__init__(service, instance, nerve_ns)
        self.drain_url_spec = drain
        self.stop_draining_url_spec = stop_draining
        self.is_draining_url_spec = is_draining
        self.is_safe_to_kill_url_spec = is_safe_to_kill

    def get_format_params(self, task: DrainTask) -> Dict[str, Any]:
        return {
            'host': task.host,
            'port': task.ports[0],
            'service': self.service,
            'instance': self.instance,
            'nerve_ns': self.nerve_ns,
        }

    def format_url(self, url_format: str, format_params: Dict[str, Any]) -> str:
        return url_format.format(**format_params)

    def parse_success_codes(self, success_codes_str: str) -> Set[int]:
        """Expand a string like 200-399,407-409,500 to a set containing all the integers in between."""
        acceptable_response_codes: Set[int] = set()
        for series_str in str(success_codes_str).split(','):
            if '-' in series_str:
                start, end = series_str.split('-')
                acceptable_response_codes.update(range(int(start), int(end) + 1))
            else:
                acceptable_response_codes.add(int(series_str))
        return acceptable_response_codes

    def check_response_code(self, status_code: int, success_codes_str: str) -> None:
        acceptable_response_codes = self.parse_success_codes(success_codes_str)
        if status_code not in acceptable_response_codes:
            raise StatusCodeNotAcceptableError("Status code %d not in %s", status_code, success_codes_str)

    async def issue_request(self, url_spec: UrlSpec, task: DrainTask) -> None:
        """Issue a request to the URL specified by url_spec regarding the task given."""
        format_params = self.get_format_params(task)
        url = self.format_url(url_spec['url_format'], format_params)
        method = url_spec.get('method', 'GET').upper()

        async with aiohttp.ClientSession() as session:
            response = await session.request(
                method=method,
                url=url,
                headers={'User-Agent': get_user_agent()},
                timeout=15,
            )
            self.check_response_code(response.status, url_spec['success_codes'])

    async def drain(self, task: DrainTask) -> None:
        return await self.issue_request(self.drain_url_spec, task)

    async def stop_draining(self, task: DrainTask) -> None:
        return await self.issue_request(self.stop_draining_url_spec, task)

    async def is_draining(self, task: DrainTask) -> bool:
        try:
            await self.issue_request(self.is_draining_url_spec, task)
        except StatusCodeNotAcceptableError:
            return False
        else:
            return True

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        try:
            await self.issue_request(self.is_safe_to_kill_url_spec, task)
        except StatusCodeNotAcceptableError:
            return False
        else:
            return True
<commit_msg>Bump drain timeout for hacheck<commit_after># Copyright 2015-2016 Yelp Inc.
#
# 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.
import re
import time
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from typing import Set
from typing import Type
from typing import TypeVar

import aiohttp
from mypy_extensions import TypedDict

from paasta_tools.utils import get_user_agent

_drain_methods: Dict[str, Type["DrainMethod"]] = {}
HACHECK_CONN_TIMEOUT = 3
HACHECK_READ_TIMEOUT = 1

_RegisterDrainMethod_T = TypeVar('_RegisterDrainMethod_T', bound=Type["DrainMethod"])

def register_drain_method(name: str) -> Callable[[_RegisterDrainMethod_T], _RegisterDrainMethod_T]:
    """Returns a decorator that registers a DrainMethod subclass at a given name
    so get_drain_method/list_drain_methods can find it."""
    def outer(drain_method: _RegisterDrainMethod_T) -> _RegisterDrainMethod_T:
        _drain_methods[name] = drain_method
        return drain_method
    return outer

def get_drain_method(
    name: str,
    service: str,
    instance: str,
    nerve_ns: str,
    drain_method_params: Optional[Dict]=None,
) -> "DrainMethod":
    return _drain_methods[name](service, instance, nerve_ns, **(drain_method_params or {}))

def list_drain_methods() -> List[str]:
    return sorted(_drain_methods.keys())

DrainTask = TypeVar('DrainTask', bound=Any)

class DrainMethod(object):
    """A drain method is a way of stopping new traffic to tasks without killing them. For example, you might take a task
    out of a load balancer by causing its healthchecks to fail.

    A drain method must have the following methods:
     - drain(task): Begin draining traffic from a task. This should be idempotent.
     - stop_draining(task): Stop draining traffic from a task. This should be idempotent.
     - is_draining(task): Whether a task has already been marked as downed. Note that this state should be stored out of
                          process, because a bounce may take multiple runs of setup_marathon_job to complete.
     - is_safe_to_kill(task): Return True if this task is safe to kill, False otherwise.

    When implementing a drain method, be sure to decorate with @register_drain_method(name).
    """

    def __init__(self, service: str, instance: str, nerve_ns: str, **kwargs: Dict) -> None:
        self.service = service
        self.instance = instance
        self.nerve_ns = nerve_ns

    async def drain(self, task: DrainTask) -> None:
        """Make a task stop receiving new traffic."""
        raise NotImplementedError()

    async def stop_draining(self, task: DrainTask) -> None:
        """Make a task that has previously been downed start receiving traffic again."""
        raise NotImplementedError()

    async def is_draining(self, task: DrainTask) -> bool:
        """Return whether a task is being drained."""
        raise NotImplementedError()

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        """Return True if a task is drained and ready to be killed, or False if we should wait."""
        raise NotImplementedError()

@register_drain_method('noop')
class NoopDrainMethod(DrainMethod):
    """This drain policy does nothing and assumes every task is safe to kill."""

    async def drain(self, task: DrainTask) -> None:
        pass

    async def stop_draining(self, task: DrainTask) -> None:
        pass

    async def is_draining(self, task: DrainTask) -> bool:
        return False

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        return True

@register_drain_method('test')
class TestDrainMethod(DrainMethod):
    """This drain policy is meant for integration testing. Do not use."""

    # These are variables on the class for ease of use in testing.
    downed_task_ids: Set[str] = set()
    safe_to_kill_task_ids: Set[str] = set()

    async def drain(self, task: DrainTask) -> None:
        if task.id not in self.safe_to_kill_task_ids:
            self.downed_task_ids.add(task.id)

    async def stop_draining(self, task: DrainTask) -> None:
        self.downed_task_ids -= {task.id}
        self.safe_to_kill_task_ids -= {task.id}

    async def is_draining(self, task: DrainTask) -> bool:
        return task.id in (self.downed_task_ids | self.safe_to_kill_task_ids)

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        return task.id in self.safe_to_kill_task_ids

    @classmethod
    def mark_arbitrary_task_as_safe_to_kill(cls) -> None:
        cls.safe_to_kill_task_ids.add(cls.downed_task_ids.pop())

@register_drain_method('crashy_drain')
class CrashyDrainDrainMethod(NoopDrainMethod):
    async def drain(self, task: DrainTask) -> None:
        raise Exception("Intentionally crashing for testing purposes")

@register_drain_method('crashy_is_safe_to_kill')
class CrashySafeToKillDrainMethod(NoopDrainMethod):
    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        raise Exception("Intentionally crashing for testing purposes")

SpoolInfo = TypedDict(
    'SpoolInfo',
    {
        'service': str,
        'state': str,
        'since': float,
        'until': float,
        'reason': str,
    },
    total=False,
)

@register_drain_method('hacheck')
class HacheckDrainMethod(DrainMethod):
    """This drain policy issues a POST to hacheck's /spool/{service}/{port}/status endpoint to cause healthchecks to
    fail. It considers tasks safe to kill if they've been down in hacheck for more than a specified delay."""

    def __init__(
        self,
        service: str,
        instance: str,
        nerve_ns: str,
        delay: float=240,
        hacheck_port: int=6666,
        expiration: float=0,
        **kwargs: Dict,
    ) -> None:
        super(HacheckDrainMethod, self).__init__(service, instance, nerve_ns)
        self.delay = float(delay)
        self.hacheck_port = hacheck_port
        self.expiration = float(expiration) or float(delay) * 10

    def spool_url(self, task: DrainTask) -> str:
        if task.ports == []:
            return None
        else:
            return 'http://%(task_host)s:%(hacheck_port)d/spool/%(service)s.%(nerve_ns)s/%(task_port)d/status' % {
                'task_host': task.host,
                'task_port': task.ports[0],
                'hacheck_port': self.hacheck_port,
                'service': self.service,
                'nerve_ns': self.nerve_ns,
            }

    async def post_spool(self, task: DrainTask, status: str) -> None:
        spool_url = self.spool_url(task)
        if spool_url is not None:
            data: Dict[str, str] = {'status': status}
            if status == 'down':
                data.update({
                    'expiration': str(time.time() + self.expiration),
                    'reason': 'Drained by Paasta',
                })
            async with aiohttp.ClientSession(
                conn_timeout=HACHECK_CONN_TIMEOUT,
                read_timeout=HACHECK_READ_TIMEOUT,
            ) as session:
                async with session.post(
                    self.spool_url(task),
                    data=data,
                    headers={'User-Agent': get_user_agent()},
                ) as resp:
                    resp.raise_for_status()

    async def get_spool(self, task: DrainTask) -> SpoolInfo:
        """Query hacheck for the state of a task, and parse the result into a dictionary."""
        spool_url = self.spool_url(task)
        if spool_url is None:
            return None

        # TODO: aiohttp says not to create a session per request. Fix this.
        async with aiohttp.ClientSession(
            conn_timeout=HACHECK_CONN_TIMEOUT,
            read_timeout=HACHECK_READ_TIMEOUT,
        ) as session:
            response = await session.get(
                self.spool_url(task),
                headers={'User-Agent': get_user_agent()},
            )
            if response.status == 200:
                return {
                    'state': 'up',
                }

            regex = ''.join([
                "^",
                r"Service (?P<service>.+)",
                r" in (?P<state>.+) state",
                r"(?: since (?P<since>[0-9.]+))?",
                r"(?: until (?P<until>[0-9.]+))?",
                r"(?:: (?P<reason>.*))?",
                "$",
            ])

            response_text = await response.text()
            match = re.match(regex, response_text)
            groupdict = match.groupdict()
            info: SpoolInfo = {}
            info['service'] = groupdict['service']
            info['state'] = groupdict['state']
            if 'since' in groupdict:
                info['since'] = float(groupdict['since'] or 0)
            if 'until' in groupdict:
                info['until'] = float(groupdict['until'] or 0)
            if 'reason' in groupdict:
                info['reason'] = groupdict['reason']
            return info

    async def drain(self, task: DrainTask) -> None:
        return await self.post_spool(task, 'down')

    async def stop_draining(self, task: DrainTask) -> None:
        return await self.post_spool(task, 'up')

    async def is_draining(self, task: DrainTask) -> bool:
        info = await self.get_spool(task)
        if info is None or info["state"] == "up":
            return False
        else:
            return True

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        info = await self.get_spool(task)
        if info is None or info["state"] == "up":
            return False
        else:
            return info.get("since", 0) < (time.time() - self.delay)

class StatusCodeNotAcceptableError(Exception):
    pass

UrlSpec = TypedDict(
    'UrlSpec',
    {
        'url_format': str,
        'method': str,
        'success_codes': str,
    },
    total=False,
)

@register_drain_method('http')
class HTTPDrainMethod(DrainMethod):
    """This drain policy issues arbitrary HTTP calls to arbitrary URLs specified by the parameters. The URLs are
    specified as format strings, and will have variables such as {host}, {port}, etc. filled in."""

    def __init__(
        self,
        service: str,
        instance: str,
        nerve_ns: str,
        drain: UrlSpec,
        stop_draining: UrlSpec,
        is_draining: UrlSpec,
        is_safe_to_kill: UrlSpec,
    ) -> None:
        super(HTTPDrainMethod, self).__init__(service, instance, nerve_ns)
        self.drain_url_spec = drain
        self.stop_draining_url_spec = stop_draining
        self.is_draining_url_spec = is_draining
        self.is_safe_to_kill_url_spec = is_safe_to_kill

    def get_format_params(self, task: DrainTask) -> Dict[str, Any]:
        return {
            'host': task.host,
            'port': task.ports[0],
            'service': self.service,
            'instance': self.instance,
            'nerve_ns': self.nerve_ns,
        }

    def format_url(self, url_format: str, format_params: Dict[str, Any]) -> str:
        return url_format.format(**format_params)

    def parse_success_codes(self, success_codes_str: str) -> Set[int]:
        """Expand a string like 200-399,407-409,500 to a set containing all the integers in between."""
        acceptable_response_codes: Set[int] = set()
        for series_str in str(success_codes_str).split(','):
            if '-' in series_str:
                start, end = series_str.split('-')
                acceptable_response_codes.update(range(int(start), int(end) + 1))
            else:
                acceptable_response_codes.add(int(series_str))
        return acceptable_response_codes

    def check_response_code(self, status_code: int, success_codes_str: str) -> None:
        acceptable_response_codes = self.parse_success_codes(success_codes_str)
        if status_code not in acceptable_response_codes:
            raise StatusCodeNotAcceptableError("Status code %d not in %s", status_code, success_codes_str)

    async def issue_request(self, url_spec: UrlSpec, task: DrainTask) -> None:
        """Issue a request to the URL specified by url_spec regarding the task given."""
        format_params = self.get_format_params(task)
        url = self.format_url(url_spec['url_format'], format_params)
        method = url_spec.get('method', 'GET').upper()

        async with aiohttp.ClientSession() as session:
            response = await session.request(
                method=method,
                url=url,
                headers={'User-Agent': get_user_agent()},
                timeout=15,
            )
            self.check_response_code(response.status, url_spec['success_codes'])

    async def drain(self, task: DrainTask) -> None:
        return await self.issue_request(self.drain_url_spec, task)

    async def stop_draining(self, task: DrainTask) -> None:
        return await self.issue_request(self.stop_draining_url_spec, task)

    async def is_draining(self, task: DrainTask) -> bool:
        try:
            await self.issue_request(self.is_draining_url_spec, task)
        except StatusCodeNotAcceptableError:
            return False
        else:
            return True

    async def is_safe_to_kill(self, task: DrainTask) -> bool:
        try:
            await self.issue_request(self.is_safe_to_kill_url_spec, task)
        except StatusCodeNotAcceptableError:
            return False
        else:
            return True
<|endoftext|>


<commit_before>import asyncio
import discord
import commands
import os
import permissions
from datetime import datetime

"""This is a plugin for developer utilities to aid in programming and debugging.
   !info: pms information about the channel, server, and author
   !game: sets the name of the game the bot is playing"""

client = None

@commands.registerEventHandler(name="info")
async def info(triggerMessage):
    target = triggerMessage.author
    if triggerMessage.mentions.__len__() == 1:
        targetUser = triggerMessage.mentions[0]
        unixtime=((int(targetUser.id)>>22)+ 1420070400000)
        acctCreateDate = datetime.utcfromtimestamp(unixtime/1000).strftime('%Y-%m-%d %H:%M:%S')
        await target.send("User name: " + targetUser.name +
                                  "\nUser id: " + targetUser.id +
                                  "\nUser discriminator: " + targetUser.discriminator +
                                  "\nAccount Create Date:" + acctCreateDate)
        await client.delete_message(triggerMessage)
    else:
        unixtime=((int(target.id)>>22)+ 1420070400000)
        acctCreateDate = datetime.utcfromtimestamp(unixtime/1000).strftime('%Y-%m-%d %H:%M:%S')
        await target.send("Channel name: " + triggerMessage.channel.name +
                                  "\nChannel id: " + str(triggerMessage.channel.id) +
                                  "\nServer  name: " + triggerMessage.guild.name +
                                  "\nServer id: " + str(triggerMessage.guild.id) +
                                  "\nAuthor name: " + triggerMessage.author.name +
                                  "\nAuthor id: " + str(triggerMessage.author.id) +
                                  "\nAccount Create Date:" + str(acctCreateDate) +
                                  "\nChannel Type:" + str(triggerMessage.channel.ChannelType) +
                                  "\nChannel NSFW:" + str(triggerMessage.channel.is_nsfw())
                         )

@commands.registerEventHandler(name="game")
async def game(triggerMessage):
    await client.change_presence(game=discord.Game(name=triggerMessage.content[6:]))

@commands.registerEventHandler(name="embeds")
async def embeds(triggerMessage):
    print(str(len(triggerMessage.embeds)) + " embeds in message")
    for embed in triggerMessage.embeds:
        await triggerMessage.author.send(str(dir(embed)))

@permissions.needs_moderator
@commands.registerEventHandler(name="gitpull")
async def gitpull(triggerMessage):
    os.system("git pull origin master")

@permissions.needs_admin
@commands.registerEventHandler(name="oauth")
async def oauthlink(triggerMessage):
   await triggerMessage.author.send("https://discordapp.com/oauth2/authorize?client_id=245814417609064448&scope=bot")

<commit_msg>fixed !info again<commit_after>import asyncio
import discord
import commands
import os
import permissions
from datetime import datetime

"""This is a plugin for developer utilities to aid in programming and debugging.
   !info: pms information about the channel, server, and author
   !game: sets the name of the game the bot is playing"""

client = None

@commands.registerEventHandler(name="info")
async def info(triggerMessage):
    target = triggerMessage.author
    if triggerMessage.mentions.__len__() == 1:
        targetUser = triggerMessage.mentions[0]
        unixtime=((int(targetUser.id)>>22)+ 1420070400000)
        acctCreateDate = datetime.utcfromtimestamp(unixtime/1000).strftime('%Y-%m-%d %H:%M:%S')
        await target.send("User name: " + targetUser.name +
                                  "\nUser id: " + targetUser.id +
                                  "\nUser discriminator: " + targetUser.discriminator +
                                  "\nAccount Create Date:" + acctCreateDate)
        await client.delete_message(triggerMessage)
    else:
        unixtime=((int(target.id)>>22)+ 1420070400000)
        acctCreateDate = datetime.utcfromtimestamp(unixtime/1000).strftime('%Y-%m-%d %H:%M:%S')
        await target.send("Channel name: " + triggerMessage.channel.name +
                                  "\nChannel id: " + str(triggerMessage.channel.id) +
                                  "\nServer  name: " + triggerMessage.guild.name +
                                  "\nServer id: " + str(triggerMessage.guild.id) +
                                  "\nAuthor name: " + triggerMessage.author.name +
                                  "\nAuthor id: " + str(triggerMessage.author.id) +
                                  "\nAccount Create Date:" + str(acctCreateDate) +
                                  "\nChannel Type:" + str(triggerMessage.channel.type) +
                                  "\nChannel NSFW:" + str(triggerMessage.channel.is_nsfw())
                         )

@commands.registerEventHandler(name="game")
async def game(triggerMessage):
    await client.change_presence(game=discord.Game(name=triggerMessage.content[6:]))

@commands.registerEventHandler(name="embeds")
async def embeds(triggerMessage):
    print(str(len(triggerMessage.embeds)) + " embeds in message")
    for embed in triggerMessage.embeds:
        await triggerMessage.author.send(str(dir(embed)))

@permissions.needs_moderator
@commands.registerEventHandler(name="gitpull")
async def gitpull(triggerMessage):
    os.system("git pull origin master")

@permissions.needs_admin
@commands.registerEventHandler(name="oauth")
async def oauthlink(triggerMessage):
   await triggerMessage.author.send("https://discordapp.com/oauth2/authorize?client_id=245814417609064448&scope=bot")

<|endoftext|>


<commit_before>import os
import sys

import numpy as np

from .. import files

TEST_DATA_DIR=os.path.join('ifcb','data','tests','data')

WHITELIST = ['data','white']

TEST_FILES = {
    'D20130526T095207_IFCB013': {
        'n_rois': 19,
        'roi_numbers': [7, 11, 13, 21, 32, 33, 47, 49, 54, 61, 66, 68, 73, 78, 80, 92, 99, 102, 114],
        'roi_number': 99,
        'roi_shape': (34, 64),
        'roi_slice': np.array([[172, 168, 172, 166, 171],
                               [168, 170, 172, 171, 170],
                               [167, 174, 171, 175, 168],
                               [173, 171, 173, 170, 171],
                               [176, 169, 176, 173, 172]], dtype=np.uint8),
        'sizes': {
            'roi': 98472,
            'hdr': 2970,
            'adc': 19513
        }
    },
    'IFCB5_2012_028_081515': {
        'n_rois': 6,
        'roi_numbers': [1, 2, 3, 4, 5, 6],
        'roi_number': 1,
        'roi_shape': (45, 96),
        'roi_slice': np.array([[208, 207, 206, 206, 207],
                               [206, 206, 206, 207, 206],
                               [206, 207, 205, 206, 208],
                               [208, 208, 208, 208, 209],
                               [206, 206, 205, 207, 207]], dtype=np.uint8),
        'stitched_roi_number': 3,
        'stitched_roi_shape': (86, 263),
        'stitched_roi_coords': [slice(23,27), slice(177,183)],
        'stitched_roi_slice': np.array([[205, 204, 205, 0, 0, 0],
                                        [202, 203, 206, 0, 0, 0],
                                        [205, 206, 205, 204, 202, 202],
                                        [204, 202, 205, 203, 202, 204]], dtype=np.uint8),
        'sizes': {
            'roi': 71083,
            'hdr': 307,
            'adc': 1011
        }
    }
}

def data_dir():
    for p in sys.path:
        fp = os.path.join(p, TEST_DATA_DIR)
        if os.path.exists(fp):
            return fp
    raise KeyError('cannot find %s on sys.path' % TEST_DATA_DIR)

def list_test_filesets():
    for b in files.DataDirectory(data_dir(), whitelist=WHITELIST):
        yield b.fileset
<commit_msg>adding list_test_bins<commit_after>import os
import sys

import numpy as np

from .. import files

TEST_DATA_DIR=os.path.join('ifcb','data','tests','data')

WHITELIST = ['data','white']

TEST_FILES = {
    'D20130526T095207_IFCB013': {
        'n_rois': 19,
        'roi_numbers': [7, 11, 13, 21, 32, 33, 47, 49, 54, 61, 66, 68, 73, 78, 80, 92, 99, 102, 114],
        'roi_number': 99,
        'roi_shape': (34, 64),
        'roi_slice': np.array([[172, 168, 172, 166, 171],
                               [168, 170, 172, 171, 170],
                               [167, 174, 171, 175, 168],
                               [173, 171, 173, 170, 171],
                               [176, 169, 176, 173, 172]], dtype=np.uint8),
        'sizes': {
            'roi': 98472,
            'hdr': 2970,
            'adc': 19513
        }
    },
    'IFCB5_2012_028_081515': {
        'n_rois': 6,
        'roi_numbers': [1, 2, 3, 4, 5, 6],
        'roi_number': 1,
        'roi_shape': (45, 96),
        'roi_slice': np.array([[208, 207, 206, 206, 207],
                               [206, 206, 206, 207, 206],
                               [206, 207, 205, 206, 208],
                               [208, 208, 208, 208, 209],
                               [206, 206, 205, 207, 207]], dtype=np.uint8),
        'stitched_roi_number': 3,
        'stitched_roi_shape': (86, 263),
        'stitched_roi_coords': [slice(23,27), slice(177,183)],
        'stitched_roi_slice': np.array([[205, 204, 205, 0, 0, 0],
                                        [202, 203, 206, 0, 0, 0],
                                        [205, 206, 205, 204, 202, 202],
                                        [204, 202, 205, 203, 202, 204]], dtype=np.uint8),
        'sizes': {
            'roi': 71083,
            'hdr': 307,
            'adc': 1011
        }
    }
}

def data_dir():
    for p in sys.path:
        fp = os.path.join(p, TEST_DATA_DIR)
        if os.path.exists(fp):
            return fp
    raise KeyError('cannot find %s on sys.path' % TEST_DATA_DIR)

def list_test_bins():
    return list(files.DataDirectory(data_dir(), whitelist=WHITELIST))

def list_test_filesets():
    return [b.fileset for b in list_test_bins()]
<|endoftext|>


<commit_before># coding: utf-8

# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009  David Decotigny
# Copyright (C) 2009  Frédéric Lehobey
# Copyright (C) 2009  David Mentré
# Copyright (C) 2009  Maxime Petazzoni
# Copyright (C) 2009  Thomas Petazzoni
# Copyright (C) 2009  Gaël Utard

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Django settings for www project.

import logging
from settings_local import *
from django.utils.translation import ugettext_lazy as _

TEMPLATE_DEBUG = DEBUG

MANAGERS = ADMINS

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Europe/Paris'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = 'tm+wb)lp5q%br=p0d2toz&km_-w)cmcelv!7inons&^v9(q!d2'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
#     'django.template.loaders.eggs.load_template_source',
)

from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS

TEMPLATE_CONTEXT_PROCESSORS += (
     'django.core.context_processors.request',
     'www.maposmatic.context_processors.all',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
)

ROOT_URLCONF = 'www.urls'

import os.path

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

TEMPLATE_DIRS = (
    os.path.join(PROJECT_PATH, 'templates'),
)

LOCAL_MEDIA_PATH = os.path.join(PROJECT_PATH, 'media')

INSTALLED_APPS = (
    'django.contrib.sessions',
    'www.maposmatic',
)

formatter = logging.Formatter("%(name)s - %(asctime)s - %(levelname)s - %(message)s")

LANGUAGES = (("fr", u"Français"),
             ("en", u"English"),
             ("de", u"Deutsch"),
             ("it", u"Italiano"),
             ("ca", u"Català"),
             ("ru", u"Русский"),
             ("ar", u"عربية"),
             ("pt_BR", u"Português do Brasil"))

MAP_LANGUAGES = [("fr_BE.UTF-8", u"Royaume de Belgique (FR)"),
                 ("fr_FR.UTF-8", u"France"),
                 ("fr_CA.UTF-8", u"Canada (FR)"),
                 ("fr_CH.UTF-8", u"Suisse (FR)"),
                 ("fr_LU.UTF-8", u"Luxembourg (FR)"),
                 ("en_AG", u"Antigua and Barbuda (EN)"),
                 ("en_AU.UTF-8", u"Australia (EN)"),
                 ("en_BW.UTF-8", u"Botswana (EN)"),
                 ("en_CA.UTF-8", u"Canada (EN)"),
                 ("en_DK.UTF-8", u"Denmark (EN)"),
                 ("en_GB.UTF-8", u"United Kingdom (EN)"),
                 ("en_HK.UTF-8", u"Hong Kong (EN)"),
                 ("en_IE.UTF-8", u"Ireland (EN)"),
                 ("en_IN", u"India (EN)"),
                 ("en_NG", u"Nigeria (EN)"),
                 ("en_NZ.UTF-8", u"New Zealand (EN)"),
                 ("en_PH.UTF-8", u"Philippines (EN)"),
                 ("en_SG.UTF-8", u"Singapore (EN)"),
                 ("en_US.UTF-8", u"United States (EN)"),
                 ("en_ZA.UTF-8", u"South Africa (EN)"),
                 ("en_ZW.UTF-8", u"Zimbabwe (EN)"),
                 ("de_BE.UTF-8", u"Königreich Belgien (DE)"),
                 ("it_CH.UTF-8", u"Svizzera (IT)"),
                 ("it_IT.UTF-8", u"Italia (IT)"),
                 ("nl_BE.UTF-8", u"Koninkrijk België (NL)"),
                 ("de_AT.UTF-8", u"Österreich (DE)"),
                 ("de_DE.UTF-8", u"Deutschland (DE)"),
                 ("de_LU.UTF-8", u"Luxemburg (DE)"),
                 ("de_CH.UTF-8", u"Schweiz (DE)"),
                 ("es_ES.UTF-8", u"España (ES)"),
                 ("ca_ES.UTF-8", u"Espanya (CA)"),
                 # "C" must be the last entry
                 ("C", _(u"No localization"))]

LOG = logging.getLogger(os.environ.get("MAPOSMATIC_LOG_TARGET",
                                       "maposmatic"))
LOG.setLevel(os.environ.get("MAPOSMATIC_LOG_LEVEL",
                            DEFAULT_MAPOSMATIC_LOG_LEVEL))
try:
    _fh = logging.FileHandler(os.environ.get('MAPOSMATIC_LOG_FILE',
                                             DEFAULT_MAPOSMATIC_LOG_FILE))
except KeyError:
    _fh = logging.FileHandler('maposmatic.log')

LOG.addHandler(_fh)
LOG.info("log restarted.")

ITEMS_PER_PAGE = 25

def has_gis_database():
    return GIS_DATABASE_NAME and GIS_DATABASE_NAME != ''
<commit_msg>Allow map generation for pt_BR<commit_after># coding: utf-8

# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009  David Decotigny
# Copyright (C) 2009  Frédéric Lehobey
# Copyright (C) 2009  David Mentré
# Copyright (C) 2009  Maxime Petazzoni
# Copyright (C) 2009  Thomas Petazzoni
# Copyright (C) 2009  Gaël Utard

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Django settings for www project.

import logging
from settings_local import *
from django.utils.translation import ugettext_lazy as _

TEMPLATE_DEBUG = DEBUG

MANAGERS = ADMINS

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Europe/Paris'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = 'tm+wb)lp5q%br=p0d2toz&km_-w)cmcelv!7inons&^v9(q!d2'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
#     'django.template.loaders.eggs.load_template_source',
)

from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS

TEMPLATE_CONTEXT_PROCESSORS += (
     'django.core.context_processors.request',
     'www.maposmatic.context_processors.all',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
)

ROOT_URLCONF = 'www.urls'

import os.path

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

TEMPLATE_DIRS = (
    os.path.join(PROJECT_PATH, 'templates'),
)

LOCAL_MEDIA_PATH = os.path.join(PROJECT_PATH, 'media')

INSTALLED_APPS = (
    'django.contrib.sessions',
    'www.maposmatic',
)

formatter = logging.Formatter("%(name)s - %(asctime)s - %(levelname)s - %(message)s")

LANGUAGES = (("fr", u"Français"),
             ("en", u"English"),
             ("de", u"Deutsch"),
             ("it", u"Italiano"),
             ("ca", u"Català"),
             ("ru", u"Русский"),
             ("ar", u"عربية"),
             ("pt_BR", u"Português do Brasil"))

MAP_LANGUAGES = [("fr_BE.UTF-8", u"Royaume de Belgique (FR)"),
                 ("fr_FR.UTF-8", u"France"),
                 ("fr_CA.UTF-8", u"Canada (FR)"),
                 ("fr_CH.UTF-8", u"Suisse (FR)"),
                 ("fr_LU.UTF-8", u"Luxembourg (FR)"),
                 ("en_AG", u"Antigua and Barbuda (EN)"),
                 ("en_AU.UTF-8", u"Australia (EN)"),
                 ("en_BW.UTF-8", u"Botswana (EN)"),
                 ("en_CA.UTF-8", u"Canada (EN)"),
                 ("en_DK.UTF-8", u"Denmark (EN)"),
                 ("en_GB.UTF-8", u"United Kingdom (EN)"),
                 ("en_HK.UTF-8", u"Hong Kong (EN)"),
                 ("en_IE.UTF-8", u"Ireland (EN)"),
                 ("en_IN", u"India (EN)"),
                 ("en_NG", u"Nigeria (EN)"),
                 ("en_NZ.UTF-8", u"New Zealand (EN)"),
                 ("en_PH.UTF-8", u"Philippines (EN)"),
                 ("en_SG.UTF-8", u"Singapore (EN)"),
                 ("en_US.UTF-8", u"United States (EN)"),
                 ("en_ZA.UTF-8", u"South Africa (EN)"),
                 ("en_ZW.UTF-8", u"Zimbabwe (EN)"),
                 ("de_BE.UTF-8", u"Königreich Belgien (DE)"),
                 ("it_CH.UTF-8", u"Svizzera (IT)"),
                 ("it_IT.UTF-8", u"Italia (IT)"),
                 ("nl_BE.UTF-8", u"Koninkrijk België (NL)"),
                 ("de_AT.UTF-8", u"Österreich (DE)"),
                 ("de_DE.UTF-8", u"Deutschland (DE)"),
                 ("de_LU.UTF-8", u"Luxemburg (DE)"),
                 ("de_CH.UTF-8", u"Schweiz (DE)"),
                 ("es_ES.UTF-8", u"España (ES)"),
                 ("ca_ES.UTF-8", u"Espanya (CA)"),
                 ("pt_BR.UTF-8", u"Brasil (PT)"),
                 # "C" must be the last entry
                 ("C", _(u"No localization"))]

LOG = logging.getLogger(os.environ.get("MAPOSMATIC_LOG_TARGET",
                                       "maposmatic"))
LOG.setLevel(os.environ.get("MAPOSMATIC_LOG_LEVEL",
                            DEFAULT_MAPOSMATIC_LOG_LEVEL))
try:
    _fh = logging.FileHandler(os.environ.get('MAPOSMATIC_LOG_FILE',
                                             DEFAULT_MAPOSMATIC_LOG_FILE))
except KeyError:
    _fh = logging.FileHandler('maposmatic.log')

LOG.addHandler(_fh)
LOG.info("log restarted.")

ITEMS_PER_PAGE = 25

def has_gis_database():
    return GIS_DATABASE_NAME and GIS_DATABASE_NAME != ''
<|endoftext|>


<commit_before>import discord
from discord.ext import commands
from .utils.dataIO import dataIO
from .utils.dataIO import fileIO
from .utils import checks
from operator import itemgetter
from random import randint
import time
import os
import ast
import csv
import requests
import re

class Hook:

    def __init__(self, bot):
        self.bot = bot
        self.data_dir = 'data/hook/users/{}/'
        self.champs_file = self.data_dir + 'champs.json'
        self.champ_re = re.compile(r'champions(?:_\d+)?.csv')
        #self.champ_str = '{0[Stars]}★ R{0[Rank]} S{0[Awakened]:<2} {0[Id]}'
        self.champ_str = '{0[Stars]}★ {0[Id]} R{0[Rank]} s{0[Awakened]:<2}'
        try:
            self.mcocCog = self.bot.get_cog('MCOC')
        except KeyError:
            raise KeyError('The MCOC Cog is not installed.')

    @commands.command(pass_context=True, no_pm=True)
    async def profile(self,ctx, *, user : discord.Member=None):
        """Displays a user profile."""
        if user is None:
            user = ctx.message.author
        # creates user if doesn't exist
        info = self.get_user_info(user.id)
        em = discord.Embed(title="User Profile", description=user.name)
        if info['top5']:
            em.add_field(name='Prestige', value=info['prestige'])
            em.add_field(name='Top Champs', value='\n'.join(info['top5']))
            em.add_field(name='Max Champs', value='\n'.join(info['max5']))
        await self.bot.say(embed=em)

    @commands.command(pass_context=True, no_pm=True)
    async def team(self,ctx, *, user : discord.Member=None):
        """Displays a user profile."""
        if user is None:
            user = ctx.message.author
        # creates user if doesn't exist
        info = self.get_user_info(user.id)
        em = discord.Embed(title="User Profile", description=user.name)
        if info['aq']:
            em.add_field(name='AQ Champs', value='\n'.join(info['aq']))
        if info['awo']:
            em.add_field(name='AWO Champs', value='\n'.join(info['awo']))
        if info['awd']:
            em.add_field(name='AWD Champs', value='\n'.join(info['awd']))
        await self.bot.say(embed=em)

    @commands.command(pass_context=True, no_pm=True)
    async def teamset(self, ctx, *, args, user : discord.Member=None)
        '''Set AQ, AW Offense or AW Defense'''
        if user is None:
            user = ctx.message.author
        info = self.get_user_info(user.id)
        aq = False
        awo = False
        awd = False
        champs = []
        for arg in args:
            if arg == 'aq':
                aq = True
            elif arg == 'awo':
                awo = True
            elif arg == 'awd':
                awd = True
            champ = self.mcocCog._resolve_alias(arg)
            champs.append(str(champ.hookid))
        if aq is True:
            info['aq'] = champs
        elif awo is True:
            info['awo'] = champs
        elif awd is True:
            info['awd'] = champs

    @commands.command(pass_context=True)
    async def clan_prestige(self, ctx, role : discord.Role, verbose=0):
        server = ctx.message.server
        width = 20
        prestige = 0
        cnt = 0
        line_out = []
        for member in server.members:
            if role in member.roles:
                champ_data = self.get_user_info(member.id)
                prestige += champ_data['prestige']
                cnt += 1
                if verbose is 1:
                    line_out.append('{:{width}} p = {}'.format(
                        member.name, champ_data['prestige'], width=width))
                elif verbose is 2:
                    line_out.append('{:{width}} p = {}'.format(
                        member.display_name, champ_data['prestige'], width=width))
        if verbose > 0:
            line_out.append('_' * (width + 11))
        line_out.append('{0:{width}} p = {1}  from {2} members'.format(
                role.name, round(prestige/cnt,0), cnt, width=width))
        await self.bot.say('```{}```'.format('\n'.join(line_out)))

    # @commands.group(pass_context=True, aliases=('teams',))
    # async def team(self, ctx):
    #     if ctx.invoked_subcommand is None:
    #         await self.bot.send_cmd_help(ctx)
    #         return
    #
    # @team.command(pass_context=True, name='awd')
    # async def _team_awd(self, ctx):
    #     '''Return user AWD team'''
    #     channel = ctx.message.channel
    #     self.bot.send_message(channel,'DEBUG: team awd invoked: {}'.format(ctx))
    #     user = ctx.message.author
    #     message = ctx.message
    #     if message is discord.Role:
    #         self.bot.say('DEBUG: discord.Role identified')
    #     elif message is discord.Member:
    #         self.bot.say('DEBUG: discord.Member identified')
    #         user = message
    #         info = self.get_user_info(user.id)
    #         em = discord.Embed(title='War Defense',description=user.name)
    #         team = []
    #         for k in info['awd']:
    #             champ = self.mcocCog._resolve_alias(k)
    #             team.append(champ.full_name)
    #         em.add_field(name='AWD:',value=team)
    #         self.bot.say(embed=em)

    @commands.group(pass_context=True, aliases=('champs',))
    async def champ(self, ctx):
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
            return

    @champ.command(pass_context=True, name='import')
    async def _champ_import(self, ctx):
        if not ctx.message.attachments:
            await self.bot.say('This command can only be used when uploading files')
            return
        for atch in ctx.message.attachments:
            if atch['filename'].endswith('.csv'):
                await self._parse_champions_csv(ctx.message, atch)
            else:
                await self.bot.say("Cannot import '{}'.".format(atch)
                        + "  File must end in .csv and come from a Hook export")

    @champ.command(pass_context=True, name='export')
    async def _champ_export(self, ctx):
        userid = ctx.message.author.id
        info = self.get_user_info(userid)
        rand = randint(1000, 9999)
        path, ext = os.path.splitext(self.champs_file.format(userid))
        tmp_file = '{}-{}.tmp'.format(path, rand)
        with open(tmp_file, 'w') as fp:
            writer = csv.DictWriter(fp, fieldnames=info['fieldnames'],
                    extrasaction='ignore', lineterminator='\n')
            writer.writeheader()
            for row in info['champs']:
                writer.writerow(row)
        filename = self.data_dir.format(userid) + '/champions.csv'
        os.replace(tmp_file, filename)
        await self.bot.upload(filename)
        os.remove(filename)

    # handles user creation, adding new server, blocking
    def _create_user(self, userid):
        if not os.path.exists(self.champs_file.format(userid)):
            if not os.path.exists(self.data_dir.format(userid)):
                os.makedirs(self.data_dir.format(userid))
            champ_data = {
                "clan": None,
                "battlegroup": None,
                "fieldnames": [],
                "champs": [],
                "prestige": 0,
                "top5": [],
                "aq": [],
                "awd": [],
                "awo": [],
                "max5": [],
            }
            dataIO.save_json(self.champs_file.format(userid), champ_data)

    def get_user_info(self, userid):
        self._create_user(userid)
        return dataIO.load_json(self.champs_file.format(userid))

    async def _parse_champions_csv(self, message, attachment):
        channel = message.channel
        self._create_user(message.author.id)
        response = requests.get(attachment['url'])
        cr = csv.DictReader(response.text.split('\n'), quoting=csv.QUOTE_NONE)
        champ_list = []
        for row in cr:
            champ_list.append({k: parse_value(k, v) for k, v in row.items()})

        chfile = self.champs_file.format(message.author.id)
        champ_data = dataIO.load_json(chfile)

        mcoc = self.bot.get_cog('MCOC')
        if mcoc:
            missing = self.hook_prestige(mcoc, champ_list)
            if missing:
                await self.bot.send_message(channel, 'Missing hookid for champs: '
                        + ', '.join(missing))

            # max prestige calcs
            champ_list.sort(key=itemgetter('maxpi', 'Id'), reverse=True)
            maxpi = sum([champ['maxpi'] for champ in champ_list[:5]])/5
            max_champs = [self.champ_str.format(champ) for champ in champ_list[:5]]
            champ_data['maxpi'] = maxpi
            champ_data['max5'] = max_champs

            # prestige calcs
            champ_list.sort(key=itemgetter('Pi', 'Id'), reverse=True)
            prestige = sum([champ['Pi'] for champ in champ_list[:5]])/5
            top_champs = [self.champ_str.format(champ) for champ in champ_list[:5]]
            champ_data['prestige'] = prestige
            champ_data['top5'] = top_champs

            em = discord.Embed(title="Updated Champions")
            em.add_field(name='Prestige', value=prestige)
            em.add_field(name='Max Prestige', value=maxpi, inline=True)
            em.add_field(name='Top Champs', value='\n'.join(top_champs), inline=False)
            em.add_field(name='Max PI Champs', value='\n'.join(max_champs), inline=True)

        champ_data['fieldnames'] = cr.fieldnames
        champ_data['champs'] = champ_list
        champ_data.update({'awd': [], 'awo': [], 'aq': []})

        for champ in champ_data['champs']:
            if champ['Role'] == 'alliance-war-defense':
                champ_data['awd'].append(champ['Id'])
            elif champ['Role'] == 'alliance-war-attack':
                champ_data['awo'].append(champ['Id'])
            elif champ['Role'] == 'alliance-quest':
                champ_data['aq'].append(champ['Id'])

        dataIO.save_json(chfile, champ_data)
        if mcoc:
            await self.bot.send_message(channel, embed=em)
        else:
            await self.bot.send_message(channel, 'Updated Champion Information')

    def hook_prestige(self, mcoc, roster):
        '''Careful.  This modifies the array of dicts in place.'''
        missing = []
        for cdict in roster:
            cdict['maxpi'] = 0
            if cdict['Stars'] < 4:
                continue
            try:
                champ_obj = mcoc.find_champ(cdict['Id'], 'hookid')
            except KeyError:
                missing.append(cdict['Id'])
                continue
            try:
                cdict['Pi'] = champ_obj.get_prestige(rank=cdict['Rank'],
                        sig=cdict['Awakened'], star=cdict['Stars'], value=True)
            except AttributeError:
                missing.append(cdict['Id'])
                continue
            if cdict['Stars'] == 5:
                maxrank = 3 if cdict['Rank'] < 4 else 4
            else:
                maxrank = 5
            cdict['maxpi'] = champ_obj.get_prestige(rank=maxrank,
                    sig=cdict['Awakened'], star=cdict['Stars'], value=True)
        return missing

    async def _on_attachment(self, msg):
        channel = msg.channel
        prefixes = tuple(self.bot.settings.get_prefixes(msg.server))
        if not msg.attachments or msg.author.bot or msg.content.startswith(prefixes):
            return
        for attachment in msg.attachments:
            if self.champ_re.match(attachment['filename']):
                await self.bot.send_message(channel,
                        "Found a CSV file to import.  Load new champions?  Type 'yes'.")
                reply = await self.bot.wait_for_message(30, channel=channel,
                        author=msg.author, content='yes')
                if reply:
                    await self._parse_champions_csv(msg, attachment)
                else:
                    await self.bot.send_message(channel, "Did not import")

def parse_value(key, value):
    try:
        return ast.literal_eval(value)
    except Exception:
        return value

#-------------- setup -------------
def check_folders():
    #if not os.path.exists("data/hook"):
        #print("Creating data/hook folder...")
        #os.makedirs("data/hook")

    if not os.path.exists("data/hook/users"):
        print("Creating data/hook/users folder...")
        os.makedirs("data/hook/users")
        #transfer_info()

def setup(bot):
    check_folders()
    n = Hook(bot)
    bot.add_cog(n)
    bot.add_listener(n._on_attachment, name='on_message')
<commit_msg>no message<commit_after>import discord
from discord.ext import commands
from .utils.dataIO import dataIO
from .utils.dataIO import fileIO
from .utils import checks
from operator import itemgetter
from random import randint
import time
import os
import ast
import csv
import requests
import re

class Hook:

    def __init__(self, bot):
        self.bot = bot
        self.data_dir = 'data/hook/users/{}/'
        self.champs_file = self.data_dir + 'champs.json'
        self.champ_re = re.compile(r'champions(?:_\d+)?.csv')
        #self.champ_str = '{0[Stars]}★ R{0[Rank]} S{0[Awakened]:<2} {0[Id]}'
        self.champ_str = '{0[Stars]}★ {0[Id]} R{0[Rank]} s{0[Awakened]:<2}'
        try:
            self.mcocCog = self.bot.get_cog('MCOC')
        except KeyError:
            raise KeyError('The MCOC Cog is not installed.')

    @commands.command(pass_context=True, no_pm=True)
    async def profile(self,ctx, *, user : discord.Member=None):
        """Displays a user profile."""
        if user is None:
            user = ctx.message.author
        # creates user if doesn't exist
        info = self.get_user_info(user.id)
        em = discord.Embed(title="User Profile", description=user.name)
        if info['top5']:
            em.add_field(name='Prestige', value=info['prestige'])
            em.add_field(name='Top Champs', value='\n'.join(info['top5']))
            em.add_field(name='Max Champs', value='\n'.join(info['max5']))
        await self.bot.say(embed=em)

    @commands.command(pass_context=True, no_pm=True)
    async def team(self,ctx, *, user : discord.Member=None):
        """Displays a user profile."""
        if user is None:
            user = ctx.message.author
        # creates user if doesn't exist
        info = self.get_user_info(user.id)
        em = discord.Embed(title="User Profile", description=user.name)
        if info['aq']:
            em.add_field(name='AQ Champs', value='\n'.join(info['aq']))
        if info['awo']:
            em.add_field(name='AWO Champs', value='\n'.join(info['awo']))
        if info['awd']:
            em.add_field(name='AWD Champs', value='\n'.join(info['awd']))
        await self.bot.say(embed=em)

    @commands.command(pass_context=True, no_pm=True)
    async def teamset(self, ctx, *, *args)#, user : discord.Member=None)
        '''Set AQ, AW Offense or AW Defense'''
        # if user is None:
        #     user = ctx.message.author
        user = ctx.message.author
        info = self.get_user_info(user.id)
        aq = False
        awo = False
        awd = False
        champs = []
        for arg in args:
            if arg == 'aq':
                aq = True
            elif arg == 'awo':
                awo = True
            elif arg == 'awd':
                awd = True
            champ = self.mcocCog._resolve_alias(arg)
            champs.append(str(champ.hookid))
        if aq is True:
            info['aq'] = champs
        elif awo is True:
            info['awo'] = champs
        elif awd is True:
            info['awd'] = champs

    @commands.command(pass_context=True)
    async def clan_prestige(self, ctx, role : discord.Role, verbose=0):
        server = ctx.message.server
        width = 20
        prestige = 0
        cnt = 0
        line_out = []
        for member in server.members:
            if role in member.roles:
                champ_data = self.get_user_info(member.id)
                prestige += champ_data['prestige']
                cnt += 1
                if verbose is 1:
                    line_out.append('{:{width}} p = {}'.format(
                        member.name, champ_data['prestige'], width=width))
                elif verbose is 2:
                    line_out.append('{:{width}} p = {}'.format(
                        member.display_name, champ_data['prestige'], width=width))
        if verbose > 0:
            line_out.append('_' * (width + 11))
        line_out.append('{0:{width}} p = {1}  from {2} members'.format(
                role.name, round(prestige/cnt,0), cnt, width=width))
        await self.bot.say('```{}```'.format('\n'.join(line_out)))

    # @commands.group(pass_context=True, aliases=('teams',))
    # async def team(self, ctx):
    #     if ctx.invoked_subcommand is None:
    #         await self.bot.send_cmd_help(ctx)
    #         return
    #
    # @team.command(pass_context=True, name='awd')
    # async def _team_awd(self, ctx):
    #     '''Return user AWD team'''
    #     channel = ctx.message.channel
    #     self.bot.send_message(channel,'DEBUG: team awd invoked: {}'.format(ctx))
    #     user = ctx.message.author
    #     message = ctx.message
    #     if message is discord.Role:
    #         self.bot.say('DEBUG: discord.Role identified')
    #     elif message is discord.Member:
    #         self.bot.say('DEBUG: discord.Member identified')
    #         user = message
    #         info = self.get_user_info(user.id)
    #         em = discord.Embed(title='War Defense',description=user.name)
    #         team = []
    #         for k in info['awd']:
    #             champ = self.mcocCog._resolve_alias(k)
    #             team.append(champ.full_name)
    #         em.add_field(name='AWD:',value=team)
    #         self.bot.say(embed=em)

    @commands.group(pass_context=True, aliases=('champs',))
    async def champ(self, ctx):
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
            return

    @champ.command(pass_context=True, name='import')
    async def _champ_import(self, ctx):
        if not ctx.message.attachments:
            await self.bot.say('This command can only be used when uploading files')
            return
        for atch in ctx.message.attachments:
            if atch['filename'].endswith('.csv'):
                await self._parse_champions_csv(ctx.message, atch)
            else:
                await self.bot.say("Cannot import '{}'.".format(atch)
                        + "  File must end in .csv and come from a Hook export")

    @champ.command(pass_context=True, name='export')
    async def _champ_export(self, ctx):
        userid = ctx.message.author.id
        info = self.get_user_info(userid)
        rand = randint(1000, 9999)
        path, ext = os.path.splitext(self.champs_file.format(userid))
        tmp_file = '{}-{}.tmp'.format(path, rand)
        with open(tmp_file, 'w') as fp:
            writer = csv.DictWriter(fp, fieldnames=info['fieldnames'],
                    extrasaction='ignore', lineterminator='\n')
            writer.writeheader()
            for row in info['champs']:
                writer.writerow(row)
        filename = self.data_dir.format(userid) + '/champions.csv'
        os.replace(tmp_file, filename)
        await self.bot.upload(filename)
        os.remove(filename)

    # handles user creation, adding new server, blocking
    def _create_user(self, userid):
        if not os.path.exists(self.champs_file.format(userid)):
            if not os.path.exists(self.data_dir.format(userid)):
                os.makedirs(self.data_dir.format(userid))
            champ_data = {
                "clan": None,
                "battlegroup": None,
                "fieldnames": [],
                "champs": [],
                "prestige": 0,
                "top5": [],
                "aq": [],
                "awd": [],
                "awo": [],
                "max5": [],
            }
            dataIO.save_json(self.champs_file.format(userid), champ_data)

    def get_user_info(self, userid):
        self._create_user(userid)
        return dataIO.load_json(self.champs_file.format(userid))

    async def _parse_champions_csv(self, message, attachment):
        channel = message.channel
        self._create_user(message.author.id)
        response = requests.get(attachment['url'])
        cr = csv.DictReader(response.text.split('\n'), quoting=csv.QUOTE_NONE)
        champ_list = []
        for row in cr:
            champ_list.append({k: parse_value(k, v) for k, v in row.items()})

        chfile = self.champs_file.format(message.author.id)
        champ_data = dataIO.load_json(chfile)

        mcoc = self.bot.get_cog('MCOC')
        if mcoc:
            missing = self.hook_prestige(mcoc, champ_list)
            if missing:
                await self.bot.send_message(channel, 'Missing hookid for champs: '
                        + ', '.join(missing))

            # max prestige calcs
            champ_list.sort(key=itemgetter('maxpi', 'Id'), reverse=True)
            maxpi = sum([champ['maxpi'] for champ in champ_list[:5]])/5
            max_champs = [self.champ_str.format(champ) for champ in champ_list[:5]]
            champ_data['maxpi'] = maxpi
            champ_data['max5'] = max_champs

            # prestige calcs
            champ_list.sort(key=itemgetter('Pi', 'Id'), reverse=True)
            prestige = sum([champ['Pi'] for champ in champ_list[:5]])/5
            top_champs = [self.champ_str.format(champ) for champ in champ_list[:5]]
            champ_data['prestige'] = prestige
            champ_data['top5'] = top_champs

            em = discord.Embed(title="Updated Champions")
            em.add_field(name='Prestige', value=prestige)
            em.add_field(name='Max Prestige', value=maxpi, inline=True)
            em.add_field(name='Top Champs', value='\n'.join(top_champs), inline=False)
            em.add_field(name='Max PI Champs', value='\n'.join(max_champs), inline=True)

        champ_data['fieldnames'] = cr.fieldnames
        champ_data['champs'] = champ_list
        champ_data.update({'awd': [], 'awo': [], 'aq': []})

        for champ in champ_data['champs']:
            if champ['Role'] == 'alliance-war-defense':
                champ_data['awd'].append(champ['Id'])
            elif champ['Role'] == 'alliance-war-attack':
                champ_data['awo'].append(champ['Id'])
            elif champ['Role'] == 'alliance-quest':
                champ_data['aq'].append(champ['Id'])

        dataIO.save_json(chfile, champ_data)
        if mcoc:
            await self.bot.send_message(channel, embed=em)
        else:
            await self.bot.send_message(channel, 'Updated Champion Information')

    def hook_prestige(self, mcoc, roster):
        '''Careful.  This modifies the array of dicts in place.'''
        missing = []
        for cdict in roster:
            cdict['maxpi'] = 0
            if cdict['Stars'] < 4:
                continue
            try:
                champ_obj = mcoc.find_champ(cdict['Id'], 'hookid')
            except KeyError:
                missing.append(cdict['Id'])
                continue
            try:
                cdict['Pi'] = champ_obj.get_prestige(rank=cdict['Rank'],
                        sig=cdict['Awakened'], star=cdict['Stars'], value=True)
            except AttributeError:
                missing.append(cdict['Id'])
                continue
            if cdict['Stars'] == 5:
                maxrank = 3 if cdict['Rank'] < 4 else 4
            else:
                maxrank = 5
            cdict['maxpi'] = champ_obj.get_prestige(rank=maxrank,
                    sig=cdict['Awakened'], star=cdict['Stars'], value=True)
        return missing

    async def _on_attachment(self, msg):
        channel = msg.channel
        prefixes = tuple(self.bot.settings.get_prefixes(msg.server))
        if not msg.attachments or msg.author.bot or msg.content.startswith(prefixes):
            return
        for attachment in msg.attachments:
            if self.champ_re.match(attachment['filename']):
                await self.bot.send_message(channel,
                        "Found a CSV file to import.  Load new champions?  Type 'yes'.")
                reply = await self.bot.wait_for_message(30, channel=channel,
                        author=msg.author, content='yes')
                if reply:
                    await self._parse_champions_csv(msg, attachment)
                else:
                    await self.bot.send_message(channel, "Did not import")

def parse_value(key, value):
    try:
        return ast.literal_eval(value)
    except Exception:
        return value

#-------------- setup -------------
def check_folders():
    #if not os.path.exists("data/hook"):
        #print("Creating data/hook folder...")
        #os.makedirs("data/hook")

    if not os.path.exists("data/hook/users"):
        print("Creating data/hook/users folder...")
        os.makedirs("data/hook/users")
        #transfer_info()

def setup(bot):
    check_folders()
    n = Hook(bot)
    bot.add_cog(n)
    bot.add_listener(n._on_attachment, name='on_message')
<|endoftext|>


<commit_before>
from operator import and_, or_, sub, xor
from uuid import uuid4
from redis import Redis
from redis.exceptions import ResponseError

_redis = Redis()
_lua_scripts = {}

def _load_lua_scripts():
    with open("atoms.lua", "r") as f:
        for func in f.read().strip().split("function "):
            if not func:
                continue
            name, code = func.split("\n", 1)
            name = name.split("(")[0].strip()
            code = code.rsplit("end", 1)[0].strip()
            _lua_scripts[name] = _redis.register_script(code)

_load_lua_scripts()

class Base(object):

    def __init__(self, value=None, key=None):
        self.key = key or str(uuid4())
        if value:
            self.value = value

    def _proxy(self, name):
        try:
            func = getattr(_redis, name)
        except AttributeError:
            pass
        else:
            return lambda *a, **k: func(self.key, *a, **k)
        try:
            func = _lua_scripts[name]
        except KeyError:
            pass
        else:
            return lambda *a, **k: func(keys=[self.key], args=a, **k)
        try:
            func = getattr(self.value, name)
        except KeyError:
            pass
        else:
            return func
        raise AttributeError(name)

    def _to_value(self, value):
        if isinstance(value, self.__class__):
            return value.value
        return value

    def __getattr__(self, name):
        return self._proxy(name)

    def __repr__(self):
        value = repr(self.value)
        return "%s(%s, '%s')" % (self.__class__.__name__, value, self.key)

    def __eq__(self, value):
        return self.value == self._to_value(value)

    def __iter__(self):
        return iter(self.value)

    def __lt__(self, value):
        return self.value < self._to_value(value)

    def __le__(self, value):
        return self.value <= self._to_value(value)

    def __gt__(self, value):
        return self.value > self._to_value(value)

    def __ge__(self, value):
        return self.value >= self._to_value(value)

    def __del__(self):
        self.delete()

class List(Base):

    @property
    def value(self):
        return self[:]

    @value.setter
    def value(self, value):
        self.extend(value)

    def __add__(self, l):
        return self.__class__(self.value + self._to_value(l))

    def __iadd__(self, l):
        self.extend(self._to_value(l))
        return self

    def __mul__(self, i):
        return self.__class__(self.value * i)

    def __imul__(self, i):
        self.list_multiply(i)
        return self

    def __len__(self):
        return self.llen()

    def __setitem__(self, i, value):
        try:
            self.lset(i, value)
        except ResponseError:
            raise IndexError

    def __getitem__(self, i):
        if isinstance(i, slice):
            start = i.start if i.start is not None else 0
            stop = i.stop if i.stop is not None else 0
            return self.lrange(start, stop - 1)
        item = self.lindex(i)
        if item is None:
            raise IndexError
        return item

    def __delitem__(self, i):
        self.pop(i)

    def extend(self, l):
        self.rpush(*l)

    def append(self, value):
        self.extend([value])

    def insert(self, i, value):
        self.list_insert(i, value)

    def pop(self, i=-1):
        if i == -1:
            return self.rpop()
        elif i == 0:
            return self.lpop()
        else:
            return self.list_pop(i)

    def reverse(self):
        self.list_reverse()

    def index(self, value):
        return self.value.index(value)

    def count(self, value):
        return self.value.count(value)

    def sort(self, reverse=False):
        self._proxy("sort")(desc=reverse, store=self.key, alpha=True)

class Set(Base):

    @property
    def value(self):
        return self.smembers()

    @value.setter
    def value(self, value):
        self.update(value)

    def _all_redis(self, values):
        return all([isinstance(value, self.__class__) for value in values])

    def _rop(self, op, value):
        right = self if isinstance(value, self.__class__) else self.value
        return op(value, right)

    def _to_keys(self, values):
        return [value.key for value in values]

    def add(self, value):
        self.update([value])

    def update(self, *values):
        self.sadd(*reduce(or_, values))

    def pop(self):
        return self.spop()

    def clear(self):
        self.delete()

    def remove(self, value):
        if self.srem(value) == 0:
            raise KeyError(value)

    def discard(self, value):
        try:
            self.remove(value)
        except KeyError:
            pass

    def __len__(self):
        return self.scard()

    def __contains__(self, value):
        return self.sismember(value)

    def __and__(self, value):
        return self.intersection(value)

    def __iand___(self, value):
        self.intersection_update(value)
        return self

    def __rand__(self, value):
        return self._rop(and_, value)

    def intersection(self, *values):
        if self._all_redis(values):
            return self.sinter(*self._to_keys(values))
        else:
            return reduce(and_, (self.value,) + values)

    def intersection_update(self, *values):
        if self._all_redis(values):
            self.sinterstore(self.key, *self._to_keys(values))
        else:
            values = list(reduce(and_, values))
            self.set_intersection_update(*values)
        return self

    def __or__(self, value):
        return self.union(value)

    def __ior___(self, value):
        self.update(value)
        return self

    def __ror__(self, value):
        return self._rop(or_, value)

    def union(self, *values):
        if self._all_redis(values):
            return self.sunion(*self._to_keys(values))
        else:
            return reduce(or_, (self.value,) + values)

    def __sub__(self, value):
        return self.difference(value)

    def __isub__(self, value):
        self.difference_update(value)
        return self

    def __rsub__(self, value):
        return self._rop(sub, value)

    def difference(self, *values):
        if self._all_redis(values):
            return self.sdiff(*self._to_keys(values))
        else:
            return reduce(sub, (self.value,) + values)

    def difference_update(self, *values):
        if self._all_redis(values):
            self.sdiffstore(self.key, *self._to_keys(values))
        else:
            all_values = [str(uuid4())]
            for value in values:
                all_values.extend(value)
                all_values.append(all_values[0])
            self.set_difference_update(*all_values)
        return self

    def __xor__(self, value):
        return self.symmetric_difference(value)

    def __ixor__(self, value):
        self.symmetric_difference_update(value)
        return self

    def __rxor__(self, value):
        return self._rop(xor, value)

    def symmetric_difference(self, value):
        if isinstance(value, self.__class__):
            return set(self.set_symmetric_difference("return", value.key))
        else:
            return self.value ^ value

    def symmetric_difference_update(self, value):
        if isinstance(value, self.__class__):
            self.set_symmetric_difference("update", value.key)
        else:
            self.set_symmetric_difference("create", *value)
        return self

    def isdisjoint(self, value):
        return not self.intersection(value)

    def issubset(self, value):
        return self <= value

    def issuperset(self, value):
        return self >= value

class Dict(Base):

    @property
    def value(self):
        return self.hgetall()

    @value.setter
    def value(self, value):
        if not isinstance(value, dict):
            try:
                value = dict(value)
            except TypeError:
                value = None
        if value:
            self.update(value)

    def __len__(self):
        return self.hlen()

    def __contains__(self, name):
        return self.hexists(name)

    def __iter__(self):
        return self.iterkeys()

    def __setitem__(self, name, value):
        self.hset(name, value)

    def __getitem__(self, name):
        value = self.get(name)
        if value is None:
            raise KeyError(name)
        return value

    def __delitem__(self, name):
        if self.hdel(name) == 0:
            raise KeyError(name)

    def update(self, value):
        self.hmset(value)

    def keys(self):
        return self.hkeys()

    def values(self):
        return self.hvals()

    def items(self):
        return self.value.items()

    def iterkeys(self):
        return iter(self.keys())

    def itervalues(self):
        return iter(self.values())

    def iteritems(self):
        return iter(self.items())

    def setdefault(self, name, value=None):
        if self.hsetnx(name, value) == 1:
            return value
        else:
            return self[name]

    def get(self, name, default=None):
        value = self.hget(name)
        return value if value is not None else default

    def has_key(self, name):
        return name in self

    def copy(self):
        return self.__class__(self.value)

    def clear(self):
        self.delete()

    @classmethod
    def fromkeys(cls, *args):
        if len(args) == 1:
            args += ("",)
        return cls({}.fromkeys(*args))

class String(Base):

    @property
    def value(self):
        return self.get()

    @value.setter
    def value(self, value):
        if value:
            self.set(value)

    def __add__(self, s):
        return self.__class__(self.value + self._to_value(s))

    def __iadd__(self, s):
        self.append(self._to_value(s))
        return self

    def __mul__(self, i):
        return self.__class__(self.value * i)

    def __imul__(self, i):
        self.string_multiply(i)
        return self

    def __len__(self):
        return self.strlen()

    def __setitem__(self, i, value):
        if isinstance(i, slice):
            start = i.start if i.start is not None else 0
            stop = i.stop
        else:
            start = i
            stop = None
        if stop is not None and stop < start + len(value):
            self.string_setitem(start, stop, value)
        else:
            self.setrange(start, value)

    def __getitem__(self, i):
        if not isinstance(i, slice):
            i = slice(i, i + 1)
        start = i.start if i.start is not None else 0
        stop = i.stop if i.stop is not None else 0
        value = self.getrange(start, stop - 1)
        if not value:
            raise IndexError
        return value

class ImmutableString(String):

    def __iadd__(self, s):
        return self + s

    def __imul__(self, i):
        return self * i

    def __setitem__(self, i):
        raise TypeError
<commit_msg>Initial Int<commit_after>
from operator import and_, or_, sub, xor
from uuid import uuid4
from redis import Redis
from redis.exceptions import ResponseError

_redis = Redis()
_lua_scripts = {}

def _load_lua_scripts():
    with open("atoms.lua", "r") as f:
        for func in f.read().strip().split("function "):
            if not func:
                continue
            name, code = func.split("\n", 1)
            name = name.split("(")[0].strip()
            code = code.rsplit("end", 1)[0].strip()
            _lua_scripts[name] = _redis.register_script(code)

_load_lua_scripts()

class Base(object):

    def __init__(self, value=None, key=None):
        self.key = key or str(uuid4())
        if value:
            self.value = value

    def _proxy(self, name):
        try:
            func = getattr(_redis, name)
        except AttributeError:
            pass
        else:
            return lambda *a, **k: func(self.key, *a, **k)
        try:
            func = _lua_scripts[name]
        except KeyError:
            pass
        else:
            return lambda *a, **k: func(keys=[self.key], args=a, **k)
        try:
            func = getattr(self.value, name)
        except KeyError:
            pass
        else:
            return func
        raise AttributeError(name)

    def _to_value(self, value):
        if isinstance(value, self.__class__):
            return value.value
        return value

    def __getattr__(self, name):
        return self._proxy(name)

    def __repr__(self):
        value = repr(self.value)
        return "%s(%s, '%s')" % (self.__class__.__name__, value, self.key)

    def __eq__(self, value):
        return self.value == self._to_value(value)

    def __iter__(self):
        return iter(self.value)

    def __lt__(self, value):
        return self.value < self._to_value(value)

    def __le__(self, value):
        return self.value <= self._to_value(value)

    def __gt__(self, value):
        return self.value > self._to_value(value)

    def __ge__(self, value):
        return self.value >= self._to_value(value)

    def __del__(self):
        self.delete()

class List(Base):

    @property
    def value(self):
        return self[:]

    @value.setter
    def value(self, value):
        self.extend(value)

    def __add__(self, l):
        return self.__class__(self.value + self._to_value(l))

    def __iadd__(self, l):
        self.extend(self._to_value(l))
        return self

    def __mul__(self, i):
        return self.__class__(self.value * i)

    def __imul__(self, i):
        self.list_multiply(i)
        return self

    def __len__(self):
        return self.llen()

    def __setitem__(self, i, value):
        try:
            self.lset(i, value)
        except ResponseError:
            raise IndexError

    def __getitem__(self, i):
        if isinstance(i, slice):
            start = i.start if i.start is not None else 0
            stop = i.stop if i.stop is not None else 0
            return self.lrange(start, stop - 1)
        item = self.lindex(i)
        if item is None:
            raise IndexError
        return item

    def __delitem__(self, i):
        self.pop(i)

    def extend(self, l):
        self.rpush(*l)

    def append(self, value):
        self.extend([value])

    def insert(self, i, value):
        self.list_insert(i, value)

    def pop(self, i=-1):
        if i == -1:
            return self.rpop()
        elif i == 0:
            return self.lpop()
        else:
            return self.list_pop(i)

    def reverse(self):
        self.list_reverse()

    def index(self, value):
        return self.value.index(value)

    def count(self, value):
        return self.value.count(value)

    def sort(self, reverse=False):
        self._proxy("sort")(desc=reverse, store=self.key, alpha=True)

class Set(Base):

    @property
    def value(self):
        return self.smembers()

    @value.setter
    def value(self, value):
        self.update(value)

    def _all_redis(self, values):
        return all([isinstance(value, self.__class__) for value in values])

    def _rop(self, op, value):
        right = self if isinstance(value, self.__class__) else self.value
        return op(value, right)

    def _to_keys(self, values):
        return [value.key for value in values]

    def add(self, value):
        self.update([value])

    def update(self, *values):
        self.sadd(*reduce(or_, values))

    def pop(self):
        return self.spop()

    def clear(self):
        self.delete()

    def remove(self, value):
        if self.srem(value) == 0:
            raise KeyError(value)

    def discard(self, value):
        try:
            self.remove(value)
        except KeyError:
            pass

    def __len__(self):
        return self.scard()

    def __contains__(self, value):
        return self.sismember(value)

    def __and__(self, value):
        return self.intersection(value)

    def __iand___(self, value):
        self.intersection_update(value)
        return self

    def __rand__(self, value):
        return self._rop(and_, value)

    def intersection(self, *values):
        if self._all_redis(values):
            return self.sinter(*self._to_keys(values))
        else:
            return reduce(and_, (self.value,) + values)

    def intersection_update(self, *values):
        if self._all_redis(values):
            self.sinterstore(self.key, *self._to_keys(values))
        else:
            values = list(reduce(and_, values))
            self.set_intersection_update(*values)
        return self

    def __or__(self, value):
        return self.union(value)

    def __ior___(self, value):
        self.update(value)
        return self

    def __ror__(self, value):
        return self._rop(or_, value)

    def union(self, *values):
        if self._all_redis(values):
            return self.sunion(*self._to_keys(values))
        else:
            return reduce(or_, (self.value,) + values)

    def __sub__(self, value):
        return self.difference(value)

    def __isub__(self, value):
        self.difference_update(value)
        return self

    def __rsub__(self, value):
        return self._rop(sub, value)

    def difference(self, *values):
        if self._all_redis(values):
            return self.sdiff(*self._to_keys(values))
        else:
            return reduce(sub, (self.value,) + values)

    def difference_update(self, *values):
        if self._all_redis(values):
            self.sdiffstore(self.key, *self._to_keys(values))
        else:
            all_values = [str(uuid4())]
            for value in values:
                all_values.extend(value)
                all_values.append(all_values[0])
            self.set_difference_update(*all_values)
        return self

    def __xor__(self, value):
        return self.symmetric_difference(value)

    def __ixor__(self, value):
        self.symmetric_difference_update(value)
        return self

    def __rxor__(self, value):
        return self._rop(xor, value)

    def symmetric_difference(self, value):
        if isinstance(value, self.__class__):
            return set(self.set_symmetric_difference("return", value.key))
        else:
            return self.value ^ value

    def symmetric_difference_update(self, value):
        if isinstance(value, self.__class__):
            self.set_symmetric_difference("update", value.key)
        else:
            self.set_symmetric_difference("create", *value)
        return self

    def isdisjoint(self, value):
        return not self.intersection(value)

    def issubset(self, value):
        return self <= value

    def issuperset(self, value):
        return self >= value

class Dict(Base):

    @property
    def value(self):
        return self.hgetall()

    @value.setter
    def value(self, value):
        if not isinstance(value, dict):
            try:
                value = dict(value)
            except TypeError:
                value = None
        if value:
            self.update(value)

    def __len__(self):
        return self.hlen()

    def __contains__(self, name):
        return self.hexists(name)

    def __iter__(self):
        return self.iterkeys()

    def __setitem__(self, name, value):
        self.hset(name, value)

    def __getitem__(self, name):
        value = self.get(name)
        if value is None:
            raise KeyError(name)
        return value

    def __delitem__(self, name):
        if self.hdel(name) == 0:
            raise KeyError(name)

    def update(self, value):
        self.hmset(value)

    def keys(self):
        return self.hkeys()

    def values(self):
        return self.hvals()

    def items(self):
        return self.value.items()

    def iterkeys(self):
        return iter(self.keys())

    def itervalues(self):
        return iter(self.values())

    def iteritems(self):
        return iter(self.items())

    def setdefault(self, name, value=None):
        if self.hsetnx(name, value) == 1:
            return value
        else:
            return self[name]

    def get(self, name, default=None):
        value = self.hget(name)
        return value if value is not None else default

    def has_key(self, name):
        return name in self

    def copy(self):
        return self.__class__(self.value)

    def clear(self):
        self.delete()

    @classmethod
    def fromkeys(cls, *args):
        if len(args) == 1:
            args += ("",)
        return cls({}.fromkeys(*args))

class String(Base):

    @property
    def value(self):
        return self.get()

    @value.setter
    def value(self, value):
        if value:
            self.set(value)

    def __add__(self, s):
        return self.__class__(self.value + self._to_value(s))

    def __iadd__(self, s):
        self.append(self._to_value(s))
        return self

    def __mul__(self, i):
        return self.__class__(self.value * i)

    def __imul__(self, i):
        self.string_multiply(i)
        return self

    def __len__(self):
        return self.strlen()

    def __setitem__(self, i, value):
        if isinstance(i, slice):
            start = i.start if i.start is not None else 0
            stop = i.stop
        else:
            start = i
            stop = None
        if stop is not None and stop < start + len(value):
            self.string_setitem(start, stop, value)
        else:
            self.setrange(start, value)

    def __getitem__(self, i):
        if not isinstance(i, slice):
            i = slice(i, i + 1)
        start = i.start if i.start is not None else 0
        stop = i.stop if i.stop is not None else 0
        value = self.getrange(start, stop - 1)
        if not value:
            raise IndexError
        return value

class ImmutableString(String):

    def __iadd__(self, s):
        return self + s

    def __imul__(self, i):
        return self * i

    def __setitem__(self, i):
        raise TypeError

class Int(Base):

    @property
    def value(self):
        return int(self.get())

    @value.setter
    def value(self, value):
        if value:
            self.set(value)

    def __iadd__(self, i):
        self.incr(i)
        return self

    def __isub__(self, i):
        self.decr(i)
        return self
<|endoftext|>


<commit_before><commit_msg>Team Elements<commit_after>import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'scrapers'))
sys.path.append("..")
from datetime import datetime
from pymongo import MongoClient
from database import *
import error
import sync
import team_elements as teamElementsApi

def importTeamElements ( school_id, branch_id, team_id ):
	try:
		objectList = teamElementsApi.team_elements({
			"school_id" : school_id,
			"branch_id" : branch_id,
			"team_id" : team_id
		})

		if objectList is None:
				error.log(__file__, False, "Unknown Object")
				return False

		if not "status" in objectList:
			error.log(__file__, False, "Unknown Object")
			return False

		if objectList["status"] == "ok":
			for row in objectList["team_elements"]:
				unique = {
					"team_element_id" : row["team_element_id"],
					"term" : objectList["term"]["value"]
				}

				element = {
					"team_element_id" : row["team_element_id"],
					"school_id" : row["school_id"],
					"branch_id" : row["branch_id"],
					"term" : objectList["term"]["value"],
					"name" : row["name"]
				}

				status = sync.sync(db.team_elements, unique, element)

				if sync.check_action_event(status) == True:
					for url in sync.find_listeners('team_element', unique):
						sync.send_event(url, status["action"], element)

					for url in sync.find_general_listeners('team_element_general'):
						sync.send_event(url, status["action"], element)

			return True
		else:
			if "error" in objectList:
				error.log(__file__, False, objectList["error"])
				return False
			else:
				error.log(__file__, False, "Unknown error")
				return False

	except Exception, e:
		error.log(__file__, False, str(e))
		return False<|endoftext|>


<commit_before>import mraa
import sys
import time
import socket
import fcntl
import struct

buttonState = 0
buttonPin = 13

while 1:
	buttonState = buttonPin.read()
	print buttonState<commit_msg>Test2<commit_after>import mraa
import sys
import time
import socket
import fcntl
import struct

buttonState = 0
buttonPin = 13

while 1:
	button = mraa.Gpio(buttonPin)
	buttonState = button.read()
	print buttonState<|endoftext|>