<commit_before>import os, pickle, re, sys
from common.safeprint import safeprint
from multiprocessing import Lock
from hashlib import sha256

global bountyList
global bountyLock
global bountyPath
bountyList = []
bountyLock = Lock()
bounty_path = "data" + os.sep + "bounties.pickle"

class Bounty(object):
    """An object representation of a Bounty

    Parts:
    ip       -- The ip address of the requesting node
    btc      -- The Bitcoin address of the requesting party
    reward   -- The reward amount in Satoshis to be given over 24 hours (x | x == 0 or 1440 <= x <= 100000000)
    ident    -- A value set by the issuer to determine which problem/test to send
    timeout  -- Unix time at which the bounty expires
    data     -- A dictionary containing optional, additional information
      author -- String which represents the group providing the Bounty
      reqs   -- Dict containing requirements keyed by the related python calls ("sys.platform":"win32")
      TDL    -- More to be defined in later versions
    """
    ip = ""
    btc = ""
    reward = 0
    ident = None
    timeout = 0
    data = {}

    def __repr__(self):
        """Gives a string representation of the bounty"""
        output = "<Bounty: ip=" + str(self.ip) + ", btc=" + str(self.btc) + ", reward=" + str(self.reward)
        if self.ident != None:
            output = output + ", id=" + str(self.ident)
        if self.timeout != None:
            from calendar import timegm
            from time import gmtime
            output = output + ", time_left=" + str(self.timeout - timegm(gmtime()))
        if self.data != {} and self.data != None:
            output = output + ", data=" + str(self.data)
        output = output + ">"
        return output

    def __eq__(self, other):
        """Determines whether the bounties are equal"""
        return (self.reward == other.reward) and (self.ident == other.ident) and (self.data.get('author') == other.data.get('author'))

    def __ne__(self, other):
        """Determines whether the bounties are unequal"""
        return not self.__eq__(other)

    def __lt__(self, other):
        """Determines whether this bounty has a lower priority"""
        if self.reward < other.reward:
            return True
        elif self.timeout < other.timeout:
            return True
        else:
            return False

    def __gt__(self, other):
        """Determines whether this bounty has a higher priority"""
        if self.reward > other.reward:
            return True
        elif self.timeout > other.timeout:
            return True
        else:
            return False

    def __le__(self, other):
        """Determines whether this bounty has a lower or equal priority"""
        return not self.__gt__(other)

    def __ge__(self, other):
        """Determines whether this bounty has a higher or equal priority"""
        return not self.__lt__(other)

    def __init__(self, ipAddress, btcAddress, rewardAmount, timeout=None, ident=None, dataDict={}):
        """Initialize a Bounty; constructor"""
        self.ip = ipAddress
        self.btc = btcAddress
        self.reward = rewardAmount
        self.data = dataDict
        self.ident = ident
        if timeout is None:
            from calendar import timegm
            from time import gmtime
            self.timeout = timegm(gmtime()) + 86400 #24 hours from now in UTC (forced)
        else:
            self.timeout = timeout

    def isValid(self):
        """Internal method which checks the Bounty as valid under the most minimal version

        ip      -- Must be in valid range
        btc     -- Must be in valid namespace
        reward  -- Must be in valid range
        timeout -- Must be greater than the current time
        """
        try:
            safeprint("Testing IP address")
            boolean = int(self.ip.split(":")[1]) in range(1024,49152)
            boolean = int(self.ip.split(":")[0].split(".")[0]) in range(0,256) and boolean
            boolean = int(self.ip.split(":")[0].split(".")[1]) in range(0,256) and boolean
            boolean = int(self.ip.split(":")[0].split(".")[2]) in range(0,256) and boolean
            boolean = int(self.ip.split(":")[0].split(".")[3]) in range(0,256) and boolean
            if not boolean:
                return False
            safeprint("Testing Bitcoin address")
            address = str(self.btc)
            #The following is a soft check
            #A deeper check will need to be done in order to assure this is correct
            if not checkAddressValid(address):
                return False
            safeprint("Testing reward")
            reward = int(self.reward)
            boolean = (reward == 0 or (reward >= 1440 and reward <= 100000000))
            if boolean is False:
                return False
            safeprint("Testing timeout")
            from calendar import timegm
            from time import gmtime
            return test.timeout > timegm(gmtime()) #check against current UTC
        except:
            return False

    def isPayable(self, factor):
        """check if address has enough"""
        return True

def checkAddressValid(address):
    """Check to see if a Bitcoin address is within the valid namespace. Will potentially give false positives based on leading 1s"""
    if not re.match(re.compile("^[a-zA-Z1-9]{26,35}$"),address):
        return False
    decimal = 0
    for char in address:
        decimal = decimal * 58 + '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.index(char)
    if sys.version_info[0] < 3:
        """long does not have a to_bytes() in versions less than 3. This is an equivalent function"""
        bcbytes = (('%%0%dx' % (25 << 1) % decimal).decode('hex')[-25:])
        return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]
    else:
        bcbytes = decimal.to_bytes(25, 'big')
        return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]

def verify(string):
    """External method which checks the Bounty as valid under implementation-specific requirements. This can be defined per user.

    ip      -- Must be in valid range
    btc     -- Must be in valid namespace
    reward  -- Must be in valid range
    timeout -- Must be greater than the current time
    """
    test = None
    if type(string) == type(Bounty(None,None,None)):
        safeprint("You fed this as a Bounty. This is inefficient for addBounty(). Don't do that.")
        test = string
    else:
        test = pickle.loads(string)
    try:
        safeprint("Testing IP address")
        boolean = int(test.ip.split(":")[1]) in range(1024,49152)
        boolean = int(test.ip.split(":")[0].split(".")[0]) in range(0,256) and boolean
        boolean = int(test.ip.split(":")[0].split(".")[1]) in range(0,256) and boolean
        boolean = int(test.ip.split(":")[0].split(".")[2]) in range(0,256) and boolean
        boolean = int(test.ip.split(":")[0].split(".")[3]) in range(0,256) and boolean
        if not boolean:
            return False
        safeprint("Testing Bitcoin address")
        address = str(test.btc)
        #The following is a soft check
        #A deeper check will need to be done in order to assure this is correct
        if not checkAddressValid(address):
            return False
        safeprint("Testing reward")
        reward = int(test.reward)
        boolean = (reward == 0 or (reward >= 1440 and reward <= 100000000))
        if boolean is False:
            return False
        safeprint("Testing timeout")
        from calendar import timegm
        from time import gmtime
        return self.timeout > timegm(gmtime()) #check against current UTC
    except:
        return False

def getBountyList():
    """Retrieves the bounty list. Temporary method"""
    temp = []
    with bountyLock:
        temp = bountyList
    return temp

def saveToFile(bountyList):
    """Save the current bounty list to a file"""
    if not os.path.exists(bounty_path.split(os.sep)[0]):
        os.mkdir(bounty_path.split(os.sep)[0])
    pickle.dump(bountyList,open(bounty_path, "wb"),0)
    return True

def loadFromFile():
    """Load a previous bounty list from a file"""
    if os.path.exists(bounty_path):
        with bountyLock:
            bountyList = pickle.load(open(bounty_path,"rb"))
        return True
    return False

def addBounty(bounty):
    """Verify a bounty, and add it to the list if it is valid"""
    first = False
    safeprint([sys.version_info[0],sys.version_info[1],sys.version_info[2]])
    if sys.version_info[0] == 2 and sys.version_info[1] == 6 and (type(bounty) == type("aaa") or type(bounty) == type(unicode("aaa"))):
        safeprint("Fed as string in 2.6; encoding ascii and ignoring errors")
        try:
            bounty = bounty.encode('ascii','ignore')
        except:
            bounty = str(bounty)
    elif type(bounty) == type("aaa") and sys.version_info[0] >= 3:
        safeprint("Fed as string; encoding utf-8")
        bounty = bounty.encode('utf-8')
    safeprint(pickle.loads(bounty))
    safeprint("External verify")
    first = verify(bounty)
    bounty = pickle.loads(bounty)
    safeprint("Internal verify")
    second = bounty.isValid()
    if first and second:
        with bountyLock:
            bountyList.append(bounty)
    return (first and second)

def getBounty(charity, factor):
    """Retrieve the next best bounty from the list"""
    temp = getBountyList()
    safeprint("bountyList = " + str(temp))
    if temp == []:
        return None
    elif charity:
        for bounty in temp:
            if bounty.isValid():
                index = temp.index(bounty)
                return temp.pop(index)
    else:
        best = None
        for bounty in temp:
            if best is None:
                best = bounty
            elif best.reward < bounty.reward and bounty.isValid() and bounty.isPayable(factor):
                best = bounty
        return best
<commit_msg>Fix stupid typos<commit_after>import os, pickle, re, sys
from common.safeprint import safeprint
from multiprocessing import Lock
from hashlib import sha256

global bountyList
global bountyLock
global bountyPath
bountyList = []
bountyLock = Lock()
bounty_path = "data" + os.sep + "bounties.pickle"

class Bounty(object):
    """An object representation of a Bounty

    Parts:
    ip       -- The ip address of the requesting node
    btc      -- The Bitcoin address of the requesting party
    reward   -- The reward amount in Satoshis to be given over 24 hours (x | x == 0 or 1440 <= x <= 100000000)
    ident    -- A value set by the issuer to determine which problem/test to send
    timeout  -- Unix time at which the bounty expires
    data     -- A dictionary containing optional, additional information
      author -- String which represents the group providing the Bounty
      reqs   -- Dict containing requirements keyed by the related python calls ("sys.platform":"win32")
      TDL    -- More to be defined in later versions
    """
    ip = ""
    btc = ""
    reward = 0
    ident = None
    timeout = 0
    data = {}

    def __repr__(self):
        """Gives a string representation of the bounty"""
        output = "<Bounty: ip=" + str(self.ip) + ", btc=" + str(self.btc) + ", reward=" + str(self.reward)
        if self.ident != None:
            output = output + ", id=" + str(self.ident)
        if self.timeout != None:
            from calendar import timegm
            from time import gmtime
            output = output + ", time_left=" + str(self.timeout - timegm(gmtime()))
        if self.data != {} and self.data != None:
            output = output + ", data=" + str(self.data)
        output = output + ">"
        return output

    def __eq__(self, other):
        """Determines whether the bounties are equal"""
        return (self.reward == other.reward) and (self.ident == other.ident) and (self.data.get('author') == other.data.get('author'))

    def __ne__(self, other):
        """Determines whether the bounties are unequal"""
        return not self.__eq__(other)

    def __lt__(self, other):
        """Determines whether this bounty has a lower priority"""
        if self.reward < other.reward:
            return True
        elif self.timeout < other.timeout:
            return True
        else:
            return False

    def __gt__(self, other):
        """Determines whether this bounty has a higher priority"""
        if self.reward > other.reward:
            return True
        elif self.timeout > other.timeout:
            return True
        else:
            return False

    def __le__(self, other):
        """Determines whether this bounty has a lower or equal priority"""
        return not self.__gt__(other)

    def __ge__(self, other):
        """Determines whether this bounty has a higher or equal priority"""
        return not self.__lt__(other)

    def __init__(self, ipAddress, btcAddress, rewardAmount, timeout=None, ident=None, dataDict={}):
        """Initialize a Bounty; constructor"""
        self.ip = ipAddress
        self.btc = btcAddress
        self.reward = rewardAmount
        self.data = dataDict
        self.ident = ident
        if timeout is None:
            from calendar import timegm
            from time import gmtime
            self.timeout = timegm(gmtime()) + 86400 #24 hours from now in UTC (forced)
        else:
            self.timeout = timeout

    def isValid(self):
        """Internal method which checks the Bounty as valid under the most minimal version

        ip      -- Must be in valid range
        btc     -- Must be in valid namespace
        reward  -- Must be in valid range
        timeout -- Must be greater than the current time
        """
        try:
            safeprint("Testing IP address")
            boolean = int(self.ip.split(":")[1]) in range(1024,49152)
            boolean = int(self.ip.split(":")[0].split(".")[0]) in range(0,256) and boolean
            boolean = int(self.ip.split(":")[0].split(".")[1]) in range(0,256) and boolean
            boolean = int(self.ip.split(":")[0].split(".")[2]) in range(0,256) and boolean
            boolean = int(self.ip.split(":")[0].split(".")[3]) in range(0,256) and boolean
            if not boolean:
                return False
            safeprint("Testing Bitcoin address")
            address = str(self.btc)
            #The following is a soft check
            #A deeper check will need to be done in order to assure this is correct
            if not checkAddressValid(address):
                return False
            safeprint("Testing reward")
            reward = int(self.reward)
            boolean = (reward == 0 or (reward >= 1440 and reward <= 100000000))
            if boolean is False:
                return False
            safeprint("Testing timeout")
            from calendar import timegm
            from time import gmtime
            return self.timeout > timegm(gmtime()) #check against current UTC
        except:
            return False

    def isPayable(self, factor):
        """check if address has enough"""
        return True

def checkAddressValid(address):
    """Check to see if a Bitcoin address is within the valid namespace. Will potentially give false positives based on leading 1s"""
    if not re.match(re.compile("^[a-zA-Z1-9]{26,35}$"),address):
        return False
    decimal = 0
    for char in address:
        decimal = decimal * 58 + '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.index(char)
    if sys.version_info[0] < 3:
        """long does not have a to_bytes() in versions less than 3. This is an equivalent function"""
        bcbytes = (('%%0%dx' % (25 << 1) % decimal).decode('hex')[-25:])
        return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]
    else:
        bcbytes = decimal.to_bytes(25, 'big')
        return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]

def verify(string):
    """External method which checks the Bounty as valid under implementation-specific requirements. This can be defined per user.

    ip      -- Must be in valid range
    btc     -- Must be in valid namespace
    reward  -- Must be in valid range
    timeout -- Must be greater than the current time
    """
    test = None
    if type(string) == type(Bounty(None,None,None)):
        safeprint("You fed this as a Bounty. This is inefficient for addBounty(). Don't do that.")
        test = string
    else:
        test = pickle.loads(string)
    try:
        safeprint("Testing IP address")
        boolean = int(test.ip.split(":")[1]) in range(1024,49152)
        boolean = int(test.ip.split(":")[0].split(".")[0]) in range(0,256) and boolean
        boolean = int(test.ip.split(":")[0].split(".")[1]) in range(0,256) and boolean
        boolean = int(test.ip.split(":")[0].split(".")[2]) in range(0,256) and boolean
        boolean = int(test.ip.split(":")[0].split(".")[3]) in range(0,256) and boolean
        if not boolean:
            return False
        safeprint("Testing Bitcoin address")
        address = str(test.btc)
        #The following is a soft check
        #A deeper check will need to be done in order to assure this is correct
        if not checkAddressValid(address):
            return False
        safeprint("Testing reward")
        reward = int(test.reward)
        boolean = (reward == 0 or (reward >= 1440 and reward <= 100000000))
        if boolean is False:
            return False
        safeprint("Testing timeout")
        from calendar import timegm
        from time import gmtime
        return test.timeout > timegm(gmtime()) #check against current UTC
    except:
        return False

def getBountyList():
    """Retrieves the bounty list. Temporary method"""
    temp = []
    with bountyLock:
        temp = bountyList
    return temp

def saveToFile(bountyList):
    """Save the current bounty list to a file"""
    if not os.path.exists(bounty_path.split(os.sep)[0]):
        os.mkdir(bounty_path.split(os.sep)[0])
    pickle.dump(bountyList,open(bounty_path, "wb"),0)
    return True

def loadFromFile():
    """Load a previous bounty list from a file"""
    if os.path.exists(bounty_path):
        with bountyLock:
            bountyList = pickle.load(open(bounty_path,"rb"))
        return True
    return False

def addBounty(bounty):
    """Verify a bounty, and add it to the list if it is valid"""
    first = False
    safeprint([sys.version_info[0],sys.version_info[1],sys.version_info[2]])
    if sys.version_info[0] == 2 and sys.version_info[1] == 6 and (type(bounty) == type("aaa") or type(bounty) == type(unicode("aaa"))):
        safeprint("Fed as string in 2.6; encoding ascii and ignoring errors")
        try:
            bounty = bounty.encode('ascii','ignore')
        except:
            bounty = str(bounty)
    elif type(bounty) == type("aaa") and sys.version_info[0] >= 3:
        safeprint("Fed as string; encoding utf-8")
        bounty = bounty.encode('utf-8')
    safeprint(pickle.loads(bounty))
    safeprint("External verify")
    first = verify(bounty)
    bounty = pickle.loads(bounty)
    safeprint("Internal verify")
    second = bounty.isValid()
    if first and second:
        with bountyLock:
            bountyList.append(bounty)
    return (first and second)

def getBounty(charity, factor):
    """Retrieve the next best bounty from the list"""
    temp = getBountyList()
    safeprint("bountyList = " + str(temp))
    if temp == []:
        return None
    elif charity:
        for bounty in temp:
            if bounty.isValid():
                index = temp.index(bounty)
                return temp.pop(index)
    else:
        best = None
        for bounty in temp:
            if best is None:
                best = bounty
            elif best.reward < bounty.reward and bounty.isValid() and bounty.isPayable(factor):
                best = bounty
        return best
<|endoftext|>


<commit_before>import pytest
from ckan.plugins.toolkit import ValidationError
from ckan.tests.factories import User, Dataset, Organization, Resource
from ckan.tests.helpers import call_action
from .fixtures import apply_permissions_for_service_setup  # noqa

# import unittest.mock as mock
# from ckan import model

# from ckan.tests import factories
# import ckan.tests.helpers as helpers

@pytest.mark.usefixtures('with_plugins', 'clean_db', 'clean_index', 'apply_permissions_for_service_setup')
class TestApplyPermissionsForServicePlugin():
    def test_user_creates_application(self):
        organization1 = Organization()

        user2 = User()
        org2_users = [{"name": user2["name"], "capacity": "admin"}]

        organization2 = Organization(id='TEST.ORG.1234567-1',
                                     users=org2_users,
                                     xroad_instance='TEST',
                                     xroad_memberclass='ORG',
                                     xroad_membercode='1234567-1')
        dataset1 = Dataset(owner_org=organization1['id'],
                           name='dataset1')
        resource1 = Resource(package_id=dataset1['id'],
                             xroad_servicecode='resource1',
                             xroad_serviceversion='v1')

        dataset2 = Dataset(owner_org=organization2['id'],
                           name='dataset2',
                           xroad_subsystemcode='dataset2')

        application = dict(
                    organization_id=organization2['id'],
                    target_organization_id=organization1['id'],
                    business_code=organization2['xroad_membercode'],
                    contact_name=user2['name'],
                    contact_email=user2['email'],
                    ip_address_list=['1.2.3.4'],
                    subsystem_id=dataset1['id'],
                    subsystem_code=dataset2['xroad_subsystemcode'],
                    service_code_list='.'.join([resource1['xroad_servicecode'],
                                                resource1['xroad_serviceversion']])
                    )
        call_action('service_permission_application_create',
                    {u"user": user2["name"], "ignore_auth": False},
                    **application
                    )

    def test_user_creates_application_with_inconsistent_subsystem(self):
        organization1 = Organization()

        user2 = User()
        org2_users = [{"name": user2["name"], "capacity": "admin"}]

        organization2 = Organization(id='TEST.ORG.1234567-1',
                                     users=org2_users,
                                     xroad_instance='TEST',
                                     xroad_memberclass='ORG',
                                     xroad_membercode='1234567-1')
        dataset1 = Dataset(owner_org=organization1['id'],
                           name='dataset1')
        resource1 = Resource(package_id=dataset1['id'],
                             xroad_servicecode='resource1',
                             xroad_serviceversion='v1')

        Dataset(owner_org=organization2['id'],
                name='dataset2',
                xroad_subsystemcode='dataset2')
        with pytest.raises(ValidationError):
            call_action('service_permission_application_create',
                        {u"user": user2["name"], "ignore_auth": False},
                        organization_id=organization2['id'],
                        target_organization_id=organization1['id'],
                        business_code=organization2['xroad_membercode'],
                        contact_name=user2['name'],
                        contact_email=user2['email'],
                        ip_address_list=['1.2.3.4'],
                        subsystem_id=dataset1['id'],
                        subsystem_code=dataset1['xroad_subsystemcode'],
                        service_code_list='.'.join([resource1['xroad_servicecode'],
                                                    resource1['xroad_serviceversion']])
                        )
<commit_msg>LIKA-515: Add more asserts to tests<commit_after>import pytest
from ckan.plugins.toolkit import ValidationError
from ckan.tests.factories import User, Dataset, Organization, Resource
from ckan.tests.helpers import call_action
from .fixtures import apply_permissions_for_service_setup  # noqa

# import unittest.mock as mock
# from ckan import model

# from ckan.tests import factories
# import ckan.tests.helpers as helpers

@pytest.mark.usefixtures('with_plugins', 'clean_db', 'clean_index', 'apply_permissions_for_service_setup')
class TestApplyPermissionsForServicePlugin():
    def test_user_creates_application(self):
        organization1 = Organization()

        user2 = User()
        org2_users = [{"name": user2["name"], "capacity": "admin"}]

        organization2 = Organization(id='TEST.ORG.1234567-1',
                                     users=org2_users,
                                     xroad_instance='TEST',
                                     xroad_memberclass='ORG',
                                     xroad_membercode='1234567-1')
        dataset1 = Dataset(owner_org=organization1['id'],
                           name='dataset1')
        resource1 = Resource(package_id=dataset1['id'],
                             xroad_servicecode='resource1',
                             xroad_serviceversion='v1')

        dataset2 = Dataset(owner_org=organization2['id'],
                           name='dataset2',
                           xroad_subsystemcode='dataset2')

        application = dict(
                    organization_id=organization2['id'],
                    target_organization_id=organization1['id'],
                    business_code=organization2['xroad_membercode'],
                    contact_name=user2['name'],
                    contact_email=user2['email'],
                    ip_address_list=['1.2.3.4'],
                    subsystem_id=dataset1['id'],
                    subsystem_code=dataset2['xroad_subsystemcode'],
                    service_code_list=[resource1['id']]
                    )
        call_action('service_permission_application_create',
                    {u"user": user2["name"], "ignore_auth": False},
                    **application
                    )

        applications = call_action('service_permission_application_list', {'ignore_auth': True})

        assert(len(applications) == 1)
        for key, value in application.items():
            assert(applications[0][key] == value)

    def test_user_creates_application_with_inconsistent_subsystem(self):
        organization1 = Organization()

        user2 = User()
        org2_users = [{"name": user2["name"], "capacity": "admin"}]

        organization2 = Organization(id='TEST.ORG.1234567-1',
                                     users=org2_users,
                                     xroad_instance='TEST',
                                     xroad_memberclass='ORG',
                                     xroad_membercode='1234567-1')
        dataset1 = Dataset(owner_org=organization1['id'],
                           name='dataset1')
        resource1 = Resource(package_id=dataset1['id'],
                             xroad_servicecode='resource1',
                             xroad_serviceversion='v1')

        Dataset(owner_org=organization2['id'],
                name='dataset2',
                xroad_subsystemcode='dataset2')
        with pytest.raises(ValidationError):
            call_action('service_permission_application_create',
                        {u"user": user2["name"], "ignore_auth": False},
                        organization_id=organization2['id'],
                        target_organization_id=organization1['id'],
                        business_code=organization2['xroad_membercode'],
                        contact_name=user2['name'],
                        contact_email=user2['email'],
                        ip_address_list=['1.2.3.4'],
                        subsystem_id=dataset1['id'],
                        subsystem_code=dataset1['xroad_subsystemcode'],
                        service_code_list='.'.join([resource1['xroad_servicecode'],
                                                    resource1['xroad_serviceversion']])
                        )

        applications = call_action('service_permission_application_list',
                                   {'ignore_auth': True},
                                   subsystem_id=dataset1['id'])
        assert(len(applications) == 0)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Grade a Python assignment.

usage:
    pygrade grade --students <file> --test <file> --output <file> [--workdir <file>]

Options
    -h, --help
    -s, --students <file>           Students JSON file
    -t, --test <file>               File containing python tests for grading
    -o, --output <file>             Output file
    -w, --workdir <file>            Temporary directory for storing assignments [default: /tmp/pygrade]
"""
import csv
from docopt import docopt
import errno
import git
import importlib
import os
import re
import time
import unittest

from . import __version__

def get_local_repo(s, path):
    return os.path.join(path, os.path.basename(s['github_repo']))

def clone_repos(students, path):
    """ Clone all student repos. """
    for s in students:
        repo = s['github_repo']
        topath = get_local_repo(s, path)
        print('cloning %s to %s ...' % (repo, topath))
        git.repo.base.Repo.clone_from(repo + '.git', topath)

def read_assignment_metadata(test_file):
    result = {'file_to_test': None,
              'points': None}

    for line in open(test_file):
        match = re.search(r'\@name\s*=\s*(.+.py)', line)
        if match:
             result['file_to_test'] = match.group(1)
        match = re.search(r'\@points\s*=\s*([0-9\.]+)', line)
        if match:
            result['points'] = match.group(1)
    return result

def path2name(path):
    return re.sub(r'\..+', '', os.path.basename(path))

def import_file_as_module(path):
    module_name = path2name(path)
    print('importing %s from %s' % (module_name, path))
    loader = importlib.machinery.SourceFileLoader(module_name, path)
    return loader.load_module()

def run_tests(students, test_path, path):
    metadata = read_assignment_metadata(test_path)
    assignment_subpath = metadata['file_to_test']
    results = []
    for s in students:
        result = {'student': s, 'assignment': assignment_subpath, 'time_graded': time.asctime()}
        repo = get_local_repo(s, path)
        assignment_path = os.path.join(repo, assignment_subpath)
        try:
            assignment_module = import_file_as_module(assignment_path)
        except Exception as e:
            print('cannot find assignment file %s' % assignment_path)
            result['deductions'] = [('cannot import %s' % assignment_path, metadata['points'])]
            results.append(result)
            continue
        print('assignment module: %s' % str(assignment_module))
        test_module = import_file_as_module(test_path)
        print('test module: %s' % (str(test_module)))
        suite = unittest.TestLoader().loadTestsFromModule(test_module)
        test_results = unittest.TestCase().defaultTestResult()
        test_results = suite.run(test_results)
        print(test_results)
        print(dir(test_results))
        for failure in test_results.failures:
            print('failure: %s\n%s' % (failure[1], dir(failure[0])))
    return results

def report_results():
    pass

def mktmpdir(subdir):
    """ Make a unique, temporary directory for student repos. """
    path = '%s-%d' % (subdir, time.time())
    try:
        os.makedirs(path)
    except OSError as e:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else: raise
    return path

def read_students(path):
    """ Read a tab-separated file of students. The only required field is 'github_repo', which is this
    student's github repository. """
    return [line for line in csv.DictReader(open(path), delimiter='\t')]

def check_students(students):
    """ Make sure we have requisite fields for each student."""
    for s in students:
        if 'github_repo' not in s:
            print('missing github_repo for %s' % str(s))

def main():
    args = docopt(__doc__)
    path = mktmpdir(args['--workdir'])
    print('working directory=%s' % path)
    students = read_students(args['--students'])
    print('read %d students' % len(students))
    check_students(students)
    clone_repos(students, path)
    results = run_tests(students, args['--test'], path)
    print(results)

if __name__ == '__main__':
    main()
<commit_msg>run unit tests and report json<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Grade a Python assignment.

usage:
    pygrade grade --students <file> --test <file> --output <file> [--workdir <file>]

Options
    -h, --help
    -s, --students <file>           Students JSON file
    -t, --test <file>               File containing python tests for grading
    -o, --output <file>             Output file
    -w, --workdir <file>            Temporary directory for storing assignments [default: /tmp/pygrade]
"""
import csv
from docopt import docopt
import errno
import git
import importlib
import json
import os
import re
import time
import traceback
import unittest

def get_local_repo(s, path):
    return os.path.join(path, os.path.basename(s['github_repo']))

def clone_repos(students, path):
    """ Clone all student repos. """
    for s in students:
        repo = s['github_repo']
        topath = get_local_repo(s, path)
        print('cloning %s to %s ...' % (repo, topath))
        git.repo.base.Repo.clone_from(repo + '.git', topath)

def read_assignment_metadata(test_file):
    """
    Extracts metadata in the comments of the unit test file. E.g.:
    @name=a0/boolean_search.py
    @points=50
    """
    result = {'file_to_test': None,
              'points': None}

    for line in open(test_file):
        match = re.search(r'\@name\s*=\s*(.+.py)', line)
        if match:
             result['file_to_test'] = match.group(1)
        match = re.search(r'\@points\s*=\s*([0-9\.]+)', line)
        if match:
            result['points'] = float(match.group(1))
    return result

def path2name(path):
    return re.sub(r'\..+', '', os.path.basename(path))

def import_file_as_module(path):
    module_name = path2name(path)
    print('importing %s from %s' % (module_name, path))
    loader = importlib.machinery.SourceFileLoader(module_name, path)
    return loader.load_module()

def run_tests(students, test_path, path):
    metadata = read_assignment_metadata(test_path)
    assignment_subpath = metadata['file_to_test']
    results = []
    for s in students:
        result = {'student': s, 'assignment': assignment_subpath, 'time_graded': time.asctime()}
        repo = get_local_repo(s, path)
        assignment_path = os.path.join(repo, assignment_subpath)
        try:
            assignment_module = import_file_as_module(assignment_path)
        except Exception as e:
            result['deductions'] = [{'summary': 'cannot import %s' % assignment_subpath,
                                     'trace': str(e),
                                     'points': metadata['points']}]
            result['grade'] = 0
            results.append(result)
            continue
        test_module = import_file_as_module(test_path)
        suite = unittest.TestLoader().loadTestsFromModule(test_module)
        test_results = unittest.TestCase().defaultTestResult()
        test_results = suite.run(test_results)
        # print(test_results)
        deductions = []
        for failure in test_results.failures:
            msg = failure[1]
            match = re.search(r'\: ([0-9\.]+)\s*$', msg)
            points = float(match.group(1)) if match else 0
            deduction = {'summary': '%s%s' % (failure[0]._testMethodName,
                                              ': ' + failure[0]._testMethodDoc
                                              if failure[0]._testMethodDoc else ''),
                         'trace': msg,
                         'points': points}
            deductions.append(deduction)
        result['deductions'] = deductions
        result['grade'] = max(0, metadata['points'] - sum(d['points'] for d in deductions))
        results.append(result)
    return results

def report_results():
    pass

def mktmpdir(subdir):
    """ Make a unique, temporary directory for student repos. """
    path = '%s-%d' % (subdir, time.time())
    try:
        os.makedirs(path)
    except OSError as e:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else: raise
    return path

def read_students(path):
    """ Read a tab-separated file of students. The only required field is 'github_repo', which is this
    student's github repository. """
    return [line for line in csv.DictReader(open(path), delimiter='\t')]

def check_students(students):
    """ Make sure we have requisite fields for each student."""
    for s in students:
        if 'github_repo' not in s:
            print('missing github_repo for %s' % str(s))

def main():
    args = docopt(__doc__)
    path = mktmpdir(args['--workdir'])
    print('working directory=%s' % path)
    students = read_students(args['--students'])
    print('read %d students' % len(students))
    check_students(students)
    clone_repos(students, path)
    results = run_tests(students, args['--test'], path)
    json.dump(results, open(args['--output'], 'w'), sort_keys=True, indent=2)

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


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

__title__ = 'pyhn'
__version__ = '0.1.7'
__author__ = 'Geoffrey Lehée'
__license__ = 'AGPL3'
__copyright__ = 'Copyright 2012 Geoffrey Lehée'
<commit_msg>0.1.8<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

__title__ = 'pyhn'
__version__ = '0.1.8'
__author__ = 'Geoffrey Lehée'
__license__ = 'AGPL3'
__copyright__ = 'Copyright 2012 Geoffrey Lehée'
<|endoftext|>


<commit_before>import curses
import sys
from requests.exceptions import HTTPError

from .errors import SubredditNameError
from .page import BasePage
from .submission import SubmissionPage
from .content import SubredditContent
from .utils import LoadScreen, text_input, display_message, Color, ESCAPE

class SubredditPage(BasePage):

    def __init__(self, stdscr, reddit, name):

        self.reddit = reddit
        self.name = name
        self.loader = LoadScreen(stdscr)

        content = SubredditContent.from_name(reddit, name, self.loader)
        super(SubredditPage, self).__init__(stdscr, content)

    def loop(self):

        self.draw()
        while True:
            cmd = self.stdscr.getch()

            if cmd in (curses.KEY_UP, ord('k')):
                self.move_cursor_up()
                self.clear_input_queue()

            elif cmd in (curses.KEY_DOWN, ord('j')):
                self.move_cursor_down()
                self.clear_input_queue()

            # View submission
            elif cmd in (curses.KEY_RIGHT, curses.KEY_ENTER, ord('l')):
                self.open_submission()
                self.draw()

            # Enter edit mode to change subreddit
            elif cmd == ord('/'):
                self.prompt_subreddit()
                self.draw()

            # Refresh page
            elif cmd in (curses.KEY_F5, ord('r')):
                self.refresh_content()
                self.draw()

            elif cmd == curses.KEY_RESIZE:
                self.draw()

            # Quit
            elif cmd == ord('q'):
                sys.exit()

            else:
                curses.beep()

    def refresh_content(self, name=None):

        name = name or self.name

        try:
            self.content = SubredditContent.from_name(
                self.reddit, name, self.loader)

        except (SubredditNameError, HTTPError):
            display_message(self.stdscr, 'Invalid Subreddit')

        else:
            self.nav.page_index, self.nav.cursor_index = 0, 0
            self.nav.inverted = False
            self.name = name

    def prompt_subreddit(self):

        attr = curses.A_BOLD | Color.MAGENTA
        prompt = 'Enter Subreddit: /r/'
        n_rows, n_cols = self.stdscr.getmaxyx()
        self.stdscr.addstr(n_rows-1, 0, prompt, attr)
        self.stdscr.refresh()
        window = self.stdscr.derwin(n_rows-1, len(prompt))
        window.attrset(attr)

        out = text_input(window)
        if out is not None:
            self.refresh_content(name=out)

    def open_submission(self):
        "Select the current submission to view posts"

        submission = self.content.get(self.nav.absolute_index)['object']
        page = SubmissionPage(self.stdscr, self.reddit, submission=submission)
        page.loop()

    @staticmethod
    def draw_item(win, data, inverted=False):

        n_rows, n_cols = win.getmaxyx()
        n_cols -= 1  # Leave space for the cursor in the first column

        # Handle the case where the window is not large enough to fit the data.
        valid_rows = range(0, n_rows)
        offset = 0 if not inverted else -(data['n_rows'] - n_rows)

        n_title = len(data['split_title'])
        for row, text in enumerate(data['split_title'], start=offset):
            if row in valid_rows:
                attr = curses.A_BOLD
                win.addstr(row, 1, text, attr)

        row = n_title + offset
        if row in valid_rows:
            attr = curses.A_UNDERLINE | Color.BLUE
            text = '{url}'.format(**data)
            win.addnstr(row, 1, text, n_cols-1, attr)

        row = n_title + offset + 1
        if row in valid_rows:
            text = '{created} {comments} {score}'.format(**data)
            win.addnstr(row, 1, text, n_cols-1)

        row = n_title + offset + 2
        if row in valid_rows:
            text = '{author}'.format(**data)
            win.addnstr(row, 1, text, n_cols-1, curses.A_BOLD)
            text = ' {subreddit}'.format(**data)
            win.addnstr(text, n_cols - win.getyx()[1], Color.YELLOW)
<commit_msg>Added functionality to open the submission link in the browser.<commit_after>import curses
import sys
import webbrowser
from requests.exceptions import HTTPError

from .errors import SubredditNameError
from .page import BasePage
from .submission import SubmissionPage
from .content import SubredditContent
from .utils import LoadScreen, text_input, display_message, Color, ESCAPE

class SubredditPage(BasePage):

    def __init__(self, stdscr, reddit, name):

        self.reddit = reddit
        self.name = name
        self.loader = LoadScreen(stdscr)

        content = SubredditContent.from_name(reddit, name, self.loader)
        super(SubredditPage, self).__init__(stdscr, content)

    def loop(self):

        self.draw()
        while True:
            cmd = self.stdscr.getch()

            if cmd in (curses.KEY_UP, ord('k')):
                self.move_cursor_up()
                self.clear_input_queue()

            elif cmd in (curses.KEY_DOWN, ord('j')):
                self.move_cursor_down()
                self.clear_input_queue()

            # View submission
            elif cmd in (curses.KEY_RIGHT, curses.KEY_ENTER, ord('l')):
                self.open_submission()
                self.draw()

            elif cmd == ord('o'):
                self.open_link()

            # Enter edit mode to change subreddit
            elif cmd == ord('/'):
                self.prompt_subreddit()
                self.draw()

            # Refresh page
            elif cmd in (curses.KEY_F5, ord('r')):
                self.refresh_content()
                self.draw()

            elif cmd == curses.KEY_RESIZE:
                self.draw()

            # Quit
            elif cmd == ord('q'):
                sys.exit()

            else:
                curses.beep()

    def refresh_content(self, name=None):

        name = name or self.name

        try:
            self.content = SubredditContent.from_name(
                self.reddit, name, self.loader)

        except (SubredditNameError, HTTPError):
            display_message(self.stdscr, 'Invalid Subreddit')

        else:
            self.nav.page_index, self.nav.cursor_index = 0, 0
            self.nav.inverted = False
            self.name = name

    def prompt_subreddit(self):

        attr = curses.A_BOLD | Color.MAGENTA
        prompt = 'Enter Subreddit: /r/'
        n_rows, n_cols = self.stdscr.getmaxyx()
        self.stdscr.addstr(n_rows-1, 0, prompt, attr)
        self.stdscr.refresh()
        window = self.stdscr.derwin(n_rows-1, len(prompt))
        window.attrset(attr)

        out = text_input(window)
        if out is not None:
            self.refresh_content(name=out)

    def open_submission(self):
        "Select the current submission to view posts"

        submission = self.content.get(self.nav.absolute_index)['object']
        page = SubmissionPage(self.stdscr, self.reddit, submission=submission)
        page.loop()

    @staticmethod
    def draw_item(win, data, inverted=False):

        n_rows, n_cols = win.getmaxyx()
        n_cols -= 1  # Leave space for the cursor in the first column

        # Handle the case where the window is not large enough to fit the data.
        valid_rows = range(0, n_rows)
        offset = 0 if not inverted else -(data['n_rows'] - n_rows)

        n_title = len(data['split_title'])
        for row, text in enumerate(data['split_title'], start=offset):
            if row in valid_rows:
                attr = curses.A_BOLD
                win.addstr(row, 1, text, attr)

        row = n_title + offset
        if row in valid_rows:
            attr = curses.A_UNDERLINE | Color.BLUE
            text = '{url}'.format(**data)
            win.addnstr(row, 1, text, n_cols-1, attr)

        row = n_title + offset + 1
        if row in valid_rows:
            text = '{created} {comments} {score}'.format(**data)
            win.addnstr(row, 1, text, n_cols-1)

        row = n_title + offset + 2
        if row in valid_rows:
            text = '{author}'.format(**data)
            win.addnstr(row, 1, text, n_cols-1, curses.A_BOLD)
            text = ' {subreddit}'.format(**data)
            win.addnstr(text, n_cols - win.getyx()[1], Color.YELLOW)

    def open_link(self):
        url = self.content.get(self.nav.absolute_index)['url']
        webbrowser.open_new_tab(url)
<|endoftext|>


<commit_before># !/usr/bin/env python3
# -*- coding: utf-8 -*-
# -----------------------------
# Author:  Bruce Zhang
# Email:   zy183525594@163.com
# Version: 0.1
# -----------------------------

import irc.bot
import irc.client
import irc.buffer
import os
import json
import logging
from termcolor import colored
import re
import sys
import signal
import plugin

PREFIX = '$'
PLUGINDIR = './plugins/'

class MyBot(irc.bot.SingleServerIRCBot):

    version = "201606-dev"

    def __init__(self, channels, nickname, server, port, realname):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)],
                                            nickname, realname)
        self.plugins = plugin.load_plugins(PLUGINDIR)
        self.handlers = list(filter(lambda plugin: plugin.endswith('handler'), plugins))
        self.commands = list(filter(lambda plugin: not plugin.endswith('handler'), plugins))
        self.chs = channels
        logger.info("Bot started successfully.")
        signal.signal(signal.SIGINT, self._quit)

    def _quit(self, arg1, arg2):
        logger.info("Bot interuptted from console.")
        msg = input("The reason for stopping bot:")
        self.die(msg or "")

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        for channel in self.chs:
            c.join(channel)

    def on_kick(self, c, e):
        channel = e.target
        c.join(channel)

    def exec_command(self, commandline):
        cmdargs = commandline.split(' ', 1)
        if cmdargs[0] in self.commands:
            exec('msg = %s.%s("%s")' % (cmdargs[0], cmdargs[0], cmdargs[1]))
            return msg
        return False

    def passive_exec(self, line, nick='', channel=''):
        if line.strip().endswith(" #"):
            return []
        for handler in self.handlers:
            resmsg = exec('resmsg = %s.%s(line, nick, channel)' % (handler, handler))
            return resmsg

    def on_privmsg(self, c, e):
        nm = e.source
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(nm.nick, msg)
            else:
                msgs = self.passive_exec(line, nm.nick)
                for msg in msgs:
                    if msg:
                        c.privmsg(nm.nick, msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_pubmsg(self, c, e):
        nick = e.source.nick
        channel = e.target
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(channel, "%s: %s" % (nick, msg))
            else:
                msgs = self.passive_exec(line, nick, channel)
                for msg in msgs:
                    if msg:
                        c.privmsg(channel, "%s" % msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_dccmsg(self, c, e):
        # non-chat DCC messages are raw bytes; decode as text
        pass

    def on_dccchat(self, c, e):
        pass

    def get_version(self):
        return "PyIrcBot | https://github.com/BruceZhang1993/PyIrcBot | Version: %s" % self.version

def _do_nothing():
    pass

class IgnoreErrorsBuffer(irc.buffer.DecodingLineBuffer):
    def handle_exception(self):
        pass

def main():
    # DONE:10 Try using config file
    confdir = os.environ['HOME'] + "/.pyircbot/"
    conffile = confdir + "config.json"
    logfile = confdir + "bot.log"

    try:
        os.mkdir(confdir)
    except FileExistsError:
        _do_nothing()

    # Logging
    global logger
    logger = logging.getLogger("ircbot")
    logger.setLevel(logging.DEBUG)
    logfilehandler = logging.FileHandler(logfile)
    logfilehandler.setLevel(logging.NOTSET)
    consolehandler = logging.StreamHandler()
    consolehandler.setLevel(logging.NOTSET)
    formatter = logging.Formatter("[%(levelname)s] %(msg)s (%(name)s)")
    consolehandler.setFormatter(formatter)
    logfilehandler.setFormatter(formatter)
    logger.addHandler(consolehandler)
    logger.addHandler(logfilehandler)

    if os.path.exists(conffile):
        logger.debug("Configure file found. Using now...")
        fp = None
        try:
            fp = open(conffile, "r")
            config = json.load(fp)
            channels = config["channels"]
            nickname = config["nick"]
            server = config["network"]
            port = config["port"]
            realname = config["realname"]
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file loaded. Starting bot...")
    else:
        logger.info("Configure file not found. Creating now...")
        print(colored("-- PyIrcBot 配置向导 --", "yellow"))
        config = dict()
        config['nick'] = input(colored("Nickname: ", "green")).strip()
        config["realname"] = input(colored("Real Name: ", "green")).strip()
        print(colored("-- 配置 IRC 服务器 --", "blue"))
        config['network'] = input(colored("Server: ", "green")).strip()
        config['port'] = int(input(colored("Port: ", "green")).strip())
        config['channels'] = re.split(r'\s+', input(colored("Channels (Split with space): ", "green")))
        fp = None
        try:
            fp = open(conffile, "w")
            json.dump(config, fp)
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file created. Starting bot...")
        print(colored("配置文件创建成功，启动 PyIrcBot...", "yellow"))
        channels = config["channels"]
        nickname = config["nick"]
        server = config["network"]
        port = config["port"]
        realname = config["realname"]
    logger.info("Loading plugins...")
    bot = MyBot(channels, nickname, server, port, realname)
    irc.client.ServerConnection.buffer_class = IgnoreErrorsBuffer
    bot.start()

if __name__ == "__main__":
    main()
<commit_msg>fix more bugs<commit_after># !/usr/bin/env python3
# -*- coding: utf-8 -*-
# -----------------------------
# Author:  Bruce Zhang
# Email:   zy183525594@163.com
# Version: 0.1
# -----------------------------

import irc.bot
import irc.client
import irc.buffer
import os
import json
import logging
from termcolor import colored
import re
import sys
import signal
import plugin

PREFIX = '$'
PLUGINDIR = './plugins/'

class MyBot(irc.bot.SingleServerIRCBot):

    version = "201606-dev"

    def __init__(self, channels, nickname, server, port, realname):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)],
                                            nickname, realname)
        self.plugins = plugin.load_plugins(PLUGINDIR)
        self.handlers = list(filter(lambda plugin: plugin.endswith('handler'), self.plugins))
        self.commands = list(filter(lambda plugin: not plugin.endswith('handler'), self.plugins))
        self.chs = channels
        logger.info("Bot started successfully.")
        signal.signal(signal.SIGINT, self._quit)

    def _quit(self, arg1, arg2):
        logger.info("Bot interuptted from console.")
        msg = input("The reason for stopping bot:")
        self.die(msg or "")

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        for channel in self.chs:
            c.join(channel)

    def on_kick(self, c, e):
        channel = e.target
        c.join(channel)

    def exec_command(self, commandline):
        cmdargs = commandline.split(' ', 1)
        if cmdargs[0] in self.commands:
            exec('msg = %s.%s("%s")' % (cmdargs[0], cmdargs[0], cmdargs[1]))
            return msg
        return False

    def passive_exec(self, line, nick='', channel=''):
        if line.strip().endswith(" #"):
            return []
        for handler in self.handlers:
            resmsg = exec('resmsg = %s.%s(line, nick, channel)' % (handler, handler))
            return resmsg

    def on_privmsg(self, c, e):
        nm = e.source
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(nm.nick, msg)
            else:
                msgs = self.passive_exec(line, nm.nick)
                for msg in msgs:
                    if msg:
                        c.privmsg(nm.nick, msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_pubmsg(self, c, e):
        nick = e.source.nick
        channel = e.target
        line = e.arguments[0]
        try:
            if line.startswith(PREFIX):
                commandline = line.strip(PREFIX).strip()
                msg = self.exec_command(commandline)
                if msg:
                    c.privmsg(channel, "%s: %s" % (nick, msg))
            else:
                msgs = self.passive_exec(line, nick, channel)
                for msg in msgs:
                    if msg:
                        c.privmsg(channel, "%s" % msg)
        except irc.client.InvalidCharacters:
            logger.warning("Invalid characters sent.")
            _do_nothing()

    def on_dccmsg(self, c, e):
        # non-chat DCC messages are raw bytes; decode as text
        pass

    def on_dccchat(self, c, e):
        pass

    def get_version(self):
        return "PyIrcBot | https://github.com/BruceZhang1993/PyIrcBot | Version: %s" % self.version

def _do_nothing():
    pass

class IgnoreErrorsBuffer(irc.buffer.DecodingLineBuffer):
    def handle_exception(self):
        pass

def main():
    # DONE:10 Try using config file
    confdir = os.environ['HOME'] + "/.pyircbot/"
    conffile = confdir + "config.json"
    logfile = confdir + "bot.log"

    try:
        os.mkdir(confdir)
    except FileExistsError:
        _do_nothing()

    # Logging
    global logger
    logger = logging.getLogger("ircbot")
    logger.setLevel(logging.DEBUG)
    logfilehandler = logging.FileHandler(logfile)
    logfilehandler.setLevel(logging.NOTSET)
    consolehandler = logging.StreamHandler()
    consolehandler.setLevel(logging.NOTSET)
    formatter = logging.Formatter("[%(levelname)s] %(msg)s (%(name)s)")
    consolehandler.setFormatter(formatter)
    logfilehandler.setFormatter(formatter)
    logger.addHandler(consolehandler)
    logger.addHandler(logfilehandler)

    if os.path.exists(conffile):
        logger.debug("Configure file found. Using now...")
        fp = None
        try:
            fp = open(conffile, "r")
            config = json.load(fp)
            channels = config["channels"]
            nickname = config["nick"]
            server = config["network"]
            port = config["port"]
            realname = config["realname"]
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file loaded. Starting bot...")
    else:
        logger.info("Configure file not found. Creating now...")
        print(colored("-- PyIrcBot 配置向导 --", "yellow"))
        config = dict()
        config['nick'] = input(colored("Nickname: ", "green")).strip()
        config["realname"] = input(colored("Real Name: ", "green")).strip()
        print(colored("-- 配置 IRC 服务器 --", "blue"))
        config['network'] = input(colored("Server: ", "green")).strip()
        config['port'] = int(input(colored("Port: ", "green")).strip())
        config['channels'] = re.split(r'\s+', input(colored("Channels (Split with space): ", "green")))
        fp = None
        try:
            fp = open(conffile, "w")
            json.dump(config, fp)
        except IOError:
            logger.error("I/O Error. Check filesystem permissions.")
            import sys
            sys.exit(1)
        finally:
            if fp:
                fp.close()
        logger.debug("Configure file created. Starting bot...")
        print(colored("配置文件创建成功，启动 PyIrcBot...", "yellow"))
        channels = config["channels"]
        nickname = config["nick"]
        server = config["network"]
        port = config["port"]
        realname = config["realname"]
    logger.info("Loading plugins...")
    bot = MyBot(channels, nickname, server, port, realname)
    irc.client.ServerConnection.buffer_class = IgnoreErrorsBuffer
    bot.start()

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


<commit_before>"""The version number of pyjob is recorded here"""

# Maintain sematantic versioning. Further information can
# be found here [http://semver.org/]
__version_info__ = (0, '1.b1')

# ======================================================
# Do __NOT__ change anything below here
__version__ = '.'.join(str(v) for v in __version_info__)
<commit_msg>version normalized<commit_after>"""The version number of pyjob is recorded here"""

# Maintain sematantic versioning. Further information can
# be found here [http://semver.org/]
__version_info__ = (0, '1b1')

# ======================================================
# Do __NOT__ change anything below here
__version__ = '.'.join(str(v) for v in __version_info__)
<|endoftext|>


<commit_before>import sys
import os
try:
    import lib2to3
except ImportError:
    import pgen
    import lib2to3

path = [os.path.abspath('')]

# default to None indicates 'relative paths' so that as a self-contained
# archive, pyjs can run its tests.
try:
    import pyjswidgets
    import pyjswaddons
    pyjspth = os.path.abspath(os.path.join(__file__,'../'))
    path += [os.path.dirname(pyjswidgets.__file__),
             os.path.dirname(pyjswaddons.__file__), ]
except ImportError:
    pyjspth = None

if os.environ.has_key('PYJSPATH'):
    for p in os.environ['PYJSPATH'].split(os.pathsep):
        p = os.path.abspath(p)
        if os.path.isdir(p):
            path.append(p)

MOD_SUFFIX = '.js'

PYTHON = os.path.realpath(sys.executable) if sys.executable else None
if PYTHON is None or not os.access(PYTHON, os.X_OK):
    PYTHON = 'python'

<commit_msg>Use in <commit_after>import sys
import os
try:
    import lib2to3
except ImportError:
    import pgen
    import lib2to3

path = [os.path.abspath('')]

# default to None indicates 'relative paths' so that as a self-contained
# archive, pyjs can run its tests.
try:
    import pyjswidgets
    import pyjswaddons
    pyjspth = os.path.abspath(os.path.join(__file__,'../'))
    path += [os.path.dirname(pyjswidgets.__file__),
             os.path.dirname(pyjswaddons.__file__), ]
except ImportError:
    pyjspth = None

if os.environ in 'PYJSPATH'):
    for p in os.environ['PYJSPATH'].split(os.pathsep):
        p = os.path.abspath(p)
        if os.path.isdir(p):
            path.append(p)

MOD_SUFFIX = '.js'

PYTHON = os.path.realpath(sys.executable) if sys.executable else None
if PYTHON is None or not os.access(PYTHON, os.X_OK):
    PYTHON = 'python'

<|endoftext|>


<commit_before>"""Legacy functionality for pre Pylons 0.9.3 projects
"""
import sys
import types
import warnings

from paste.registry import StackedObjectProxy

import pylons
import pylons.decorators
from pylons.controllers import Controller as OrigController
from pylons.util import deprecated, func_move

config_attr_moved = (
    "The attribute 'config.%s' has moved to the pylons.config dictionary: "
    "Please access it via pylons.config['%s']")

default_charset_warning = (
"The 'default_charset' keyword argument to the %(klass)s constructor is "
"deprecated. Please specify response_settings=dict(charset='%(charset)s') to "
"""the Config constructor in your 'config/environment.py file instead, e.g.:\n
    return pylons.config.Config(tmpl_options, map, paths,
                                response_settings=dict(charset='%(charset)s'))"
""")

helpers_and_g_warning = (
"Pylons 0.9.3 and above now explicitly pass helpers and g "
"references to the PylonsApp constructor. Please update your "
"""middleware.py with:

    import %(package)s.lib.app_globals as app_globals
    import %(package)s.lib.helpers

Then edit the PylonsApp instantiation with:

    app = pylons.wsgiapp.PylonsApp(config, helpers=%(package)s.lib.helpers,
                                   g=app_globals.Globals)
""")

prefix_warning = (
"The [app:main] 'prefix' configuration option has been deprecated, please use "
"paste.deploy.config.PrefixMiddleware instead. To enable PrefixMiddleware in "
"""the config file, add the following line to the [app:main] section:

    filter-with = app-prefix

and the following lines to the end of the config file:

    [filter:app-prefix]
    use = egg:PasteDeploy#prefix
    prefix = %s
""")

pylons_h_warning = (
"pylons.h is deprecated: use your project's lib.helpers module directly "
"""instead. Your lib/helpers.py may require the following additional imports:

    from pylons.helpers import log
    from pylons.i18n import get_lang, set_lang

Use the following in your project's lib/base.py file (and any other module that
uses h):

    import MYPROJ.lib.helpers as h

(where MYPROJ is the name of your project) instead of:

    from pylons import h
""")

def load_h(package_name):
    """
    This is a legacy test for pre-0.9.3 projects to continue using the old
    style Helper imports. The proper style is to pass the helpers module ref
    to the PylonsApp during initialization.
    """
    __import__(package_name + '.lib.base')
    their_h = getattr(sys.modules[package_name + '.lib.base'], 'h', None)
    if isinstance(their_h, types.ModuleType):
        # lib.base.h is a module (and thus not pylons.h) -- assume lib.base
        # uses new style (self contained) helpers via:
        # import ${package}.lib.helpers as h
        return their_h

    # Assume lib.base.h is a StackedObjectProxy -- lib.base is using pre 0.9.2
    # style helpers via:
    # from pylons import h
    helpers_name = package_name + '.lib.helpers'
    __import__(helpers_name)
    helpers_module = sys.modules[helpers_name]

    # Pre 0.9.2 lib.helpers did not import the pylons helper functions,
    # manually add them. Don't overwrite user functions (allowing pylons
    # helpers to be overridden)
    for func_name, func in {'_': pylons.i18n._, 'log': pylons.helpers.log,
                            'set_lang': pylons.i18n.set_lang,
                            'get_lang': pylons.i18n.get_lang}.iteritems():
        if not hasattr(helpers_module, func_name):
            setattr(helpers_module, func_name, func)

    return sys.modules[helpers_name]

jsonify = deprecated(pylons.decorators.jsonify,
                     func_move('pylons.jsonify',
                               moved_to='pylons.decorators.jsonify'))

controller_warning = ('pylons.Controller has been moved to '
                      'pylons.controllers.Controller.')
class Controller(OrigController):
    def __init__(self, *args, **kwargs):
        warnings.warn(controller_warning, DeprecationWarning, 2)
        OrigController.__init__(self, *args, **kwargs)

    def __call__(self, *args, **kwargs):
        warnings.warn(controller_warning, DeprecationWarning, 2)
        return OrigController.__call__(self, *args, **kwargs)

class DeprecatedStackedObjectProxy(StackedObjectProxy):
    def _current_obj(*args, **kwargs):
        warnings.warn(pylons_h_warning, DeprecationWarning, 3)
        return StackedObjectProxy._current_obj(*args, **kwargs)
h = DeprecatedStackedObjectProxy(name="h")

__all__ = ['load_h']
<commit_msg>[svn] o update the legacy warnings to reflect the new config object o add a legacy warning for the pylons.config.Config constructor<commit_after>"""Legacy functionality for pre Pylons 0.9.3 projects
"""
import sys
import types
import warnings

from paste.registry import StackedObjectProxy

import pylons
import pylons.decorators
from pylons.controllers import Controller as OrigController
from pylons.util import deprecated, func_move

config_attr_moved = (
    "The attribute 'config.%s' has moved to the pylons.config dictionary: "
    "Please access it via pylons.config['%s']")

config_load_environment = (
"The pylons.config.Config object is deprecated. Please load the environment "
"configuration via the pylons.config object in config/environment.py instead, "
".e.g:"
"""

    from pylons import config

And in in the load_environment function:

    config['routes.map'] = make_map()
    config['pylons.template_options'] = tmpl_options
    # etc.

See the default config/environment.py created via the "paster create -t pylons"
command for a full example.
""")

default_charset_warning = (
"The 'default_charset' keyword argument to the %(klass)s constructor is "
"deprecated. Please specify the charset in the response_options dictionary "
"in your config/environment.py file instead, .e.g."
"""

    from pylons import config

Add the following lines to the end of the load_environment function:

    config['pylons.response_options']['charset'] = '%(charset)s'
""")

helpers_and_g_warning = (
"Pylons 0.9.3 and above now explicitly specify the helpers and g objects. "
"Please update your config/environment.py with:"
"""

    from pylons import config

    import %(package)s.lib.app_globals as app_globals
    import %(package)s.lib.helpers

And add the following lines to the load_environment function:

    config['pylons.g'] = app_globals.Globals()
    config['pylons.h'] = ${package}.lib.helpers
""")

prefix_warning = (
"The [app:main] 'prefix' configuration option has been deprecated, please use "
"paste.deploy.config.PrefixMiddleware instead. To enable PrefixMiddleware in "
"""the config file, add the following line to the [app:main] section:

    filter-with = app-prefix

and the following lines to the end of the config file:

    [filter:app-prefix]
    use = egg:PasteDeploy#prefix
    prefix = %s
""")

pylons_h_warning = (
"pylons.h is deprecated: use your project's lib.helpers module directly "
"""instead. Your lib/helpers.py may require the following additional imports:

    from pylons.helpers import log
    from pylons.i18n import get_lang, set_lang

Use the following in your project's lib/base.py file (and any other module that
uses h):

    import MYPROJ.lib.helpers as h

(where MYPROJ is the name of your project) instead of:

    from pylons import h
""")

def load_h(package_name):
    """
    This is a legacy test for pre-0.9.3 projects to continue using the old
    style Helper imports. The proper style is to pass the helpers module ref
    to the PylonsApp during initialization.
    """
    __import__(package_name + '.lib.base')
    their_h = getattr(sys.modules[package_name + '.lib.base'], 'h', None)
    if isinstance(their_h, types.ModuleType):
        # lib.base.h is a module (and thus not pylons.h) -- assume lib.base
        # uses new style (self contained) helpers via:
        # import ${package}.lib.helpers as h
        return their_h

    # Assume lib.base.h is a StackedObjectProxy -- lib.base is using pre 0.9.2
    # style helpers via:
    # from pylons import h
    helpers_name = package_name + '.lib.helpers'
    __import__(helpers_name)
    helpers_module = sys.modules[helpers_name]

    # Pre 0.9.2 lib.helpers did not import the pylons helper functions,
    # manually add them. Don't overwrite user functions (allowing pylons
    # helpers to be overridden)
    for func_name, func in {'_': pylons.i18n._, 'log': pylons.helpers.log,
                            'set_lang': pylons.i18n.set_lang,
                            'get_lang': pylons.i18n.get_lang}.iteritems():
        if not hasattr(helpers_module, func_name):
            setattr(helpers_module, func_name, func)

    return sys.modules[helpers_name]

jsonify = deprecated(pylons.decorators.jsonify,
                     func_move('pylons.jsonify',
                               moved_to='pylons.decorators.jsonify'))

controller_warning = ('pylons.Controller has been moved to '
                      'pylons.controllers.Controller.')
class Controller(OrigController):
    def __init__(self, *args, **kwargs):
        warnings.warn(controller_warning, DeprecationWarning, 2)
        OrigController.__init__(self, *args, **kwargs)

    def __call__(self, *args, **kwargs):
        warnings.warn(controller_warning, DeprecationWarning, 2)
        return OrigController.__call__(self, *args, **kwargs)

class DeprecatedStackedObjectProxy(StackedObjectProxy):
    def _current_obj(*args, **kwargs):
        warnings.warn(pylons_h_warning, DeprecationWarning, 3)
        return StackedObjectProxy._current_obj(*args, **kwargs)
h = DeprecatedStackedObjectProxy(name="h")

__all__ = ['load_h']
<|endoftext|>


<commit_before>import numpy as np
from netCDF4 import Dataset as dset, MFDataset as mfdset
from functools import partial

class GridNdarray(np.ndarray):
    """A class to hold a grid-located variable."""
    def __new__(cls,input_array,loc):
        obj = input_array.view(cls)
        obj.loc = loc
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.loc = getattr(obj, 'loc', None)

    def __array_wrap__(self, out_arr, context=None):
        return np.ndarray.__array_wrap__(self, out_arr, context)

class GridVariable():

    """A class to hold a variable."""
    def __init__(self,var,domain,loc,*fhl,**kwargs):
        for fh in fhl:
            try:
                self._v = fh.variables[var]
            except KeyError:
                print('Trying next file.')
            else:
                self.var = var
                self.dom = domain
                self.loc = loc
                self.plot_loc = kwargs.get('plot_loc',self.loc)[0]
                self._plot_slice = self.dom.slices[self.plot_loc]
                self.implement_syntactic_sugar_for_plot_slice()
                self.Time = fh.variables['Time'][:]
                self.dom.dt = np.diff(self.Time[:2])*3600
                average_DT = fh.variables['average_DT'][:]
                average_DT = average_DT[:,np.newaxis,np.newaxis,np.newaxis]
                self.average_DT = average_DT
                break

    def __add__(self,other):
        if self.values.loc == other.values.loc:
            new_variable = GridVariable(self.var,self.dom,self.values.loc)
            new_variable.values = self.values + other.values
            return new_variable
        else:
            raise ValueError('The two variables are not co-located.')

    def __sub__(self,other):
        if self.values.loc == other.values.loc:
            new_variable = GridVariable(self.var,self.dom,self.values.loc)
            new_variable.values = self.values - other.values
            return new_variable
        else:
            raise ValueError('The two variables are not co-located.')

    def __neg__(self):
        self.values *= -1
        return self

    @property
    def plot_slice(self):
        return self._plot_slice

    @plot_slice.setter
    def plot_slice(self,operation_string):
        axis,limit,operation = list(operation_string)

        axes = ['t','l','y','x']
        limits = ['s','e']
        operations = { 'm': -1,
                       'p': +1 }
        self._plot_slice[axes.index(axis)][limits.index(limit)] += operations[operation]

    def plot_slice_modifier(self,string):
        self.plot_slice = string
        return self

    def implement_syntactic_sugar_for_plot_slice(self):
        axes = ['t','l','y','x']
        limits = ['s','e']
        operations = ['m','p']
        for axis in axes:
            for limit in limits:
                for op in operations:
                    string = axis+limit+op
                    setattr(self,string,partial(self.plot_slice_modifier,string))

    @staticmethod
    def extend_halos(array,axis,boundary_index,**kwargs):
        method = kwargs.get('method')
        if method == 'vorticity':
            slip = kwargs.get('slip',False)
            slip_multiplyer = 1 if slip else -1
            array_extendor = slip_multiplyer*array.take([boundary_index],axis=axis)
            if boundary_index == 0:
                array1 = array_extendor
                array2 = array
            else:
                array1 = array
                array2 = array_extendor
            array = np.append(array1,array2,axis=axis)
        if method == 'mirror':
            array_extendor = array.take([boundary_index],axis=axis)
            if boundary_index == 0:
                array1 = array_extendor
                array2 = array
            else:
                array1 = array
                array2 = array_extendor
            array = np.append(array1,array2,axis=axis)
        if method == 'zeros':
            array_extendor = np.zeros(array.take([boundary_index],axis=axis).shape)
            if boundary_index == 0:
                array1 = array_extendor
                array2 = array
            else:
                array1 = array
                array2 = array_extendor
            array = np.append(array1,array2,axis=axis)
        return array

    def read_array(self,extend_kwargs=None,**kwargs):
        self._slice = self._slice_array_to_slice(self._plot_slice)
        out_array = self._v[self._slice]
        if np.ma.isMaskedArray(out_array):
            filled = kwargs.get('filled',np.nan)
            out_array = out_array.filled(filled)

        if self._plot_slice[2,0] < 0:
            out_array = self.extend_halos(out_array,axis=2,
                                          boundary_index=0,**extend_kwargs)
        if self._plot_slice[2,1] > self.dom.total_ylen:
            out_array = self.extend_halos(out_array,axis=2,
                                          boundary_index=-1,**extend_kwargs)
        if self._plot_slice[3,0] < 0:
            out_array = self.extend_halos(out_array,axis=3,
                                          boundary_index=0,**extend_kwargs)
        if self._plot_slice[3,1] > self.dom.total_xlen:
            out_array = self.extend_halos(out_array,axis=3,
                                          boundary_index=-1,**extend_kwargs)
        tmean = kwargs.get('tmean',True)
        if tmean:
            dt = self.average_DT
            out_array = np.apply_over_axes(np.sum,out_array*dt,0)/np.sum(dt)
        out_array = GridNdarray(out_array,self.loc)
        self.values = out_array
        return self

    def _modify_slice(self,axis,ns,ne):
        out_slice = self._plot_slice[axis,0] + ns
        out_slice = out_slice[axis,1] + ne
        return out_slice

    @staticmethod
    def _slice_array_to_slice(slice_array):
        """Creates a slice object from a slice array"""
        Slice = np.s_[ slice_array[0,0]:slice_array[0,1]:slice_array[0,2],
                       slice_array[1,0]:slice_array[1,1]:slice_array[1,2],
                       slice_array[2,0]:slice_array[2,1]:slice_array[2,2],
                       slice_array[3,0]:slice_array[3,1]:slice_array[3,2] ]
        return Slice

    def o1diff(self,axis):
        possible_hlocs = dict(u = ['u','u','q','h'],
                              v = ['v','v','h','q'],
                              h = ['h','h','v','u'],
                              q = ['q','q','u','v'])
        possible_vlocs = dict(l = ['l','i','l','l'],
                              i = ['i','l','i','i'])

        out_array = np.diff(self.values,n=1,axis=axis)
        out_array.loc = (  possible_hlocs[self.values.loc[0]][axis]
                           + possible_vlocs[self.values.loc[1]][axis] )
        self.values = out_array
        return self

    def ddx(self,axis):
        possible_divisors = dict(u = [self.dom.dt, self.dom.db,
                                      self.dom.dyBu, self.dom.dxT],
                                 v = [self.dom.dt, self.dom.db,
                                      self.dom.dyT,  self.dom.dxBu],
                                 h = [self.dom.dt, self.dom.db,
                                      self.dom.dyCv, self.dom.dxCu],
                                 q = [self.dom.dt, self.dom.db,
                                      self.dom.dyCu, self.dom.dxCv])
        if axis == 1:
            divisor = possible_divisors[self.values.loc[0]][axis]
        else:
            divisor = possible_divisors[self.values.loc[0]][axis][self._slice[2:]]
        ddx = self.o1diff(axis)/divisor
        self.values = ddx
        return self

    def move_to(self,new_loc):
        possible_hlocs = dict(u = ['q','h'],
                              v = ['h','q'],
                              h = ['v','u'],
                              q = ['u','v'])
        loc = self.values.loc
        if new_loc[0] in possible_hlocs[loc[0]]:
            axis = possible_hlocs[loc[0]].index(new_loc[0])+2
        elif new_loc[1] is not loc[1]:
            axis = 1
        out_array = 0.5*(  np.take(self.values,range(self.values.shape[axis]-1),axis=axis)
                         + np.take(self.values,range(1,self.values.shape[axis]),axis=axis)  )
        out_array.loc = new_loc
        self.values = out_array
        return self
<commit_msg>Fix ddx. ddx now operates on values instead of gridvariable object.<commit_after>import numpy as np
from netCDF4 import Dataset as dset, MFDataset as mfdset
from functools import partial

class GridNdarray(np.ndarray):
    """A class to hold a grid-located variable."""
    def __new__(cls,input_array,loc):
        obj = input_array.view(cls)
        obj.loc = loc
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.loc = getattr(obj, 'loc', None)

    def __array_wrap__(self, out_arr, context=None):
        return np.ndarray.__array_wrap__(self, out_arr, context)

class GridVariable():

    """A class to hold a variable."""
    def __init__(self,var,domain,loc,*fhl,**kwargs):
        for fh in fhl:
            try:
                self._v = fh.variables[var]
            except KeyError:
                print('Trying next file.')
            else:
                self.var = var
                self.dom = domain
                self.loc = loc
                self.plot_loc = kwargs.get('plot_loc',self.loc)[0]
                self._plot_slice = self.dom.slices[self.plot_loc]
                self.implement_syntactic_sugar_for_plot_slice()
                self.Time = fh.variables['Time'][:]
                self.dom.dt = np.diff(self.Time[:2])*3600
                average_DT = fh.variables['average_DT'][:]
                average_DT = average_DT[:,np.newaxis,np.newaxis,np.newaxis]
                self.average_DT = average_DT
                break

    def __add__(self,other):
        if self.values.loc == other.values.loc:
            new_variable = GridVariable(self.var,self.dom,self.values.loc)
            new_variable.values = self.values + other.values
            return new_variable
        else:
            raise ValueError('The two variables are not co-located.')

    def __sub__(self,other):
        if self.values.loc == other.values.loc:
            new_variable = GridVariable(self.var,self.dom,self.values.loc)
            new_variable.values = self.values - other.values
            return new_variable
        else:
            raise ValueError('The two variables are not co-located.')

    def __neg__(self):
        self.values *= -1
        return self

    @property
    def plot_slice(self):
        return self._plot_slice

    @plot_slice.setter
    def plot_slice(self,operation_string):
        axis,limit,operation = list(operation_string)

        axes = ['t','l','y','x']
        limits = ['s','e']
        operations = { 'm': -1,
                       'p': +1 }
        self._plot_slice[axes.index(axis)][limits.index(limit)] += operations[operation]

    def plot_slice_modifier(self,string):
        self.plot_slice = string
        return self

    def implement_syntactic_sugar_for_plot_slice(self):
        axes = ['t','l','y','x']
        limits = ['s','e']
        operations = ['m','p']
        for axis in axes:
            for limit in limits:
                for op in operations:
                    string = axis+limit+op
                    setattr(self,string,partial(self.plot_slice_modifier,string))

    @staticmethod
    def extend_halos(array,axis,boundary_index,**kwargs):
        method = kwargs.get('method')
        if method == 'vorticity':
            slip = kwargs.get('slip',False)
            slip_multiplyer = 1 if slip else -1
            array_extendor = slip_multiplyer*array.take([boundary_index],axis=axis)
            if boundary_index == 0:
                array1 = array_extendor
                array2 = array
            else:
                array1 = array
                array2 = array_extendor
            array = np.append(array1,array2,axis=axis)
        if method == 'mirror':
            array_extendor = array.take([boundary_index],axis=axis)
            if boundary_index == 0:
                array1 = array_extendor
                array2 = array
            else:
                array1 = array
                array2 = array_extendor
            array = np.append(array1,array2,axis=axis)
        if method == 'zeros':
            array_extendor = np.zeros(array.take([boundary_index],axis=axis).shape)
            if boundary_index == 0:
                array1 = array_extendor
                array2 = array
            else:
                array1 = array
                array2 = array_extendor
            array = np.append(array1,array2,axis=axis)
        return array

    def read_array(self,extend_kwargs=None,**kwargs):
        self._slice = self._slice_array_to_slice(self._plot_slice)
        out_array = self._v[self._slice]
        if np.ma.isMaskedArray(out_array):
            filled = kwargs.get('filled',np.nan)
            out_array = out_array.filled(filled)

        if self._plot_slice[2,0] < 0:
            out_array = self.extend_halos(out_array,axis=2,
                                          boundary_index=0,**extend_kwargs)
        if self._plot_slice[2,1] > self.dom.total_ylen:
            out_array = self.extend_halos(out_array,axis=2,
                                          boundary_index=-1,**extend_kwargs)
        if self._plot_slice[3,0] < 0:
            out_array = self.extend_halos(out_array,axis=3,
                                          boundary_index=0,**extend_kwargs)
        if self._plot_slice[3,1] > self.dom.total_xlen:
            out_array = self.extend_halos(out_array,axis=3,
                                          boundary_index=-1,**extend_kwargs)
        tmean = kwargs.get('tmean',True)
        if tmean:
            dt = self.average_DT
            out_array = np.apply_over_axes(np.sum,out_array*dt,0)/np.sum(dt)
        out_array = GridNdarray(out_array,self.loc)
        self.values = out_array
        return self

    def _modify_slice(self,axis,ns,ne):
        out_slice = self._plot_slice[axis,0] + ns
        out_slice = out_slice[axis,1] + ne
        return out_slice

    @staticmethod
    def _slice_array_to_slice(slice_array):
        """Creates a slice object from a slice array"""
        Slice = np.s_[ slice_array[0,0]:slice_array[0,1]:slice_array[0,2],
                       slice_array[1,0]:slice_array[1,1]:slice_array[1,2],
                       slice_array[2,0]:slice_array[2,1]:slice_array[2,2],
                       slice_array[3,0]:slice_array[3,1]:slice_array[3,2] ]
        return Slice

    def o1diff(self,axis):
        possible_hlocs = dict(u = ['u','u','q','h'],
                              v = ['v','v','h','q'],
                              h = ['h','h','v','u'],
                              q = ['q','q','u','v'])
        possible_vlocs = dict(l = ['l','i','l','l'],
                              i = ['i','l','i','i'])

        out_array = np.diff(self.values,n=1,axis=axis)
        out_array.loc = (  possible_hlocs[self.values.loc[0]][axis]
                           + possible_vlocs[self.values.loc[1]][axis] )
        self.values = out_array
        return self

    def ddx(self,axis):
        possible_divisors = dict(u = [self.dom.dt, self.dom.db,
                                      self.dom.dyBu, self.dom.dxT],
                                 v = [self.dom.dt, self.dom.db,
                                      self.dom.dyT,  self.dom.dxBu],
                                 h = [self.dom.dt, self.dom.db,
                                      self.dom.dyCv, self.dom.dxCu],
                                 q = [self.dom.dt, self.dom.db,
                                      self.dom.dyCu, self.dom.dxCv])
        if axis == 1:
            divisor = possible_divisors[self.values.loc[0]][axis]
        else:
            divisor = possible_divisors[self.values.loc[0]][axis][self._slice[2:]]
        ddx = self.o1diff(axis).values/divisor
        self.values = ddx
        return self

    def move_to(self,new_loc):
        possible_hlocs = dict(u = ['q','h'],
                              v = ['h','q'],
                              h = ['v','u'],
                              q = ['u','v'])
        loc = self.values.loc
        if new_loc[0] in possible_hlocs[loc[0]]:
            axis = possible_hlocs[loc[0]].index(new_loc[0])+2
        elif new_loc[1] is not loc[1]:
            axis = 1
        out_array = 0.5*(  np.take(self.values,range(self.values.shape[axis]-1),axis=axis)
                         + np.take(self.values,range(1,self.values.shape[axis]),axis=axis)  )
        out_array.loc = new_loc
        self.values = out_array
        return self
<|endoftext|>