Comments (10)
对,我当时想要不要支持按目录来分命令集,但是按当时的情况觉得一系列命令放在一个文件就够了,就没,这可能不太好。
我刚刚重新看了下源码,加载 commands 的代码主要在这 _add_registry_mod_cb
,这里我觉得如果把那个 exception 给忽略掉,就可以接受没有 __registry__
的模块了,这样的话应该就可以把复杂的逻辑拆分成多个文件(放到子目录中),然后外部保留一个含有 __register__
的模块来注册命令。以现在这个代码来看这样应该是改动比较少的办法。
如果不行的话,其实暂时也可以在整个根目录开一个新的文件夹来存命令的复杂业务逻辑,反正 import 也都可以导入。
上面写完我才发现一个问题,load_plugins
是直接遍历非 _
开头的文件来导入模块,只要对它做一个小修改让它能导入 package 就行了,这样,在子目录的 __init__.py
里面放 __registry__
,其它业务相关的 py 文件就可以随意放在子目录里。我没有测试,但这样应该就行:
plugin_files = filter(
lambda filename: not filename.startswith('_'),
os.listdir(plugin_dir)
)
这样改动比较少,缺点就是不能放其它类型的文件了(不过一般应该也不会放)。
from nonebot.
这样不行,我试了下,因为get_plugin_dir中已经指定了plugin_dir_name在get_root_dir下面,因此__init__.py再放__registry__也还是找commands下的py文件,不会去找子目录下的py文件
from nonebot.
我意思就是让它不光找 py 文件,还找 package(包含 __init__.py
的目录),package 应该是可以和 module 一样通过 importlib 导入的,比如目录结构:
commands/
-- cmd1.py
-- cmd2/
---- __init__.py
这两个 cmd 应该都可以通过 import cmd1
、import cmd2
导入,后者其实导入的就是 cmd2/__init__.py
。
from nonebot.
我刚刚测试了一下,importlib
是可以正常导入包的,行为和导入模块相同,也就是说把 load_plugins
改成:
def load_plugins(plugin_dir_name, module_callback=None):
plugin_dir = get_plugin_dir(plugin_dir_name)
plugin_files = filter(
lambda filename: not filename.startswith('_'),
os.listdir(plugin_dir)
)
plugins = [os.path.splitext(file)[0] for file in plugin_files]
for mod_name in plugins:
mod = importlib.import_module(plugin_dir_name + '.' + mod_name)
if module_callback:
module_callback(mod)
应该就行了,这样就可以正确导入结构如下的命令:
commands/cmd1/__init__.py
commands/cmd1/module1.py
commands/cmd1/module2.py
# commands/cmd1/__init__.py
__registry__ = #...
这样。
from nonebot.
# commands/cmd1/__init__.py
__registry__ = #...
这段怎么写?我是直接写成__registry__ = cr = CommandRegistry()的,不知道对不对
from nonebot.
对的吧,还是跟其它模块里的一样,cr
不是必须的,主要要 __registry__
,我加了个 cr
主要方便后面用装饰器注册
from nonebot.
我的意思是说不仅仅是导入包的问题,而是你的cmdHub中也有注册指令的问题。
第一,command.py中的add_registry中的代码要求__init__.py的__registry__必须要有init_func参数才能成功注册到registry_map中,否则会直接退出
def add_registry(self, registry_name, registry):
"""
Add a registry to the hub, running the init function of the registry.
:param registry_name: registry name
:param registry: registry object
"""
if registry.init_func:
registry.init_func()
self.registry_map[registry_name] = registry
这个还好办,我把__init__.py的代码增加一个init_func就好了
def _init():
pass
__registry__ = cr = CommandRegistry(init_func=_init)
其次,add_registry仍然只是注册了cmd1到registry_map,cmd1/module1并没有注册进去,所以在def call(self, command_name, args_text, ctx_msg, **options)中registry.has(command_name)的判断会导致module1的方法都没法通过,这步还是必须要在add_registry中正确处理遍历package才行
from nonebot.
不是,add_registry
是如果有 init_func
就先执行完再添加,如果没有就直接添加,你可以看我的大部分命令是没有传 init_func 的。
第二点确实是这样,我之前那个改法没有解决子目录中其它模块的导入,但这些模块可以在子目录的 __init__.py
中导入,我主要意思是在 __init__.py
中对 __registry__
进行注册,在需要拆分逻辑的时候,分到子目录中的其它模块,__init__.py
导入之后来添加到 __registry__
,这样注册进 cmdhub
之后,命令的前缀是子目录名(也就是包名),这和其它使用模块的情况是一样的(模块名),也就是说你把 __registry__
放在 cmd1/__init__.py
,它会导入到 cmdhub
的 cmd1
下,假如注册有 abc
这个命令,那就可以通过 cmd1.abc
来调用。
比如使用包的命令可能结构是这样的:
# cmd1/__init__.py
__registry__ = cr = CommandRegistry()
from . import module1
from .. import core
@cr.register('hello')
def hello(args_text, ctx_msg):
reply = module1.process(ctx_msg)
core.echo(reply, ctx_msg)
# cmd1/module1.py
def process(ctx_msg):
# 一些复杂的逻辑
return '回复'
这时候 cmdhub
会把 cmd1/__init__.py
中的 __registry__
放到 cmd1
键下,调用 cmd1.hello
也就调用了相应的命令。
我这个思路是目前代码的情况下,快速实现跟以前相同的两级命令划分的(也就是一个子目录(包)就相当于以前的一个模块,__init__.py
就是它的门面),我觉得你可能想的是按子目录和文件自动分级,子目录中的每个模块都自动再分一级,但这样代码改动应该比较多吧,cmdhub
那边得大改,重构的时候可以想想这个怎么实现比较好。
from nonebot.
嗯,原本我也认为不传init_func应该从语句上看没问题,只是跟踪时发现执行到if registry.init_func:的时候就直接跳出了,好像没有执行下面的self.registry_map[registry_name] = registry,不过我也没有深入去找什么原因造成的,如果其他命令没有问题应该是我跟踪时的问题导致的。
所有命令注册放在__init__.py下更不符合我的思路,那就等重构时再讨论这个问题吧,谢谢你的耐心答复,等下我加个你的QQ保持联系。
from nonebot.
行,我 QQ 1002647525,加的时候备注一下
from nonebot.
Related Issues (20)
- 请问如何在只是User is calling me的情况下保持会话? HOT 2
- scheduler与message_preprocessor不在同一个eventloop导致两者之间很难进行同步 HOT 6
- nonebot+cqhttp反向websocket 时出现错误: websocket: bad handshake HOT 8
- [提问]如何关闭heartbeat的logging HOT 6
- aget 无法发送prompt HOT 3
- 1.8.3移除`CommandSession.args`导致类 Shell 参数解析Command出错 HOT 2
- 以 node-onebot 为后端无法正确设置 `ctx['to_me']` HOT 5
- 加載“失敗”的插件注冊的命令仍然可用 HOT 1
- 考慮移除 sched HOT 1
- NLPSession无法处理被两个qq表情夹着的关键词 HOT 11
- 运行`nb run`命令后直接抛出`cannot import name 'WebSocketSetup' from 'nonebot.drivers' ` HOT 1
- say 和 echo失踪 HOT 3
- NLPSession在较长的句子中不能识别到关键词 HOT 2
- 1
- 关于Pyinstaller打包后的exe为什么会报错的解决方案【建议调整一部分代码】
- 启动时遇到ImportError HOT 2
- m1 运行报错cannot import name 'escape' from 'jinja2' HOT 9
- ImportError: cannot import name 'overrides' from 'nonebot.typing' HOT 1
- 无法正确识别“回复”类型消息中的指令 HOT 2
- 按组一同注册命令的关键词 内容 权限 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nonebot.