Aio应用程序运行器
项目描述
适用于aio asyncio框架的应用程序运行器
构建状态
安装
需要python >= 3.4
使用以下方式安装
pip install aio.app
快速开始 - “Hello World”调度器
将以下内容保存到文件“hello.conf”中
[schedule/EXAMPLE]
every = 2
func = my_example.schedule_handler
并将以下内容保存到名为“my_example.py”的文件中
import asyncio
def schedule_handler(event):
yield from asyncio.sleep(1)
print ("Received scheduled: %s" % event.name)
使用aio run命令运行
aio run -c hello.conf
aio config命令
在保存或读取配置选项时,配置文件将从以下位置按顺序搜索:
aio.conf
etc/aio.conf
/etc/aio/aio.conf
要转储系统配置,可以运行
aio config
要转储配置部分,可以使用-g或–get与部分名称
aio config -g aio
aio config --get aio/commands
要获取配置选项,可以使用-g与部分名称和选项
aio config -g aio:log_level
aio config --get listen/example:example-signal
您可以使用-s或–set设置配置选项
包含插值的选项应放在单引号内
多行选项应放在“”内,并用“\n”分隔
aio config --set aio:log_level DEBUG
aio config -s aio/otherapp:log_level '${aio:log_level}'
aio config -s listen/example:example-signal "my.listener\nmy.listener2"
如果标准位置中没有配置文件,aio将尝试在当前工作目录中的“aio.conf”中保存
要获取或设置特定文件中的选项,您可以使用-f标志
aio config -g aio:modules -f custom.conf
aio config -s aio:log_level DEBUG -f custom.conf
当使用-f标志获取配置值时,不使用ExtendedInterpolation,因此您看到的是原始值
aio run命令
您可以如下运行aio应用程序:
aio run
或使用自定义配置文件
aio -c custom.conf run
在启动时,aio run会设置以下内容:
配置 - 系统级配置
模块 - 模块的初始化和配置
日志 - 系统日志策略
调度器 - 在设定时间调用的函数
服务器 - 监听tcp/udp或其他类型的套接字
信号 - 对事件响应的函数
配置
配置使用ini语法
[aio]
foo = eggs
spam
当应用程序运行时,系统配置可以从 aio.app 导入
from aio.app import config
配置使用以下方式解析 ExtendedInterpolation
读取 aio.app 默认配置
读取用户配置以初始化模块
从初始化的模块中读取“aio.conf”(如果存在)
再次读取用户配置
日志记录
日志策略可以放置在配置文件中,遵循 Python 的 fileConfig 格式
由于配置使用 ExtendedInterpolation 解析,您可以使用其他部分中的选项
[logger_root]
level=${aio:log_level}
handlers=consoleHandler
qualname=aio
默认的 aio:log_level 是 INFO
以 handler、logger 或 formatter 开头的任何部分将自动添加到相关的日志部分
因此,通过添加以下部分
[logger_custom]
level=${aio:log_level}
handlers=consoleHandler
qualname=custom
“logger_custom” 将自动添加到 logger 键
[loggers]
keys=root,custom
模块
您可以在配置中列出在运行时应该导入的任何模块
[aio]
modules = aio.web.server
aio.manhole.server
如果存在,将从模块路径中名为“aio.conf”的文件中读取每个模块的配置
可以通过 aio.app 访问初始化的模块
from aio.app import modules
调度器
调度定义部分具有以下格式
[schedule/SCHEDULE_NAME]
指定频率和要调用的函数。如果函数不是协程,则将其包装在协程中
[schedule/example]
every = 2
func = my.scheduler.example_scheduler
调度器函数接收一个 ScheduledEvent 对象
def example_scheduler(event):
yield from asyncio.sleep(2)
# do something
print(event.name)
pass
服务器
服务器定义部分具有以下格式
[server/SERVER_NAME]
服务器需要工厂或协议才能启动
协议配置示例
[server/example]
protocol = my.example.MyServerProtocol
port = 8888
协议示例代码
class MyServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
# do stuff
self.transport.close()
对于协议选项,您可以指定 asyncio.Protocol 的子类,或者使用带有 aio.app.server.protocol 装饰器的函数
[server/example]
protocol = my.example.protocol
port = 8888
服务器协议函数的示例代码
import asyncio
import aio.app
@aio.app.server.protocol
def server_protocol():
yield from asyncio.sleep(1)
# do something
return MyServerProtocol
如果您需要进一步控制协议的附加方式,可以指定一个工厂方法
工厂配置示例
[server/example]
factory = my.example.server_factory
port = 8080
工厂方法必须包装在 aio.app.server.factory 中,并以协程方式调用
@aio.app.server.factory
def server_factory(name, protocol, address, port):
yield from asyncio.sleep(1)
# do something
loop = asyncio.get_event_loop()
return (
yield from loop.create_server(
MyServerProtocol, address, port))
信号
信号定义部分具有以下格式
[signal/SIGNAL_NAME]
示例监听配置部分
[listen/example]
example-signal = my.example.listener
以及示例监听函数。监听函数将以协程的方式被调用
def listener(signal):
yield from asyncio.sleep(2)
print(signal.data)
信号是在协程中发出的
yield from app.signals.emit(
'example-signal', "BOOM!")
您可以在每个配置部分中添加多个订阅
您还可以将多个函数订阅到信号,并且可以有多个“listen/”部分
[listen/example]
example-signal = my.example.listener
example-signal-2 = my.example.listener2
my.example.listener
[listen/example-2]
example-signal-3 = my.example.listener2
“aio test”命令
您可以测试 aio:modules 配置选项中设置的模块
[aio]
modules = aio.config
aio.core
aio.signals
默认情况下,aio test 命令将测试所有测试模块
aio test
您也可以指定一个或多个模块
aio test aio.app
aio test aio.app aio.core
如果您想为测试指定不同于应用程序模块的模块集合,可以在 aio/testing:modules 中列出它们
[aio/testing]
modules = aio.config
aio.core
这可以包括应用程序模块
[aio/testing]
modules = ${aio:modules}
aio.web.page
aio.web.server
依赖项
aio.app 依赖于以下包
aio.app 使用
您可以使用配置中 [aio/commands] 部分列出的任何命令运行 aio 命令
还有 3 个内置命令 - run、config 和 test
最初,aio.app 没有任何配置、信号、模块或服务器
>>> import aio.app
>>> print(aio.app.signals, aio.app.config, aio.app.modules, aio.app.servers) None None () {}
让我们以默认配置在测试循环中启动应用程序运行器,并打印出信号和配置对象
>>> import aio.testing >>> from aio.app.runner import runner
>>> @aio.testing.run_until_complete ... def run_app(): ... runner(['run']) ... ... print(aio.app.signals) ... print(aio.app.config) ... print(aio.app.modules) ... print(aio.app.servers)
>>> run_app() <aio.signals.Signals object ...> <configparser.ConfigParser ...> (<module 'aio.app' from ...>,) {}
清除应用程序
我们可以清除应用程序变量。
这将关闭任何当前正在运行的套接字服务器
>>> aio.app.clear()
>>> print(aio.app.signals, aio.app.config, aio.app.modules, aio.app.servers) None None () {}
添加信号监听器
我们可以在应用程序配置中添加信号监听器
>>> config = """ ... [listen/testlistener] ... test-signal = aio.app.tests._example_listener ... """
让我们创建一个测试监听器,并使其可导入
监听器需要使用 aio.app.signal.listener 进行包装,并在协程中调用
>>> import asyncio
>>> @aio.app.signal.listener ... def listener(signal): ... yield from asyncio.sleep(1) ... print("Listener received: %s" % signal.data)
>>> aio.app.tests._example_listener = listener
运行测试…
>>> @aio.testing.run_until_complete ... def run_app(message): ... runner(['run'], config_string=config) ... yield from aio.app.signals.emit('test-signal', message) ... aio.app.clear()
>>> run_app('BOOM!') Listener received: BOOM!
我们还可以以编程方式添加监听器
>>> @aio.testing.run_until_complete ... def run_app(message): ... runner(['run']) ... ... aio.app.signals.listen('test-signal-2', aio.app.signal.listener(listener)) ... yield from aio.app.signals.emit('test-signal-2', message) ... aio.app.clear()
>>> run_app('BOOM AGAIN!') Listener received: BOOM AGAIN!
添加应用程序模块
当您以默认配置运行应用程序时,列出的唯一模块是 aio.app
>>> @aio.testing.run_until_complete ... def run_app(config_string=None): ... runner(['run'], config_string=config_string) ... print(aio.app.modules) ... aio.app.clear()
>>> run_app() (<module 'aio.app' from ...>,)
我们可以让应用程序运行器了解我们想要包含的任何模块,这些模块在运行时导入
>>> config = """ ... [aio] ... modules = aio.app ... aio.core ... """
>>> run_app(config_string=config) (<module 'aio.app' from ...>, <module 'aio.core' from ...>)
运行计划程序
计划程序的基本配置
>>> config = """ ... [schedule/test-scheduler] ... every: 2 ... func: aio.app.tests._example_scheduler ... """
让我们创建一个计划程序函数并使其可导入。
计划程序函数被包装在协程中
>>> def scheduler(event): ... print('HIT: %s' % event.name)
>>> aio.app.tests._example_scheduler = scheduler
我们需要使用 aio.testing.run_forever 来等待计划事件的发生
>>> @aio.testing.run_forever(timeout=5) ... def run_app(): ... runner(['run'], config_string=config) ... ... return aio.app.clear
运行 5 秒钟的测试我们得到 3 次命中
>>> run_app() HIT: test-scheduler HIT: test-scheduler HIT: test-scheduler
运行服务器
让我们设置和运行一个附加服务器
至少我们应该提供一个协议和一个要监听的端口
>>> config_server_protocol = """ ... [server/additiontest] ... protocol: aio.app.tests._example_AdditionServerProtocol ... port: 8888 ... """
让我们创建服务器协议并使其可导入
>>> class AdditionServerProtocol(asyncio.Protocol): ... ... def connection_made(self, transport): ... self.transport = transport ... ... def data_received(self, data): ... nums = [ ... int(x.strip()) ... for x in ... data.decode("utf-8").split("+")] ... self.transport.write(str(sum(nums)).encode()) ... self.transport.close()
>>> aio.app.tests._example_AdditionServerProtocol = AdditionServerProtocol
在设置好服务器后,让我们用简单的加法来调用它
>>> @aio.testing.run_forever ... def run_addition_server(config_string, addition): ... runner(['run'], config_string=config_string) ... ... def call_addition_server(): ... reader, writer = yield from asyncio.open_connection( ... '127.0.0.1', 8888) ... writer.write(addition.encode()) ... yield from writer.drain() ... result = yield from reader.read() ... aio.app.clear() ... ... print(int(result)) ... ... return call_addition_server
>>> run_addition_server( ... config_server_protocol, ... '2 + 2 + 3') 7
如果您需要更多控制服务器协议的创建方式,可以指定一个工厂
>>> config_server_factory = """ ... [server/additiontest] ... factory = aio.app.tests._example_addition_server_factory ... port: 8888 ... """
工厂方法必须使用 aio.app.server.factory 装饰
>>> @aio.app.server.factory ... def addition_server_factory(name, protocol, address, port): ... loop = asyncio.get_event_loop() ... return ( ... yield from loop.create_server( ... AdditionServerProtocol, ... address, port))
>>> aio.app.tests._example_addition_server_factory = addition_server_factory
>>> run_addition_server( ... config_server_protocol, ... '17 + 5 + 1') 23
项目详情
aio.app-0.1.8.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 41c1860e904fd01b09315c8143d577b5ea92726f3cb5b4092a62e7b8dd40ebfa |
|
MD5 | 53fb2543aaa8ee60e05e809936097bec |
|
BLAKE2b-256 | c164f11c23560bd621781f634ce47eacd3e1296af9c5e70565e41126a56b5c2f |