[Pytest][Part 3]检测python package状态

发布于:2025-07-04 ⋅ 阅读:(9) ⋅ 点赞:(0)

 

目录

实现需求1:

检查python package状态——pkg_resource

hook实现自动检测包状态

conftest.py

hook钩子函数


Part1:

https://blog.csdn.net/x1987200567/article/details/144915315?spm=1001.2014.3001.5501

从这里开始逐个实现Part1中的需求

实现需求1:

测试开始前检查测试需要的python package是否安装完成,若未安装完成,则安装缺失的package

检查python package状态——pkg_resource

python中的pkg_resource库是用来管理python中的包的,这个库提供了检查python安装包的API:

pkg_resources.require()

import pkg_resources
package = "pytest-repeat>=0.9.1"

#若已安装对应版本的包,则返回对应的包以及相关联的包信息,否则返回exception
 try:
    pkg_resources.require(package)
 except pkg_resources.DistributionNotFound:
    print(f"package not found {package}")
 except pkg_resources.VersionConflict:
    print(f"package version is wrong {package}")

 当require没有找到相应的package时就会返回不同的exception,那么根据这些不同的exception来install 或者upgrade 对应的包。

import pkg_resources
package = "pytest-repeat>=0.9.1"

#若已安装对应版本的包,则返回对应的包以及相关联的包信息,否则返回exception
 try:
    pkg_resources.require(package)
 except pkg_resources.DistributionNotFound:
     subprocess.check_call([sys.executable, "-m", "pip", "install", package])
 except pkg_resources.VersionConflict:
    subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", package])
 else:
    print(f"{package} is already meet requirement")

上面执行Install和upgrade的操作时用到了这一行代码

subprocess.check_call([sys.executable, "-m", "pip", "install", package])

subprocess 是python中用于执行cmd命令的一个库,check_call()是其中一个方法。当check_all()执行成功时返回0,失败时返回非0。接收一个list作为参数。

def check_call(*popenargs, **kwargs):
    """Run command with arguments.  Wait for command to complete.  If
    the exit code was zero then return, otherwise raise
    CalledProcessError.  The CalledProcessError object will have the
    return code in the returncode attribute.

    The arguments are the same as for the call function.  Example:

    check_call(["ls", "-l"])
    """

所以实现python package检测的完整实现代码如下:

import subprocess
import sys
import pkg_resources


def check_package_status(requirements_file='requirements.txt'):
    """
    use to check if python packages needed in test are all installed , if not , install package
    :param requirements_file: python package needed in the test
    :return:
    """
    logger.info("checking required python package status.....")
    try:
        with open(requirements_file, 'r') as file:
            requirements = file.readlines()

        for requirement in requirements:
            package = requirement.strip()
            try:
                pkg_resources.require(package)
            except pkg_resources.DistributionNotFound:
                logger.info(f"{package} is not installed. Installing...")
                subprocess.check_call([sys.executable, "-m", "pip", "install", package])
            except pkg_resources.VersionConflict as e:
                logger.error(f"Version conflict for {package}: {e}. Updating...")
                subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", package])
            else:
                logger.info(f"{package} is already installed.")
    except Exception as e:
        logger.exception(f"Error while checking/installing packages: {e}")

hook实现自动检测包状态

上面已经实现了包检测这个功能,那么下面的问题是如何实现每次测试开始之前都自动检测包的状态。pytest中提供的hook钩子函数这个功能可以帮我们快速实现这个需求。

conftest.py

这里放一段官方的介绍,大概意思是conftest.py是一个共享test fixture的文件,所有的test fixture 都定义在conftest.py中。作用范围可以是整个项目,也可以是文件夹内。如果作用域是整个项目,那么需要放在项目的根目录下。

The conftest.py file serves as a means of providing fixtures for an entire directory. Fixtures defined in a conftest.py can be used by any test in that package without needing to import them (pytest will automatically discover them).

You can have multiple nested directories/packages containing your tests, and each directory can have its own conftest.py with its own fixtures, adding on to the ones provided by the conftest.py files in parent directories.

hook钩子函数

hook也是在conftest.py中实现的,实现方式比较简单。pytest_sessionstart()是pytest提供的一个钩子函数,在session被创建之后,收集和执行测试case之前被调用,所以可以执行一些测试前的配置和检查工作。

pytest_sessionstart(session)[source]

Called after the Session object has been created and before performing collection and entering the run test loop.

Parameters

session (pytest.Session) – The pytest session object.

Return type

None

 

def check_package_status(requirements_file='requirements.txt'):
    pass

# 测试开始时检查当前的测试配置
@pytest.hookimpl(tryfirst=True)
def pytest_sessionstart(session):
    check_package_status()

这样就完成了测试开始前对python package的自动检测和安装功能。完整代码为:

import pkg_resources
import subprocess
import sys
import utils.TestLogger as testLogger

logger = testLogger.TefLogger().get_logger()

def check_package_status(requirements_file='requirements.txt'):
    """
    use to check if python packages needed in test are all installed , if not , install package
    :param requirements_file: python package needed in the test
    :return:
    """
    logger.info("checking required python package status.....")
    try:
        with open(requirements_file, 'r') as file:
            requirements = file.readlines()

        for requirement in requirements:
            package = requirement.strip()
            try:
                pkg_resources.require(package)
            except pkg_resources.DistributionNotFound:
                logger.info(f"{package} is not installed. Installing...")
                subprocess.check_call([sys.executable, "-m", "pip", "install", package])
            except pkg_resources.VersionConflict as e:
                logger.error(f"Version conflict for {package}: {e}. Updating...")
                subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", package])
            else:
                logger.info(f"{package} is already installed.")
    except Exception as e:
        logger.exception(f"Error while checking/installing packages: {e}")


# 测试开始前检查当前的测试配置
@pytest.hookimpl(tryfirst=True)
def pytest_sessionstart(session):
    check_package_status()