The .env File

Some settings belong to the computer a program runs on, not to the program: where an instrument is plugged in, which network port a server uses, a password. They differ from lab to lab, and some of them are secret, so they must not be written into code or into a file that is shared with others.

plesty-lib reads such settings from environment variables. An environment variable is a named value that the program finds in its surroundings instead of in its code. There are two places to set one:

  • in the terminal, before starting the program:

    export PM_ADDRESS=tcp://192.168.1.20:5555          # macOS, Linux
    $env:PM_ADDRESS = "tcp://192.168.1.20:5555"        # Windows PowerShell
    
  • in a file called .env, one NAME=value per line. This is the usual place, because the file stays where it is and you do not have to set anything again in each new terminal:

    # .env — lines starting with # are comments
    PM_ADDRESS=tcp://192.168.1.20:5555
    PM100D_VISA=USB0::0x1313::0x8078::P0000001::INSTR
    

Where the file goes

plesty-lib looks for .env in the folder you start the program from, not in the folder of the script. Start your programs from the module’s top folder and keep .env there.

Never share the real file

.env holds what is specific, and sometimes secret, to your lab. Keep it out of git or any other version control. A module created with plesty init, the command from plesty-sdk that creates a new module’s files (see Tools for publishing a module), already lists .env in its .gitignore, the file that tells git what to leave out.

What you share instead is .env.example: the same variable names with empty or harmless values, and a comment on each saying what it is for. Someone setting the module up copies it to .env and fills in their own values.

cp .env.example .env

Which value wins

When a name is set in more than one place, the first of these wins:

  1. a value given to the program directly, such as a command-line option (see override below);

  2. the terminal’s environment;

  3. the .env file;

  4. the default in the code.

Variables plesty-lib reads by itself

You do not have to read these yourself: the parts of plesty-lib that need them do.

Variable

Read by

Holds

<NAME>_ADDRESS

CompositeDevice, for each device you name without an address (see Building a composite)

the network address of that device’s server; the name in capitals, so a device called pm reads PM_ADDRESS

PLESTY_DATA

experiments, Run, and the viewer made with Viz

the folder where this computer sees the lab’s shared data disk (see Data on a Shared Disk); a leading ~ is this computer’s home folder

Reading your own variables: EnvSettings

For settings of your own, use EnvSettings from plesty.lib.utils. It reads .env and the terminal’s environment together, and converts a value to the type you ask for:

from plesty.lib.service import build_server, run_server
from plesty.lib.utils import EnvSettings
from powermeter_device import PowermeterDevice

env = EnvSettings.load()

address = env.require("PM100D_VISA")                          # must be set
tcp_port = env.get("PM100D_TCP_PORT", default=5555, cast=int)  # may be left out

device = PowermeterDevice(address, sensor_type="S155C")
run_server(build_server(device, address=f"tcp://*:{tcp_port}").run())

Call

Does

EnvSettings.load()

reads .env from the current folder, then the environment. A missing .env is not an error.

env.get(name, default=…, cast=…)

the value, converted with cast (int, float, bool, …), or default when it is unset or empty. With cast=bool, 1, true, yes and on mean true.

env.require(name, cast=…)

the same, but stops the program with an error naming the variable when it is unset. Use it for anything the program cannot run without.

name in env

whether the variable is set and not empty

Both get and require take override=: a value that wins over everything else when it is not None. Pass a parsed command-line option there, and the option replaces the environment for that one start:

address = env.require("PM100D_VISA", override=args.address)   # --address, if given

load() also copies the values it read from .env into the program’s environment, without replacing any that are already set, so programs it starts see them too. Pass export=False to only read them.