当前位置:网站首页>Why use pycharm to run the use case successfully but cannot exit?
Why use pycharm to run the use case successfully but cannot exit?
2022-07-03 21:26:00 【Quick and bold】
Related documents
Want to learn Python My friends can pay attention to Xiaobian's official account 【Python journal 】
There are many resources to whore for nothing , It will be updated from time to time Python Little knowledge of ha !!
Preface
Some time ago, due to a SDK It's upgraded , In the use of PyCharm+unittest When running a use case , Can run and output results , But has been unable to exit the use case . With the in-depth investigation , Found this SDK Thread in “ Make trouble ”.
Reproduce with simple code
Simplicity , Here's the code (Python 2) It contains simple thread logic and a use case , To reproduce the problems encountered :
# coding: utf-8
import threading
import time
import unittest
def tick():
while True:
print('tick')
time.sleep(3)
t = threading.Thread(target=tick)
t.start()
class TestString(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
This code starts a thread , every other 3 A second output tick. On the other hand , Define a use case , Determine the of the string upper() Method . If you delete thread logic , The use case can end normally ; conversely ,PyCharm Show the successful execution of the use case , But has been unable to exit the use case , As shown in the figure below :
Why not quit ?
A new thread must be opened before running the use case , perform tick() function , Because this function uses while The loop keeps outputting strings , It is not difficult to infer that the use case framework has been waiting for the thread to end when exiting , Thus, the use case cannot exit .
To test the idea , Check out PyCharm Run the entry code of the use case . Different operating systems 、PyCharm( Community Edition 、 pro ) It is different from the path of the use case entry file under the single test framework .Mac Upper PyCharm The Community Edition is for unittest The path of the case entry file of is
“/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pycharm/_jb_unittest_runner.py” ,
The contents of the document are as follows :
# coding=utf-8
import os
import sys
from unittest import main
from _jb_runner_tools import jb_start_tests, jb_doc_args, JB_DISABLE_BUFFERING, PROJECT_DIR
from teamcity import unittestpy
if __name__ == '__main__':
path, targets, additional_args = jb_start_tests()
args = ["python -m unittest"]
if path:
assert os.path.exists(path), "{0}: No such file or directory".format(path)
if sys.version_info > (3, 0) and os.path.isfile(path):
# In Py3 it is possible to run script directly which is much more stable than discovery machinery
# For example it supports hyphens in file names PY-23549
additional_args = [path] + additional_args
else:
discovery_args = ["discover", "-s"]
# Unittest in py2 does not support running script directly (and folders in py2 and py3),
# but it can use "discover" to find all tests in some folder (optionally filtering by script)
if os.path.isfile(path):
discovery_args += [os.path.dirname(path), "-p", os.path.basename(path)]
else:
discovery_args.append(path)
discovery_args += ["-t", PROJECT_DIR] # To force unit calculate path relative to this folder
additional_args = discovery_args + additional_args
elif targets:
additional_args += targets
args += additional_args
jb_doc_args("unittests", args)
# Working dir should be on path, that is how unittest work when launched from command line
sys.path.insert(0, PROJECT_DIR)
sys.exit(main(argv=args, module=None, testRunner=unittestpy.TeamcityTestRunner, buffer=not JB_DISABLE_BUFFERING))
The previous logic is mainly used to combine the parameters of running use cases , The key to the problem encountered in this article is the last line
main(argv=args, module=None,testRunner=unittestpy.TeamcityTestRunner, buffer=notJB_DISABLE_BUFFERING)
there main Namely unittest.TestProgram , The relevant core contents are as follows :
class TestProgram(object):
"""A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. """
USAGE = USAGE_FROM_MODULE
# defaults for testing
failfast = catchbreak = buffer = progName = None
def __init__(self, module='__main__', defaultTest=None, argv=None,
testRunner=None, testLoader=loader.defaultTestLoader,
exit=True, verbosity=1, failfast=None, catchbreak=None,
buffer=None):
...
self.exit = exit
...
self.parseArgs(argv)
self.runTests()
def runTests(self):
...
self.result = testRunner.run(self.test)
if self.exit:
sys.exit(not self.result.wasSuccessful())
PyCharm Of _jb_unittest_runner.py call main() ( namely TestProgram()) when , There was no introduction exit Parameters , So take the default True , In the specified runTests() Run the end of the use case , Determine the exit code according to the result of the use case (0 or 1), And then call sys.exit() Exit the use case execution process . If you break here, you will find that you have been stuck in this sentence .
sys.exit() The function of is to exit the current thread , If other threads do not end , Naturally, the process will not end . Obviously ,tick The thread of the function is not explicitly exited , As a result, the use case has been successfully run , But unable to quit .
How to solve ?
Now that you understand the reason , The solution is just around the corner .
Method 1 : Run the use case without executing thread logic
If the thread logic to perform periodic tasks is not required by the use case , Through the environment variable 、 Configuration files, etc , Thread logic is not executed when running the use case , So as to avoid that the use case cannot exit .
Method 2 : Explicitly exit the process instead of the thread
Use os._exit(n) Withdraw from the process . It should be noted that , This method does not call the cleanup logic 、 Refresh standard IO Cache, etc , It is usually used for fork() In the child process after . Because unit testing has no special requirements for the process , The test cases here generally do not cause side effects .
We can simply modify _jb_unittest_runner.py Final logic , Explicitly specify exit=False , That is not to let unittest call sys.exit() , It is called externally os._exit().
prog = main(argv=args, module=None, testRunner=unittestpy.TeamcityTestRunner, buffer=not JB_DISABLE_BUFFERING, exit=False)
os._exit(not prog.result.wasSuccessful())
Method 3 : Exit the thread gracefully
_jb_unittest_runner.py Send to the current process at the end of the use case run SIGKILL The signal , When the use case thread receives this signal , Execute cleanup logic ( If necessary ) Graceful exit , And then exit the process . This method will be discussed in detail in another article , This article knows this kind of thinking .
summary
If you pass PyCharm When executing the use case, the thread logic of running periodic tasks is triggered , Then it will lead to the completion of use case execution but cannot exit . The reason is sys.exit() Used to exit the current thread instead of the process , If a thread does not exit , This will cause the process to fail to exit . There are no more than three solutions , Do not execute thread logic 、 Exit the process or gracefully exit the thread .
边栏推荐
- 强化學習-學習筆記1 | 基礎概念
- Idea shortcut word operation
- 运维各常用命令总结
- Nmap and masscan have their own advantages and disadvantages. The basic commands are often mixed to increase output
- Reinforcement learning - learning notes 1 | basic concepts
- Quickly distinguish slices and arrays
- 抓包整理外篇——————autoResponder、composer 、statistics [ 三]
- Capturing and sorting out external articles -- autoresponder, composer, statistics [III]
- Nacos common configuration
- Baohong industry | good habits that Internet finance needs to develop
猜你喜欢
Link aggregation based on team mechanism
常用sql集合
MySQL——索引
强化學習-學習筆記1 | 基礎概念
UI automation test: selenium+po mode +pytest+allure integration
Getting started with postman -- environment variables and global variables
90 後,辭職創業,說要卷死雲數據庫
Transformer structure analysis and the principle of blocks in it
Getting started with postman -- built-in dynamic parameters, custom parameters and assertions
Notes on MySQL related knowledge points (startup, index)
随机推荐
QT6 QML book/qt quick 3d/ Basics
2022-2-14 acwing1027 grid access
Summary of common operation and maintenance commands
The White House held an open source security summit, attended by many technology giants
Day 9 HomeWrok-ClassHierarchyAnalysis
内存分析器 (MAT)
Minio deployment
常用sql集合
Cesiumjs 2022 ^ source code interpretation [7] - Analysis of the request and loading process of 3dfiles
Yyds dry inventory hcie security Day12: concept of supplementary package filtering and security policy
2022-02-15 Daily: 2022 AAAI fellow release
Memory analyzer (MAT)
Yiwen teaches you how to choose your own NFT trading market
Global and Chinese market of wall mounted kiosks 2022-2028: Research Report on technology, participants, trends, market size and share
MySQL -- standardize database design
Goodbye 2021, how do programmers go to the top of the disdain chain?
TiDB 之 TiCDC6.0 初体验
Refer to some books for the distinction between blocking, non blocking and synchronous asynchronous
Capturing and sorting out external articles -- autoresponder, composer, statistics [III]
Hcie security Day12: supplement the concept of packet filtering and security policy