我正在围绕 SQL 数据库访问调用编写 Python 包装器,但无法使实际的子进程正常工作,因为从单元测试和实际脚本调用时,它的行为不同。
如果我注释掉 proc.wait() 调用,那么单元测试会引发一堆关于仍在运行的子进程的“资源警告”。如果我取消对 proc.wait() 和 proc.stdout.close() 和 proc.stderr.close() 语句的注释,那么单元测试可以完美运行,但是从命令行运行时脚本偶尔会挂在我身上。>
单元测试环境与从命令行实际运行脚本之间的区别是什么会导致它(a)在单元测试中启动资源警告或(b)导致实际脚本从命令行运行时挂起?
有没有办法同时消除上述(a)和(b)问题?
感谢您的建议,
凯瑟琳
子进程调用
def execute_command(command, env=os.environ):
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, \
stderr=subprocess.PIPE, env=env)
#proc.wait()
out_string = proc.stdout.read()
err_string = proc.stderr.read()
#proc.stdout.close()
#proc.stderr.close()
out = [s.decode("utf-8") for s in out_string.split(b"\n") if (len(s) > 0)]
err = [s.decode("utf-8") for s in err_string.split(b"\n") if (len(s) > 0)]
#print("Command %s: out=%s, err=%s" % (command, out, err))
return (out, err)
单元测试
from filemgr_oco3 import FileMgrOco3
import parameters_oco3 as parameters
import os
import unittest
TESTDIR = "testdata/in"
class FileMgrOco3Test(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_lites(self):
<snip>
products = ["OCO3_L2DailyFP", "OCO3_L2DailySIF"]
select = ["Filename", "StartDateTime", "EndDateTime", "CollectionLabel"]
output = ["Filename", "StartDateTime", "EndDateTime", "CollectionLabel"]
conditions = {"StartDateTime": (">=", "2020-04-29T00:00:00.000Z"), \
"EndDateTime": ("<=", "2020-04-30T00:00:00.000Z")}
query = FileMgrOco3(products, select, output, conditions, logic="AND")
result = query.execute_query()
<snip>
类定义
class FileMgrOco3(object):
<snip>
def execute_query(self, print_debug=False):
self.validate_query()
if ("L2Daily" in self.products[0]):
self.command = f"{self.PCSQUERYBIN} --url {self.FILEMGR_LITES} --sql "
else:
self.command = f"{self.PCSQUERYBIN} --url {self.FILEMGR_L1L2} --sql "
self.from_string = f','.join(self.products)
self.query_string = f"SELECT {','.join(self.select)}"
self.output_string = ",".join([f"${o}" for o in self.output])
self.where_string = self.build_conditions()
self.command += f'-query "{self.query_string} ' \
+ f'FROM {self.from_string} WHERE {self.where_string}" ' \
+ f"-outputFormat '{self.output_string}' "
(self.out, self.err) = python_utility.execute_command(self.command, \
env=self.environ)
答案 0 :(得分:1)
关键是用对 proc.communicate() 的单个调用替换 proc.wait()、proc.stdout.read() 和 proc.stderr.read() 调用。
以下子流程代码非常适合我:
def execute_command(command, env=os.environ):
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, \
stderr=subprocess.PIPE, env=env)
(out_string, err_string) = proc.communicate()
out = [s.decode("utf-8") for s in out_string.split(b"\n") \
if (len(s) > 0)]
err = [s.decode("utf-8") for s in err_string.split(b"\n") \
if (len(s) > 0)]