Я хочу выполнить другой файл Python в моем коде, поэтому я использую этот код, он отлично работает:
runner.py
with open(pyfile, encoding="utf-8") as f:
code = f.read()
gl = globals()
gl["__name__"] = "__main__"
gl["__file__"] = pyfile
exec(compile(code, pyfile, 'exec'), gl)
, чтобы я мог выполнить код в a.py
с помощью if __name__ in __main__
:
a.py
def testprint():
print(123321)
if __name__ == "__main__":
testprint()
в runner.py
, я изменяю __file__
и __name__
, чтобы убедиться, что при запуске a.py
в runner.py
, точно так же, как я использую python a.py
для его запуска.
это будет хорошо, пока я не получу файл Python, используя unittest
, например:
b.py
import unittest
class Test(unittest.TestCase):
def setUp(self):
pass
def test_case1(self):
pass
def tearDown(self):
pass
if __name__ == '__main__':
unittest.main()
при попытке запустить b.py в runner.py
произойдет сбой:
File "runner.py", line 72, in run_pyfile
exec(compile(code, pyfile, 'exec'), gl)
File "a.py", line 23, in <module>
unittest.main()
File "C:\Python36\Lib\unittest\main.py", line 96, in __init__
self.parseArgs(argv)
File "C:\Python36\Lib\unittest\main.py", line 143, in parseArgs
self.createTests()
File "C:\Python36\Lib\unittest\main.py", line 147, in createTests
self.test = self.testLoader.loadTestsFromModule(self.module)
File "C:\Python36\Lib\unittest\loader.py", line 123, in loadTestsFromModule
tests.append(self.loadTestsFromTestCase(obj))
File "C:\Python36\Lib\unittest\loader.py", line 92, in loadTestsFromTestCase
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
File "C:\Python36\Lib\unittest\suite.py", line 24, in __init__
for test in tests:
TypeError: __init__() takes 1 positional argument but 2 were given
эта проблема связана с тем, что в unittest он будет использовать __main__
для инициализации TestProgram
, но он будет использовать runner.py
как __main__
, а не реальный путь к файлу (b.py)
class TestProgram(object):
def __init__(self, module='__main__', defaultTest=None, argv=None,
testRunner=None, testLoader=loader.defaultTestLoader,
exit=True, verbosity=1, failfast=None, catchbreak=None,
buffer=None, warnings=None, *, tb_locals=False):
if isinstance(module, str):
self.module = __import__(module) # <---the result is self.module= runner.py, not b.py
-
Я пробовал эти способы, но они не работают:
- попробуйте использовать importlib
import importlib.util
spec = importlib.util.spec_from_file_location("__main__", "a.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
все еще хорошо работает, когда я использую a.py, но не удалось в b.py. потому что он передает какой-то странный argv на unittest (не путь b.py, а путь моего python.exe и какое-то странное число)
- попробуйте использовать runpy
import runpy
runpy.run_path("a.py")
Я могу получить дикт и некоторые результаты (некоторые вещи, связанные с авторским правом), но не то, что я хочу.
так как выполнить файл Python unittest
в коде?
Я использую Python3.6 +