Cannot install 'black' formatter for Python in VS22
This issue has been moved from a ticket on Developer Community.
[severity:It's more difficult to complete my work]
When trying to reformat Python code in Visual Studio 2022 (CTRL + K + D), it shows this pop-up:

After pressing "Yes", the Output window shows install progress, but after it's done, I still get the same pop-up:

Changing formatter to something other than 'black' doesn't resolve the issue, I still get stuck in an endless loop.
Original Comments
Feedback Bot on 7/4/2024, 07:18 PM:
(private comment, text removed)
Original Solutions
(no solutions)
What Python environment are you currently using for your project? My guess is that black might not be installed in your active environment. If you right-click on the selected environment, navigate to Manage Python Packages, and install black from the package management window, does it resolve the error you're encountering?
What Python environment are you currently using for your project? My guess is that
blackmight not be installed in your active environment. If you right-click on the selected environment, navigate toManage Python Packages, and installblackfrom the package management window, does it resolve the error you're encountering?
My project isn't a VS solution, but just a folder with packages being managed through Poetry. I can confirm that black is installed in my active environment, yet I keep getting that popup every time.
Poetry_Black_Python_Diagnostics.zip
dunno if this would help matters at all but I think it's a decent start with just these few scripts that can be attached and includes an extremely detailed README alongside a Document for guiding the implementation for a more semi-permanent to permanent diagnostics solution.
Poetry_Black_Python_Diagnostics.zip
dunno if this would help matters at all but I think it's a decent start with just these few scripts that can be attached and includes an extremely detailed README alongside a Document for guiding the implementation for a more semi-permanent to permanent diagnostics solution.
Thank you! I just did some deeper testing and I think I found the reason this is happening.
Basically, our project is a monorepo with multiple Python projects inside, and each one of them has their own venv directory.
I switch virtual environments every time I work on another project within that monorepo to match the given venv. since each of those projects has their own packages installed.
I can't 100% confirm this right now, as I'm out of office, but could it be possible that Visual Studio tried to find black in the root of the monorepo instead of the selected venv?
Before doing some more testing, I uninstalled everything Python from my machine and reinstalled only what's necessary, then opened only one of the projects within that monorepo and the black formatter started working.
Before the uninstall, I also had Anaconda installed, but I'm not sure if that would make a difference.
Can't hurt but to test, I'm glad I was able to help with some objective thinking here, even if the solution isn't a great fit. It helped me get some applicable library information thinking started for my own projects sake. I like to detach every now and again and do something of the "Open-Sector" Work. I've had people spend a ridiculous amount of time for much more minor issues than this example. I couldn't actually see the image submissions, they were either redacted , embedded, hidden, etc. So i just put a super simple in-line file and some potential usage in this folder I am attaching with the response e-mail here. I had a 8-10 Potential Errors from different perspectives and some logical reasoning on how to go about dealing with each specific potential. I will add the updated Scripts File and README + Implentation HOWTO to my repo and set it public for usage later should I ever need a diagnostics to use in conjunction with Poetry. If I can be of any more assistance in any capacity, please reach back out and I'd be happy to take a look. Good luck in the future endeavors as well.
Sincerely,
You should be able to clone the with this link HTTPS:// CLONE https://github.com/TheTruthCooper/Poetry-and-Python-Diagnostics.git GITHUBCLI CLONE link gh repo clone TheTruthCooper/Poetry-and-Python-Diagnostics
Or u can just read the repo here if that suits you better https://github.com/TheTruthCooper/Poetry-and-Python-Diagnostics
Feel free to add questions anywhere and if contributing changes please append for transparency where applicable
From: Kewin Kupilas @.> Sent: Tuesday, August 13, 2024 1:45 PM To: microsoft/PTVS @.> Cc: Cooper, Andrew @.>; Comment @.> Subject: Re: [microsoft/PTVS] Cannot install 'black' formatter for Python in VS22 (Issue #7952)
Poetry_Black_Python_Diagnostics.ziphttps://urldefense.com/v3/__https://github.com/user-attachments/files/16602945/Poetry_Black_Python_Diagnostics.zip__;!!BeImMA!-1YG_uweEOe18WA_-7yp2oJlkbffk1d3x7ktG7UylLMr2NilTvTIMGGhfZZEDq1x3p9mO_nu7y-yYea-NeLHadwfxMIuow$
dunno if this would help matters at all but I think it's a decent start with just these few scripts that can be attached and includes an extremely detailed README alongside a Document for guiding the implementation for a more semi-permanent to permanent diagnostics solution.
Thank you! I just did some deeper testing and I think I found the reason this is happening. Basically, our project is a monorepo with multiple Python projects inside, and each one of them has their own venv directory. I switch virtual environments every time I work on another project within that monorepo to match the given venv. since each of those projects has their own packages installed. I can't 100% confirm this right now, as I'm out of office, but could it be possible that Visual Studio tried to find black in the root of the monorepo instead of the selected venv? Before doing some more testing, I uninstalled everything Python from my machine and reinstalled only what's necessary, then opened only one of the projects within that monorepo and the black formatter started working. Before the uninstall, I also had Anaconda installed, but I'm not sure if that would make a difference.
— Reply to this email directly, view it on GitHubhttps://urldefense.com/v3/__https://github.com/microsoft/PTVS/issues/7952*issuecomment-2286896667__;Iw!!BeImMA!-1YG_uweEOe18WA_-7yp2oJlkbffk1d3x7ktG7UylLMr2NilTvTIMGGhfZZEDq1x3p9mO_nu7y-yYea-NeLHadzWfrxAFQ$, or unsubscribehttps://urldefense.com/v3/__https://github.com/notifications/unsubscribe-auth/A4QQ6FI7CF4RDWTDTA2X6WLZRJH4BAVCNFSM6AAAAABK7EN6QCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOBWHA4TMNRWG4__;!!BeImMA!-1YG_uweEOe18WA_-7yp2oJlkbffk1d3x7ktG7UylLMr2NilTvTIMGGhfZZEDq1x3p9mO_nu7y-yYea-NeLHadysPVjj-g$. You are receiving this because you commented.Message ID: @.***>
After doing some preliminary tests and research I was able to add a bit more information as to what my take is on the cause. Especially considering the Anaconda context I have added a second report for objectively looking at your system structure approximated from your initial reply in here. I also have linked a automation solution for ensuring venv is maintained during performance lifecycle and less for the current and future developers to deal with nor worry about. The solution uses .synopsis as a venv emulator inside of the VS 22 PowerShell console for command input and venv setup inside the powershell console. This is a very well documented delivery system and I believe a very appealing and viable option moving forward.
Sincerely. Andrew PYDEV
From: Cooper, Andrew @.> Sent: Tuesday, August 13, 2024 5:12 PM To: microsoft/PTVS @.> Subject: Re: [microsoft/PTVS] Cannot install 'black' formatter for Python in VS22 (Issue #7952)
Can't hurt but to test, I'm glad I was able to help with some objective thinking here, even if the solution isn't a great fit. It helped me get some applicable library information thinking started for my own projects sake. I like to detach every now and again and do something of the "Open-Sector" Work. I've had people spend a ridiculous amount of time for much more minor issues than this example. I couldn't actually see the image submissions, they were either redacted , embedded, hidden, etc. So i just put a super simple in-line file and some potential usage in this folder I am attaching with the response e-mail here. I had a 8-10 Potential Errors from different perspectives and some logical reasoning on how to go about dealing with each specific potential. I will add the updated Scripts File and README + Implentation HOWTO to my repo and set it public for usage later should I ever need a diagnostics to use in conjunction with Poetry. If I can be of any more assistance in any capacity, please reach back out and I'd be happy to take a look. Good luck in the future endeavors as well.
Sincerely,
You should be able to clone the with this link HTTPS:// CLONE https://github.com/TheTruthCooper/Poetry-and-Python-Diagnostics.git GITHUBCLI CLONE link gh repo clone TheTruthCooper/Poetry-and-Python-Diagnostics
Or u can just read the repo here if that suits you better https://github.com/TheTruthCooper/Poetry-and-Python-Diagnostics
Feel free to add questions anywhere and if contributing changes please append for transparency where applicable
From: Kewin Kupilas @.> Sent: Tuesday, August 13, 2024 1:45 PM To: microsoft/PTVS @.> Cc: Cooper, Andrew @.>; Comment @.> Subject: Re: [microsoft/PTVS] Cannot install 'black' formatter for Python in VS22 (Issue #7952)
Poetry_Black_Python_Diagnostics.ziphttps://urldefense.com/v3/__https://github.com/user-attachments/files/16602945/Poetry_Black_Python_Diagnostics.zip__;!!BeImMA!-1YG_uweEOe18WA_-7yp2oJlkbffk1d3x7ktG7UylLMr2NilTvTIMGGhfZZEDq1x3p9mO_nu7y-yYea-NeLHadwfxMIuow$
dunno if this would help matters at all but I think it's a decent start with just these few scripts that can be attached and includes an extremely detailed README alongside a Document for guiding the implementation for a more semi-permanent to permanent diagnostics solution.
Thank you! I just did some deeper testing and I think I found the reason this is happening. Basically, our project is a monorepo with multiple Python projects inside, and each one of them has their own venv directory. I switch virtual environments every time I work on another project within that monorepo to match the given venv. since each of those projects has their own packages installed. I can't 100% confirm this right now, as I'm out of office, but could it be possible that Visual Studio tried to find black in the root of the monorepo instead of the selected venv? Before doing some more testing, I uninstalled everything Python from my machine and reinstalled only what's necessary, then opened only one of the projects within that monorepo and the black formatter started working. Before the uninstall, I also had Anaconda installed, but I'm not sure if that would make a difference.
— Reply to this email directly, view it on GitHubhttps://urldefense.com/v3/__https://github.com/microsoft/PTVS/issues/7952*issuecomment-2286896667__;Iw!!BeImMA!-1YG_uweEOe18WA_-7yp2oJlkbffk1d3x7ktG7UylLMr2NilTvTIMGGhfZZEDq1x3p9mO_nu7y-yYea-NeLHadzWfrxAFQ$, or unsubscribehttps://urldefense.com/v3/__https://github.com/notifications/unsubscribe-auth/A4QQ6FI7CF4RDWTDTA2X6WLZRJH4BAVCNFSM6AAAAABK7EN6QCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOBWHA4TMNRWG4__;!!BeImMA!-1YG_uweEOe18WA_-7yp2oJlkbffk1d3x7ktG7UylLMr2NilTvTIMGGhfZZEDq1x3p9mO_nu7y-yYea-NeLHadysPVjj-g$. You are receiving this because you commented.Message ID: @.***>
<# .Synopsis Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the pyvenv.cfg file values present in the virtual environment.
.Parameter VenvDir Path to the directory that contains the virtual environment to activate. The default value for this is the parent of the directory that the Activate.ps1 script is located within.
.Parameter Prompt The prompt prefix to display when this virtual environment is activated. By default, this prompt is the name of the virtual environment folder (VenvDir) surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example Activate.ps1 Activates the Python virtual environment that contains the Activate.ps1 script.
.Example Activate.ps1 -Verbose Activates the Python virtual environment that contains the Activate.ps1 script, and shows extra information about the activation as it executes.
.Example Activate.ps1 -VenvDir C:\Users\MyUser\Common.venv Activates the Python virtual environment located in the specified location.
.Example Activate.ps1 -Prompt "MyPython" Activates the Python virtual environment that contains the Activate.ps1 script, and prefixes the current prompt with the specified string (surrounded in parentheses) while the virtual environment is active.
.Notes On Windows, it may be required to enable this Activate.ps1 script by setting the execution policy for the user. You can do this by issuing the following PowerShell command:
PS C:> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies: https://go.microsoft.com/fwlink/?LinkID=135170
#> Param( [Parameter(Mandatory = $false)] [String] $VenvDir, [Parameter(Mandatory = $false)] [String] $Prompt )
<# Function declarations --------------------------------------------------- #>
<# .Synopsis Remove all shell session elements added by the Activate script, including the addition of the virtual environment's Python executable from the beginning of the PATH variable.
.Parameter NonDestructive If present, do not remove this function from the global namespace for the session.
#> function global:deactivate ([switch]$NonDestructive) { # Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<# .Description Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by = (with any amount of whitespace surrounding the =)
then it is considered a key = value line. The left hand string is the key,
the right hand is the value.
If the value starts with a ' or a " then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the pyvenv.cfg file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition $VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'" Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
Set values required in priority: CmdLine, ConfigFile, Default
First, get the location of the virtual environment, it might not be
VenvExecDir if specified on the command line.
if ($VenvDir) { Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" } else { Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\/") Write-Verbose "VenvDir=$VenvDir" }
Next, read the pyvenv.cfg file to determine any required value such
as prompt.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
Next, set the prompt from the command line, or the config file, or
just use the name of the virtual environment folder.
if ($Prompt) { Write-Verbose "Prompt specified as argument, using '$Prompt'" } else { Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" if ($pyvenvCfg -and $pyvenvCfg['prompt']) { Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" $Prompt = $pyvenvCfg['prompt']; } else { Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" $Prompt = Split-Path -Path $venvDir -Leaf } }
Write-Verbose "Prompt = '$Prompt'" Write-Verbose "VenvDir='$VenvDir'"
Deactivate any currently active virtual environment, but leave the
deactivate function in place.
deactivate -nondestructive
Now set the environment variable VIRTUAL_ENV, used by many tools to determine
that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
$env:VIRTUAL_ENV_PROMPT = $Prompt
}
Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) { Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME Remove-Item -Path Env:PYTHONHOME }
Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH $Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
Context:
Your project is structured as a monorepo with multiple Python projects housed within it. Each of these projects has its own dedicated virtual environment (venv) directory. To manage dependencies specific to each project, I (Current Developer) switch between these virtual environments based on which project I’m currently working on.
Developer First Thoughts Findings:
"I suspect the issue arose because Visual Studio Code might have been attempting to locate the black formatter at the root of the monorepo rather than within the currently selected venv. This could explain why the formatter wasn't functioning as expected when multiple virtual environments were in play."
"To investigate further, I did the following: "
Uninstall and Reinstall:
Great starting with old-faithful**** I uninstalled all Python-related installations from my machine, including Anaconda, which was previously installed. I then reinstalled only the necessary Python components.
Developer Focused Testing Results:
After the reinstall, I opened only one project within the monorepo, activated the corresponding venv, and observed that the black formatter started working as expected.
This is a surefire start towards the right direction undoubtably, however I have additional commentary after having researched the VS implementations with this specific type of system operation, content delivery, and file directory management in conjunction with the .git framework and my findings, analysis and report is as follows
START OF REPORT
Potential Issues Identified:
- Monorepo Structure: Visual Studio Code might be searching for the black formatter in the wrong location (the root of the monorepo rather than the active venv). When working with multiple virtual environments within a monorepo, the editor might not correctly detect the active venv, leading to issues like the one experienced.
2.Environment Conflicts: Having Anaconda installed alongside multiple virtual environments could have introduced conflicts or confusion within the editor’s environment detection mechanism. Anaconda often modifies PATH variables or includes its own package manager (conda), which could interfere with the expected Python setup when using venv.
-
Suggested Next Steps: Further Testing: I plan to conduct additional tests to confirm whether Visual Studio Code is indeed searching for black in the wrong location when multiple venv directories exist within the monorepo.
-
Configuration Adjustments: If confirmed, you might need to adjust the workspace settings in Visual Studio Code to ensure it correctly identifies and uses the active venv for each project. You could explore creating a .vscode/settings.json file within each project’s directory to explicitly define the Python path for the active venv.
Documentation of Tests : TODO
I’ll document the findings and any necessary adjustments so that you can avoid similar issues when switching between projects in the monorepo. Please let me know if there’s anything specific you would like me to test or if you have any suggestions for further troubleshooting.
Thanks, [Andrew : @.***
Analysis and Recommendations System Structure & Data Delivery Concerns: 1st Primary Concern
Virtual Environment Detection: 2nd Primary Concern
The primary concern is how Visual Studio Code detects and utilizes virtual environments within a monorepo. The editor might default to the root of the monorepo, ignoring the specific environment activated for each project. Ensure that the Python extension in Visual Studio Code is correctly configured to respect the selected venv for each workspace. Editor Configuration:
Workspace-specific settings may need to be explicitly defined to avoid conflicts, especially in environments where multiple venv directories exist. Consider using a .vscode/settings.json file to specify the Python interpreter path within each project directory. This prevents the editor from defaulting to the wrong interpreter.
SIMPLE .json implement for automated venv check for very little resource or time consumption overall
{ "python.pythonPath": "path/to/your/venv/bin/python" }
Environment Isolation: 3rd Primary Concern
Having Anaconda and multiple venv setups on the same system can lead to conflicts. Anaconda’s modifications to the system’s PATH can interfere with venv environments, leading to issues in dependency resolution or tool detection like black. Ensure Anaconda is either fully isolated or uninstalled if not required, to avoid these conflicts.
I will include an extensive .synopsis usage here in a separate file for viewing on how you could use powershell to test, modify venv policy, and other possible relevant scripts that could apply here. The file name is Synopsis_venv_With_PS1_scripting
A
gain this is all super off topic for what I generally do but interesting to me nonetheless as a way to give back where I can.