我正在创建一个Python3.8脚本,它执行一系列测试,从CAN总线网络读取和写入信息。我正在使用python和cantools包。我已经成功地发送和接收到了具有小功能的数据,没有问题。
我觉得我没有创建合适的"Pythonic“脚本体系结构,它允许我的脚本在模块之间使用所有函数、实例和变量。
Intended架构目标:
main.py
-包含CAN总线的发送和接收功能,通过位于test_case.py
模块中的每个测试用例执行初始化和循环。test_case.py
-存储所有测试用例。其中每个测试用例都是一个独立的函数。每个测试用例都必须是一个独立的函数,这样如果需要删除一个测试,或者添加了一个新的测试,脚本就不会中断。此外,可能会有几十个,甚至几百个测试用例。因此,为了保持代码的整洁性,我希望将它们隔离到一个模块中。test_thresholds.py
-将保留test_case.py
中每个测试用例将引用的所有pass/ will阈值变量。问题/问题:
main.py
实例化CAN总线对象bus = can.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
该对象是发送和接收函数所必需的。因为发送和接收函数都在main.py
中,所以直到我尝试在test_case.py
模块中执行一个引用main.py
中的发送和接收函数的测试用例时,才会出现问题--一旦我试图执行测试用例,就会发生错误,说明从test_case.py
模块NameError: name 'bus' is not defined
调用的receive()
函数--我理解这一点,因为test_case.py
不知道bus
实例是什么。这个问题也发生在我的can
实例中。我的test_case.py
中有D27
,我知道这很糟糕,但我不确定test_cases.py
将如何使用发送和接收函数以及bus
和can
实例How,我可以在模块之间共享这个实例吗?这里的最佳实践是什么?我尝试浏览过关于传递对象的堆栈溢出的几个帖子(我认为这就是我的问题所在),但似乎没有一个能回答我正在寻找的内容。<#>注意:我减少了大量代码,以使它在这里更加可读性。如果您尝试它,它可能不会运行。
main.py
import can
import cantools
import test_cases.test_cases # import all test cases
import time
# sending a single CAN message
def single_send(message):
try:
bus.send(message)
except can.CanError:
print("Message NOT sent")
# receive a message and decode payload
def receive(message, signal):
_counter = 0
try:
while True:
msg = bus.recv(1)
try:
if msg.arbitration_id == message.arbitration_id:
message_data = db.decode_message(msg.arbitration_id, msg.data)
signal_data = message_data.get(signal)
return signal_data
except AttributeError:
_counter += 1
if _counter == 5:
print("CAN Bus InActive")
break
finally:
if _counter == 5:
# reports false if message fails to be received
return False
def main():
for name, tests in test_cases.test_cases.__dict__.items():
if name.startswith("tc") and callable(tests):
tests()
if __name__ == "__main__":
bus = can.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
db = cantools.db.load_file('C:\\Users\\tw\\Desktop\\dbc_file.dbc')
verbose_log = open("verbose_log.txt", "a")
main()
bus.shutdown()
verbose_log.close()
test_case.py
from test_thresholds.test_thresholds import *
from main import * # to use the single_send and receive functions in main
def tc_1():
ct = receive(0x300, 'ct_signal') # this is where the issue occurs. receive expects the bus instance
message = can.Message(arbitration_id=0x303, data=1)
if (ct > ct_min) and (ct < ct_max):
verbose_log.write("PASS")
else:
verbose_log.write("FAIL")
test_thresholds.py
ct_min = 4.2
ct_max = 5.3
发布于 2020-06-28 16:01:23
return signal_data
# ...
# reports false if message fails to be received
return False
是有问题的。您强制调用此代码的人理解返回值至少有两种不同的类型:布尔值或任何“信号数据”。
Python处理此问题的方法是使用异常。与其重新抛出AttributeError
,不如抛出您自己的异常类型可能更有意义。
此外,重试计数的逻辑也有点复杂。您应该能够假设,如果循环已经结束而没有返回,那么它就失败了。另外,不要自己增加计数器。换句话说,
for attempt in range(5):
msg = bus.recv(1)
try:
if msg.arbitration_id == message.arbitration_id:
message_data = db.decode_message(msg.arbitration_id, msg.data)
signal_data = message_data.get(signal)
return signal_data
except AttributeError:
pass
raise CANBusInactiveError()
我会走得更远。我的猜测是,msg
--如果失败--不具有arbitration_id
属性。因此,与其试图捕获AttributeError
,不如:
hasattr
,或isinstance
。把这个:
verbose_log = open("verbose_log.txt", "a")
verbose_log.close()
在with
中。
'C:\\Users\\tw\\Desktop\\dbc_file.dbc'
至少应该进入一个常数变量。最好是从命令行参数、conf文件或env var获得它。
https://codereview.stackexchange.com/questions/244590
复制相似问题