microsoft / vscode-python

Python extension for Visual Studio Code
https://aka.ms/pvsc-marketplace
MIT License
4.32k stars 1.18k forks source link

Create a Python profile #20823

Closed luabud closed 1 year ago

luabud commented 1 year ago

4th iteration: https://insiders.vscode.dev/profile/github/c8c826aca68c0bf263554e1bafa955d0

Extensions

Extension Functionality Reasoning
Python Core language support Official Python language support in VS Code
Pylance IntelliSense features Official Python language server in VS Code
Black formatter Formatting Popular formatter for Python development.
Ruff Linting and import organizing Ruff is a Python linter which offers syntactic and stylistic warnings with quick fixes support. It also implements the Organize Imports command. It has great reviews.
Even Better TOML TOML language support To offer support for pyproject.toml, introduced by PEP 518 and which specifies the build system requirements of Python projects. This extension has great reviews and is quite popular.
autoDocstring Docstrings generation Popular extension for automatically adding docstrings to the code once users type """. This extension is very popular and has great reviews.
Python Environment Manager Enables visualization of existing Python environments as well as installed packages. Package management/visualization support is a common feature request we get from our users. This is a popular extension (> 3M downloads) that alongside the Python extension's create environment command largely address this feature request.
Docker Docker container support To improve discoverability of the Docker container features, as Docker is pretty popular for Python development (source)
Remote Development First class dev container, SSH and WSL development support To improve discoverability of these features in VS Code.

UI State

Settings

    "python.interpreter.infoVisibility": "always", // to always display the Python interpreter info/picker on the status bar 
    "python.analysis.autoImportCompletions": true, // to enable auto imports by default with Pylance 
    "python.analysis.fixAll": ["source.unusedImports"],  // to enable Fix All to be applied for unused imports
    "workbench.colorTheme": "Default Dark+ Experimental", //  to improve discoverability of new color theme
    "editor.defaultFormatter": "ms-python.black-formatter" // to set Black as the default formatter for a better formatting UX

Snippets


{
    "if": {
        "prefix": "if",
        "body": ["if ${1:expression}:", "\t${2:pass}"],
        "description": "Code snippet for an if statement"
    },
    "if/else": {
        "prefix": "if/else",
        "body": ["if ${1:condition}:", "\t${2:pass}", "else:", "\t${3:pass}"],
        "description": "Code snippet for an if statement with else"
    },
    "elif": {
        "prefix": "elif",
        "body": ["elif ${1:expression}:", "\t${2:pass}"],
        "description": "Code snippet for an elif"
    },
    "else": {
        "prefix": "else",
        "body": ["else:", "\t${1:pass}"],
        "description": "Code snippet for an else"
    },
    "while": {
        "prefix": "while",
        "body": ["while ${1:expression}:", "\t${2:pass}"],
        "description": "Code snippet for a while loop"
    },
    "while/else": {
        "prefix": "while/else",
        "body": ["while ${1:expression}:", "\t${2:pass}", "else:", "\t${3:pass}"],
        "description": "Code snippet for a while loop with else"
    },
    "for": {
        "prefix": "for",
        "body": ["for ${1:target_list} in ${2:expression_list}:", "\t${3:pass}"],
        "description": "Code snippet for a for loop"
    },
    "for/else": {
        "prefix": "for/else",
        "body": ["for ${1:target_list} in ${2:expression_list}:", "\t${3:pass}", "else:", "\t${4:pass}"],
        "description": "Code snippet for a for loop with else"
    },
    "try/except": {
        "prefix": "try/except",
        "body": ["try:", "\t${1:pass}", "except ${2:expression} as ${3:identifier}:", "\t${4:pass}"],
        "description": "Code snippet for a try/except statement"
    },
    "try/finally": {
        "prefix": "try/finally",
        "body": ["try:", "\t${1:pass}", "finally:", "\t${2:pass}"],
        "description": "Code snippet for a try/finally statement"
    },
    "try/except/else": {
        "prefix": "try/except/else",
        "body": [
            "try:",
            "\t${1:pass}",
            "except ${2:expression} as ${3:identifier}:",
            "\t${4:pass}",
            "else:",
            "\t${5:pass}"
        ],
        "description": "Code snippet for a try/except/else statement"
    },
    "try/except/finally": {
        "prefix": "try/except/finally",
        "body": [
            "try:",
            "\t${1:pass}",
            "except ${2:expression} as ${3:identifier}:",
            "\t${4:pass}",
            "finally:",
            "\t${5:pass}"
        ],
        "description": "Code snippet for a try/except/finally statement"
    },
    "try/except/else/finally": {
        "prefix": "try/except/else/finally",
        "body": [
            "try:",
            "\t${1:pass}",
            "except ${2:expression} as ${3:identifier}:",
            "\t${4:pass}",
            "else:",
            "\t${5:pass}",
            "finally:",
            "\t${6:pass}"
        ],
        "description": "Code snippet for a try/except/else/finally statement"
    },
    "with": {
        "prefix": "with",
        "body": ["with ${1:expression} as ${2:target}:", "\t${3:pass}"],
        "description": "Code snippet for a with statement"
    },
    "def": {
        "prefix": "def",
        "body": ["def ${1:funcname}(${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"","\t${4:pass}"],
        "description": "Code snippet for a function definition"
    },
    "def(class method)": {
        "prefix": "def(class method)",
        "body": ["def ${1:funcname}(self, ${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\t${4:pass}"],
        "description": "Code snippet for a class method"
    },
    "def(static class method)": {
        "prefix": "def(static class method)",
        "body": ["@staticmethod", "def ${1:funcname}(${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\t${4:pass}"],
        "description": "Code snippet for a static class method"
    },
    "def(abstract class method)": {
        "prefix": "def(abstract class method)",
        "body": ["def ${1:funcname}(self, ${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\traise NotImplementedError"],
        "description": "Code snippet for an abstract class method"
    },
    "class": {
        "prefix": "class",
        "body": ["class ${1:classname}(${2:object}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\t${4:pass}"],
        "description": "Code snippet for a class definition"
    },
    "lambda": {
        "prefix": "lambda",
        "body": ["lambda ${1:parameter_list}: ${2:expression}"],
        "description": "Code snippet for a lambda statement"
    },
    "if(main)": {
        "prefix": "__main__",
        "body": ["if __name__ == \"__main__\":", "    ${1:pass}"],
        "description": "Code snippet for a `if __name__ == \"__main__\": ...` block"
    },
    "async/def": {
        "prefix": "async/def",
        "body": ["async def ${1:funcname}(${2:parameter_list}):", "\t${3:pass}"],
        "description": "Code snippet for an async statement"
    },
    "async/for": {
        "prefix": "async/for",
        "body": ["async for ${1:target} in ${2:iter}:", "\t${3:block}"],
        "description": "Code snippet for an async for statement"
    },
    "async/for/else": {
        "prefix": "async/for/else",
        "body": ["async for ${1:target} in ${2:iter}:", "\t${3:block}", "else:", "\t${4:block}"],
        "description": "Code snippet for an async for statement with else"
    },
    "async/with": {
        "prefix": "async/with",
        "body": ["async with ${1:expr} as ${2:var}:", "\t${3:block}"],
        "description": "Code snippet for an async with statement"
    }
}

Backlog for additional extensions that could be added:

luabud commented 1 year ago

cc @cwebster-99

isidorn commented 1 year ago

Just tried it out, looks great! Some feedback:

fyi @sandy081

cwebster-99 commented 1 year ago

@isidorn Is there a way to configure the profile so the terminal shows upon open? I see "terminal.hidden": "[{\"id\":\"terminal\",\"isHidden\":false}]" but I don't believe that is what this setting is controlling, correct?

isidorn commented 1 year ago

@cwebster-99 correct, the setting is not for that.

If you make the terminal visible in your profile. And then you export the profile with the UX state - the terminal visibility will be a part of the profile.

These docs have more details https://code.visualstudio.com/docs/editor/profiles

luabud commented 1 year ago

How come we use the name "Python Scripts" and not just "Python"?

Given we'll have a Django and a Python one, I thought that if people were e.g. going to do Django but saw the Python one first, they'd be tempted to pick it. I'm not attached to this idea though, so happy to remove it and leave it as just "Python"

Can we use some theme? For example the Dark theme V2 so we promote our new default themes?

Yes, absolutely! I thought of including One Dark Pro as that's a common choice in the team but I personally prefer the Default theme v2

Should we add some other VS Code settings? For example autoSave? Are there other setting we could add that we know are popular in the python community?

Auto save has been called out as a must by Python devs we interviewed in the past, but after chatting with a few folks in the team we preferred not to add it for this profile, at least for now. We couldn't think of other popular editor settings for Python devs, but if someone comes up with an idea I'll update this issue.

Can we customize the layout a bit more. For example, should we have the terminal visible? Not sure if Python users indeed use the terminal, but are there other views we should show?

Yes! My intention was the let the terminal visible, and when I exported the profile I explicitly had it open up. But I guess it didn't propagate for some reason? I'm not sure if it's a bug or if I'm doing something wrong 😅

Should we set some search.exclude, files.exclude settings so we cover Python files that should be ignored (if such exist)?

We add a few common folders by default in our code already (e.g. src to analysis.extraPaths). We could explicitly add it for transparency sake, but the functionality would be the same.

Are there other things our python users are struggling with (settings, view discoverability) that we could use the profile for?

Chatting with the team a few ideas came up, so I'm adding them to the 2nd draft of the profile:

isidorn commented 1 year ago

@luabud thank you!

Given we'll have a Django and a Python one, I thought that if people were e.g. going to do Django but saw the Python one first, they'd be tempted to pick it. I'm not attached to this idea though, so happy to remove it and leave it as just "Python"

I was just curious. We should start with a name that you think is best :)

Auto save has been called out as a must by Python devs we interviewed in the past, but after chatting with a few folks in the team we preferred not to add it for this profile, at least for now.

Just curious what is the concern here?

Yes! My intention was the let the terminal visible, and when I exported the profile I explicitly had it open up. But I guess it didn't propagate for some reason? I'm not sure if it's a bug or if I'm doing something wrong 😅

Interesting. Could you file a new bug please and ping me on it?

Chatting with the team a few ideas came up, so I'm adding them to the 2nd draft of the profile:

Awesome. Let me know once that 2nd draft is ready and I would gladly try it out.

cwebster-99 commented 1 year ago

when I exported the profile I explicitly had it open up. But I guess it didn't propagate for some reason? I'm not sure if it's a bug or if I'm doing something wrong

I ran into the same issue when I was creating and testing the Python EDU profile. I can file a bug today :)

luabud commented 1 year ago

oh sorry, I edited the opening comment with the 2nd draft, here it is: https://insiders.vscode.dev/profile/github/b00353b96014a77b2a541f62d696b910

isidorn commented 1 year ago

Thank you @luabud - this looks great to me! If the team is happy with this I think we can go ahead with it as the first version

I only have three questions:

  1. Why containers + docker from all the remote extensions? Is it more likely that python users use Containers than other setups?
  2. Why IntelliCode? Currently it does not behave well if Copilot is installed (it auto disables itself). And Copilot is becoming more popular, which makes me cautious about promoting IntelliCode further.
  3. Should we configure some formatter to be the default? The current experience is that users get asked on first open of a Python file to choose which is not smooth

fyi @sandy081

luabud commented 1 year ago

Why containers + docker from all the remote extensions? Is it more likely that python users use Containers than other setups?

For non-data science work, yes! From most of our customer interviews + the Python Developer Survey we see containers are far more popular than VMs for Python devs.

image

The most recent Django developer survey shows something similar: https://lp.jetbrains.com/django-developer-survey-2022/. I don't have any reservations against promoting the other extensions, though, especially to improve discoverability 😊

Why IntelliCode?

That's a fair point. Our thinking here was that IntelliCode works quite nicely with Pylance, and even though it's not as powerful as Copilot, it could be a good addition for those who aren't able to afford it. Don't feel strongly enough to keep it, though.

Should we configure some formatter to be the default?

Yes, great point! Thanks for bringing it up 😊

Version 3 is the same as version 2 but with:

https://insiders.vscode.dev/profile/github/aca3091333dae6fd0064b7c052da5bdb

isidorn commented 1 year ago

Awesome! This looks great to me 👏 Thanks you very much @luabud

@sandy081 might have additional feedback

pamelafox commented 1 year ago

I just tried it out in vscode.dev. The first thing I notice is the dark mode - I prefer light mode, so I don't know why a Python profile in particular would impose dark mode. I get harassed about liking light mode all the time, since dark mode has some association with "cool programmer culture" or some such, so I'm perhaps a bit sensitive about that.

Anyways, I may be the minority, so moving on to more important things: the autosuggest feels like it might be more intimidating than helpful. It suggests lots of things that I would never expect. I would turn off this autosuggest myself, and would not recommend it to new Python programmers. We had a similar autosuggest for the KA coding environment that we turned off for similar reasons. Do you have user studies on the autosuggest? (I don't know what extension it's from)

Screenshot 2023-03-17 at 12 00 49 PM Screenshot 2023-03-17 at 12 00 28 PM
luabud commented 1 year ago

These are snippets coming from the Python Snippets 3 extension. I was also on the fence on including this because of the overwhelming amount of suggestions, but ended up including giving the popularity and the good reviews/remarks on how that's helpful for Python beginners.

For context, we used to have built-in snippets in the Python extension, but after running some user studies with new to Python and new to VS Code users, we found they were confusing to them. Giving snippets are configurable, we ended up removing them by default from the core Python extension. We got a lot of users upset with this change, and to their point snippets are really helpful for productivity, which is why I think it's worth including some in this Profile. The hypothesis here is that we're adding more transparency to the snippets by adding them in the built-in profile, so hopefully it'll be less confusing to users who follow the same profile of those we interviewed in the past and found snippets were confusing.

That all said, I agree with your point on how too many snippets are being shown there, many being more confusing than useful (in a built-in Profile perspective at least. I think the extension itself sets up the right expectation, which could explain why it's performing so well in terms of reviews). I'll look into creating a subset of snippets that we believe to be most helpful and will update the Profile.

luabud commented 1 year ago

Chatting with Sarah Kaiser during PyCascades she gave a good idea of including the Python Environment Manager extension. It's pretty popular as well and folks seem to really enjoy it once we introduce it to them. I created a new profile proposal (4th iteration, I think?) with a subset of snippets and the Python env manager extension: https://insiders.vscode.dev/profile/github/c8c826aca68c0bf263554e1bafa955d0

Let me know what you all think 😊

isidorn commented 1 year ago

@luabud awesome! Thank you very much. Looks great to me. I expect us to ship this in Insiders start of April and then we can react on user feedback and fine tune this profile further.

luabud commented 1 year ago

This has been done some months ago, forgot to close the issue: image