<commit_before>import tempfile
import time
import re
import uuid
import random

import pytest

from synapseclient import Evaluation, File, SubmissionViewSchema, Synapse, Team
from synapseclient.core.exceptions import SynapseHTTPError

def test_evaluations(syn, project, schedule_for_cleanup):
    # Create an Evaluation
    name = 'Test Evaluation %s' % str(uuid.uuid4())
    ev = Evaluation(name=name, description='Evaluation for testing',
                    contentSource=project['id'], status='CLOSED')
    ev = syn.store(ev)

    try:

        # -- Get the Evaluation by name
        evalNamed = syn.getEvaluationByName(name)
        assert ev['contentSource'] == evalNamed['contentSource']
        assert ev['createdOn'] == evalNamed['createdOn']
        assert ev['description'] == evalNamed['description']
        assert ev['etag'] == evalNamed['etag']
        assert ev['id'] == evalNamed['id']
        assert ev['name'] == evalNamed['name']
        assert ev['ownerId'] == evalNamed['ownerId']
        assert ev['status'] == evalNamed['status']

        # -- Get the Evaluation by project
        evalProj = syn.getEvaluationByContentSource(project)
        evalProj = next(evalProj)
        assert ev['contentSource'] == evalProj['contentSource']
        assert ev['createdOn'] == evalProj['createdOn']
        assert ev['description'] == evalProj['description']
        assert ev['etag'] == evalProj['etag']
        assert ev['id'] == evalProj['id']
        assert ev['name'] == evalProj['name']
        assert ev['ownerId'] == evalProj['ownerId']
        assert ev['status'] == evalProj['status']

        # Update the Evaluation
        ev['status'] = 'OPEN'
        ev = syn.store(ev, createOrUpdate=True)
        schedule_for_cleanup(ev)
        assert ev.status == 'OPEN'

        # Add the current user as a participant
        myOwnerId = int(syn.getUserProfile()['ownerId'])
        syn._allowParticipation(ev, myOwnerId)

        # AUTHENTICATED_USERS = 273948
        # PUBLIC = 273949
        syn.setPermissions(ev, 273948, accessType=['READ'])
        syn.setPermissions(ev, 273949, accessType=['READ'])

        # test getPermissions
        permissions = syn.getPermissions(ev, 273949)
        assert ['READ'] == permissions

        permissions = syn.getPermissions(ev, syn.getUserProfile()['ownerId'])
        for p in ['READ', 'CREATE', 'DELETE', 'UPDATE', 'CHANGE_PERMISSIONS', 'READ_PRIVATE_SUBMISSION']:
            assert p in permissions

        # Test getSubmissions with no Submissions (SYNR-453)
        submissions = syn.getSubmissions(ev)
        assert len(list(submissions)) == 0

        # Increase this to fully test paging by getEvaluationSubmissions
        # not to be less than 2
        num_of_submissions = 2

        # Create a bunch of Entities and submit them for scoring
        for i in range(num_of_submissions):
            with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
                filename = f.name
                f.write(str(random.gauss(0, 1)) + '\n')

            f = File(filename, parentId=project.id, name='entry-%02d' % i,
                     description='An entry for testing evaluation')
            entity = syn.store(f)

            # annotate the submission entity in order to flex some extra
            # code paths
            annos = syn.get_annotations(entity)
            annos['submissionCount'] = i
            syn.set_annotations(annos)

            entity = syn.get(entity.id)

            last_submission = syn.submit(ev, entity, name='Submission %02d' % i, submitterAlias='My Team')

        # retrieve the submission individually to exercise that call
        submission = syn.getSubmission(last_submission.id)
        assert submission.id == last_submission.id
        assert submission.entity.annotations['submissionCount'] == [num_of_submissions - 1]

        # Score the submissions
        submissions = syn.getSubmissions(ev, limit=num_of_submissions-1)
        for submission in submissions:
            assert re.match('Submission \\d+', submission['name'])
            status = syn.getSubmissionStatus(submission)
            if submission['name'] == 'Submission 01':
                status.status = 'INVALID'
            else:
                status.status = 'SCORED'
            syn.store(status)

        # Annotate the submissions
        bogosity = {}
        submissions = syn.getSubmissions(ev)
        b = 123
        for submission, status in syn.getSubmissionBundles(ev):

            bogosity[submission.id] = b
            a = dict(foo='bar', bogosity=b)
            b += 123
            status.submissionAnnotations = a
            syn.store(status)

        # Test that the annotations stuck
        for submission, status in syn.getSubmissionBundles(ev):
            a = status.submissionAnnotations
            assert a['foo'] == ['bar']
            assert a['bogosity'] == [bogosity[submission.id]]

        # test query by submission annotations
        # These queries run against an eventually consistent index table which is
        # populated by an asynchronous worker. Thus, the queries may remain out
        # of sync for some unbounded, but assumed to be short time.
        attempts = 2
        while attempts > 0:
            try:
                results = syn.restGET("/evaluation/submission/query?query=SELECT+*+FROM+evaluation_%s" % ev.id)
                assert len(results['rows']) == num_of_submissions + 1

                results = syn.restGET(
                    "/evaluation/submission/query?query=SELECT+*+FROM+evaluation_%s where bogosity > 200" % ev.id)
                assert len(results['rows']) == num_of_submissions
            except AssertionError:
                attempts -= 1
                time.sleep(2)
            else:
                attempts = 0

        # Test that we can retrieve submissions with a specific status
        invalid_submissions = list(syn.getSubmissions(ev, status='INVALID'))
        assert len(invalid_submissions) == 1, len(invalid_submissions)
        assert invalid_submissions[0]['name'] == 'Submission 01'

        view = SubmissionViewSchema(name="Testing view", scopes=[ev['id']],
                                    parent=project['id'])
        view_ent = syn.store(view)
        view_table = syn.tableQuery(f"select * from {view_ent.id}")
        viewdf = view_table.asDataFrame()
        assert viewdf['foo'].tolist() == ["bar", "bar"]
        assert viewdf['bogosity'].tolist() == [123, 246]
        assert viewdf['id'].astype(str).tolist() == list(bogosity.keys())

    finally:
        # Clean up
        syn.delete(ev)

    # Just deleted it. Shouldn't be able to get it.
    pytest.raises(SynapseHTTPError, syn.getEvaluation, ev)

def test_teams(syn, project, schedule_for_cleanup):
    name = "My Uniquely Named Team " + str(uuid.uuid4())
    team = syn.store(Team(name=name, description="A fake team for testing..."))
    schedule_for_cleanup(team)

    # not logged in, teams are public
    anonymous_syn = Synapse()

    found_team = anonymous_syn.getTeam(team.id)
    assert team == found_team

    p = syn.getUserProfile()
    found = None
    for m in anonymous_syn.getTeamMembers(team):
        if m.member.ownerId == p.ownerId:
            found = m
            break

    assert found is not None, "Couldn't find user {} in team".format(p.userName)

    # needs to be retried 'cause appending to the search index is asynchronous
    tries = 10
    found_team = None
    while tries > 0:
        try:
            found_team = anonymous_syn.getTeam(name)
            break
        except ValueError:
            tries -= 1
            if tries > 0:
                time.sleep(1)
    assert team == found_team
<commit_msg>simplify evaluation test, rm use of deprecated /evaluation/submission/query API<commit_after>import tempfile
import time
import re
import uuid
import random

import pytest

from synapseclient import Evaluation, File, SubmissionViewSchema, Synapse, Team
from synapseclient.core.exceptions import SynapseHTTPError

def test_evaluations(syn, project, schedule_for_cleanup):
    # Create an Evaluation
    name = 'Test Evaluation %s' % str(uuid.uuid4())
    ev = Evaluation(name=name, description='Evaluation for testing',
                    contentSource=project['id'], status='CLOSED')
    ev = syn.store(ev)

    try:

        # -- Get the Evaluation by name
        evalNamed = syn.getEvaluationByName(name)
        assert ev['contentSource'] == evalNamed['contentSource']
        assert ev['createdOn'] == evalNamed['createdOn']
        assert ev['description'] == evalNamed['description']
        assert ev['etag'] == evalNamed['etag']
        assert ev['id'] == evalNamed['id']
        assert ev['name'] == evalNamed['name']
        assert ev['ownerId'] == evalNamed['ownerId']
        assert ev['status'] == evalNamed['status']

        # -- Get the Evaluation by project
        evalProj = syn.getEvaluationByContentSource(project)
        evalProj = next(evalProj)
        assert ev['contentSource'] == evalProj['contentSource']
        assert ev['createdOn'] == evalProj['createdOn']
        assert ev['description'] == evalProj['description']
        assert ev['etag'] == evalProj['etag']
        assert ev['id'] == evalProj['id']
        assert ev['name'] == evalProj['name']
        assert ev['ownerId'] == evalProj['ownerId']
        assert ev['status'] == evalProj['status']

        # Update the Evaluation
        ev['status'] = 'OPEN'
        ev = syn.store(ev, createOrUpdate=True)
        schedule_for_cleanup(ev)
        assert ev.status == 'OPEN'

        # Add the current user as a participant
        myOwnerId = int(syn.getUserProfile()['ownerId'])
        syn._allowParticipation(ev, myOwnerId)

        # AUTHENTICATED_USERS = 273948
        # PUBLIC = 273949
        syn.setPermissions(ev, 273948, accessType=['READ'])
        syn.setPermissions(ev, 273949, accessType=['READ'])

        # test getPermissions
        permissions = syn.getPermissions(ev, 273949)
        assert ['READ'] == permissions

        permissions = syn.getPermissions(ev, syn.getUserProfile()['ownerId'])
        for p in ['READ', 'CREATE', 'DELETE', 'UPDATE', 'CHANGE_PERMISSIONS', 'READ_PRIVATE_SUBMISSION']:
            assert p in permissions

        # Test getSubmissions with no Submissions (SYNR-453)
        submissions = syn.getSubmissions(ev)
        assert len(list(submissions)) == 0

        # Increase this to fully test paging by getEvaluationSubmissions
        # not to be less than 2
        num_of_submissions = 2

        # Create a bunch of Entities and submit them for scoring
        for i in range(num_of_submissions):
            with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
                filename = f.name
                f.write(str(random.gauss(0, 1)) + '\n')

            f = File(filename, parentId=project.id, name='entry-%02d' % i,
                     description='An entry for testing evaluation')
            entity = syn.store(f)

            # annotate the submission entity in order to flex some extra
            # code paths
            annos = syn.get_annotations(entity)
            annos['submissionCount'] = i
            syn.set_annotations(annos)

            entity = syn.get(entity.id)

            last_submission = syn.submit(ev, entity, name='Submission %02d' % i, submitterAlias='My Team')

        # retrieve the submission individually to exercise that call
        submission = syn.getSubmission(last_submission.id)
        assert submission.id == last_submission.id
        assert submission.entity.annotations['submissionCount'] == [num_of_submissions - 1]

        # Score the submissions
        submissions = syn.getSubmissions(ev, limit=num_of_submissions-1)
        for submission in submissions:
            assert re.match('Submission \\d+', submission['name'])
            status = syn.getSubmissionStatus(submission)
            if submission['name'] == 'Submission 01':
                status.status = 'INVALID'
            else:
                status.status = 'SCORED'
            syn.store(status)

        # Annotate the submissions
        bogosity = {}
        submissions = syn.getSubmissions(ev)
        b = 123
        for submission, status in syn.getSubmissionBundles(ev):

            bogosity[submission.id] = b
            a = dict(foo='bar', bogosity=b)
            b += 123
            status.submissionAnnotations = a
            syn.store(status)

        # Test that the annotations stuck
        for submission, status in syn.getSubmissionBundles(ev):
            a = status.submissionAnnotations
            assert a['foo'] == ['bar']
            assert a['bogosity'] == [bogosity[submission.id]]

        # Test that we can retrieve submissions with a specific status
        invalid_submissions = list(syn.getSubmissions(ev, status='INVALID'))
        assert len(invalid_submissions) == 1, len(invalid_submissions)
        assert invalid_submissions[0]['name'] == 'Submission 01'

        # test that we can retrieve annotations via a submission view
        # retry a few times because this may be related to asynchronous worker activity
        attempts = 10
        sleep_time = 1
        i = 0
        while True:
            try:
                view = SubmissionViewSchema(name="Testing view", scopes=[ev['id']],
                                            parent=project['id'])
                view_ent = syn.store(view)
                view_table = syn.tableQuery(f"select * from {view_ent.id}")
                viewdf = view_table.asDataFrame()
                assert viewdf['foo'].tolist() == ["bar", "bar"]
                assert viewdf['bogosity'].tolist() == [123, 246]
                assert viewdf['id'].astype(str).tolist() == list(bogosity.keys())
                break
            except (AssertionError, KeyError):
                i += 1
                if i >= attempts:
                    raise

                time.sleep(sleep_time)
                sleep_time *= 2

    finally:
        # Clean up
        syn.delete(ev)

    # Just deleted it. Shouldn't be able to get it.
    pytest.raises(SynapseHTTPError, syn.getEvaluation, ev)

def test_teams(syn, project, schedule_for_cleanup):
    name = "My Uniquely Named Team " + str(uuid.uuid4())
    team = syn.store(Team(name=name, description="A fake team for testing..."))
    schedule_for_cleanup(team)

    # not logged in, teams are public
    anonymous_syn = Synapse()

    found_team = anonymous_syn.getTeam(team.id)
    assert team == found_team

    p = syn.getUserProfile()
    found = None
    for m in anonymous_syn.getTeamMembers(team):
        if m.member.ownerId == p.ownerId:
            found = m
            break

    assert found is not None, "Couldn't find user {} in team".format(p.userName)

    # needs to be retried 'cause appending to the search index is asynchronous
    tries = 10
    sleep_time = 1
    found_team = None
    while tries > 0:
        try:
            found_team = anonymous_syn.getTeam(name)
            break
        except ValueError:
            tries -= 1
            if tries > 0:
                time.sleep(sleep_time)
                sleep_time *= 2
    assert team == found_team
<|endoftext|>


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

from wxpy import *
from config import *
import re
from wxpy.utils import start_new_thread
import time
import os

'''
使用 cache 来缓存登陆信息，同时使用控制台登陆
'''
bot = Bot('bot.pkl', console_qr=True)
bot.messages.max_history = 0

'''
开启 PUID 用于后续的控制
'''
bot.enable_puid('wxpy_puid.pkl')

'''
邀请信息处理
'''
rp_new_member_name = (
    re.compile(r'^"(.+)"通过'),
    re.compile(r'邀请"(.+)"加入'),
)

# 格式化 Group
try:
    groups = list(map(lambda x: bot.groups().search(puid=x)[0], group_puids))
except:
    print("查找管理群出错！请检查管理群 puid 是否输入正确")
    quit()

# 格式化 Admin
try:
    admins = list(map(lambda x: bot.friends().search(puid=x)[0], admin_puids))
except:
    print("查找管理员出错！请检查管理员 puid 是否输入正确")
    quit()

# 远程踢人命令: 移出 @<需要被移出的人>
rp_kick = re.compile(r'^(?:移出|移除|踢出|拉黑)\s*@(.+?)(?:\u2005?\s*$)')

# 下方为函数定义

def get_time():
    return str(time.strftime("%Y-%m-%d %H:%M:%S"))

'''
机器人消息提醒设置
'''
group_receiver = ensure_one(bot.groups().search(alert_group))
logger = get_wechat_logger(group_receiver)
logger.error(str("机器人登陆成功！"+ get_time()))

'''
重启机器人
'''
def _restart():
    os.execv(sys.executable, [sys.executable] + sys.argv)

'''
定时报告进程状态
'''
def heartbeat():
    while bot.alive:
        time.sleep(3600)
        # noinspection PyBroadException
        try:
            logger.error(get_time() + " 机器人目前在线,共有好友 【" + str(len(bot.friends())) + "】 群 【 " + str(len(bot.groups())) + "】" )
        except ResponseError as e:
            if 1100 <= e.err_code <= 1102:
                logger.critical('LCBot offline: {}'.format(e))
                _restart()

start_new_thread(heartbeat)

'''
条件邀请
'''
def condition_invite(user):
    if user.sex == 2:
        female_groups = bot.groups().search(female_group)[0]
        try:
            female_groups.add_members(user, use_invitation=True)
            pass
        except:
            pass
    if (user.province in city_group.keys() or user.city in city_group.keys()):
        try:
            target_city_group = bot.groups().search(city_group[user.province])[0]
            pass
        except:
            target_city_group = bot.groups().search(city_group[user.city])[0]
            pass
        try:
            if user not in target_city_group:
                target_city_group.add_members(user, use_invitation=True)
        except:
            pass

'''
判断消息发送者是否在管理员列表
'''
def from_admin(msg):
    """
    判断 msg 中的发送用户是否为管理员
    :param msg:
    :return:
    """
    if not isinstance(msg, Message):
        raise TypeError('expected Message, got {}'.format(type(msg)))
    from_user = msg.member if isinstance(msg.chat, Group) else msg.sender
    return from_user in admins

'''
远程踢人命令
'''
def remote_kick(msg):
    if msg.type is TEXT:
        match = rp_kick.search(msg.text)
        if match:
            name_to_kick = match.group(1)

            if not from_admin(msg):
                return '感觉有点不对劲… @{}'.format(msg.member.name)

            member_to_kick = ensure_one(list(filter(
                lambda x: x.name == name_to_kick, msg.chat)))
            if member_to_kick  == bot.self:
                return '无法移出 @{}'.format(member_to_kick.name)
            if member_to_kick in admins:
                return '无法移出 @{}'.format(member_to_kick.name)

            logger.error(get_time() + str(" 【"+member_to_kick.name + "】 被 【"+msg.member.name+"】 移出 【" + msg.sender.name+"】"))
            member_to_kick.set_remark_name("[黑名单]-"+get_time())
            member_to_kick.remove()
            for ready_to_kick_group in  groups:
                if member_to_kick in ready_to_kick_group:
                    ready_to_kick_group.remove_members(member_to_kick)
                    logger.error(get_time()+ str("【"+member_to_kick.name + "】 被系统自动移出 " +  ready_to_kick_group.name))

            return '成功移出 @{}'.format(member_to_kick.name)

'''
邀请消息处理
'''
def get_new_member_name(msg):
    # itchat 1.2.32 版本未格式化群中的 Note 消息
    from itchat.utils import msg_formatter
    msg_formatter(msg.raw, 'Text')

    for rp in rp_new_member_name:
        match = rp.search(msg.text)
        if match:
            return match.group(1)

'''
定义邀请用户的方法。
按关键字搜索相应的群，如果存在相应的群，就向用户发起邀请。
'''
def invite(user, keyword):
    from random import randrange
    group = bot.groups().search(keyword_of_group[keyword])
    if len(group) > 0:
        for i in range(0, len(group)):
            if user in group[i]:
                content = "您已经加入了 {} [微笑]".format(group[i].nick_name)
                user.send(content)
                return
        if len(group) == 1:
            target_group = group[0]
        else:
            index = randrange(len(group))
            target_group = group[index]
        try:
            target_group.add_members(user, use_invitation=True)
        except:
            user.send("邀请错误！机器人邀请好友进群已达当日限制。请您明日再试")
    else:
        user.send("该群状态有误，您换个关键词试试？")

# 下方为消息处理

'''
处理加好友请求信息。
如果验证信息文本是字典的键值之一，则尝试拉群。
'''
@bot.register(msg_types=FRIENDS)
def new_friends(msg):
    user = msg.card.accept()
    if msg.text.lower() in keyword_of_group.keys():
        invite(user, msg.text.lower())
    else:
        user.send(invite_text)

@bot.register(Friend, msg_types=TEXT)
def exist_friends(msg):
    if msg.sender.name.find("黑名单") != -1:
        return "您已被拉黑！"
    else:
        if msg.text.lower() in keyword_of_group.keys():
            invite(msg.sender, msg.text.lower())
        else:
            return invite_text

# 管理群内的消息处理
@bot.register(groups, except_self=False)
def wxpy_group(msg):
    ret_msg = remote_kick(msg)
    if ret_msg:
        return ret_msg
    elif msg.is_at:
        if turing_key :
            tuling = Tuling(api_key=turing_key)
            tuling.do_reply(msg)
        else:
            return "忙着呢，别烦我！";
            pass

@bot.register(groups, NOTE)
def welcome(msg):
    name = get_new_member_name(msg)
    if name:
        return welcome_text.format(name)

embed()
<commit_msg>增加拉黑时判断用户是否在群<commit_after>#!/usr/bin/env python3
# coding: utf-8

from wxpy import *
from config import *
import re
from wxpy.utils import start_new_thread
import time
import os

'''
使用 cache 来缓存登陆信息，同时使用控制台登陆
'''
bot = Bot('bot.pkl', console_qr=True)
bot.messages.max_history = 0

'''
开启 PUID 用于后续的控制
'''
bot.enable_puid('wxpy_puid.pkl')

'''
邀请信息处理
'''
rp_new_member_name = (
    re.compile(r'^"(.+)"通过'),
    re.compile(r'邀请"(.+)"加入'),
)

# 格式化 Group
try:
    groups = list(map(lambda x: bot.groups().search(puid=x)[0], group_puids))
except:
    print("查找管理群出错！请检查管理群 puid 是否输入正确")
    quit()

# 格式化 Admin
try:
    admins = list(map(lambda x: bot.friends().search(puid=x)[0], admin_puids))
except:
    print("查找管理员出错！请检查管理员 puid 是否输入正确")
    quit()

# 远程踢人命令: 移出 @<需要被移出的人>
rp_kick = re.compile(r'^(?:移出|移除|踢出|拉黑)\s*@(.+?)(?:\u2005?\s*$)')

# 下方为函数定义

def get_time():
    return str(time.strftime("%Y-%m-%d %H:%M:%S"))

'''
机器人消息提醒设置
'''
group_receiver = ensure_one(bot.groups().search(alert_group))
logger = get_wechat_logger(group_receiver)
logger.error(str("机器人登陆成功！"+ get_time()))

'''
重启机器人
'''
def _restart():
    os.execv(sys.executable, [sys.executable] + sys.argv)

'''
定时报告进程状态
'''
def heartbeat():
    while bot.alive:
        time.sleep(3600)
        # noinspection PyBroadException
        try:
            logger.error(get_time() + " 机器人目前在线,共有好友 【" + str(len(bot.friends())) + "】 群 【 " + str(len(bot.groups())) + "】" )
        except ResponseError as e:
            if 1100 <= e.err_code <= 1102:
                logger.critical('LCBot offline: {}'.format(e))
                _restart()

start_new_thread(heartbeat)

'''
条件邀请
'''
def condition_invite(user):
    if user.sex == 2:
        female_groups = bot.groups().search(female_group)[0]
        try:
            female_groups.add_members(user, use_invitation=True)
            pass
        except:
            pass
    if (user.province in city_group.keys() or user.city in city_group.keys()):
        try:
            target_city_group = bot.groups().search(city_group[user.province])[0]
            pass
        except:
            target_city_group = bot.groups().search(city_group[user.city])[0]
            pass
        try:
            if user not in target_city_group:
                target_city_group.add_members(user, use_invitation=True)
        except:
            pass

'''
判断消息发送者是否在管理员列表
'''
def from_admin(msg):
    """
    判断 msg 中的发送用户是否为管理员
    :param msg:
    :return:
    """
    if not isinstance(msg, Message):
        raise TypeError('expected Message, got {}'.format(type(msg)))
    from_user = msg.member if isinstance(msg.chat, Group) else msg.sender
    return from_user in admins

'''
远程踢人命令
'''
def remote_kick(msg):
    if msg.type is TEXT:
        match = rp_kick.search(msg.text)
        if match:
            name_to_kick = match.group(1)

            if not from_admin(msg):
                return '感觉有点不对劲… @{}'.format(msg.member.name)

            member_to_kick = ensure_one(list(filter(
                lambda x: x.name == name_to_kick, msg.chat)))
            if member_to_kick  == bot.self:
                return '无法移出 @{}'.format(member_to_kick.name)
            if member_to_kick in admins:
                return '无法移出 @{}'.format(member_to_kick.name)

            logger.error(get_time() + str(" 【"+member_to_kick.name + "】 被 【"+msg.member.name+"】 移出 【" + msg.sender.name+"】"))
            member_to_kick.set_remark_name("[黑名单]-"+get_time())
            if member_to_kick in msg.sender:
                member_to_kick.remove()
                kick_info = '成功移出 @{}'.format(member_to_kick.name)
            else:
                kick_info = '@{} 已不在群中'.format(member_to_kick.name)

            for ready_to_kick_group in  groups:
                if member_to_kick in ready_to_kick_group:
                    ready_to_kick_group.remove_members(member_to_kick)
                    logger.error(get_time()+ str("【"+member_to_kick.name + "】 被系统自动移出 " +  ready_to_kick_group.name))

            return kick_info

'''
邀请消息处理
'''
def get_new_member_name(msg):
    # itchat 1.2.32 版本未格式化群中的 Note 消息
    from itchat.utils import msg_formatter
    msg_formatter(msg.raw, 'Text')

    for rp in rp_new_member_name:
        match = rp.search(msg.text)
        if match:
            return match.group(1)

'''
定义邀请用户的方法。
按关键字搜索相应的群，如果存在相应的群，就向用户发起邀请。
'''
def invite(user, keyword):
    from random import randrange
    group = bot.groups().search(keyword_of_group[keyword])
    if len(group) > 0:
        for i in range(0, len(group)):
            if user in group[i]:
                content = "您已经加入了 {} [微笑]".format(group[i].nick_name)
                user.send(content)
                return
        if len(group) == 1:
            target_group = group[0]
        else:
            index = randrange(len(group))
            target_group = group[index]
        try:
            target_group.add_members(user, use_invitation=True)
        except:
            user.send("邀请错误！机器人邀请好友进群已达当日限制。请您明日再试")
    else:
        user.send("该群状态有误，您换个关键词试试？")

# 下方为消息处理

'''
处理加好友请求信息。
如果验证信息文本是字典的键值之一，则尝试拉群。
'''
@bot.register(msg_types=FRIENDS)
def new_friends(msg):
    user = msg.card.accept()
    if msg.text.lower() in keyword_of_group.keys():
        invite(user, msg.text.lower())
    else:
        user.send(invite_text)

@bot.register(Friend, msg_types=TEXT)
def exist_friends(msg):
    if msg.sender.name.find("黑名单") != -1:
        return "您已被拉黑！"
    else:
        if msg.text.lower() in keyword_of_group.keys():
            invite(msg.sender, msg.text.lower())
        else:
            return invite_text

# 管理群内的消息处理
@bot.register(groups, except_self=False)
def wxpy_group(msg):
    ret_msg = remote_kick(msg)
    if ret_msg:
        return ret_msg
    elif msg.is_at:
        if turing_key :
            tuling = Tuling(api_key=turing_key)
            tuling.do_reply(msg)
        else:
            return "忙着呢，别烦我！";
            pass

@bot.register(groups, NOTE)
def welcome(msg):
    name = get_new_member_name(msg)
    if name:
        return welcome_text.format(name)

embed()
<|endoftext|>


<commit_before>"""
    :codeauthor: Nicole Thomas <nicole@saltstack.com>
"""

import logging

import pytest  # pylint: disable=unused-import
import salt.exceptions
import salt.state
import salt.utils.files
import salt.utils.platform
from tests.support.mock import MagicMock, patch

log = logging.getLogger(__name__)

@pytest.fixture
def state_obj():
    with patch("salt.state.State._gather_pillar"):
        minion_opts = salt.config.DEFAULT_MINION_OPTS.copy()
        yield salt.state.State(minion_opts)

def test_format_slots_no_slots(state_obj):
    """
    Test the format slots keeps data without slots untouched.
    """
    cdata = {"args": ["arg"], "kwargs": {"key": "val"}}
    state_obj.format_slots(cdata)
    assert cdata == {"args": ["arg"], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_arg(state_obj):
    """
    Test the format slots is calling a slot specified in args with corresponding arguments.
    """
    cdata = {
        "args": ["__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["fun_return"], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_dict_arg(state_obj):
    """
    Test the format slots is calling a slot specified in dict arg.
    """
    cdata = {
        "args": [{"subarg": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"}],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": [{"subarg": "fun_return"}], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_listdict_arg(state_obj):
    """
    Test the format slots is calling a slot specified in list containing a dict.
    """
    cdata = {
        "args": [[{"subarg": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"}]],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": [[{"subarg": "fun_return"}]], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_liststr_arg(state_obj):
    """
    Test the format slots is calling a slot specified in list containing a dict.
    """
    cdata = {
        "args": [["__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"]],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": [["fun_return"]], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_kwarg(state_obj):
    """
    Test the format slots is calling a slot specified in kwargs with corresponding arguments.
    """
    cdata = {
        "args": ["arg"],
        "kwargs": {"key": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["arg"], "kwargs": {"key": "fun_return"}}

@pytest.mark.slow_test
def test_format_slots_multi(state_obj):
    """
    Test the format slots is calling all slots with corresponding arguments when multiple slots
    specified.
    """
    cdata = {
        "args": [
            "__slot__:salt:test_mod.fun_a(a_arg, a_key=a_kwarg)",
            "__slot__:salt:test_mod.fun_b(b_arg, b_key=b_kwarg)",
        ],
        "kwargs": {
            "kw_key_1": "__slot__:salt:test_mod.fun_c(c_arg, c_key=c_kwarg)",
            "kw_key_2": "__slot__:salt:test_mod.fun_d(d_arg, d_key=d_kwarg)",
        },
    }
    mock_a = MagicMock(return_value="fun_a_return")
    mock_b = MagicMock(return_value="fun_b_return")
    mock_c = MagicMock(return_value="fun_c_return")
    mock_d = MagicMock(return_value="fun_d_return")
    with patch.dict(
        state_obj.functions,
        {
            "test_mod.fun_a": mock_a,
            "test_mod.fun_b": mock_b,
            "test_mod.fun_c": mock_c,
            "test_mod.fun_d": mock_d,
        },
    ):
        state_obj.format_slots(cdata)
    mock_a.assert_called_once_with("a_arg", a_key="a_kwarg")
    mock_b.assert_called_once_with("b_arg", b_key="b_kwarg")
    mock_c.assert_called_once_with("c_arg", c_key="c_kwarg")
    mock_d.assert_called_once_with("d_arg", d_key="d_kwarg")
    assert cdata == {
        "args": ["fun_a_return", "fun_b_return"],
        "kwargs": {"kw_key_1": "fun_c_return", "kw_key_2": "fun_d_return"},
    }

@pytest.mark.slow_test
def test_format_slots_malformed(state_obj):
    """
    Test the format slots keeps malformed slots untouched.
    """
    sls_data = {
        "args": [
            "__slot__:NOT_SUPPORTED:not.called()",
            "__slot__:salt:not.called(",
            "__slot__:salt:",
            "__slot__:salt",
            "__slot__:",
            "__slot__",
        ],
        "kwargs": {
            "key3": "__slot__:NOT_SUPPORTED:not.called()",
            "key4": "__slot__:salt:not.called(",
            "key5": "__slot__:salt:",
            "key6": "__slot__:salt",
            "key7": "__slot__:",
            "key8": "__slot__",
        },
    }
    cdata = sls_data.copy()
    mock = MagicMock(return_value="return")
    with patch.dict(state_obj.functions, {"not.called": mock}):
        state_obj.format_slots(cdata)
    mock.assert_not_called()
    assert cdata == sls_data

@pytest.mark.slow_test
def test_slot_traverse_dict(state_obj):
    """
    Test the slot parsing of dict response.
    """
    cdata = {
        "args": ["arg"],
        "kwargs": {"key": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val).key1"},
    }
    return_data = {"key1": "value1"}
    mock = MagicMock(return_value=return_data)
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["arg"], "kwargs": {"key": "value1"}}

@pytest.mark.slow_test
def test_slot_append(state_obj):
    """
    Test the slot parsing of dict response.
    """
    cdata = {
        "args": ["arg"],
        "kwargs": {
            "key": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val).key1 ~ thing~",
        },
    }
    return_data = {"key1": "value1"}
    mock = MagicMock(return_value=return_data)
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["arg"], "kwargs": {"key": "value1thing~"}}

# Skip on windows like integration.modules.test_state.StateModuleTest.test_parallel_state_with_long_tag
@pytest.mark.skip_on_spawning_platform(
    reason="Skipped until parallel states can be fixed on spawning platforms."
)
def test_format_slots_parallel(state_obj):
    """
    Test if slots work with "parallel: true".
    """
    high_data = {
        "always-changes-and-succeeds": {
            "test": [
                {"changes": True},
                {"comment": "__slot__:salt:test.echo(fun_return)"},
                {"parallel": True},
                "configurable_test_state",
                {"order": 10000},
            ],
            "__env__": "base",
            "__sls__": "parallel_slots",
        }
    }
    state_obj.jid = "123"
    res = state_obj.call_high(high_data)
    state_obj.jid = None
    [(_, data)] = res.items()
    assert data["comment"] == "fun_return"
<commit_msg>Fix test cases with PermissionError on /var/cache<commit_after>"""
    :codeauthor: Nicole Thomas <nicole@saltstack.com>
"""

import logging

import pytest  # pylint: disable=unused-import
import salt.exceptions
import salt.state
import salt.utils.files
import salt.utils.platform
from tests.support.mock import MagicMock, patch

log = logging.getLogger(__name__)

@pytest.fixture
def state_obj(tmp_path):
    with patch("salt.state.State._gather_pillar"):
        minion_opts = salt.config.DEFAULT_MINION_OPTS.copy()
        minion_opts["cachedir"] = str(tmp_path)
        yield salt.state.State(minion_opts)

def test_format_slots_no_slots(state_obj):
    """
    Test the format slots keeps data without slots untouched.
    """
    cdata = {"args": ["arg"], "kwargs": {"key": "val"}}
    state_obj.format_slots(cdata)
    assert cdata == {"args": ["arg"], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_arg(state_obj):
    """
    Test the format slots is calling a slot specified in args with corresponding arguments.
    """
    cdata = {
        "args": ["__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["fun_return"], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_dict_arg(state_obj):
    """
    Test the format slots is calling a slot specified in dict arg.
    """
    cdata = {
        "args": [{"subarg": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"}],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": [{"subarg": "fun_return"}], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_listdict_arg(state_obj):
    """
    Test the format slots is calling a slot specified in list containing a dict.
    """
    cdata = {
        "args": [[{"subarg": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"}]],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": [[{"subarg": "fun_return"}]], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_liststr_arg(state_obj):
    """
    Test the format slots is calling a slot specified in list containing a dict.
    """
    cdata = {
        "args": [["__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"]],
        "kwargs": {"key": "val"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": [["fun_return"]], "kwargs": {"key": "val"}}

@pytest.mark.slow_test
def test_format_slots_kwarg(state_obj):
    """
    Test the format slots is calling a slot specified in kwargs with corresponding arguments.
    """
    cdata = {
        "args": ["arg"],
        "kwargs": {"key": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)"},
    }
    mock = MagicMock(return_value="fun_return")
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["arg"], "kwargs": {"key": "fun_return"}}

@pytest.mark.slow_test
def test_format_slots_multi(state_obj):
    """
    Test the format slots is calling all slots with corresponding arguments when multiple slots
    specified.
    """
    cdata = {
        "args": [
            "__slot__:salt:test_mod.fun_a(a_arg, a_key=a_kwarg)",
            "__slot__:salt:test_mod.fun_b(b_arg, b_key=b_kwarg)",
        ],
        "kwargs": {
            "kw_key_1": "__slot__:salt:test_mod.fun_c(c_arg, c_key=c_kwarg)",
            "kw_key_2": "__slot__:salt:test_mod.fun_d(d_arg, d_key=d_kwarg)",
        },
    }
    mock_a = MagicMock(return_value="fun_a_return")
    mock_b = MagicMock(return_value="fun_b_return")
    mock_c = MagicMock(return_value="fun_c_return")
    mock_d = MagicMock(return_value="fun_d_return")
    with patch.dict(
        state_obj.functions,
        {
            "test_mod.fun_a": mock_a,
            "test_mod.fun_b": mock_b,
            "test_mod.fun_c": mock_c,
            "test_mod.fun_d": mock_d,
        },
    ):
        state_obj.format_slots(cdata)
    mock_a.assert_called_once_with("a_arg", a_key="a_kwarg")
    mock_b.assert_called_once_with("b_arg", b_key="b_kwarg")
    mock_c.assert_called_once_with("c_arg", c_key="c_kwarg")
    mock_d.assert_called_once_with("d_arg", d_key="d_kwarg")
    assert cdata == {
        "args": ["fun_a_return", "fun_b_return"],
        "kwargs": {"kw_key_1": "fun_c_return", "kw_key_2": "fun_d_return"},
    }

@pytest.mark.slow_test
def test_format_slots_malformed(state_obj):
    """
    Test the format slots keeps malformed slots untouched.
    """
    sls_data = {
        "args": [
            "__slot__:NOT_SUPPORTED:not.called()",
            "__slot__:salt:not.called(",
            "__slot__:salt:",
            "__slot__:salt",
            "__slot__:",
            "__slot__",
        ],
        "kwargs": {
            "key3": "__slot__:NOT_SUPPORTED:not.called()",
            "key4": "__slot__:salt:not.called(",
            "key5": "__slot__:salt:",
            "key6": "__slot__:salt",
            "key7": "__slot__:",
            "key8": "__slot__",
        },
    }
    cdata = sls_data.copy()
    mock = MagicMock(return_value="return")
    with patch.dict(state_obj.functions, {"not.called": mock}):
        state_obj.format_slots(cdata)
    mock.assert_not_called()
    assert cdata == sls_data

@pytest.mark.slow_test
def test_slot_traverse_dict(state_obj):
    """
    Test the slot parsing of dict response.
    """
    cdata = {
        "args": ["arg"],
        "kwargs": {"key": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val).key1"},
    }
    return_data = {"key1": "value1"}
    mock = MagicMock(return_value=return_data)
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["arg"], "kwargs": {"key": "value1"}}

@pytest.mark.slow_test
def test_slot_append(state_obj):
    """
    Test the slot parsing of dict response.
    """
    cdata = {
        "args": ["arg"],
        "kwargs": {
            "key": "__slot__:salt:mod.fun(fun_arg, fun_key=fun_val).key1 ~ thing~",
        },
    }
    return_data = {"key1": "value1"}
    mock = MagicMock(return_value=return_data)
    with patch.dict(state_obj.functions, {"mod.fun": mock}):
        state_obj.format_slots(cdata)
    mock.assert_called_once_with("fun_arg", fun_key="fun_val")
    assert cdata == {"args": ["arg"], "kwargs": {"key": "value1thing~"}}

# Skip on windows like integration.modules.test_state.StateModuleTest.test_parallel_state_with_long_tag
@pytest.mark.skip_on_spawning_platform(
    reason="Skipped until parallel states can be fixed on spawning platforms."
)
def test_format_slots_parallel(state_obj):
    """
    Test if slots work with "parallel: true".
    """
    high_data = {
        "always-changes-and-succeeds": {
            "test": [
                {"changes": True},
                {"comment": "__slot__:salt:test.echo(fun_return)"},
                {"parallel": True},
                "configurable_test_state",
                {"order": 10000},
            ],
            "__env__": "base",
            "__sls__": "parallel_slots",
        }
    }
    state_obj.jid = "123"
    res = state_obj.call_high(high_data)
    state_obj.jid = None
    [(_, data)] = res.items()
    assert data["comment"] == "fun_return"
<|endoftext|>


<commit_before>from sqlalchemy import *
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.expression import ColumnClause
from migrate import *

meta = MetaData()

team_users = Table('team_users', meta,
                   Column('team_id', Integer, ForeignKey('team.id')),
                   Column('user_id', Integer, ForeignKey('user.id')))

def upgrade(migrate_engine):
    # Upgrade operations go here. Don't create your own engine; bind
    # migrate_engine to your metadata
    meta.bind = migrate_engine

    team = Table('team', meta, autoload=True)
    user = Table('user', meta, autoload=True)

    try:
        team_users.drop()
    except:
        pass
    team_users.create()

    # Create a session
    Session = sessionmaker(bind=migrate_engine)
    session = Session()

    for u in session.query(user).all():
        if u.team_id:
            values={'team_id': u.team_id, 'user_id': u.id,}
            team_users.insert(values=values).execute()

    user.c.team_id.drop()

def downgrade(migrate_engine):
    # Operations to reverse the above upgrade go here.
    meta.bind = migrate_engine

    team = Table('team', meta, autoload=True)
    user = Table('user', meta, autoload=True)

    team_id = Column('team_id', Integer, ForeignKey('team.id'))
    team_id.create(user)

    # Create a session
    Session = sessionmaker(bind=migrate_engine)
    session = Session()

    for team_user in session.query(team_users).all():
        values = {'team_id': team_user.team_id}
        user.update(values=values).where(user.c.id==team_user.user_id).execute()

    session.commit()

    team_users.drop()
<commit_msg>Fix migration<commit_after>from sqlalchemy import *
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.expression import ColumnClause
from migrate import *

meta = MetaData()

team_users = Table('team_users', meta,
                   Column('team_id', Integer, ForeignKey('team.id')),
                   Column('user_id', Integer, ForeignKey('user.id')))

def upgrade(migrate_engine):
    # Upgrade operations go here. Don't create your own engine; bind
    # migrate_engine to your metadata
    meta.bind = migrate_engine

    team = Table('team', meta, autoload=True)
    user = Table('user', meta, autoload=True)

    try:
        team_users.drop()
    except:
        pass
    team_users.create()

    result = user.select().execute().fetchall()

    for row in result:
        if row.team_id:
            values={'team_id': row.team_id, 'user_id': row.id,}
            team_users.insert(values=values).execute()

    user.c.team_id.drop()

def downgrade(migrate_engine):
    # Operations to reverse the above upgrade go here.
    meta.bind = migrate_engine

    team = Table('team', meta, autoload=True)
    user = Table('user', meta, autoload=True)

    team_id = Column('team_id', Integer, ForeignKey('team.id'))
    team_id.create(user)

    result = team_users.select().execute().fetchall()

    for row in result:
        values = {'team_id': row.team_id,}
        user.update(values=values).where(user.c.id==row.user_id).execute()

    team_users.drop()
<|endoftext|>


<commit_before>import os

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

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@example.com'),
)

MANAGERS = ADMINS

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'dev.db',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

# 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.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'

# 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

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = '/media/'

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

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

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

# Make this unique, and don't share it with anybody.
SECRET_KEY = '!gz7b74mfu7^mj0yj&dxc&^$o7tf%^0&i07y7s#zv73x($g%pa'

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

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

ROOT_URLCONF = 'example.urls'

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

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',

    'cumulus',

    'photos',
)

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

DEFAULT_FILE_STORAGE = 'cumulus.storage.CloudFilesStorage'
STATICFILES_STORAGE = 'cumulus.storage.CloudFilesStaticStorage'

# these are the default cumulus settings
CUMULUS = {
    'API_KEY': None,
    'AUTH_URL': 'us_authurl',
    'CNAMES': None,
    'CONTAINER': None,
    'SERVICENET': False,
    'TIMEOUT': 5,
    'TTL': 600,
    'USE_SSL': False,
    'USERNAME': None,
    'STATIC_CONTAINER': None,
    'FILTER_LIST': []
}

try:
    from local_settings import *
except:
    pass
<commit_msg>fix project root in test settings<commit_after>import os

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

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@example.com'),
)

MANAGERS = ADMINS

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'dev.db',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

# 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.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'

# 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

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = '/media/'

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

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

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

# Make this unique, and don't share it with anybody.
SECRET_KEY = '!gz7b74mfu7^mj0yj&dxc&^$o7tf%^0&i07y7s#zv73x($g%pa'

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

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

ROOT_URLCONF = 'example.urls'

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

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',

    'cumulus',

    'photos',
)

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

DEFAULT_FILE_STORAGE = 'cumulus.storage.CloudFilesStorage'
STATICFILES_STORAGE = 'cumulus.storage.CloudFilesStaticStorage'

# these are the default cumulus settings
CUMULUS = {
    'API_KEY': None,
    'AUTH_URL': 'us_authurl',
    'CNAMES': None,
    'CONTAINER': None,
    'SERVICENET': False,
    'TIMEOUT': 5,
    'TTL': 600,
    'USE_SSL': False,
    'USERNAME': None,
    'STATIC_CONTAINER': None,
    'FILTER_LIST': []
}

try:
    from local_settings import *
except:
    pass
<|endoftext|>


<commit_before>"""Functions for parsing sitemap.

Copyright 2017 Stephan Kulla
"""

import re

from mfnf.utils import remove_prefix, lookup

SITEMAP_NODE_TYPES = ["mfnf_sitemap", "book", "chapter", "article"]
SITEMAP_DELIMITER = "= Bücher ="

def generate_sitemap_nodes(sitemap_text):
    """Generator for all node specifications in a sitemap source code. It
    yields dictionaries of the form:

        { "code": code, "depth": depth, "children": [] }

    Thereby `code` is a string representation of the node and `depth` is a
    number corresponding to the node's depth. The higher the depth is, the
    deeper the node need to be included in the final tree.
    """
    # In MediaWiki the maximal depth of a headline is 6 (as in HTML).
    # For list elements this maximal header depth is added so that list
    # elements will always be included under a headline node.
    max_headline_depth = 6

    headline_re = re.compile(r"""(={1,%s}) # Equal signs of the headline
                                 (.*)      # code defining the node
                                 \1        # Repeatation of the equal signs
                              """ % max_headline_depth, re.X)

    list_re = re.compile(r"""([*]+) # asteriks of a list element
                             (.*)   # code defining a sitemap node
                          """, re.X)

    for line in sitemap_text.splitlines():
        for regex, depth_start in ((headline_re, 0),
                                   (list_re, max_headline_depth)):
            match = regex.fullmatch(line.strip())

            if match:
                yield {
                    "code": match.group(2).strip(),
                    "depth": depth_start + len(match.group(1)),
                    "children": []
                }

        if line.startswith(": Exclude:"):
            header = remove_prefix(line, ": Exclude:").strip()

            yield { "type": "exclude", "header": header }

def insert_node(node, new_node):
    """Inserts the node `new_node` in the tree `node` at the right position
    regarding to the attribute `depth` of `node`."""
    if node["children"] and new_node["depth"] > node["children"][-1]["depth"]:
        insert_node(node["children"][-1], new_node)
    else:
        node["children"].append(new_node)

def parse_sitemap_node_codes(node):
    """Returns a new tree where the `code` attributes are parsed. The nodes of
    the new tree contain a `name` and a `title` attribute. The `name` attribute
    corresponds to the name of the node which shall be appear in the table of
    contents. The `title` corresponds to the title of the Wikibooks page the
    node points to. In case there is no article behind the node, the attribute
    `title` is `None`.
    """

    # Delete `{{Symbol|..%}}` at the end of the code
    code = re.sub(r"\s+\{Symbol\|\d+%\}\}\s+\Z", "", node["code"])

    # Parse links of the form `[[<title>|<name>]]`
    match = re.match(r"""
        \[\[      # [[
        ([^|\]]+) # title of the page on Wikibooks
        \|        # |
        ([^|\]]+) # name of the node in toc
        \]\]      # ]]
    """, code, re.X)

    if match:
        title = match.group(1)
        name = match.group(2)
    else:
        name = code
        title = None

    parsed_node = {
        "title": title,
        "name": name,
        "children": [parse_sitemap_node_codes(x) for x in node["children"]],
        "excludes": node.get("excludes", [])
    }
    return add_sitemap_node_type(parsed_node)

def add_sitemap_node_type(node, depth=0):
    """Returns a new tree where each node is enriched by a `type` attribute,
    which depends on its depth in the tree."""
    title = node["title"]
    name = node["name"]
    children = node["children"]

    return {
        "title": title,
        "name": name,
        "type": SITEMAP_NODE_TYPES[depth],
        "children": [add_sitemap_node_type(x, depth + 1) for x in children],
        "excludes": node["excludes"]
    }

def parse_sitemap(sitemap_text):
    """Parse the sitemap and returns a JSON object representing it.

    Arguments:
        sitemap_text -- content of the sitemap (a string)
    """
    root = {"children":[], "depth":0, "code": "Mathe für Nicht-Freaks"}

    (introduction, separator, stripped_sitemap_text) = sitemap_text.partition(SITEMAP_DELIMITER)
    last_node = None

    for node in generate_sitemap_nodes(stripped_sitemap_text):
        if lookup(node, "type") == "exclude":
            assert last_node

            if "excludes" not in last_node:
                last_node["excludes"] = []

            last_node["excludes"].append(node["header"])
        else:
            last_node = node
            insert_node(root, node)

    return parse_sitemap_node_codes(root)
<commit_msg>sitemap: Add annotation ": After:" (for #119)<commit_after>"""Functions for parsing sitemap.

Copyright 2017 Stephan Kulla
"""

import re

from mfnf.utils import remove_prefix, lookup

SITEMAP_NODE_TYPES = ["mfnf_sitemap", "book", "chapter", "article"]
SITEMAP_DELIMITER = "= Bücher ="
SITEMAP_ANNOTATIONS = {
    "exlcudes": ": Exclude:",
    "after": ": After:",
}

def generate_sitemap_nodes(sitemap_text):
    """Generator for all node specifications in a sitemap source code. It
    yields dictionaries of the form:

        { "code": code, "depth": depth, "children": [] }

    Thereby `code` is a string representation of the node and `depth` is a
    number corresponding to the node's depth. The higher the depth is, the
    deeper the node need to be included in the final tree.
    """
    # In MediaWiki the maximal depth of a headline is 6 (as in HTML).
    # For list elements this maximal header depth is added so that list
    # elements will always be included under a headline node.
    max_headline_depth = 6

    headline_re = re.compile(r"""(={1,%s}) # Equal signs of the headline
                                 (.*)      # code defining the node
                                 \1        # Repeatation of the equal signs
                              """ % max_headline_depth, re.X)

    list_re = re.compile(r"""([*]+) # asteriks of a list element
                             (.*)   # code defining a sitemap node
                          """, re.X)

    for line in sitemap_text.splitlines():
        for regex, depth_start in ((headline_re, 0),
                                   (list_re, max_headline_depth)):
            match = regex.fullmatch(line.strip())

            if match:
                yield {
                    "code": match.group(2).strip(),
                    "depth": depth_start + len(match.group(1)),
                    "children": []
                }

        for an_type, an_prefix in SITEMAP_ANNOTATIONS.items():
            if line.startswith(an_prefix):
                value = remove_prefix(line, an_prefix).strip()

                yield { "type": "annotation", "value": value,
                        "annotation_type": an_type }

def insert_node(node, new_node):
    """Inserts the node `new_node` in the tree `node` at the right position
    regarding to the attribute `depth` of `node`."""
    if node["children"] and new_node["depth"] > node["children"][-1]["depth"]:
        insert_node(node["children"][-1], new_node)
    else:
        node["children"].append(new_node)

def parse_sitemap_node_codes(node):
    """Returns a new tree where the `code` attributes are parsed. The nodes of
    the new tree contain a `name` and a `title` attribute. The `name` attribute
    corresponds to the name of the node which shall be appear in the table of
    contents. The `title` corresponds to the title of the Wikibooks page the
    node points to. In case there is no article behind the node, the attribute
    `title` is `None`.
    """

    # Delete `{{Symbol|..%}}` at the end of the code
    code = re.sub(r"\s+\{Symbol\|\d+%\}\}\s+\Z", "", node["code"])

    # Parse links of the form `[[<title>|<name>]]`
    match = re.match(r"""
        \[\[      # [[
        ([^|\]]+) # title of the page on Wikibooks
        \|        # |
        ([^|\]]+) # name of the node in toc
        \]\]      # ]]
    """, code, re.X)

    if match:
        title = match.group(1)
        name = match.group(2)
    else:
        name = code
        title = None

    parsed_node = {
        "title": title,
        "name": name,
        "children": [parse_sitemap_node_codes(x) for x in node["children"]],
        "excludes": node.get("excludes", []),
        "after": node.get("after", []),
    }

    return add_sitemap_node_type(parsed_node)

def add_sitemap_node_type(node, depth=0):
    """Returns a new tree where each node is enriched by a `type` attribute,
    which depends on its depth in the tree."""
    title = node["title"]
    name = node["name"]
    children = node["children"]

    return {
        "title": title,
        "name": name,
        "type": SITEMAP_NODE_TYPES[depth],
        "children": [add_sitemap_node_type(x, depth + 1) for x in children],
        "excludes": node["excludes"],
        "after": node["after"],
    }

def parse_sitemap(sitemap_text):
    """Parse the sitemap and returns a JSON object representing it.

    Arguments:
        sitemap_text -- content of the sitemap (a string)
    """
    root = {"children":[], "depth":0, "code": "Mathe für Nicht-Freaks"}

    (introduction, separator, stripped_sitemap_text) = sitemap_text.partition(SITEMAP_DELIMITER)
    last_node = None

    for node in generate_sitemap_nodes(stripped_sitemap_text):
        if lookup(node, "type") == "annotation":
            assert last_node

            an_type = node["annotation_type"]

            if an_type not in last_node:
                last_node[an_type] = []

            last_node[an_type].append(node["value"])
        else:
            last_node = node
            insert_node(root, node)

    return parse_sitemap_node_codes(root)
<|endoftext|>


<commit_before>import datetime
import sys

import aiohttp
import discord
from discord.ext import commands

from config import Config
from utils import contextmanagers, exceptions

class BContext(commands.Context):
    """An extension of Context to add reply and mention methods,
    as well as support use with self bots"""
    async def reply(self, content, sep=',\n'):
        if self.me.bot and not isinsance(self.channel, dicord.DMChannel):
            content = f'{self.author.display_name}{sep}{content}'
        return await self.send(content)

    async def mention(self, content, sep=',\n'):
        if self.me.bot and not isinsance(self.channel, dicord.DMChannel):
            content = f'{self.author.mention}{sep}{content}'
        return await self.send(content)

    async def send(self, content=None, *, embed=None, **kwargs):
        if self.me.bot:
            return await super().send(content, embed=embed, **kwargs)
        elif content is not None:
            content = f'{self.message.content}\n{content}'
            await self.message.edit(content=content)
            return self.message
        elif embed is not None:
            await self.message.delete()
            return await super().send(embed=embed, **kwargs)

    def typing(self):
        if self.me.bot:
            return super().typing()
        else:
            return contextmanagers.null()

class BeattieBot(commands.Bot):
    """An extension of Bot. Allow use with self bots and handles errors in an
    ordered way"""
    command_ignore = (commands.CommandNotFound, commands.CheckFailure)
    general_ignore = (ConnectionResetError, )

    def __init__(self, *args, **kwargs):
        self_bot = kwargs.get('self_bot')
        if self_bot:
            game = None
            status = discord.Status.idle
        else:
            game = discord.Game(name='b>help')
            status = None
        super().__init__(*args, **kwargs, game=game, status=status)
        if self_bot:
            self.loop.create_task(self.change_presence(afk=True))
            self.owner_id = self.user.id
        self.session = aiohttp.ClientSession(loop=self.loop)
        self.uptime = datetime.datetime.utcnow()
        self.config = Config(self)

    def __del__(self):
        self.session.close()
        try:
            delete = super().__del__
        except AttributeError:
            pass
        else:
            delete()

    async def handle_error(self, ctx, e):
        e = getattr(e, 'original', e)
        if isinstance(e, commands.MissingRequiredArgument):
            await ctx.send('Missing required arguments.')
        elif isinstance(e, commands.BadArgument):
            await ctx.send('Bad arguments.')
        elif isinstance(e, exceptions.ResponseError):
            await ctx.send(f'An HTTP request failled with error code {e.code}')
        elif not isinstance(e, self.command_ignore):
            await ctx.send(f'{type(e).__name__}: {e}')
            raise e from None

    async def on_ready(self):
        print('Logged in as')
        print(self.user.name)
        print(self.user.id)
        print('------')

    async def on_message(self, message):
        ctx = await self.get_context(message, cls=BContext)
        if ctx.prefix is not None:
            command = ctx.invoked_with
            if command:
                ctx.command = self.get_command(command.lower())
                await self.invoke(ctx)

    async def on_guild_join(self, guild):
        bots = sum(m.bot for m in guild.members)
        if bots / len(guild.members) > 0.5:
            await guild.leave()
        else:
            await self.config.add(guild.id)

    async def on_guild_remove(self, guild):
        await self.config.remove(guild.id)

    async def on_member_join(self, member):
        if not self.user.bot:
            return
        guild = member.guild
        guild_conf = await self.config.get(guild.id)
        message = guild_conf['welcome']
        if message:
            await guild.default_channel.send(message.format(member.mention))

    async def on_member_remove(self, member):
        if not self.user.bot:
            return
        guild = member.guild
        guild_conf = await self.config.get(guild.id)
        message = guild_conf['farewell']
        if message:
            await guild.default_channel.send(message.format(member.mention))

    async def on_command_error(self, ctx, e):
        if not hasattr(ctx.command, 'on_error'):
            await self.handle_error(ctx, e)

    async def on_error(self, event_method, *args, **kwargs):
        _, e, _ = sys.exc_info()
        e = getattr(e, 'original', e)
        if not isinstance(e, self.general_ignore):
            await super().on_error(event_method, *args, **kwargs)

    def get(self, *args, **kwargs):
        return contextmanagers.get(self.session, *args, **kwargs)

    def tmp_dl(self, *args, **kwargs):
        return contextmanagers.tmp_dl(self.session, *args, **kwargs)
<commit_msg>Manually set owner_id in on_ready if running as a self bot<commit_after>import datetime
import sys

import aiohttp
import discord
from discord.ext import commands

from config import Config
from utils import contextmanagers, exceptions

class BContext(commands.Context):
    """An extension of Context to add reply and mention methods,
    as well as support use with self bots"""
    async def reply(self, content, sep=',\n'):
        if self.me.bot and not isinsance(self.channel, dicord.DMChannel):
            content = f'{self.author.display_name}{sep}{content}'
        return await self.send(content)

    async def mention(self, content, sep=',\n'):
        if self.me.bot and not isinsance(self.channel, dicord.DMChannel):
            content = f'{self.author.mention}{sep}{content}'
        return await self.send(content)

    async def send(self, content=None, *, embed=None, **kwargs):
        if self.me.bot:
            return await super().send(content, embed=embed, **kwargs)
        elif content is not None:
            content = f'{self.message.content}\n{content}'
            await self.message.edit(content=content)
            return self.message
        elif embed is not None:
            await self.message.delete()
            return await super().send(embed=embed, **kwargs)

    def typing(self):
        if self.me.bot:
            return super().typing()
        else:
            return contextmanagers.null()

class BeattieBot(commands.Bot):
    """An extension of Bot. Allow use with self bots and handles errors in an
    ordered way"""
    command_ignore = (commands.CommandNotFound, commands.CheckFailure)
    general_ignore = (ConnectionResetError, )

    def __init__(self, *args, **kwargs):
        self_bot = kwargs.get('self_bot')
        if self_bot:
            game = None
            status = discord.Status.idle
        else:
            game = discord.Game(name='b>help')
            status = None
        super().__init__(*args, **kwargs, game=game, status=status)
        if self_bot:
            self.loop.create_task(self.change_presence(afk=True))
        self.session = aiohttp.ClientSession(loop=self.loop)
        self.uptime = datetime.datetime.utcnow()
        self.config = Config(self)

    def __del__(self):
        self.session.close()
        try:
            delete = super().__del__
        except AttributeError:
            pass
        else:
            delete()

    async def handle_error(self, ctx, e):
        e = getattr(e, 'original', e)
        if isinstance(e, commands.MissingRequiredArgument):
            await ctx.send('Missing required arguments.')
        elif isinstance(e, commands.BadArgument):
            await ctx.send('Bad arguments.')
        elif isinstance(e, exceptions.ResponseError):
            await ctx.send(f'An HTTP request failled with error code {e.code}')
        elif not isinstance(e, self.command_ignore):
            await ctx.send(f'{type(e).__name__}: {e}')
            raise e from None

    async def on_ready(self):
        print('Logged in as')
        print(self.user.name)
        print(self.user.id)
        print('------')
        if not self.user.bot:
            self.owner_id = self.user.id

    async def on_message(self, message):
        ctx = await self.get_context(message, cls=BContext)
        if ctx.prefix is not None:
            command = ctx.invoked_with
            if command:
                ctx.command = self.get_command(command.lower())
                await self.invoke(ctx)

    async def on_guild_join(self, guild):
        bots = sum(m.bot for m in guild.members)
        if bots / len(guild.members) > 0.5:
            await guild.leave()
        else:
            await self.config.add(guild.id)

    async def on_guild_remove(self, guild):
        await self.config.remove(guild.id)

    async def on_member_join(self, member):
        if not self.user.bot:
            return
        guild = member.guild
        guild_conf = await self.config.get(guild.id)
        message = guild_conf['welcome']
        if message:
            await guild.default_channel.send(message.format(member.mention))

    async def on_member_remove(self, member):
        if not self.user.bot:
            return
        guild = member.guild
        guild_conf = await self.config.get(guild.id)
        message = guild_conf['farewell']
        if message:
            await guild.default_channel.send(message.format(member.mention))

    async def on_command_error(self, ctx, e):
        if not hasattr(ctx.command, 'on_error'):
            await self.handle_error(ctx, e)

    async def on_error(self, event_method, *args, **kwargs):
        _, e, _ = sys.exc_info()
        e = getattr(e, 'original', e)
        if not isinstance(e, self.general_ignore):
            await super().on_error(event_method, *args, **kwargs)

    def get(self, *args, **kwargs):
        return contextmanagers.get(self.session, *args, **kwargs)

    def tmp_dl(self, *args, **kwargs):
        return contextmanagers.tmp_dl(self.session, *args, **kwargs)
<|endoftext|>


<commit_before>import random

import taichi as ti

def test_minimization():
    from taichi.examples.autodiff.minimization import (L, gradient_descent, n,
                                                       reduce, x, y)

    for i in range(n):
        x[i] = random.random()
        y[i] = random.random()

    for k in range(100):
        with ti.Tape(loss=L):
            reduce()
        gradient_descent()

    for i in range(n):
        assert x[i] == ti.approx(y[i], rel=1e-3)
<commit_msg>[ci] Fix approx in autodiff example test (#4132)<commit_after>import random

import taichi as ti

def test_minimization():
    from taichi.examples.autodiff.minimization import (L, gradient_descent, n,
                                                       reduce, x, y)

    for i in range(n):
        x[i] = random.random()
        y[i] = random.random()

    for k in range(100):
        with ti.Tape(loss=L):
            reduce()
        gradient_descent()

    for i in range(n):
        assert x[i] == ti._testing.approx(y[i], rel=1e-3)
<|endoftext|>


<commit_before>#!/usr/bin/python

from test_component import *

if __name__ == "__main__":
    unittest.main()
<commit_msg>added test_config to the runtests script<commit_after>#!/usr/bin/python

from test_component import *
from test_config import*

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


<commit_before>from django.http import Http404
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from simplecms.models import Page

def page_detail(request, path):
    stripped = path.strip('/') if path else ''
    stripped = stripped and u'/%s/' % stripped or '/'

    try:
        page = Page.objects.get(_cached_url=stripped)
    except Page.DoesNotExist:
        raise Http404("No page found for the path '%s'" % stripped)

    return render_to_response(page.template_name, {
        'simplecms_page': page,
    }, context_instance=RequestContext(request))
<commit_msg>update views.py to use django shortcuts render()<commit_after>from django.http import Http404
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from simplecms.models import Page

def page_detail(request, path):
    stripped = path.strip('/') if path else ''
    stripped = stripped and u'/%s/' % stripped or '/'

    try:
        page = Page.objects.get(_cached_url=stripped)
    except Page.DoesNotExist:
        raise Http404("No page found for the path '%s'" % stripped)

return render(request, page.template_name, {
        'simplecms_page': page,
        })
<|endoftext|>


<commit_before>#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4

import unittest, time, logging
from rapidsms.log import Logger
from rapidsms.component import Component
from tempfile import NamedTemporaryFile

expected_output = """
DEBUG [Testing]: this is a debug message: 1
INFO [Testing]: this is a info message: 2
WARNING [Testing]: this is a warning message: 3
ERROR [Testing]: this is a error message: 4
CRITICAL [Testing]: this is a critical message: 5
"""

class TestLog(unittest.TestCase):
    def setUp(self):
        #self.tmp = NamedTemporaryFile()
        self.tmp = file("/tmp/log_output.txt","w+")

    def test_write (self):
        log = Logger("debug", self.tmp.name,
                    "%(levelname)s [%(component)s]: %(message)s",
                    False)
        c = Component()
        c.name = "Testing"
        log.write(c, "debug", "this is a debug message: %d", 1)
        log.write(c, "info", "this is a info message: %d", 2)
        log.write(c, "warning", "this is a warning message: %d", 3)
        log.write(c, "error", "this is a error message: %d", 4)
        log.write(c, "critical", "this is a critical message: %d", 5)
        self.tmp.flush()
        self.tmp.seek(0)
        output = self.tmp.read()
        self.assertEquals(output, expected_output.lstrip(), "got expected output")

if __name__ == "__main__":
    unittest.main()
<commit_msg>Actually write to a temp file.<commit_after>#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4

import unittest, time, logging
from rapidsms.log import Logger
from rapidsms.component import Component
from tempfile import NamedTemporaryFile

expected_output = """
DEBUG [Testing]: this is a debug message: 1
INFO [Testing]: this is a info message: 2
WARNING [Testing]: this is a warning message: 3
ERROR [Testing]: this is a error message: 4
CRITICAL [Testing]: this is a critical message: 5
"""

class TestLog(unittest.TestCase):
    def setUp(self):
        self.tmp = NamedTemporaryFile()

    def test_write (self):
        log = Logger("debug", self.tmp.name,
                    "%(levelname)s [%(component)s]: %(message)s",
                    False)
        c = Component()
        c.name = "Testing"
        log.write(c, "debug", "this is a debug message: %d", 1)
        log.write(c, "info", "this is a info message: %d", 2)
        log.write(c, "warning", "this is a warning message: %d", 3)
        log.write(c, "error", "this is a error message: %d", 4)
        log.write(c, "critical", "this is a critical message: %d", 5)
        self.tmp.flush()
        self.tmp.seek(0)
        output = self.tmp.read()
        self.assertEquals(output, expected_output.lstrip(), "got expected output")

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


<commit_before>import discord
import re
from unitconverter import *

client = discord.Client()

triggerString = '!convert'
historyLimit = 10
answerDecimalPlaces = '2'

def parse_units(message):
    for unit in Units:
        if re.search('[0-9]+(| )(' + unit.prefix + '|' + unit.name + ')', message.content) is not None:
            message_regex = re.search('[0-9]+(| )(' + unit.prefix + '|' + unit.name + ')', message.content)
            string = message_regex.group(0) + ' is '
            current_value = int(message_regex.group(0).replace(message_regex.group(2), ''))
            converted_value = current_value * unit.conversionValue
            return string + str("{0:." + answerDecimalPlaces + "f}".format(converted_value)) + ' ' + UnitPairs[
                unit.name]
    return ''

@client.event
async def on_message(message):
    channel = message.channel
    if message.author == client.user:
        return
    if message.content.startswith('!ping'):
        msg = 'Pong! This bot is alive.'
        await client.send_message(message.channel, msg)

    elif message.content.startswith(triggerString):
        bulk = False
        if 'all' in message.content:
            bulk = True
        if message.content == triggerString or message.content == triggerString + ' all':
            async for msg in client.logs_from(channel, limit=historyLimit):
                if msg.author != client.user:
                    send_message = parse_units(msg)
                    if send_message != '':
                        await client.send_message(message.channel, send_message)
                        if not bulk:
                            break
        else:
            parse_units(message)

@client.event
async def on_ready():
    print('Logged in as')
    print('User:', client.user.name)
    print('ID', client.user.id)
    print('------')

tokenFile = open('token')
token = tokenFile.read().replace('\n', '')
client.run(token)
<commit_msg>fix some bugs<commit_after>import discord
import re
from unitconverter import *

client = discord.Client()

triggerString = '!convert'
historyLimit = 10

def parse_units(message):
    for unit in Units:
        if re.search('[0-9]+(| )(' + unit.prefix + '|' + unit.name + ')', message.content) is not None:
            message_regex = re.search('[0-9]+(| )(' + unit.prefix + '|' + unit.name + ')', message.content)
            string = message_regex.group(0) + ' is '
            current_value = int(message_regex.group(0).replace(message_regex.group(2), ''))
            converted_value = current_value * unit.conversionValue
            return string + str("{0:.2f}".format(converted_value)) + ' ' + UnitPairs[
                unit.name]
    return ''

@client.event
async def on_message(message):
    channel = message.channel
    if message.author == client.user:
        return
    if message.content.startswith('!ping'):
        msg = 'Pong! This bot is alive.'
        await client.send_message(message.channel, msg)

    elif message.content.startswith(triggerString):
        bulk = False
        if 'all' in message.content:
            bulk = True
        if message.content == triggerString or message.content == triggerString + ' all':
            async for msg in client.logs_from(channel, limit=historyLimit):
                if msg.author != client.user:
                    send_message = parse_units(msg)
                    if send_message != '':
                        await client.send_message(message.channel, send_message)
                        if not bulk:
                            break
        else:
            send_message = parse_units(message)
            await client.send_message(message.channel, send_message)

@client.event
async def on_ready():
    print('Logged in as')
    print('User:', client.user.name)
    print('ID', client.user.id)
    print('------')

tokenFile = open('token')
token = tokenFile.read().replace('\n', '')
client.run(token)
<|endoftext|>


<commit_before>import sys
import megatableau, data_prob
import scipy, scipy.optimize
import math

def learn_weights(mt):
    """ Given a filled-in megatableau, optimize and return its weight vector.
    """
    # Set up the initial weights and weight bounds (nonpositive reals)
    w_0 = -scipy.rand(len(mt.weights))
    nonpos_reals = [(-25,0) for wt in mt.weights]

    # Learn
    print(data_prob.nlpwg(w_0, mt.tableau))
    learned_weights, fneval, rc = scipy.optimize.fmin_tnc(data_prob.nlpwg, w_0, args = (mt.tableau,), bounds=nonpos_reals)

    ## Previous version below: tells fmin_tnc to approximate the gradient itself
    # learned_weights, fneval, rc = scipy.optimize.fmin_tnc(data_prob.neg_log_probability, w_0, args = (mt.tableau,), bounds=nonpos_reals, approx_grad=True)

    return learned_weights

### HELPER FUNCTIONS FOR CALCULATING PROBABILITY ###

def maxent_value(weights, tableau, ur, sr):
    """ Compute maxent value P* = exp(harmony) for a particular UR/SR pair.
    """
    harmony = 0
    for c in range (0, len(weights)):
        harmony += weights[c] * tableau[ur][sr][1][c]
    return math.exp(harmony)

def z_score(tableau, ur):
    """ Compute the Z-score for a particular UR, using current maxent values.
    """
    zScore = 0
    for j in tableau[ur]:
        zScore += tableau[ur][j][2]
    return zScore

def update_maxent_values(weights, tableau):
    """ Computes maxent value P* = exp(harmony) for all UR/SR pairs
    in a supplied tableau, and updates the tableau with these values.
    """
    for ur in tableau:
        for sr in tableau[ur]:
            tableau[ur][sr][2] = maxent_value(weights, tableau, ur, sr)

### OBJECTIVE FUNCTIONS ###

def neg_log_probability_with_gradient(weights, tableau):
    """ Returns the negative log probability of the data AND a gradient vector.
    """
    update_maxent_values(weights, tableau)
    logProbDat = 0
    observed = [0 for i in range(len(weights))] # Vector of observed violations
    expected = [0 for i in range(len(weights))] # Vector of expected violations
    data_size = 0 # Number of total data points: the sum of all counts.
    for ur in tableau:
        z = z_score(tableau, ur)
        for sr in tableau[ur]:
            data_size += tableau[ur][sr][0]
            prob = tableau[ur][sr][2] / z
            logProbDat += math.log(prob) * tableau[ur][sr][0]
            for c in range(len(tableau[ur][sr][1])):
                observed[c] += tableau[ur][sr][1][c] * tableau[ur][sr][0]
                expected[c] += tableau[ur][sr][1][c] * prob
    expected[:] = [x * data_size for x in expected] # multiply expected values by size of data
    #print observed
    #print expected
    gradient = [y - x for x, y in zip(observed, expected)] # i.e. observed minus expected
    return (-logProbDat, gradient)

nlpwg = neg_log_probability_with_gradient # So you don't get carpal tunnel syndrome.

def neg_log_probability(weights, tableau):
    """ Returns the negative log probability of the data.
    """
    update_maxent_values(weights, tableau)
    logProbDat = 0
    for ur in tableau:
        z = z_score(tableau, ur)
        for sr in tableau[ur]:
            prob = tableau[ur][sr][2] / z
            logProbDat += math.log(prob) * tableau[ur][sr][0]
    return - logProbDat

def probability(weights, tableau):
    """ Returns the probability of the data.
    This function just makes a call to neg_log_probability, and
    transforms the results out of the log space.
    """
    return math.exp(- neg_log_probability(weights, tableau))<commit_msg>optimizer.py now works and is pretty<commit_after>''' A moduled used by maxent.py and phlearn.py to find the ideal weights for a tableau.
'''

import megatableau
import scipy, scipy.optimize
import math

### HELPER FUNCTIONS FOR CALCULATING PROBABILITY ###

def maxent_value(weights, tableau, ur, sr):
    """ Compute maxent value P* = exp(harmony) for a particular UR/SR pair.
    """
    harmony = 0
    for c in range (0, len(weights)):
        harmony += weights[c] * tableau[ur][sr][1][c]
    return math.exp(harmony)

def z_score(tableau, ur):
    """ Compute the Z-score for a particular UR, using current maxent values.
    """
    zScore = 0
    for j in tableau[ur]:
        zScore += tableau[ur][j][2]
    return zScore

def update_maxent_values(weights, tableau):
    """ Computes maxent value P* = exp(harmony) for all UR/SR pairs
    in a supplied tableau, and updates the tableau with these values.
    """
    for ur in tableau:
        for sr in tableau[ur]:
            tableau[ur][sr][2] = maxent_value(weights, tableau, ur, sr)

### OBJECTIVE FUNCTION(S) ###

def neg_log_probability_with_gradient(weights, tableau):
    """ Returns the negative log probability of the data AND a gradient vector.
    This is the objective function used in learn_weights().
    """
    update_maxent_values(weights, tableau)
    logProbDat = 0
    observed = [0 for i in range(len(weights))] # Vector of observed violations
    expected = [0 for i in range(len(weights))] # Vector of expected violations
    data_size = 0 # Number of total data points: the sum of all counts.
    for ur in tableau:
        z = z_score(tableau, ur)
        for sr in tableau[ur]:
            data_size += tableau[ur][sr][0]
            prob = tableau[ur][sr][2] / z
            logProbDat += math.log(prob) * tableau[ur][sr][0]
            for c in range(len(tableau[ur][sr][1])):
                observed[c] += tableau[ur][sr][1][c] * tableau[ur][sr][0]
                expected[c] += tableau[ur][sr][1][c] * prob
    expected[:] = [x * data_size for x in expected] # multiply expected values by size of data
    gradient = [e - o for o, e in zip(observed, expected)] # i.e. -(observed minus expected)
    return (-logProbDat, gradient)

nlpwg = neg_log_probability_with_gradient # So you don't get carpal tunnel syndrome.

def neg_log_probability(weights, tableau):
    """ Returns just the negative log probability of the data.
    This function isn't currently used, it's just here in case you want it.
    """
    return (nlpwg(weights, tableau))[0]

def probability(weights, tableau):
    """ Returns just the probability of the data.
    This function isn't currently used, it's just here in case you want it.
    """
    return math.exp(-(nlpwg(weights, tableau))[0])

### OPTIMIZATION FUNCTION

def learn_weights(mt):
    """ Given a filled-in megatableau, return the optimal weight vector.
    """
    # Set up the initial weights and weight bounds (nonpositive reals)
    w_0 = -scipy.rand(len(mt.weights))
    nonpos_reals = [(-25,0) for wt in mt.weights]

    # Find the best weights
    learned_weights, fneval, rc = scipy.optimize.fmin_tnc(nlpwg, w_0, args = (mt.tableau,), bounds=nonpos_reals)

    # Update the mt in place with the new weights
    mt.weights = learned_weights

    # Be sociable
    print "Initial (neglogprob, gradient):", (nlpwg(w_0, mt.tableau))
    print "Final   (neglogprob, gradient):", (nlpwg(learned_weights, mt.tableau))
    print "\nBoom! Weights have been updated:"
    for i in range(0,len(learned_weights)):
        print mt.constraints_abbrev[i],"\t",learned_weights[i]
    print ""

    # Return
    return learned_weights
<|endoftext|>