Skip to content

Latest commit

 

History

History
139 lines (85 loc) · 10.1 KB

notes.md

File metadata and controls

139 lines (85 loc) · 10.1 KB

项目笔记

2021/2/22凌晨 从nb2学到了可以让Service信息用loguru记录的方式,于是对日志进行了封装,并让Service.logger得以实现。

同时,实现了对nonebot.matcher的封装,并命名为MatcherWrapperMatcherWrapper联系了matcherService,记录了matcher的更为丰富的信息,而且终于MatcherWrapper成为了具体实例对象,梦寐以求的matcher直接装饰函数得以变相实现(等同于handle()),梦回nb1, 撒花~。

利用nb2的run_preprocessorrun_postprocessor,结合MatcherWrapper, 使日志记录更多事件处理的信息。

这次更新之后,项目的核心架构真正稳定下来(但愿如此)。我真的不想折腾了。

2021/2/20凌晨 这几天项目进程依然缓慢进行,当然目前大体迁移完毕后已经投入生产使用了。使用过程中发现,对于定时任务的管理或许是可以提上日程的,于是一方面地,学习了APScheduler的官方文档, 了解到了scheduler的属性和方法。然后查看本地源码时候傻眼了,它源代码没写类型标注,job不能直接定位到job的定义,scheduler也差不多(此时就感慨之前大佬们嘱托的写好类型标注的重要性,给自己给他人都有很大的方便),学完之后就知道了怎么修改任务的状态和查看任务的属性。

另一方面,我想着将定时任务的运行状态记录下来,所以学习了loguru的官方文档,了解到了对于颜色的处理,然后就需要对定时任务装饰的函数进行一些处理,在运行前后进行日志的记录。

好吧这就又牵扯到了python的装饰器的问题, 阅读了文档之后感觉还不够,就又去菜鸟教程复习了装饰器的用法。熟悉之后大概知道了装饰器的含义:装饰器是一个参数是函数,返回值是传入的函数函数,它的目的就是对于传入的函数进行处理和装饰(装饰器的名字终于理解了),比较简单的例子就是staticmethodclassmethod

由于@语法糖装饰函数的时候,参数只有函数对象一个,函数本身的参数并未传入装饰器,这造成了如果需要函数正常运行,它会缺少参数,于是聪明的人们想到了一个办法,在装饰器内部再设立一个函数,让它与要装饰的函数的参数相同,这样相当于把函数包装成了另一个函数(往往称之为闭包),闭包会接受到装饰器对函数的装饰效果,装饰器再返回闭包对象就好,当然直接进行闭包会有一些问题,比如函数的__name__会有所改变,参数和函数的参数不一定一致等,所以一般会引用wraps来装饰闭包和对闭包进行参数检查:

from functools import wraps
def deco(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        print('before func')
        res=func(*args,**kwargs)
        print('after func')
        return res
    return wrapper
@deco
def fun(*args,**kwargs):
    print(args)
    print(kwargs)

但是有时候装饰器需要函数以外的参数来对函数进行处理(比如说,用鉴权参数来检测是否能让函数运行),要怎么办呢?聪明的人们又想到了一个方法,写一个外层函数传递参数,然后让内层的装饰器接收到这些参数, 再返回装饰器不就好了! 这样的场景很广泛,例子非常多,比如flask或者fastapiapp.get方法就是这样的,对于nb2来说,matcher.handle或者matcher.got也是这样,对于前面说的apschedulerscheduler.scheduled_job也是如此。所以,绝大多数我之前认为的装饰器都不是装饰器本身,而是返回装饰器的函数。

一般见到的装饰器函数有两个情况:大多数都有三层函数的结构,第一层接受装饰器需要的参数,第二层是接受函数的装饰器;第三层是接受函数的参数,打包函数的闭包;当然也有很多就两层结构,第一层接受装饰器的参数,第二层是接受函数的装饰器,这个装饰器往往只对函数对象本身操作。这里拿第一种情况举例:

def return_deco(ab: bool):
    def deco(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('before func')
            if ab:
                res = func(*args, **kwargs)
            else:
                print('鉴权不通过,函数不执行')
                res = None
            print('after func')
            return res
        return wrapper
    return deco


@return_deco(True)
def fun(*args, **kwargs):
    print(args)
    print(kwargs)


@return_deco(False)
def fun1(*args, **kwargs):
    print(args)
    print(kwargs)


fun('1234', name='jim')
fun1('1234', name='jim')

上面的代码运行之后,会有以下的记录,装饰器的参数确实对函数运行造成了影响:

before func
('1234',)
{'name': 'jim'}
after func
before func
鉴权不通过,函数不执行
after func

好吧其实写完这篇笔记之后我大概对装饰器的理解应该比较深的了

2021/2/15凌晨 在这段期间,项目进展算是很缓慢的,但是也学习并实践了一些nb2的feature:

  1. 对于原先HoshinoBotanti_abuse插件, 在这个项目重构为black,并利用了nb2的钩子函数(新学到的名词)event_preprocessor进行处理。

    这个插件的编写让我仔细阅读了nb2的message.py, 并理解了nb2处理事件的周期:

    上报(以及根据adapter剥离事件的tome)->事件预处理->匹配响应器->运行前处理->运行响应器->运行后处理->事件后处理

  2. 在编写poke的时候,学习到了nb2的事件处理函数重载,这个feature会运用魔法,可以让matcher运行的时候按handler规定的typing来执行handler,这个feature能减少rule的编写,可以让一个响应器针对不同的事件作响应。

    这个魔法的源代码在run_handler, 粗略来说,它会根据参数名字和参数类型进行检查,如果参数名字和类型对得上的话,才会运行handler,否则就会ignore

    当然,这个检查是在handler对象有一个__params__这样一个类似注释的存在前提下进行的,这个前提的是由process_handler制造的,查看这个代码段时候,大概查看了inspect模块,学习到了python对于类型检查的处理。

在迁移了rsspush时,想着能不能将图片输出出来,这个思考直接导致了对网络请求的封装的修改,才注意到对于返回的请求体,一定是有content这样一个bytes,但是这个bytes并不一定能解码为text或者json,比如图片和文件。

2021/2/03下午 新增interactive模块,之后会存放互动的插件;在其中增加机器人最重要的自定义问答功能QA下载卡面 下载头像使用了nonebot.util.run_sync功能,将同步函数装饰异步;引用nonebot2.00a9的新特性on_shell_command

2021/2/01凌晨 昨天的问题今天下午查阅nb2的issue#153得到了解决,跨插件访问不建议直接引用,可以利用require()export()办法来处理,于是就将chara.Chara进行导出。

另外,今天新增了pcr_arenawhois插件,pcr_arena的编写让我大概明白了Matcher处理事件的流程,于是就试着用了Matcher.new(state=...,handlers=...)的办法来初始化响应器,这样省去了大量的重复代码。

whois插件的编写让我发现了nb2的一个小bug,即在_check_matcher()阶段,如果在Rule处理了state,前一个响应器的state被后一个覆盖的情况。目前的权宜之计就是不满足checker时候直接返回False,具体的妥善办法就等更新了。

还有就是,用一个笨方法将异步请求给封装了,用一个类来实现类似的resp.content操作。

今天之后代码的最核心部分就差不多完成了,之后进行插件的慢慢迁移就可以,这几天写的我有点内耗,现在脑子发昏,读代码和写代码在进行的时候感觉很有干劲,停下来之后就觉得被掏空了;当然最大的原因还是自己基础不够,效率还是太低了。

总之该项目最艰难的阶段结束了,之后就慢慢更新了。

2021/1/31凌晨 新增gachacharaquery;并遇到一个问题,gacha引用chara的一个类,但是同时也注册了chara的三个matcher(通过nonebot.mathcer.matchersdebug可知,在启动时也会有WARNING),可能这是nb2的feature?

2021/1/29晚 重写了原HoshinobotR.py,使之支持更多的表达方式,并写了相关demo。(写代码太累了。。。。)

2021/1/29凌晨 原HoshinoBot代码框架核心部分,即Service类和控制Service的代码已迁移完成。项目启动为时两天,还算顺利(不是)。

特别感谢