How to configure VS code for pytest with environment variable - visual-studio-code

I am trying to debug pytest. I would like to inject an environment variable. Here is how I have set launch.json
{
"type": "python",
"request": "test",
"name": "pytest",
"console": "integratedTerminal",
"env": {
"ENV_VAR":"RandomStuff"
}
},
But it seems when I start debugging. I do not see the env variable injected, as a result my test which expects that env variable fails.
Also I notice error
Could not load unit test config from launch.json

pytest-env
Install
Per https://stackoverflow.com/a/39162893/13697228:
conda install -c conda-forge pytest-env
Or:
pip install pytest-env
pytest.ini
Create pytest.ini file in project directory:
[pytest]
env =
ENV_VAR=RandomStuff
Python
In your code, load environment variables as you normally would:
import os
env_var = os.environ["ENV_VAR"]
pytest / VS Code
Either run:
pytest
(Notice how it says configfile: pytest.ini)
C:\Users\sterg\Documents\GitHub\sparks-baird\mp-time-split> pytest
==================================== test session starts ===================================== platform win32 -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0 rootdir:
C:\Users\sterg\Documents\GitHub\sparks-baird\mp-time-split,
configfile: pytest.ini plugins: anyio-3.6.1, cov-3.0.0, env-0.6.2
collecting ...
Or:
This only seems to work with breakpoints that have manually been set, I'm guessing some other change is needed to pause on errors.
Python for VS Code Extension
Apparently the Python for VS Code extension recognizes a .env file automatically. E.g.
.env file:
ENV_VAR=RandomStuff
Haven't verified, but I'd assume this has the same behavior as using pytest-env with a pytest.ini file.
When all else fails
When I don't feel like dealing with the strange hackery necessary to get VS Code, Anaconda environments, and pytest playing nicely together (and/or forget how I fixed it before), I call my tests manually and run it like a normal script (see below). This may not work with more advanced pytest trickery using fixtures for example. At the end of your Python script, you can add something like:
if __name__ == "__main__":
my_first_test()
my_second_test()
and run it in debug mode (F5) as normal.

Could not really figure out how to fix "unit" test debugging with Vscode. But with Pytest one can call tests like python -m pytest <test file>(https://docs.pytest.org/en/stable/usage.html#cmdline)
That means Vscode can be configured like a module
"configurations": [
{
"name": "Python: Module",
"type": "python",
"request": "launch",
"module": "pytest",
"args": ["--headful","--capture=no", "--html=report.html"],
}
This is good enough to do debugging of python tests. Also you can then insert environment variables
"env": {
"ENV_VAR":"RandomStuff"
}

This works in v 1.72.2
Create in the workspace folder:
.vscode/launch.json
Similar to the OP, but using "module"
{
"version": "0.2.0",
"configurations": [
{
"name": "Pytest",
"type": "python",
"request": "launch",
"module": "pytest",
"console": "integratedTerminal",
"env": {
"testy": "someval"
}
}
]
}
Try some breakpoints (either in test files or app code)
Start the debugger
Watch the os.environ['testy'] value (must import os where the breakpoint is of course)

Related

Configuring multiple commands to run in parallel in VS Code tasks (to compile and autoprefix Sass)

I had previously been using Koala to compile my Sass with autoprefixing and minifying (on Windows), but have come to find that Koala is no longer maintained. I'm therefore trying to figure out how people usually compile Sass, autoprefix it, and minify it automatically on save.
I'm not super experienced with command line tools like Gulp but have used NPM enough to get to the point of being able to install Dart Sass, PostCSS, etc., and since I use VS Code, have decided that its internal Tasks feature seems like the easiest way to go.
Currently if I do this in the VS Code terminal:
sass --watch sass:. --style compressed
It works, i.e., it successfully watches for changes in the sass directory and outputs a minified .css file in the parent directory.
If I stop that and do this instead:
postcss style-raw.css --output style.css --use autoprefixer --watch
It also works. I had to rename the original .scss file because apparently postcss doesn't allow --replace and --watch at the same time.
So right now, I have style-raw.scss which compiles to style-raw.css when I run the sass command, and style-raw.css gets autoprefixed and output to style.css when I run the postcss command.
Where I'm stuck is getting both commands to run at the same time via a Task. In my tasks.json file I have:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Sass Compile",
"type": "shell",
"command": "sass --watch sass:. --style compressed | postcss style-raw.css --output style.css --use autoprefixer --watch",
"problemMatcher": [
"$node-sass"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
This is connected to the Build task, which has a keyboard shortcut of ctrl+shift+B, so my ultimate goal thus far has been to be able to just hit ctrl+shift+B to start everything up getting watched and compiled and autoprefixed, etc.
Currently though, only the Sass command runs when I use the keyboard shortcut. I found another post somewhere that said the pipe should work for multiple commands, but it doesn't seem to, or perhaps you can't --watch two things at the same time, I have no idea. I tried an array for command: but that either doesn't work or I didn't have the right format.
Or perhaps there's an entirely different and better way to go about all this, but if anyone can help with using these two commands together, that'd be much appreciated.
UPDATE: SOLUTION --------------------------------------------------------
With the kind help of #soulshined below, I got the multiple commands working (the dependsOn option was the trick), but evidently it won't run two commands with the --watch parameter in the same terminal. For my use case this wouldn't work and I eventually found this extremely helpful article that explains how to run multiple tasks in a split terminal by grouping them.
If anyone else runs across this with the same use case, here is the working tasks.json file:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Compile CSS",
"dependsOn": [
"Sass Compile",
"Prefix Output",
],
"group": {
"kind": "build",
"isDefault": true
},
},
{
"label": "Prefix Output",
"type": "shell",
"command": "postcss style-raw.css --output style.css --use autoprefixer --watch",
"presentation": {
"group": "cssCompile"
}
},
{
"label": "Sass Compile",
"type": "shell",
"command": "sass --watch sass:. --style compressed",
"problemMatcher": [
"$node-sass"
],
"presentation": {
"group": "cssCompile"
}
}
]
}
UPDATE 2: GULP --------------------------------------------------------
Randomly ran across my own post and thought I would add that I now use Gulp. I don't remember why but the VS Code tasks turned into a hassle later on, and Gulp turned out to be not that hard to learn.
Where I'm stuck is getting both commands to run at the same time via a Task
Running concurrently can be tricky to accomplish; consider taking advantage of the dependsOn property. Here is a brief example of running commands tasks consecutively:
"version": "2.0.0",
"tasks": [
{
"label": "Echo All",
"type": "shell",
"command": "echo Done",
"dependsOn": [
"Last"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Last",
"type": "shell",
"command": "echo 'Did it last'",
"dependsOn": "First",
},
{
"label": "First",
"type": "shell",
"command": "echo 'Doing it first'",
}
]
That's a language [shell] agnostic solution. If you would like to run multiple commands you can try adding a semi colon after each statement:
"command": "sass --watch sass:. --style compressed; postcss style-raw.css --output style.css --use autoprefixer --watch"

Debug FastAPI application in VSCode

i'm trying to debug an application (a web api) that use FastAPI (uvicorn)
I'm also using poetry and set the projev virtual environment in vscode.
i read this tutorial to setup uvicorn and this one to setup vscode but i think i'm doing something wrong in set it up.
I tried to setup the launch.json both as python: module and python: current file
The problem seems that it doesn't recognize the project structure cause when i run the debug it stopped in an import statement with this error:
Exception has occurred: ImportError
attempted relative import with no known parent package
This is my current launch.json configuration:
"configurations": [
{
"name": "Python: local debug",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/src/topic_service/service/__init__.py",
"args" : ["--port", "8000"]
},
]
I also tried to add a .env file setting PYTHONPATH:
PYTHONPATH=.:${PYTHONPATH}
Locally i run the application as follow:
poetry run uvicorn src.main:app --port 8080 --reload
Does anyone know how to correctly setup vscode to debug an uvicorn application?
Thank you
UPDATE:
I also tried what this article says. the debugger seems to start but nothing happen (no breakpoint is triggered)
Try this configuration.
{
"name": "Python: Module",
"type": "python",
"request": "launch",
"module": "uvicorn",
"args": ["src.main:app","--reload"]
}
Likewise you provide uvicorn module with necessary args during development of FastAPI application, you need to configure your launch.json located in .vscode directory with respective values.
I did a write up for custom project configurations to debug FastAPI in VS Code here
Suppose you issue the following command to run FastAPI on uvicorn server with args mentioned as below
uvicorn main:app --reload --port 8000
then your launch.json should have module with value of uvicorn and each of the args separated by space as items of the args array.
"module": "uvicorn",
"type": "python",
"request": "launch",
"args": [
"main:app",
"--reload",
"--port",
"8000"
],
"env": {
"usersecret": "some$Ecret",
}
You can have this launch.json file in .vscode and then modify the args array in the JSON configuration as per your project structure.
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "uvicorn",
"env": {
"db_username": "postgres",
"db_password": "secret",
"host_server": "localhost",
"database_name": "fastapi",
"ssl_mode": "prefer",
"db_server_port": "5432"
},
"args": [
"main:app",
"--reload",
"--port",
"8000"
]
}
]
}
For me worked with this configurations:
On Debug section on VSCode, choose create launch.json option. Probally it will open launch.json on .vscode folder in your root folder explorer
like this, inside of launch.json put this:
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "uvicorn",
"cwd": "${workspaceFolder}/<folder to your main.py>",
"args": [
"main:app",
"--reload",
"--port", //these arg are optional
"3003"
]
}
]
}
Now , just run your debugger and have a nice day!
Edit: The cwd ensure that your debbuger will find the right path to your main.py file. So, for whos use multiple debuggers or uses outside vsCode with launch.json it's a nice choice use it.
The quick and easy way: launch debugger F5 and then select FastAPI Debug Configuration:
(p.s. this works on the VSCode Insiders; haven't tried it on a regular version)
The way i debug is quite basic, hope it helps
i have .py file with this config:
import uvicorn
from app.main import api
if __name__ == "__main__":
dev = 1
if dev==0:
#use this one
uvicorn.run(api, host="127.0.0.1", port=5000, log_level="info")
if dev == 1:
#or this one
uvicorn.run('app.main:api', host="127.0.0.1", port=5000, log_level="info", reload=True, debug=True)
if dev == 2:
uvicorn.run('app.main:api', host="127.0.0.1", port=5000, log_level="info", workers=2)
and run the file with the vscode debugger, the important thing is to run the app with the debug flag because otherwise the debugger skips the breakpoints (at least in my case)

Launch.json: how to reference an environment variable

In order to define my environment variables in a single place a configured a task in which a run a shell script. The task is run as preLaunchTask in my launch.json.
In my launch.json I now try to reference the environment variables I configured in the script (like export AWS_REGION="eu-west-1").
The launch.json looks as follows:
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
//..
"env": {
//"AWS_REGION": "us-east-1", //works
"AWS_REGION": "${env:AWS_REGION}", //doesn't work, why?
},
"args": [],
"preLaunchTask": "setupEnv",
}
] }
Doesn't work, why?
According to this post from user weinand...
The ".env" file is read and processed after VS Code has substituted
variables in the launch config. So your debugged program will indeed
see the environment variable "FOO" with the correct value but VS
Code's variable substitution in the launch.json will not see it.
The reason for this is that ".env" files are a node.js concept and not
a generic platform mechanism. So VS Code does not know anything about
.env files, but the node.js debugger knows about .env files.
... this functionality in launch.json is specific for applications running on Node.js, although that's not what M$ explains in their documentations for VSCode.
Possible solution
For Python applications (possibly for other platforms as well) environment variables defined in a .env file (or whatever name you like) will be available for your application as long as the following configuration is present in launch.json...
{
"version": "0.2.0",
"configurations": [
{
[...]
"envFile": "${workspaceFolder}/.env", // Path to the ".env" file.
[...]
}
]
}
Note that just exporting a variable...
export SOMEVAR_A=1234
... will not make the environment variable SOMEVAR_A available for the application being executed by the VSCode debugger nor for the settings - especially inside "env" and "args" ("configurations") - in launch.json as, for example, in this case...
{
"version": "0.2.0",
"configurations": [
{
[...]
"env": {
"SOMEVAR_A": "${env:SOMEVAR_A}"
},
"args": [
"${env:SOMEVAR_A}"
]
[...]
}
]
}
NOTE: In our tests the ${env:SOMEVAR_A} syntax did not work in any scenario. That is, didn't work for the application ("env") and didn't work for the settings ("args") in launch.json.
PLUS I: Dirt Hack
For values present in "args" ("configurations") you can use the hack below...
{
"version": "0.2.0",
"configurations": [
{
[...]
"envFile": "${workspaceFolder}/.env",
"args": [
"`source \"${workspaceFolder}/.env\";echo ${SOMEVAR_A}`"
]
[...]
}
]
}
... as the configuration in "envFile" doesn't work.
Notice, although, that the following construction...
[...]
"args": [
"`echo ${SOMEVAR_A}`"
]
[...]
... would also work for "args" as long as the environment variable "SOMEVAR_A" has been previously exported in the conventional way.
The same reasoning would work for a tasks (tasks.json), but in both cases we can't guarantee that.
TIP: An .env File Example
SOMEVAR_A="abcd"
SOMEVAR_B="efgh"
SOMEVAR_C=123456
PLUS II: Export Variables
There are cases where you will need to export variables (eg. export SOMEVAR_A="abcd") so that they can be consumed by certain resources. In these cases there may be problems, because the fact that we export variables prevents (we don't know why) that they are seen in the context of the "envFile" configuration "envFile": "${workspaceFolder}/.env".
A workaround to get around these limitations is to add set -a before the variables set and set +a after it. With this we were able to meet the two scenarios as this example...
#!/usr/bin/env bash
set -a
SOMEVAR_A="abcd"
SOMEVAR_B="efgh"
SOMEVAR_C=123456
set +a
... or in a more compatible and safe way use set -a/set +a as in this example...
[...]
"args": [
"`set -a;source \"${workspaceFolder}/.env\";set +a;echo ${SOMEVAR_A}`"
[...]
VSCode's support for environment variables is a mess! 🙄
Conclusion
We don't know if the limitations we are dealing with here are from VSCode's own design or are bugs. Anyway, it doesn't seem to make much sense.
These procedures were tested on Manjaro Linux (Arch based).
Thanks! 🤗
[Ref(s).: https://unix.stackexchange.com/a/79077/61742 , https://stackoverflow.com/a/30969768/3223785 ]
Looking at the issue comment quoted below, it seems this is currently not possible.
${env:...} only expands environment variables that were set in the parent shell that ran code. It doesn't expand variables set in the tasks.json env options.
https://github.com/Microsoft/vscode/issues/47985#issuecomment-460678885
It doesn't work as Eduardo Lucio stated. Here is some alternative that works at least on my case that sometimes uses env.sh file to load the environment variables and require .env file for VsCode debugging in Go project. To launch the application normally, load the env using commmand $ source env.sh. On this case, you want to load .env file instead.
Env-Example: Linux/WSL2
If the .sh is what I tought of, probably just some line of export commands: env.sh
export DBUrl="sql-connection-string-here"
export DBPass="somedbpass"
Create the prelaunch task to generate the .env file .vscode/tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "buildenv",
"command": "sed",
"args": ["s/export //g", "local_env.sh", ">", ".env"],
"type": "shell"
}
]
}
you can see that it calls sed to replace any export with empty string and rewrites a .env file.
On .vscode/launch.json, load the preLaunchTask and change the target envFile to the generated file:
{
"version": "0.2.0",
"configurations": [
{
"name": "My App Debug",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}",
"preLaunchTask": "buildenv",
"envFile": "${workspaceFolder}/.env",
}
]
}
Now, everytime VsCode run the debugger, it generates .env file and only need to maintain single env.sh file.
Reference: https://stackoverflow.com/a/38746951/12325366

Node debugging, make `${file}` dynamic?

With the right debug config file I can make VSCode run the currently focussed file through Mocha. However, I find it frustrating that if I am working on the actual code, rather than the spec file and I press F5, it tries to run the actual code as a spec file through Mocha.
So, my question is; given a file structure like this:
Folder
File.js
File.spec.js
And a debug config (.vscode/launch.json) like this:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Unit Tests: Current File",
"program": "${workspaceRoot}/node_modules/.bin/_mocha",
"cwd": "${workspaceRoot}",
"args": [
"-u", "tdd",
"--timeout=999999",
"--colors",
"--opts", "${workspaceRoot}/mocha.opts",
"${file}" // I want to make this dynamic
],
}
]
}
Is it possible to get VSCode to debug the spec file whether the spec file (File.spec.js) or it's subject (File.js) are selected?
You can introduce a new dynamic variable by writing a simple extension that just defines one command, e.g. a smartFile command.
Then you can refer to that command in your launch config as ${command:smartFile}.
For the implementation of the command you can use everything available in VS Code extension API. So you can not only calculate a path based on your folder structure, but you can even pop-up UI. E.g. you could use QuickPick to select a test case from the list of all tests.

Start automatically python webserver from visual studio code

I would like to start automatically Python http.server when I'm hitting the run button (or F5) from visual studio code.
I assume it's the matter of the launch.json configuration but I'm not familiar with it.
How can I do that?
Please install the pythonVSCode extension. And create python file in your project directory. And place the below content on it. Refer here
import http.server
import socketserver
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()
And create launch configuration like this...
{
"name": "Documentation",
"type": "python",
"request": "launch",
"stopOnEntry": false,
"pythonPath": "${workspaceRoot}/env/bin/python",
"program": "${workspaceRoot}/your_pyton_run_file.py",
"debugOptions": [
"WaitOnAbnormalExit",
"WaitOnNormalExit",
"RedirectOutput"
]
},
Then you can start this with F5