Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need a way to find tools (linters, formatters) via PATH #4922

Closed
pfmoore opened this issue Mar 26, 2019 · 41 comments
Closed

Need a way to find tools (linters, formatters) via PATH #4922

pfmoore opened this issue Mar 26, 2019 · 41 comments
Assignees
Labels
area-formatting area-linting feature-request Request for new features or functionality

Comments

@pfmoore
Copy link

pfmoore commented Mar 26, 2019

Unless I'm misunderstanding something, if I enable a linter like flake8, VS Code expects it to be installed in my Python environment (and specifically, if I don't set Flake8Path in my settings, that's where the extension will look).

I don't install tools like flake8 or black under my project - rather, I have a separate installation using a tool-specific virtualenv (essentially using a mechanism like pipx to manage my tools, although I actually use a custom solution). So I have flake8 and black commands on my PATH.

If I want to use my globally-installed tools, I appear to have to specify the exact path to them in my VS Code settings - which is not ideal, as the whole point of installing them centrally is that no other tools have to know where they are located, they can just access them via PATH. As things stand, if I move my tool directory, my VS Code config breaks.

Please provide a way to tell VS Code to search PATH for tool locations. Even if it's not the default, and I need to check something that says "search for flake8 on PATH", etc, that would at least allow me to make my VS Code configuration portable.

@ghost ghost added the triage-needed Needs assignment to the proper sub-team label Mar 26, 2019
@DonJayamanne
Copy link

  • As things stand, if I move my tool directory, my VS Code config breaks.
    • Unfortunately that's not something we can fix.
    • The same applies to, If i move my interpreter VS Code config breaks
  • As things stand, if I move my tool directory, my VS Code config breaks.
    • You can update your global user settings.json file,
    • This way you need to only update one settings.json file (scoped to one place/one file)
  • Install your tools in a the --user space (pip install with --user option)
    • Let me know how that goes
  • Also try creating a .env file in your workspace
    • Ensure to add a variable for PYTHONPATH=xyz where xyz is the location where your tools reside.

Closing as there are at least 2 alternatives today (define path to tool in user config or install tool with --user option).

@ghost ghost removed the triage-needed Needs assignment to the proper sub-team label Mar 26, 2019
@pfmoore
Copy link
Author

pfmoore commented Mar 26, 2019

As things stand, if I move my tool directory, my VS Code config breaks.

  • Unfortunately that's not something we can fix.
  • The same applies to, If i move my interpreter VS Code config breaks

As things stand, if I move my tool directory, my VS Code config breaks.

  • You can update your global user settings.json file,
  • This way you need to only update one settings.json file (scoped to one place/one file)

OK, so basically both of these are "you have to hard code the paths, and update the settings if they change". I know that's an option, but IMO it's not ideal. I guess if you're saying "tough", I have to put up with that :-(

Install your tools in a the --user space (pip install with --user option)

  • Let me know how that goes

That has the same problem as installing into a specific Python interpreter, it's linked to the system installation. Unless I'm misunderstanding you, the tool won't be visible if I'm working on code that uses a different environment.

Also try creating a .env file in your workspace

  • Ensure to add a variable for PYTHONPATH=xyz where xyz is the location where your tools reside.

I don't know what you mean here, the tools are exe files (flake8.exe) so PYTHONPATH isn't relevant, is it?

@gramster
Copy link
Member

gramster commented Apr 5, 2019

Re-opening this issue as we haven't addressed the customer's issue.

@gramster gramster reopened this Apr 5, 2019
@ghost ghost added the triage-needed Needs assignment to the proper sub-team label Apr 5, 2019
@DonJayamanne DonJayamanne added needs decision feature-request Request for new features or functionality labels Apr 5, 2019
@ghost ghost removed triage-needed Needs assignment to the proper sub-team labels Apr 5, 2019
@DonJayamanne
Copy link

DonJayamanne commented Apr 5, 2019

I don't know what you mean here, the tools are exe files (flake8.exe) so PYTHONPATH isn't relevant, is it?

Oops, you are right, I meant PATH.

@pfmoore
Copy link
Author

pfmoore commented Apr 5, 2019

OK, so maybe I'm still confused. My user settings.json contains just

{
    "workbench.iconTheme": "vscode-icons",
    "vsicons.dontShowNewVersionMessage": true
}

My PATH environment variable contains E:\Utils\PyTools\bin, and in that directory I have E:\Utils\PyTools\bin\pylint.exe (which works fine from the command line).

When I open my project directory, I get the error "Linter pylint is not installed". So it doesn't seem to be searching PATH.

You mention a .env file - which, according to #544 (and my attempts to search for information) isn't documented. But even from the information in #544, I'm not clear how I'd write something in a .env file that would add a directory to PATH (rather than just replacing the whole value) - and even if I could, would that not mean I'd have to put something in every project where I wanted to use a linter? That seems even less portable than hard-coding the full path to pylint...

It's entirely possible I'm doing something wrong here, I'm only just starting to experiment with linter support, and I acknowledge that my preference for not installing a linter into every project environment is uncommon. But if so, I'd still like to know what it is that I'm getting wrong.

@DonJayamanne
Copy link

would that not mean I'd have to put something in every project where I wanted to use a linter? That seems even less portable than hard-coding the full path to pylint...

Unfortunately we currently do not have a solution for this. Please leave this with me, and we'll get back to you on this.

@pfmoore
Copy link
Author

pfmoore commented Apr 5, 2019

OK, no problem - glad at least that it's not me doing something wrong (I can hard-code the path for now, so it's not urgent).

@brettcannon
Copy link
Member

To give some history, we actually originally searched PATH for tools like flake8 and black, but the amount of bug reports we got from people who weren't sophisticated enough to have their PATH set appropriately to have the tool on PATH (or at least the version they wanted at the front), we decided to change to our -m approach + explicit paths.

If someone wanted to work on an opt-in solution to also search PATH we would be open to discussing on how to implement it.

@BeyondEvil

This comment has been minimized.

@vccortez
Copy link

vccortez commented Feb 29, 2020

My issue #6221 (closed as a duplicate). My issue seems a bit different, but whatever.

Maybe someone could tell me what I need to put in the settings.json to accomplish what I want? I'm happy to install my tools globally - but I need a way to point VSC to them.

I'm mostly using black, rope, and flake8

Installing them globally using --user does not work. At least not when a project is using a venv (I use pipenv)

I can see how this is related to this issue, which seems especially bad for refactoring tools like rope that don't have special settings, such as python.formatting.yapfPath or python.linting.pylintPath.

Am I wrong here or is there a workaround that allows using a virtual environment and using a tool like rope installed outside this environment?

@brettcannon
Copy link
Member

@vekat rope is a special case in that we don't have support for it being installed somewhere else. Otherwise all the linters and formatters have a way to specify their location outside of the virtual environment

@vccortez
Copy link

vccortez commented Mar 8, 2020

Alright. Well, in case anyone else faces this issue with tools like rope, that don't have a special installation path setting, I was able to circumvent it by setting include-system-site-packages = true in my virtual environment's pyvenv.cfg.

@hauntsaninja
Copy link

+1 on this thread.

If someone wanted to work on an opt-in solution to also search PATH we would be open to discussing on how to implement it.

@brettcannon I'd potentially be interested in contributing! Let me know what your thoughts on fixing this are. In an attempt to show good faith, I did some quick grepping. It seems like tools can provide a ExecutionInfo that has execPath and moduleName. Currently, while providing this info, we seem to check if execPath is just a basename, and if so, set moduleName to it.

It seems like the following could be good:

  • If execPath exists, use it (non-default execPath, that is, since we maybe seem to also be using execPath as a way of storing the tool name?)
  • Otherwise, attempt to use a module (using moduleName)
  • Otherwise, search on PATH (potentially only if opted in)
  • If none of these work, pop the existing error handling dialog that allows you to install the module.

I think we could maybe get away without adding an additional setting to opt in to this? The annoying case is when you have the tool installed, but VSCode fails to find it. This would fix that.
Unsavvy users who don't know about PATH would never have to attempt to change their PATH.
Users can continue to easily change the tool version by changing the interpreter VSCode uses. So the workflow for getting a specific version of a tool is the same as it is today.

The bad case here seems to be if you have multiple versions of a tool installed, you're savvy enough to care about the differences between versions, the version on your PATH is different from your current interpreter module version and you don't know how to change your current interpreter. In which case I don't think you're better off in today's world.

@brettcannon
Copy link
Member

@hauntsaninja thanks for the offer to implement! Let us have a chat on our end and we can get back to you.

@brettcannon brettcannon added needs proposal Need to make some design decisions and removed needs PR labels May 7, 2020
@wpyoga
Copy link

wpyoga commented May 9, 2022

I have been running into this issue for some time now, and right now I'm using a workaround, which works for my own use case:

  • set python.formatting.blackPath to /usr/bin/env
  • set python.formatting.blackArgs to ["black"]

With the above workaround, my globally-installed black is always found and used, regardless of whether I'm using a virtual environment or not. So for now, my needs are met.

My actual use case is:

  • I have black installed globally using pip, but only on my user account (~/.local/bin/black). It is not installed in the system directories. So on the terminal, black is accessible because its location is in my $PATH.
  • I don't want to hardcode the path to black in my VS Code settings, because at some point I may forget, or I might want to use my distro-provided black package instead.
  • I sometimes work with virtual environments. To prevent pip freeze from missing libraries, I don't want to allow the virtual environment to use system libraries.
  • I don't want to install black in the virtual environment, because then it will be included when I run pip freeze. It is only a dev dependency, and I don't want to production deployments to have to install a code formatter.

That said, I believe that something needs to be done. I am observing the same behaviour as @TBBle , and this is what I know so far, without reading the source code:

  • if python.formatting.blackPath is an empty string, then an error will happen when trying to format a file (The argument 'file' cannot be empty.)
  • if python.formatting.blackPath is unset, then it would try to run <interpreter> -m black <...blackArgs> ...
  • if python.formatting.blackPath does not contain a slash (I'm on Linux), then it would try to run <interpreter> -m <blackPath> <...blackArgs> ...
  • if python.formatting.blackPath contains a slash but does not start with slash, then it would try to run ./<blackPath> <...blackArgs> ...
  • if python.formatting.blackPath starts with a slash, then it would try to run <blackPath> <...blackArgs> ...

The above behavior shows that:

  • there is some kind of improper edge case handling, when blackPath is an empty string
  • blackPath is not strictly a path -- it is sometimes treated as a module name, which means the configuration entry is a misnomer

I haven't really thought this through, and I could not give a good suggestion or solution.

There are a few things I've considered:

  • rename blackPath to blackModuleOrPath: the issue is, it would not enable users to set it to "black" and have the "black" executable be searched in $PATH; also, the name may be confusing
  • add another config option blackModuleName for the module name, and treat blackPath as an executable, regardless of its contents: the issue is, if both are set, which one takes precedence? if both are unset, what's the behavior? and, with two configuration entries, would it be confusing for the user?

@hauntsaninja
Copy link

hauntsaninja commented May 9, 2022

[VSCode isn't open to accepting a PR] at the moment, no. The "needs spec" label means we need to think through a potential design before we could accept a PR that would implement that (currently) non-existent spec.

The spec I proposed in #4922 (comment) went like:

  • If execPath exists, use it (non-default execPath, that is, since we maybe seem to also be using execPath as a way of storing the tool name)
  • Otherwise, attempt to use a module (using moduleName)
  • Otherwise, search on PATH (potentially only if opted in)
  • If none of these work, pop the existing error handling dialog that allows you to install the module.

Curious for thoughts on that design!

I believe this addresses Brett's concern with the previous behaviour that looked at PATH (#4922 (comment))

(And of course, I am happy to contribute a PR if a VSCode is willing to accept one. And let me know if there's something else I could do that would be constructive)

@brettcannon
Copy link
Member

Do note we have released a stand-alone Black extension which ships with Black in the box, so specifying the path to an installation of Black is now entirely optional with that extension.

@jeremyn
Copy link

jeremyn commented May 9, 2022

@brettcannon That is definitely useful for Black, though of course this issue still remains for all other linters etc.

I notice the description for black-formatter.path in your link includes as examples both an executable path and a module name, so I suppose the word path is the plan going forward to refer to either an executable or a module name in all cases, contrary to @wpyoga's suggestions in #4922 (comment).

In your link, what does this mean:

The bundled black is only used if there is no installed version of black found in the selected python environment.

I have not tested this. Does the extension go hunting for black in various specific locations in your environment, or does it use some PATH setting in the user's environment, or do you have to specify the black-formatter.path setting? For the first two options, can that logic be used to hunt for linters etc generally (the main point of this GitHub issue)?

@jeremyn
Copy link

jeremyn commented May 10, 2022

It looks like Microsoft has recently released a suite of specific-to-one-tool extensions: Black, isort, Pylint. They all have similar wording so my previous comment applies to all of them.

(No mypy extension...yet?)

@brettcannon
Copy link
Member

I turned #4922 (comment) into an issue on the Black formatter extension. I'll answer questions not specific to that extension here.

of course this issue still remains for all other linters etc.

The plan is to drop all linters and formatters from this extension and rely on separate extensions for the linters and formatters we will support going forward. They will all be based on a template we are creating for extensions wrapping Python tools. The solution we come up with for the Pylint and Black extensions will become the solution for all of the extensions.

(No mypy extension...yet?)

We have not decided if we are going to do a mypy extension ourself as https://marketplace.visualstudio.com/items?itemName=matangover.mypy already exists.

@jeremyn
Copy link

jeremyn commented May 10, 2022

@brettcannon

I'll answer questions not specific to that extension here.

Thanks, however, since the Black and Pylint and other extensions all behave similarly, it might be better to just explain in this issue how they find a local version of the tool, instead of explaining once in microsoft/vscode-black-formatter#42 and again here. I don't have any questions for you that are specific to the Black extension.

@TBBle
Copy link

TBBle commented May 11, 2022

I think the point is that the local-version-finding logic in the extension (which is already be different than in this code-base, since there's a bundle copy of black taken into consideration as well) is going to be part of the template for all the other code formatters, so it makes sense to get it right over there, and not confuse it about how the to-be-removed code in the main python extension works.

Discussing the new extension's behaviour here is just going to confuse matters since the code that would be changed by the discussion is not in this repo, and most of the existing discussion here relates to config and behaviours in this repo, and since they will (eventually) be removed, they probably aren't worth a lot of time to change in any major way, even to match the behaviour of the new extension as it evolves.

@jeremyn
Copy link

jeremyn commented May 11, 2022

@TBBle There's a general issue tracking problem of where to discuss some common behavior in repos A, B, and C. I don't know how the VS Code Python team wants to handle that generally. In this case though, given three years of history I hope that we can keep the discussion here until it's resolved, instead of moving it off to some other repo, even if doing so might be strictly more appropriate. We should all understand now that we're talking about the local-version-finding logic in these new extensions, not in the core Python extension, where it will be removed in the near future.

Also I want to be clear that I don't have any questions for anyone about the Black extension specifically so I'm not personally interested in following up on microsoft/vscode-black-formatter#42. So, @brettcannon can close that as far as I'm concerned.

@jeremyn
Copy link

jeremyn commented May 11, 2022

@brettcannon

We have not decided if we are going to do a mypy extension ourself as https://marketplace.visualstudio.com/items?itemName=matangover.mypy already exists.

I've had several conversations recently with VS Code team members in microsoft/vscode-remote-release#6608 and various linked issues about extension trust. They lean pretty hard on the expectation that it's entirely the user's responsibility to only install extensions they trust.

With that in mind, if you mean that you intend to remove mypy integration from the main Python extension, and not make an official vscode-mypy replacement, but instead refer users unofficially to @matangover's extension without giving it first-class support or review, then that's a loss as far as I'm concerned. I mean no disrespect to @matangover personally. I'd ask that mypy integration stay in the core Python extension until some amicable arrangement can be made with @matangover.

@brettcannon
Copy link
Member

There's a general issue tracking problem of where to discuss some common behavior in repos A, B, and C. I don't know how the VS Code Python team wants to handle that generally.

Please do it on the issue I created in the Black formatter repo.

if you mean that you intend to remove mypy integration from the main Python extension

Yes.

and not make an official vscode-mypy replacement

No decision has been made yet. It's going to come down to feature usage, maintenance costs, etc. But we will consider your concern over extension trust when we do make a decision.

@jeremyn
Copy link

jeremyn commented May 11, 2022

@brettcannon

Please do it on the issue I created in the Black formatter repo.

I'm not sure what "it" means here but I've asked my specific questions here and you copied them over to microsoft/vscode-black-formatter#42 (comment). You can answer here or there as far as I'm concerned.

Also you responded to a quote where I referred to a "general issue tracking problem" but I doubt you mean you want all future common questions added to one obscure issue for one extension. I suppose going forward you'll handle these issues on a case-by-case basis and try to cross-reference open issues between the extensions as best you can.

@gramster
Copy link
Member

@jeremyn, if you are just wanting to get your code type-checked, you could change the Python > Analysis > Type Checking Mode setting to enable stricter type checking using Pylance.

@jeremyn
Copy link

jeremyn commented May 12, 2022

@gramster That's a practical solution so I'm sorry to respond with a criticism, but I don't agree with VS Code moving away from integrating with popular tooling and putting forward its proprietary product as a replacement.

@TBBle
Copy link

TBBle commented May 12, 2022

If it helps, the type-checker in Pylance is open-source (MIT): https://github.com/microsoft/pyright. You can even use it with its own extension if you really want to avoid Pylance specifically.

@brettcannon
Copy link
Member

@jeremyn To be clear, mypy is in no way more "semi-official" compared to pytype, pyre, pyright, or any of the other type checkers out there which participate as part of the typing SIG. For instance, mypy's existence in the Python org on GitHub was entirely Guido's call back in the day. I know I wouldn't support putting it there now as an SC member if I was asked to vote on it today.

I have edited your comment to be less aggressive and hurtful towards us instead of hiding your comment. Please understand you are missing a lot of context here which makes your original comment in my opinion unfair and unwarranted (e.g. the team supporting this extension is entirely separate from the team behind Pylance, you don't have access to the telemetry that shows us mypy usage compared to other features/tools we support, our team size for what we need to support, etc.). I am going to ask everyone to please keep this civil or else I will lock this issue for being too heated.

Also remember this repo is under MIT and you can always fork it to create an extension as you see fit; no one is blocking folks from supporting mypy in VS Code the way they deem fit if they do not agree with how we choose to support it ourselves.

@luabud luabud removed their assignment May 12, 2022
@jeremyn
Copy link

jeremyn commented May 12, 2022

@brettcannon I disagree that my original comment was aggressive rather than simply descriptive, but if you think the phrasing would lead to an unproductive discussion then you are welcome to modify it, as you did. I want to avoid heated political discussions. In any case the original comment is in the history.

Trying to be more clear and less charged:

  • In any organization, even when everyone is operating in good faith, there is a natural tendency toward consolidation and cross-referrals between teams. This is often stopped, if it is, by requiring support for alternatives even when it doesn't make business sense, based on metrics/telemetry/team size/etc, to do so.

  • From a practical standpoint it seems we are moving toward a future where the most popular Python code editor only de facto (see my next item) supports type checking using products VS Code/Microsoft controls.

  • I understand what you are saying about forking but: 1) the issue isn't just about my personal freedom, it's also that VS Code is going to be in a central place in the Python development ecosystem -- I can fork Chromium all day long, Google is still going to be driving web standards; and 2) VS Code has a generally weak extension security system, see my earlier comment at Need a way to find tools (linters, formatters) via PATH #4922 (comment), which in practice strongly favors first party (Microsoft) solutions, and I do understand that this is out of your control.

Please understand that I'm only writing all this because I do believe you all mean well and hope will consider this seriously. If I thought you were all villains then there would be little point, I'm not trying to use this as a soapbox or anything. I just want you to take this all onboard, mull it over and keep it in mind going forward.

Thanks for reading.

@brettcannon
Copy link
Member

if you think the phrasing would lead to an unproductive discussion then you are welcome to modify it, as you did. I want to avoid heated political discussions. In any case the original comment is in the history.

Thank you. That's appreciated.

  • From a practical standpoint it seems we are moving toward a future where the most popular Python code editor only de facto (see my next item) supports type checking using products VS Code/Microsoft controls.

I understand your security needs mean you need us to be the ones to provide you with mypy support for extensions coming from the Marketplace. But the Python side of our team isn't large and we have finite resources, and so we have to be objective about where our time and effort goes. We are data-driven and unfortunately the data puts mypy usage on the cusp of not being enough to warrant us owning mypy support (as I said, we have not made a final call on this yet, but it will be based on usage).

And while you may not want to fork this entire extension, we are working towards a Python linter extension template based on what we did for the Pylint extension to make it as easy as possible for people to support the linters they need (same goes for formatters based on our Black extension). The goal is for the templates to be easy enough to use that you could create a bespoke Python linter extension for e.g. mypy in an afternoon.

To be clear, just because we are making it easy to create extensions, that doesn't necessarily lessen the cost for us to maintain one (i.e. just because we could stamp out a mypy extension quickly doesn't mean we could keep it running to the standards we expect of ourselves, both as a company and as a team). If you create your own extension, you can choose to keep up with whatever mypy releases you want, have however much CI you want, etc. But if we publish it we have to meet certain security guidelines, quality control, platform compatibility, etc., that makes maintaining code a high-priced thing.

I just want you to take this all onboard, mull it over and keep it in mind going forward.

We definitely will!

@karrtikr
Copy link

@karthiknadig Is this still an issue now that we have separate extensions for pylint, black, flake8 etc.?

@brettcannon
Copy link
Member

Long-term this won't be here as it will be a per-tool/extension consideration (and which is supported by our tool extension template to create your own extension in an afternoon).

@karthiknadig
Copy link
Member

karthiknadig commented Oct 31, 2023

@github-actions github-actions bot removed the needs proposal Need to make some design decisions label Oct 31, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 1, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-formatting area-linting feature-request Request for new features or functionality
Projects
None yet
Development

No branches or pull requests