开发 Python 项目时,你可能会发现自己切换到命令窗口以运行特定脚本或模块、运行 pip 命令,或者将其他工具用于代码。 若要改进工作流,可以将自定义命令添加到 Visual Studio 中的 Python 项目菜单。 自定义 Python 命令可以在控制台窗口或 Visual Studio 输出 窗口中运行。 还可以使用正则表达式来指示 Visual Studio 如何分析命令输出中的错误和警告。
先决条件
- 在 Windows 上安装的 Visual Studio 支持 Python 工作负载。 有关详细信息,请参阅 在 Visual Studio中安装 Python 支持。
不支持 Visual Studio for Mac。 有关详细信息,请参阅 Visual Studio for Mac 的最新情况。Windows、Mac 和 Linux 上的 Visual Studio Code 通过可用扩展可以很好地支持 Python。
浏览自定义命令
默认情况下,Python 项目菜单包含两个命令:运行 PyLint,运行 Mypy:
定义的任何自定义 Python 命令都将显示在同一菜单中。 自定义命令可以引用 Python 文件、Python 模块、内联 Python 代码、任意可执行文件或 pip 命令。 还可以指定命令的运行方式和位置。
可以通过多种方式添加自定义命令:
直接在 Python 项目文件中定义自定义命令(.pyproj)。 这些命令适用于该特定项目。
在目标文件中定义自定义命令(.targets)。 可以轻松导入此文件中的命令,以将其用于多个项目。
在 Visual Studio 中从定义自定义 Python 命令的项目模板创建 Python 项目。
Visual Studio 中的某些 Python 项目模板使用目标文件添加自定义命令。 Bottle Web 项目和 Flask Web 项目模板添加两个命令,启动服务器 和 启动调试服务器。 Django Web 项目模板添加这些命令和多个命令:
重新加载项目以访问自定义命令
在 Visual Studio 中打开项目时,如果在编辑器中对相应的项目文件进行更改,则必须重新加载项目以应用更改。 同样,在 Python 项目文件中定义自定义 Python 命令后,需要重新加载 Python 项目,以便命令显示在 Python 项目菜单上。 修改目标文件中定义的自定义命令时,需要为导入该目标文件的任何项目重新生成完整的 Visual Studio 解决方案。
一种常见方法是直接在 Visual Studio 中更改 Python 项目文件:
在 Visual Studio 中打开 Python 项目。 (在 Visual Studio 中打开项目时,默认情况下将加载该项目。)
在 解决方案资源管理器中,右键单击 Python 项目并选择 卸载项目。
Visual Studio 卸载项目,并在编辑器中打开相应的 Python 项目文件(.pyproj)。
如果项目文件未打开,请再次右键单击 Python 项目,然后选择 编辑项目文件:
在 Visual Studio 编辑器中更改项目文件并保存工作。
在 解决方案资源管理器中,右键单击卸载的项目,然后选择 重载项目。 如果尝试重新加载项目而不将更改保存到项目文件,Visual Studio 会提示你完成该操作。
在开发自定义命令时,“卸载-编辑-保存-重新加载”过程可能会变得繁琐。 更高效的工作流涉及同时在 Visual Studio 中加载项目并在单独的编辑器中打开 Python 项目文件。 可以使用任何编辑器,例如 Visual Studio 的另一个实例、Visual Studio Code、记事本等。 在编辑器中保存更改并切换回 Visual Studio 后,Visual Studio 会检测打开的项目的项目文件更改,并提示你采取措施:
选择 重新加载 或 重新加载所有,Visual Studio 会立即将项目文件更改应用到打开的项目。
使用项目文件添加自定义命令
以下过程演示如何通过在 Python 项目文件(.pyproj)中添加定义并在 Visual Studio 中重新加载项目来创建自定义命令。 自定义命令使用 python.exe
命令直接运行项目的启动文件,这与在 Visual Studio 主工具栏上使用“调试”>“开始执行(不调试)”选项基本相同。
在 Visual Studio 中,使用 Python 应用程序 模板创建名为 Python-CustomCommands 的新 Python 项目。 有关说明,请参阅 快速入门:从模板创建 Python 项目。
Visual Studio 将创建 Python 项目并将其加载到会话中。 可以通过项目文件(.pyproj)配置项目。 此文件仅在项目打开时在 Visual Studio 中可见,但不会加载。 该项目还具有应用程序代码的 Python 文件(.py)。
在编辑器中打开 Python_CustomCommands.py 应用程序文件并添加以下代码:
print("Hello custom commands")
在 解决方案资源管理器中,右键单击 Python 项目,选择 Python,并注意上下文菜单上的命令。 目前,上下文菜单上的唯一命令是 运行 PyLint,运行 Mypy。 定义自定义命令时,它们也会在此菜单上显示。
在 Visual Studio 会话之外启动单独的编辑器,并在编辑器中打开 Python 项目文件(Python-CustomCommands.pyproj)。 (请务必打开项目文件(.pyproj),而不是 Python 应用程序文件(.py)。
在项目文件中,找到文件末尾的结尾
</Project>
元素,并在结尾元素前直接添加以下 XML:<PropertyGroup> <PythonCommands> $(PythonCommands); </PythonCommands> </PropertyGroup>
保存项目文件更改,然后切换回 Visual Studio。 Visual Studio 会检测项目文件更改,并提示你采取措施。 在提示符处,选择“重新加载”,以使用项目文件更改更新打开的项目。
在 解决方案资源管理器中,右键单击 Python 项目,选择 Python,然后检查上下文菜单上的命令。
上下文菜单仍仅显示 运行 PyLint,并 运行 Mypy 命令。 刚添加到项目文件的代码只是复制包含 PyLint 命令的默认
<PythonCommands>
属性组。 在下一步中,为自定义命令添加更多代码。切换到正在更新项目文件的编辑器。 在
<Project>
元素中添加以下<Target>
元素定义。 可以在前面所述的<PropertyGroup>
定义之前或之后放置<Target>
定义。此
<Target>
元素定义一个自定义命令,以便在控制台窗口中使用python.exe
命令运行项目的启动文件(由 StartupFile 属性标识)。 属性定义ExecuteIn="consolepause"
使用的控制台需要您按下任意键才能关闭窗口。<Target Name="Example_RunStartupFile" Label="Run startup file" Returns="@(Commands)"> <CreatePythonCommandItem TargetType="script" Target="$(StartupFile)" Arguments="" WorkingDirectory="$(MSBuildProjectDirectory)" ExecuteIn="consolepause"> <Output TaskParameter="Command" ItemName="Commands" /> </CreatePythonCommandItem> </Target>
将
<PythonCommands>
属性组(步骤 5中添加)替换为以下 XML。 此语法定义<Target>
元素的Name
属性,该属性将自定义命令添加到 Python 上下文菜单。 该命令具有菜单标签 运行启动文件。<PythonCommands> $(PythonCommands); Example_RunStartupFile </PythonCommands>
提示
如果希望自定义命令显示在
$(PythonCommands)
标记中定义的默认命令之前,请将命令的<Target>
语法置于该标记之前。保存项目文件更改,然后切换回 Visual Studio。 在提示符下,重新加载项目。
在 解决方案资源管理器中,右键单击 Python 项目,选择 Python,然后重新检查上下文菜单上的命令。
现在,菜单中有自定义 运行启动文件 命令。 如果未看到自定义命令,请确认已将
<Target>
元素的Name
属性值添加到<PythonCommands>
元素,如步骤 9 中所述。 另请参阅本文后面的 故障排除 部分中所列的注意事项。选择 运行启动文件 命令。 将打开一个控制台窗口并显示文本“了解自定义命令”,后接“按任意键继续操作”。 确认输出并关闭控制台窗口。
注意
自定义命令脚本在 Python 项目的激活环境中运行。
使用项目文件切换到编辑器。 在
<Target>
元素定义(步骤 8中添加)中,将ExecuteIn
属性的值更改为output
。<CreatePythonCommandItem ... ExecuteIn="output"> ... </CreatePythonCommandItem>
保存更改,切换回 Visual Studio,然后重新加载项目。
再次从 Python 上下文菜单中选择 运行启动文件 自定义命令。 现在,程序输出会显示在 Visual Studio 输出 窗口中,而不是控制台窗口:
若要添加更多自定义命令,请遵循以下相同的过程:
为项目文件中的自定义命令定义合适的
<Target>
元素。将
<Target>
元素的Name
属性值添加到<PythonCommands>
属性组中。保存对项目文件的更改。
在 Visual Studio 中重新加载项目。
使用项目属性
若要引用 <Target>
元素属性值中的项目属性或环境变量,请使用 $()
令牌中的属性名称,例如 $(StartupFile)
和 $(MSBuildProjectDirectory)
。 有关详细信息,请参阅 MSBuild 属性。
如果调用 ($StartupFile)
等命令,该命令使用项目属性(如 StartupFile 属性)并且命令失败,因为令牌未定义,Visual Studio 将在重新加载项目之前禁用该命令。 如果对修改属性定义的项目进行更改,则所做的更改不会刷新相关命令的状态。 在这种情况下,仍需要重新加载项目。
了解 Target 元素结构<>
使用 <Target>
元素定义自定义命令的详细信息。 <Target>
元素的一般形式显示在以下伪代码中:
<Target Name="Name1" Label="Display Name" Returns="@(Commands)">
<CreatePythonCommandItem Target="filename, module name, or code"
TargetType="executable/script/module/code/pip"
Arguments="..."
ExecuteIn="console/consolepause/output/repl[:Display name]/none"
WorkingDirectory="..."
ErrorRegex="..."
WarningRegex="..."
RequiredPackages="...;..."
Environment="...">
<!-- Output always appears in this form, with these exact attributes -->
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
目标属性
下表列出了 <Target>
元素属性。
属性 | 必需 | 描述 |
---|---|---|
Name |
是的 | Visual Studio 项目中命令的标识符。 必须将此名称添加到 <PythonCommands> 属性组中,命令才能显示在 Python 上下文菜单上。 |
Label |
是的 | Python 环境菜单中显示的 UI 名称。 |
Returns |
是的 | 返回的信息,必须包含 @(Commands) 令牌,该令牌将目标标识为命令。 |
CreatePythonCommandItem 属性
<Target>
元素包含 <CreatePythonCommandItem>
和 <Output>
元素,这些元素定义自定义命令的详细行为。 下表列出了可用的 <CreatePythonCommandItem>
元素属性。 所有属性值都不区分大小写。
Attribute |
必需 | 描述 |
---|---|---|
TargetType |
是的 | 指定 Target 属性包含的内容以及值与 Arguments 属性一起使用的方式:- executable :运行在 Target 属性中命名的可执行文件,在 Arguments 属性中追加值,就像直接在命令行上输入一样。 该值必须仅包含没有参数的程序名称。 - script :运行 python.exe 命令,使用 Target 属性中的文件名,然后是 Arguments 属性中的值。 - module :运行 python -m 命令,后跟 Target 属性中的模块名称,后跟 Arguments 属性中的值。 - code :运行 Target 属性中包含的内联代码。 忽略 Arguments 属性值。 - pip :使用 Target 属性中的命令运行 pip,后跟 Arguments 属性中的值。 如果 ExecuteIn 属性设置为 output ,pip 假定请求是运行 install 命令,并使用 Target 属性作为包名称。 |
Target |
是的 | 根据 TargetType 特性的值,指定要使用的文件名、模块名称、代码或 pip 命令。 |
Arguments |
自选 | 提供要与 Target 属性一起使用的参数字符串(如果有)。 - 当 TargetType 属性值 script 时,Arguments 值将提供给 Python 程序,而不是 python.exe 命令。 - 当 TargetType 属性值 code 时,将忽略 Arguments 值。 |
ExecuteIn |
是的 | 指定要在其中运行命令的环境: - console :(默认)将 Arguments 值与 Target 属性一起运行,就像直接在命令行中输入它们一样。 当 Target 属性正在运行时,将显示一个命令窗口并自动关闭。 - consolepause :与 console 行为相同,但在关闭窗口前会等待用户按键。 - output :运行 Target 属性,并在 Visual Studio 输出 窗口中显示结果。 如果 TargetType 属性 pip ,Visual Studio 将使用 Target 属性作为包名称,并追加 Arguments 属性值。 - repl :在 Python 交互式窗口中运行 Target 属性。 可选显示名称用于窗口的标题。 - none :与 console 行为相同。 |
WorkingDirectory |
自选 | 标识运行命令的文件夹。 |
ErrorRegex WarningRegEx |
自选 | 仅在 ExecuteIn 属性设置为 output 时才使用。 这两个属性值都指定 Visual Studio 用于分析命令输出并在 错误列表 窗口中显示错误和警告的正则表达式。 如果未指定这些属性,该命令不会影响 错误列表 窗口。 有关 Visual Studio 所需内容的详细信息,请参阅命名的捕获组。 |
RequiredPackages |
自选 | 使用与 requirements.txt 文件(pip.readthedocs.io)相同的格式提供命令的包要求列表。 例如,Run PyLint 命令指定格式 pylint>=1.0.0 。 在运行命令之前,Visual Studio 会确认列表中已安装所有包。 Visual Studio 使用 pip 安装任何缺失的包。 |
Environment |
自选 | 标识在运行命令之前要定义的环境变量字符串。 每个变量的格式为 \<NAME>=\<VALUE> ,多个变量之间用分号分隔。 具有多个值的变量必须包含在单引号或双引号中,如 'NAME=VALUE1;VALUE2' 所示。 |
正则表达式的命名的捕获组
当 Visual Studio 从自定义命令输出中解析错误和警告时,它期望 ErrorRegex
和 WarningRegex
属性值中的正则表达式包含以下命名组:
(?<message>...)
:错误文本。(?<code>...)
:错误代码值。(?<filename>...)
:报告错误的文件的名称。(?<line>...)
:报告错误的文件中位置的行号。(?<column>...)
:报告错误的文件中位置的列号。
例如,PyLint 生成以下形式的警告:
************* Module hello
C: 1, 0: Missing module docstring (missing-docstring)
若要允许 Visual Studio 从这些警告中提取正确的信息,并将其显示在 错误列表 窗口中,Run Pylint 命令的 WarningRegex
属性值如下所示:
^(?<filename>.+?)\((?<line>\d+),(?<column>\d+)\): warning (?<msg_id>.+?): (?<message>.+?)$]]
注意
WarningRegex
属性值中的 msg_id
语法实际上应是 code
,如问题 3680 中所述。
使用目标文件导入自定义命令
如果在 Python 项目文件中定义自定义命令,则命令仅适用于该特定项目。 如果要创建自定义命令并将其用于多个项目中,可以使用目标文件(.targets)中的所有 <Target>
元素定义 <PythonCommands>
属性组,然后将该文件导入 Python 项目。
目标文件使用相同的格式和语法来定义 Python 项目文件描述的自定义命令(.pyproj)。 要配置的常见元素包括
<PythonCommands>
、<Target>
、<CreatePythonCommandItem>
和<Output>
:<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <PythonCommands> $(PythonCommands); <!-- Additional command names --> </PythonCommands> </PropertyGroup> <Target Name="..." Label="..." Returns="@(Commands)"> <!-- CreatePythonCommandItem and Output elements... --> </Target> <!-- Any number of additional Target elements--> </Project>
若要将目标文件导入项目,请在项目文件中
<Project>
元素中的任何位置添加<Import Project="(path)">
元素。例如,如果在 Python 项目的 目标 文件夹中,有一个名为 CustomCommands.targets 的项目文件,请将以下代码添加到项目文件中:
<Import Project="targets/CustomCommands.targets"/>
如果项目文件导入目标文件,并且你在 Visual Studio 中打开项目时对目标文件进行更改,则需要重新生成包含该项目的 Visual Studio 解决方案,而不仅仅是项目。
示例命令
以下部分提供了可用于为 Python 项目定义自定义命令的示例代码。
运行 PyLint(模块目标)
以下代码显示在 Microsoft.PythonTools.targets 文件中:
<PropertyGroup>
<PythonCommands>$(PythonCommands);PythonRunPyLintCommand</PythonCommands>
<PyLintWarningRegex>
<![CDATA[^(?<filename>.+?)\((?<line>\d+),(?<column>\d+)\): warning (?<msg_id>.+?): (?<message>.+?)$]]>
</PyLintWarningRegex>
</PropertyGroup>
<Target Name="PythonRunPyLintCommand"
Label="resource:Microsoft.PythonTools.Common;Microsoft.PythonTools.Common.Strings;RunPyLintLabel"
Returns="@(Commands)">
<CreatePythonCommandItem Target="pylint.lint"
TargetType="module"
Arguments=""--msg-template={abspath}({line},{column}): warning {msg_id}: {msg} [{C}:{symbol}]" -r n @(Compile, ' ')"
WorkingDirectory="$(MSBuildProjectDirectory)"
ExecuteIn="output"
RequiredPackages="pylint>=1.0.0"
WarningRegex="$(PyLintWarningRegex)">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
使用特定包运行 pip 安装(pip 目标)
以下命令在 Visual Studio 输出 窗口中运行 pip install my-package
命令。 开发包并测试其安装时,可以使用如下所示的命令。 <Target>
元素包含包名称,而不是使用 ExecuteIn="output"
属性定义时假定的 install
命令。
<PropertyGroup>
<PythonCommands>$(PythonCommands);InstallMyPackage</PythonCommands>
</PropertyGroup>
<Target Name="InstallMyPackage" Label="pip install my-package" Returns="@(Commands)">
<CreatePythonCommandItem Target="my-package" TargetType="pip" Arguments=""
WorkingDirectory="$(MSBuildProjectDirectory)" ExecuteIn="output">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
显示过时的 pip 包(pip 目标)
以下命令使用 list
函数运行 pip,以标识过时的 pip 包:
<PropertyGroup>
<PythonCommands>$(PythonCommands);ShowOutdatedPackages</PythonCommands>
</PropertyGroup>
<Target Name="ShowOutdatedPackages" Label="Show outdated pip packages" Returns="@(Commands)">
<CreatePythonCommandItem Target="list" TargetType="pip" Arguments="-o --format columns"
WorkingDirectory="$(MSBuildProjectDirectory)" ExecuteIn="consolepause">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
使用 consolepause 运行可执行文件
以下命令运行 where
函数以显示从项目文件夹开始的 Python 文件的位置:
<PropertyGroup>
<PythonCommands>$(PythonCommands);ShowAllPythonFilesInProject</PythonCommands>
</PropertyGroup>
<Target Name="ShowAllPythonFilesInProject" Label="Show Python files in project" Returns="@(Commands)">
<CreatePythonCommandItem Target="where" TargetType="executable" Arguments="/r . *.py"
WorkingDirectory="$(MSBuildProjectDirectory)" ExecuteIn="output">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
运行服务器并运行调试服务器命令
若要了解如何定义 web 项目的 启动服务器 和 启动调试服务器 命令,请检查 GitHub 上的 Microsoft.PythonTools.Web.targets 存储库。
安装开发程序包
以下代码运行 pip 来安装包:
<PropertyGroup>
<PythonCommands>PipInstallDevCommand;$(PythonCommands);</PythonCommands>
</PropertyGroup>
<Target Name="PipInstallDevCommand" Label="Install package for development" Returns="@(Commands)">
<CreatePythonCommandItem Target="pip" TargetType="module" Arguments="install --editable $(ProjectDir)"
WorkingDirectory="$(WorkingDirectory)" ExecuteIn="Repl:Install package for development">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
来自 fxthomas/Example.pyproj.xml (GitHub),经授权使用。
生成 Windows 安装程序
以下脚本生成 Windows 安装程序:
<PropertyGroup>
<PythonCommands>$(PythonCommands);BdistWinInstCommand;</PythonCommands>
</PropertyGroup>
<Target Name="BdistWinInstCommand" Label="Generate Windows Installer" Returns="@(Commands)">
<CreatePythonCommandItem Target="$(ProjectDir)setup.py" TargetType="script"
Arguments="bdist_wininst --user-access-control=force --title "$(InstallerTitle)" --dist-dir="$(DistributionOutputDir)""
WorkingDirectory="$(WorkingDirectory)" RequiredPackages="setuptools"
ExecuteIn="Repl:Generate Windows Installer">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
来自 fxthomas/Example.pyproj.xml (GitHub),经许可使用。
生成 Python 滚轮包
以下脚本生成 Python wheel 包:
<PropertyGroup>
<PythonCommands>$(PythonCommands);BdistWheelCommand;</PythonCommands>
</PropertyGroup>
<Target Name="BdistWheelCommand" Label="Generate Wheel Package" Returns="@(Commands)">
<CreatePythonCommandItem Target="$(ProjectDir)setup.py" TargetType="script"
Arguments="bdist_wheel --dist-dir="$(DistributionOutputDir)""
WorkingDirectory="$(WorkingDirectory)" RequiredPackages="wheel;setuptools"
ExecuteIn="Repl:Generate Wheel Package">
<Output TaskParameter="Command" ItemName="Commands" />
</CreatePythonCommandItem>
</Target>
来自 fxthomas/Example.pyproj.xml (GitHub),经许可使用。
自定义命令故障排除
查看以下部分,了解与使用自定义命令相关的可能问题。
未加载项目文件
此错误消息指示项目文件中存在语法错误。 该消息包含特定错误的详细信息,包括行号和字符位置。
命令运行后控制台窗口关闭
如果在运行命令后立即关闭控制台窗口,请使用 ExecuteIn="consolepause"
属性定义,而不是 ExecuteIn="console"
。
菜单中缺少命令
如果在 Python 上下文菜单上看不到自定义命令,请检查以下项:
- 确认命令包含在
<PythonCommands>
属性组中。 - 验证命令列表定义的命令名称是否与
<Target>
元素中指定的名称匹配。
下面是一个示例。 在以下 XML 代码片段中,<PythonCommands>
属性组中 Example
名称与 <Target>
元素定义中的 ExampleCommand
名称不匹配。 Visual Studio 找不到名为 Example
的命令,因此不会显示任何命令。 在命令列表中使用 ExampleCommand
,或者将目标的名称更改为仅 Example
。
<PropertyGroup>
<PythonCommands>$(PythonCommands);Example</PythonCommands>
</PropertyGroup>
<Target Name="ExampleCommand" Label="Example Command" Returns="@(Commands)">
<!-- ... -->
</Target>
运行命令时出错,无法获取命令目标
此错误消息指示 <Target>
或 <CreatePythonCommandItem>
元素的内容不正确。
下面是此错误的一些可能原因:
- 必需的
<Target>
元素属性为空。 - 必需的
TargetType
属性为空或包含无法识别的值。 - 必需的
ExecuteIn
属性为空或包含无法识别的值。 - 指定
ErrorRegex
或WarningRegex
属性,而不设置ExecuteIn="output"
属性定义。 - 元素中存在无法识别的属性。 例如,属性引用可能拼错为
Argumnets
而不是Arguments
。
如果引用未定义的属性,属性值可以为空。 如果使用令牌 $(StartupFile)
但项目中未定义启动文件,则令牌解析为空字符串。 在这种情况下,可能需要定义默认值。 例如,运行服务器 和 运行调试服务器 在 Bottle、Flask 和 Django 项目模板中定义的命令默认使用 manage.py 文件(如果未在项目属性中指定服务器启动文件)。
Visual Studio 停止响应,崩溃
如果 Visual Studio 在运行自定义命令时停止响应并崩溃,可能是因为您尝试使用带有 ExecuteIn="output"
属性定义的控制台命令。 在这种情况下,Visual Studio 在尝试分析输出时可能会崩溃。 若要避免这种情况,请改用 ExecuteIn="console"
属性定义。 有关详细信息,请参阅 问题 3681。
命令无法识别为可操作的程序或批处理文件
设置 TargetType="executable"
属性定义时,Target
属性中的值只能是不带任何参数的程序名称,例如只能是 python
或 python.exe
。 在这种情况下,请将任何参数移动到 Arguments
属性。