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

Proposal: Use Nearest Configuration File #5564

Open
DanielRosenwasser opened this issue Mar 1, 2024 · 9 comments
Open

Proposal: Use Nearest Configuration File #5564

DanielRosenwasser opened this issue Mar 1, 2024 · 9 comments
Assignees
Labels
enhancement New feature or request

Comments

@DanielRosenwasser
Copy link
Member

Background

Today, the way that Pylance and Pyright work is that the editor experience only respects the options in pyrightconfig.json or pyproject.toml if they reside in a workspace root. Unfortunately this can be very confusing, and creates a lot of friction in specific workflows.

Scenario: Multi-Language Setups

.
├── javascript
│   └── package.json
└── python
    ├── pyproject.toml
    ├── package.json
    ├── pyrightconfig.json
    └── src
        └── package
            └── *.py

Here, every different language setup is sufficiently self-contained; however, a developer navigating such a codebase will not have their settings reflected in their editing experience out-of-the-box.

One could move their pyproject.toml or pyrightconfig.json to the top-level, but then the Python-specific package.json would not be co-located with the other Python-specific configuration files.

Scenario: Scripts and Examples

.
├── pyproject.toml
├── src
│   └── package
│       └── *.py
├── scripts
│   ├── pyrightconfig.json
│   └── *.py
└── examples
    ├── example1
    │   ├── pyrightconfig.json
    │   └── *.py
    └── example2
        ├── pyrightconfig.json
        └── *.py

When developing a library or shared codebase, it's common for examples and scripts to have different type-checking settings. For example,

  • you might want to check your src files against Python 3.11 and check them as strictly as possible
  • you might want to check examples and scripts against Python 3.12, but with differing strictness settings compared to each other

However, when opening this directory, Pylance will only consult the top-level pyproject.toml, making such a setup impossible. While the strict option for specifying globs of directories works okay, it doesn't offer anything more granular.

Overall Pain Points

In these workflows, a developer who wants their editor experience to align with their type-checking needs to open a specific subdirectory up rather than the package root. This runs counter to lots of out-of-the-box expectations when cloning a repo and opening a directory, or creating a Codespace/container session, and things just working after some configuration step.

Additionally, when things don't work correctly (e.g. strict type checking not kicking in), there's no obvious way to know when the configuration file is (or isn't) being consulted.

Why Not Multi-Root Workspaces?

The most obvious alternative is multi-root workspaces which kind of solves the issue for the first motivating scenario, but not so much for the second.

Multi-root workspaces also require developers to reopen a directory in a specific way and fundamentally alter the editor UI which makes things a bit weird when the codebase root has to contain both itself and its subdirectories as roots.

Additionally, it is a sort of non-obvious fix for the problem at hand because the current behavior of configuration being tied to workspace roots is surprising in itself. Many users may dismiss the "we found a workspace file" message that VS Code issues, which is a non-obvious footgun when things don't behave correctly.

As a TypeScript developer, multi-root workspaces are not a typical requirement for structuring a codebase. In fact, the same is now becoming true for Go developers as well. Needing to add a workspace file just for Python is an awkward asymmetry.

Proposal

Search for Nearest Configuration File

I would propose that the Pyright/Pylance editing experience adopt an approach where pyrightconfig.json and pyproject.toml files are searched by walking upward in the directory chain. Upon opening a Python file, the language service would need to decide on which project "owns" a file (though note that in some cases, a file might be owned by multiple projects).

In TypeScript, this problem has been tackled in a similar fashion, walking up the spine of directories looking for tsconfig.json and jsconfig.json files, rather than just consulting the workspace root. For the most part, this flexibility has worked out well for us and matches most users' intuitions. The proposal here is very similar in spirit.

UI for "Find Configuration"

In addition to this, the TypeScript/JavaScript editor integration in Visual Studio Code also provides a command called TypeScript: Go to Project Configuration (tsconfig).

TypeScript: Go to Project Configuration (tsconfig)

There is also an indicator for the configuration file path in the status bar, with an option to open that file.

When clicking the status bar icon, the editor shows the path of the tsconfig.json and lets you open that file.

I would suggest adopting similar UI/conventions here to make configuration more discoverable and diagnosable.

@github-actions github-actions bot added the needs repro Issue has not been reproduced yet label Mar 1, 2024
@rchiodo
Copy link
Contributor

rchiodo commented Mar 1, 2024

This would be rather hard for us to implement given our current design.

Each workspace folder shares settings. We have no facility for having different settings per python file or subdirectory.

@jakebailey
Copy link
Member

Given you can only have one pyrightconfig per dir, can you pretend like the user has done this via multi-root workspaces internally? LSP calls back use the URI of the file, so will still get the same settings. This isn't unlike tsserver's "ProjectService" which just maps requests down to specific language service instances.

@rchiodo
Copy link
Contributor

rchiodo commented Mar 2, 2024

You mean each pyrightconfig.js is like a different workspace? I think that might work? I don't think we actually have to map our internal workspace to a VS code one. I mean we have the <default> workspace which doesn't exist anywhere.

@jakebailey
Copy link
Member

Yeah; when I was talking to Daniel about the feasibility to it, the way I was thinking it would be possible would be to use multi-root as more of an "advisory" set of roots to consider, but to still be able to infer other roots when the user doesn't specify them.

I'm in the process of getting tsserver to do LSP, and reconsiling multi-root with our existing ProjectService is something I've been thinking about, and based on the fact that gopls does this sort of inference for go modules / workspaces, it feels possible for both sides of the pipe to have their own idea of what a "workspace" or "project" is and still interact.

@jakebailey
Copy link
Member

Expanding, I think my perspective on multi-root workspaces has sorta shifted over the years; now I see it mainly as a way to provide multiple VS Code settings in a single folder. The underlying LS implementation can completely ignore this information when serving requests or performing analysis. But when it needs to talk back to ask questions, the answers it gets may vary based on what workspace each root was. (But if I'm missing something I'd love to know!)

@DanielRosenwasser
Copy link
Member Author

Linking to microsoft/vscode-python#21204 since this issue feels like it's trying to solve many of the same issues.

@debonte debonte added enhancement New feature or request and removed needs repro Issue has not been reproduced yet labels Mar 8, 2024
@luabud
Copy link
Member

luabud commented Mar 11, 2024

I'm thinking another problem we probably have currently is that we depend on the Python extension's concept of a "selected environment", so in the example where you'd like to use Python 3.12 for one folder and Python 3.11 for another, I think the Python extension would have to support automatic "flipping" environments when users change active files, which currently isn't supported unless users are in a multi-root workspace. There are conversations happening on the Python extension side around no longer stricting environment selection to a workspace (and instead have more of a "per file" environment association), so when that happens I think it might be easier to get Pylance to work with the proposal outlined here

(cc @karthiknadig)

@ElieGallet
Copy link

ElieGallet commented May 16, 2024

For Scenario 1, could it be possible to specify in VS Code settings what pyproject.toml has to be used ?

@rchiodo rchiodo changed the title Proposal: Use Nearest Configuration File Improve monorepo support May 20, 2024
@rchiodo rchiodo changed the title Improve monorepo support Proposal: Use Nearest Configuration File May 20, 2024
@DanielRosenwasser
Copy link
Member Author

I guess one thing I didn't really mention in this write-up is anything about when a file isn't included by the nearest pyrightconfig.json. Is it implicitly covered by the nearest pyproject.toml? Or does it need to keep searching upwards?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants