【问题标题】:Windows batch file to run Python script to check installed package version?Windows批处理文件运行Python脚本来检查安装的包版本?
【发布时间】:2019-10-06 04:04:47
【问题描述】:

我正在尝试创建一个批处理文件来运行我编写的 Python 脚本,但遇到了一些障碍:

  1. 我需要确保最终用户安装了 matplotlib-3.1.1 或更高版本,所以我有一个命令:
C:\ProgramData\Anaconda3\python.exe -m pip freeze | findstr matplotlib

但这会产生一个输出:

WARNING: Could not generate requirement for distribution -atplotlib 2.2.2 (c:\pr
ogramdata\anaconda3\lib\site-packages): Parse error at "'-atplotl'": Expected W:
(abcd...)
matplotlib==3.1.1
matplotlib-venn==0.11.5

所以问题是:我如何搜索一个非常具体的包,而不是任何与搜索键大致匹配的东西?

  1. 如果用户的 matplotlib 版本比要求的版本旧,我希望自动安装最新版本。如何将版本检查(上)的输出发送到 if 子句中使用的某个变量?

提前致谢!

【问题讨论】:

  • package_name in sys.modules 帮助确定包是否可用
  • @SuryaTej 如果你已经导入了包名,它只会出现in sys.modules,如果它不可用,那么导入它的尝试将是raise ImportError

标签: python batch-file matplotlib


【解决方案1】:

如何搜索一个非常具体的包,而不是与搜索键大致匹配的任何内容?

我怀疑您根本不需要这样做(跳到最后一部分),尤其是从您的批处理文件中。

如果您真的必须从批处理中执行此操作:pip list 输出可能比pip freeze 更方便您。它应该按照以下方式为您提供表格输出:

Package        Version Location
-------------- ------- --------------------------------------------
package-name   1.0.0   c:\path\to\install\of\package-name

经过一番搜索和玩弄,我最终想出了:

(for /f "tokens=1,2" %a in ('pip list') do if "%a"=="matplotlib" set MPLVER=%b)

(在脚本中,您可能需要将百分号加倍)

然后您可以验证脚本中的%MPLVER%(不过,我不知道您将如何比较版本字符串以检查它是否为 3.1.1 或更高版本)。


在 Python 中这样做会容易得多:

import pkg_resources

def have_recent_mpl():
    try:
        pkg_resources.require('matplotlib>=3.1.1')
    except pkg_resources.VersionConflict:
        # out of date
        return False
    except pkg_resources.DistributionNotFound:
        # not installed
        return False
    return True

如果用户的 matplotlib 版本比要求的版本旧,我希望自动安装最新版本。

这部分开始听起来像是您在尝试解决错误的问题。大概,你想确保你有一个最新的 matplotlib 因为你正在安装的其他东西需要它,是吗?所以你应该只使用正确的packaging tools,并在 setup.py 中将所需的 matplotlib 版本指定为requirement

【讨论】:

  • 感谢您的详细回复!我决定听从你的建议,而不是试图解决甚至可能不存在的问题。我已将检查添加到脚本中,警告用户他们使用过时的版本,并包含另一个批处理文件,该文件只是为最新的 matplotlib 运行安装。
  • 我能否进一步了解该脚本的实际用途?
  • 哦,这只是为了创造一些情节。它适用于 python 控制台的所有版本的 matplotlib,但是如果你尝试从终端运行脚本并且 matplotlib 版本是旧的,你会得到以下错误:attribute qt::aa_enablehighdpiscaling must be set before qcoreapplication is created. 因此需要有这个错误的最新版本固定的。问题是我们在公司环境下工作,你不能只运行 pip install 因为它会被防火墙阻止,我不能指望最终用户知道如何绕过它。
  • 如果您的用户不能只是 pip install 的东西,那么您究竟希望他们如何处理 matplotlib 版本不足的问题?就此而言,如果您在公司环境中,机器设置是由其他人决定的,为什么不使用相同的版本?
  • pip install 是可能的,但我知道有一个特定的--trusted-host,但我只是不想让使用我的脚本的人过于复杂。因此,将所需的安装命令简单地放在批处理文件中会更容易。
【解决方案2】:

我绝对同意这在 python 中会更容易,但如果你真的想用批处理脚本来做(也许它是你最喜欢的语言,你不能没有它???):

更新:现在可以正确处理版本字符串。

@ECHO OFF
setlocal
setlocal EnableDelayedExpansion 

::  this is the package which you need version of
set packageName=matplotlib

::  this is the minimum version you want
set desiredVersion=3.1.1

::  this will be filled by called function
set versionString=""

call :GetPythonPackageVersionString %packageName% versionString
if %versionString% == "" (
    ECHO PACKAGE %packageName% IS NOT INSTALLED OR COULD NOT BE FOUND!
    exit /b 1
)


::  remove spaces at the start and end
call :TrimLeadingTrailingSpaces %versionString% versionString


set versionOk=""
call :CompareVersionStrings %versionString% %desiredVersion% versionOk
if %versionOk% == "" (
    ECHO PACKAGE VERSION TOO LOW
    ECHO PLEASE UPDATE %packageName% VERSION %desiredVersion%
    exit /b 3
) else (
    ECHO PACKAGE VERSION IS OK
    exit /b 0
)

::  end of main
goto:eof






::
::  helper function for getting version of a python package
::  arg 1:takes package name as string
::  arg 2 (return value): package version as string (eg "3.10.0" without quotes)
::
:GetPythonPackageVersionString
set "command1=pip show %~1"
set "command2=findstr /I version:"

::  check if package exists
set var=""
FOR /F "tokens=* USEBACKQ" %%F IN (`%command1%`) DO (
set var=%%F
)
if %var% == "" (
    set %2=""
    ECHO GetPythonPackageVersionString --- PACKAGE COULD NOT BE FOUND
    goto:eof
)

::  use pip show + findstr to capture version string
FOR /F "tokens=* USEBACKQ" %%F IN (`%command1% ^| %command2%`) DO (
set var=%%F
)
::  check result of findstr
if ERRORLEVEL 1 (
    set %2="" 
    ECHO GetPythonPackageVersionString --- FINDSTR UNABLE TO FIND
    goto:eof
)

::  get right side of the string
::separate by comma
set %2=
FOR /F "tokens=2 delims=:" %%f in ("%var%") DO (
    set %2=%%f
)
goto:eof



::
::  I found this function from
::  https://stackoverflow.com/questions/3001999/how-to-remove-trailing-and-leading-whitespace-for-user-provided-input-in-a-batch
::  answer of Foumpie
::
:TrimLeadingTrailingSpaces
set %2=%1
goto:eof




::
::  Compares to version strings
::  arg 1: version string captured from pip
::  arg 2: desired version string
::  arg 3(return value): empty or y
::
:CompareVersionStrings
::  separate by . character to get version numbers
for /f "tokens=1,2,3 delims=." %%a in ("%1") do (
   set packageVersionNumber[1]=%%a
   set packageVersionNumber[2]=%%b
   set packageVersionNumber[3]=%%c
)
::ECHO MAJOR VERSION:%packageVersionNumber[1]%
::ECHO MINOR VERSION:%packageVersionNumber[2]%
::ECHO SUBMINOR VERSION:%packageVersionNumber[3]%

for /f "tokens=1,2,3 delims=." %%a in ("%2") do (
   set desiredVersionNumber[1]=%%a
   set desiredVersionNumber[2]=%%b
   set desiredVersionNumber[3]=%%c
)
::ECHO MAJOR VERSION:%desiredVersionNumber[1]%
::ECHO MINOR VERSION:%desiredVersionNumber[2]%
::ECHO SUBMINOR VERSION:%desiredVersionNumber[3]%

for /L %%i IN (1 1 3) do (
    if !packageVersionNumber[%%i]! GTR !desiredVersionNumber[%%i]! (
        REM package version is larger than desired one
        set %3="y"
        goto:eof
    ) else if !packageVersionNumber[%%i]! EQU !desiredVersionNumber[%%i]! (
        REM this version number is equal, continue checking with next one
    ) else (
        REM package version is less than desired one
        set %3=""
        goto:eof
    )
)    

::  if we are here, all version numbers are equal
set %3="y"
goto:eof

【讨论】:

  • 我对这里的努力程度印象深刻,但我可以向您保证GEQ 不足以比较版本字符串。例如,它认为"10.0.0" 不满足"9.9.9" 或更高版本的要求。
  • @KarlKnechtel 感谢您指出这一点!我实际上有一个版本,它将版本字符串点解析为分隔符,然后对整数执行比较,但完全忘记了这种情况并放置了这个版本,因为它更简单。我会尽快更新的 =)
猜你喜欢
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-23
相关资源
最近更新 更多