Nmktronas
Nmktronas

Reputation: 237

How to run PyLint for .pyproj when building it with MsBuild?

I need to run PyLint to validate my Python files code when building. The python files are under .pyproj (I use Python tools for Visual Studio 2015). How I can do that?

Update:

So far I have code like this:

<Target Name="PythonRunPyLint">
    <PropertyGroup>
        <PyLintWarningRegex><![CDATA[^(?<filename>.+?)\((?<line>\d+),(?<column>\d+)\): warning (?<msg_id>.+?): (?<message>.+?)$]]></PyLintWarningRegex>
    </PropertyGroup>
    <RunPythonCommand Target="pylint.lint"
                             TargetType="module"
                             Arguments="&quot;--msg-template={abspath}({line},{column}): warning {msg_id}: {msg} [{C}:{symbol}]&quot; -r n @(Compile, ' ')"
                             ExecuteIn="console"
                             WorkingDirectory="$(MSBuildProjectDirectory)"
                             WarningRegex="$(PyLintWarningRegex)"
                             RequiredPackages="pylint&gt;=1.0.0"> 
        <Output TaskParameter="ConsoleOutput" PropertyName="OutputText" />
        <Output TaskParameter="ConsoleError" PropertyName="ErrorText" />
    </RunPythonCommand>
</Target>

But when I run msbuild I get output and there's 0 warnings, why regex does not parse warnings (regex is taken from Microsoft.PythonTools.targets and it works when doing Tools > Run PyLint in Visual studio)?

C:\>msbuild TestPylint.pyproj /t:Build
Microsoft (R) Build Engine version 14.0.23107.0
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 15/10/2015 20:10:26.
Project "C:\TestPylint.pyproj" on node 1 (Build target(s)).
PythonRunPyLint:
************* Module TestPylint
C:\TestPylint.py(2,0): warning C0304: Final newline missing [C:missing-final-newline]
C:\TestPylint.py(1,0): warning C0111: Missing module docstring [C:missing-docstring]
No config file found, using default configuration
Done Building Project "C:\TestPylint.pyproj" (Build target(s)) -- FAILED.

Build FAILED.
    0 Warning(s)
    0 Error(s)

Upvotes: 1

Views: 1373

Answers (4)

Artyom
Artyom

Reputation: 36

The question is old, but I have spent some time on this issue. I suggest some improvements to the accepted answer by @Nmktronas, that solve the following problems:

  1. PyLint runs only after the Rebuild Command, and not after the Build Command.
  2. Annoying Console window popups during build.

Please see the comments in the code snippet.

  <!-- Problem: PyLint is running only for Rebuild command, and never runs for Build command.
       Solution: https://github.com/Microsoft/PTVS/issues/816: "The Outputs parameter of Target 
         node won't work, but if you add an item group called OutputFiles then we will compare 
         date/time stamps against those when deciding to build." -->
  <ItemGroup>
    <!-- Visible="false" prevents the file from showing in the Solution Window.-->
    <OutputFiles Include="lint_output.txt" 
                 Visible="false"/>
  </ItemGroup>

  <Target Name="BeforeBuild">
    <!-- ExecuteIn="none" value prevents appearance of the Console window. -->
    <RunPythonCommand Target="pylint.lint"
                      TargetType="module"
                      Arguments="&quot;--msg-template={path}({line},{column}): warning: [{msg_id}{obj}] {msg}&quot; -r n @(Compile, ' ')"
                      ExecuteIn="none"
                      WorkingDirectory="$(MSBuildProjectDirectory)"
                      RequiredPackages="pylint&gt;=1.0.0"
                      ConsoleToMSBuild="true"
                      ContinueOnError="true">
      <Output TaskParameter="ConsoleOutput" ItemName="OutputText" />
      <Output TaskParameter="ConsoleError" PropertyName="ErrorText" />
    </RunPythonCommand>
    <WriteLinesToFile File="lint_output.txt"
                      Lines="@(OutputText)"
                      Overwrite="true"
                      Encoding="Unicode"/>
    <Exec ContinueOnError="true"
          IgnoreExitCode="true"
          Command='type lint_output.txt'/>
  </Target>

Upvotes: 0

PaulB
PaulB

Reputation: 119

A slight variation on the solution presented by @Nmktronas.

<Target Name="CoreCompile">
  <ResolveEnvironment ContinueOnError="WarnAndContinue">
    <Output TaskParameter="InterpreterPath" PropertyName="InterpreterPath" />
  </ResolveEnvironment>
  <Exec Condition="Exists($(InterpreterPath))"
        Command="(set PYTHONPATH=$(SearchPath)) &amp; &quot;$(InterpreterPath)&quot; -m pylint.lint &quot;--msg-template={path}({line},{column}): warning: [{msg_id}{obj}] {msg}&quot; -r n @(Compile, ' ')"
        WorkingDirectory="$(MSBuildProjectDirectory)"
        IgnoreExitCode="true" />
</Target>

Upvotes: 0

Nmktronas
Nmktronas

Reputation: 237

I ended up with the following code:

<Target Name="Build">
    <RunPythonCommand Target="pylint.lint"
                         TargetType="module"
                         Arguments="&quot;--msg-template={path}({line},{column}): warning: [{msg_id}{obj}] {msg}&quot; -r n @(Compile, ' ')"
                         ExecuteIn="console"
                         WorkingDirectory="$(MSBuildProjectDirectory)"
                         RequiredPackages="pylint&gt;=1.0.0"
                         ConsoleToMSBuild="true"
                         ContinueOnError="true">
          <Output TaskParameter="ConsoleOutput" ItemName="OutputText" />
          <Output TaskParameter="ConsoleError" PropertyName="ErrorText" />
    </RunPythonCommand>
     <WriteLinesToFile
            File="lint_output.txt"
            Lines="@(OutputText)"
            Overwrite="true"
            Encoding="Unicode"/>
     <Exec ContinueOnError="true"
          IgnoreExitCode="true"
          Command='type lint_output.txt'/>
  </Target>

Now msbuild TestPylint.pyproj /t:Build counts errors/warnings also errors/warnings are shown on Visual Studio Error List window.

Task WriteLinesToFile is used because I did not found any other way for msbuild to recognize errors/warnings <Exec Command="echo $(OutputText)/> (if OutputText is property) simply does not work!

Upvotes: 0

Pavel Minaev
Pavel Minaev

Reputation: 101555

It's not wired up out of the box, but you can add it to your project if you're so inclined. Locate Microsoft.PythonTools.targets, and find <Target Name="PythonRunPyLintCommand" ... inside. Copy that to your project, rename it to something like "PythonRunPyLint", and inside it replace CreatePythonCommandItem with RunPythonCommand. You might also have to remove some attributes on that element (basically any that MSBuild will complain do not exist), and remove the child <Output>.

Then just start build with that target.

Upvotes: 1

Related Questions