Skip to content

Conversation

@kinghuang
Copy link
Contributor

Issue: #476

Description: Set auto_envvar_prefix to STREAMLIT to accept parameters from environment variables in addition to regular CLI arguments. This is a Click option that will automatically get values from env vars if available.

Contribution License Agreement

By submiting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@kinghuang kinghuang requested a review from a team as a code owner October 20, 2019 23:24
@kinghuang kinghuang changed the title WIP: Set auto_envvar_prefix to STREAMLIT Set auto_envvar_prefix to STREAMLIT Oct 21, 2019
@tvst
Copy link
Contributor

tvst commented Oct 22, 2019

Awesome!

I'm having trouble testing this, though. How do I set the --server.port CLI argument via an environment variable?

The problem I'm running into is that STREAMLIT_SERVER.PORT is not a valid env var name...

@tvst tvst self-requested a review October 22, 2019 08:57
@kinghuang
Copy link
Contributor Author

I'm looking into this.

Set auto_envvar_prefix to STREAMLIT to accept parameters from
environment variables in addition to regular CLI arguments. This is a
Click option that will automatically get values from  env vars if
available.
@kinghuang
Copy link
Contributor Author

kinghuang commented Oct 23, 2019

@tvst I've moved auto_envvar_prefix to the context_settings on the main command group so that its applied whether the command is invoked through cli.py or via the streamlit entrypoint.

The format of the environment variables that Click generates is PREFIX_COMMAND_VARIABLE. So, for the --server.port option on the run sub-commmand, the corresponding environment variable will be STREAMLIT_RUN_SERVER_PORT. Click converts periods to underscores automatically.

root@104bd402c055:/project# streamlit run sa/gui.py

  You can now view your Streamlit app in your browser.

  Network URL: http://172.19.0.2:8501
  External URL: http://209.89.162.170:8501

^C  Stopping...
root@104bd402c055:/project# export STREAMLIT_RUN_SERVER_PORT=5678
root@104bd402c055:/project# streamlit run sa/gui.py

  You can now view your Streamlit app in your browser.

  Network URL: http://172.19.0.2:5678
  External URL: http://209.89.162.170:5678

^C  Stopping...

If you temporarily set show_envvar=True on the dynamically added options in configuration_options(func), the help text will show the corresponding environment name for each option. Here's an excerpt for --server.port.

  --server.port INTEGER           The port where the server will listen for
                                  client and browser connections.
                                  
                                  Default: 8501  [env var: STREAMLIT_RUN_SERVER_PORT]

I noticed that you attempted to set STREAMLIT_SERVER.PORT. After playing with this some more, I'm starting to think that environment variables as options should be limited to just the run command (run_main). That way there isn't a RUN in the middle of the environment name, making STREAMLIT_SERVER_PORT the corresponding environment name for the --server.port option, for example. That also means that Click won't automatically read environment variable values for options on the other commands.

With the prefix on run_main instead of the root main:

  --server.port INTEGER           The port where the server will listen for
                                  client and browser connections.
                                  
                                  Default: 8501  [env var: STREAMLIT_SERVER_PORT]

@kinghuang
Copy link
Contributor Author

Another option is to leave auto_envvar_prefix at the root, but then override the options added by configurator_options(func) with custom envvar names. They could be set to something like STREAMLIT_CONFIG_SERVER_PORT for the --server.port option.

This overlaps with the config command, but I think that's acceptable given it has no real options of its own, and it's about the options that it's showing.

Another thing that might be useful is assigning an envvar to the file_or_url argument on the run command. That would make it possible to specify the file or url to run via an environment variable, too. This would be handy from a container perspective.

root@1313373f8861:/project# export STREAMLIT_RUN_FILE_OR_URL=sa/gui.py
root@1313373f8861:/project# streamlit run

  You can now view your Streamlit app in your browser.

  Network URL: http://172.19.0.2:8501
  External URL: http://209.89.162.170:8501

Override the environment variable names for the options dynamically
added by configurator_options to be STREAMLIT_CONFIG_{option}. So, for
--server.port, the corresponding envvar is STREAMLIT_CONFIG_SERVER_PORT
instead of STREAMLIT_RUN_SERVER_PORT.
Set the environment variable for the file_or_url argument on the run
command to STREAMLIT_RUN_FILE_OR_URL. Click does not do automatic
envvars for arguments.

This makes it possible to specify the file or url to run using an
environment variable.
@kinghuang
Copy link
Contributor Author

I've pushed commits to override the envvar names for the config options and add an envvar for the file_or_url argument. Here's an example of their use.

root@1313373f8861:/project# export STREAMLIT_CONFIG_SERVER_PORT=2468
root@1313373f8861:/project# export STREAMLIT_RUN_FILE_OR_URL=sa/gui.py
root@1313373f8861:/project# streamlit run

  You can now view your Streamlit app in your browser.

  Network URL: http://172.19.0.2:2468
  External URL: http://209.89.162.170:2468

@treuille
Copy link
Contributor

Awesome PR @kinghuang!

Two questions (@tvst should be the decider):

  1. STREAMLIT_RUN_FILE_OR_URL sounds weird and limiting. How about STREAMLIT_RUN_TARGET?

  2. Why do we need this at all? Can’t we just do the following?

$ export STREAMLIT_RUN_TARGET=sa/gui.py
$ streamlit run ${STREAMLIT_RUN_TARGET}

Copy link
Contributor

@tvst tvst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tried this and it's really amazing! 💯

Can you also add this to docs/cli.md line 63:

Shows all config options available for Streamlit, including their current
values. You can set these options in four different ways:

- **In a global config file at `~/.streamlit/config.toml`.** For instance:
  ```toml
  [server]
  port = 80
  ```

- **In a per-project config file at `$CWD/.streamlit/config.toml`,** where
  `$CWD` is the folder you're running Streamlit from.

- **Through `STREAMLIT_CONFIG_*` environment variables,** such as:
  ```bash
  $ export STREAMLIT_CONFIG_SERVER_PORT=80
  ```

- **As flags in the command line** when running `streamlit run`. For example:
  ```bash
  $ streamlit run your_script.py --server.port 80
  ```

And while you're at it, do you mind fixing line 26? 😉

.. note::
  When passing your script some custom arguments, **they must be passed after a
  "--"** (double dash). Otherwise the arguments get interpreted as arguments to
  Streamlit itself.

parsed_parameter["param"],
help=parsed_parameter["description"],
type=parsed_parameter["type"],
envvar='STREAMLIT_CONFIG_{}'.format(parsed_parameter["param"].upper()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the suffix use snake case too. We have a function called to_snake_case() in case_converters.py that should do the trick.

In which case this line will get really long and nasty, so you could pull this logic into the _convert_config_option_to_click_option function.

Even better if we could change line 145 to just

config_option = click.option(**parsed_parameter)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll take a look at all these tomorrow!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the logic into _convert_config_option_to_click_option(). But, I'm not so sure about applying to_snake_case.

For an option like server.baseUrlPath, we have:

STREAMLIT_CONFIG_SERVER_BASE_URL_PATH (with snakecase)
STREAMLIT_CONFIG_SERVER_BASEURLPATH (without snakecase)

I think the without snakecase version matches the underlying config name better. With the snakecase version, I wouldn't know if it's supposed to match a config named server.base.url.path, server.baseUrl.path, serverBaseUrlPath, etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plan is to have only a two-level hierarchy for config options, so there shouldn't be any ambiguity so I think STREAMLIT_CONFIG_SERVER_BASE_URL_PATH is better.

Copy link
Contributor Author

@kinghuang kinghuang Oct 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-snakecase version has already been merged. But, here's how some other projects do config to environment variable mappings, for comparison. Overall, I feel that converting camelCase to straight uppercase without snake-casing is the better choice because it matches more closely with other apps.

Click's Default Behaviour

Turning on automatic environment variables in Click converts option names to uppercase, without snake casing.

--server.baseUrlPath == {PREFIX}_SERVER_BASEURLPATH

Traefik

Traefik's configs have camelCase names, and are mapped to CLI options in lowercase. The corresponding environment variables are not snake-cased.

[accessLog] filePath == --accesslog.filepath == TRAEFIK_ACCESSLOG_FILEPATH

Kafka (using Confluent Platform images)

Kafka's configs are all lowercase, and tend to have each word separated by a period (as opposed to camelCasing or snake_casing). In the Confluent Platform image for Kafka, the corresponding environment variables are only uppercased.

auto.create.topics.enable == KAFKA_AUTO_CREATE_TOPICS_ENABLE

Grafana

Grafana's configs are snake cased, which are preserved in environment variables.

[server] http_port == GF_SERVER_HTTP_PORT

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops, I think I merged this too soon. No problem, we'll address it in another PR.

@kinghuang
Copy link
Contributor Author

For @treuille's questions:

  1. STREAMLIT_RUN_TARGET sounds good to me, too. It might also help with PR Adding run -m option to run modules #79. Maybe the underlying argument should be renamed from file_or_url to target?
  2. The downside to streamlit run ${STREAMLIT_RUN_TARGET} is that it prevents containers from writing that in their entrypoint or command in exec form. There's no shell in the exec form to expand variables. While writing them in shell form is not the end of the world, the exec form is preferred.

Move the logic for constructing an environment variable name out of
configuration_options() to _convert_config_option_to_click_option(),
where the other Click options are prepped.
Add the copy from @tvst explaining the now four ways Streamlit can be
configured.
Add the updated copy from @tvst about delineating custom script
arguments with --.
@tvst
Copy link
Contributor

tvst commented Oct 24, 2019

STREAMLIT_RUN_TARGET sounds good to me, too. It might also help with PR #79. Maybe the underlying argument should be renamed from file_or_url to target?

👍
"Target" is much better than "file_or_url"

@tvst
Copy link
Contributor

tvst commented Oct 25, 2019

Ok, I just changed it to target in the PR 😃

@kinghuang
Copy link
Contributor Author

Awesome. I couldn't quite squeeze in that change in between meetings, today. :D

@tvst tvst merged commit c9a4001 into streamlit:develop Oct 25, 2019
@kinghuang kinghuang deleted the 476-auto-envvar branch October 25, 2019 01:45
@treuille
Copy link
Contributor

  1. The downside to streamlit run ${STREAMLIT_RUN_TARGET} is that it prevents containers from writing that in their [entrypoint]

Ah. That's compelling. Still I feel like streamlit run is kinda weird, but I don't feel strongly. I can go either way. Any thoughts @tvst ?

@treuille
Copy link
Contributor

Btw, this is really exciting work, @kinghuang !

tconkling added a commit to tconkling/streamlit that referenced this pull request Oct 29, 2019
* develop:
  Use custom context manager for temporary file in cli.py (streamlit#489)
  Update pull_request_template.md
  Update pull_request_template.md
  Handle lack of trailing slash (streamlit#528)
  Set auto_envvar_prefix to STREAMLIT (streamlit#477)
  Strip slashes in path components (streamlit#523)
  Create doc_improvement.md
  ESlint: allow @ts-ignore (streamlit#499)
  Update Pipfile (streamlit#505)
  Release 0.49.0 (streamlit#509)
  Removing package json (streamlit#501)
  Feature/input number (streamlit#416)
  ESLint warnings are fatal in Circle (streamlit#492)
  Doc updates (streamlit#286)
@dijitali
Copy link

Thanks for this PR @kinghuang , it's exactly what I'm after but I'm just a bit confused on the correct usage.

The v0.50.1 release notes state:

You can now set config options using environment variables. For example, export STREAMLIT_SERVER_PORT=9876.

But the docs state:

Through STREAMLIT_CONFIG_* environment variables, such as:
$ export STREAMLIT_CONFIG_SERVER_PORT=80

I've tried setting both STREAMLIT_SERVER_BASEURLPATH and STREAMLIT_CONFIG_SERVER_BASE_URL_PATH and neither seem to take effect (setting it in the config.toml does work).

@kinghuang
Copy link
Contributor Author

@dijitali Ah, the docs are incorrect! The CONFIG part was intentionally dropped from the final environment variables as shown in the release notes, but I missed the corresponding change in the docs. I'll fix that up.

For the server.baseUrlPath option, the corresponding environment variable is STREAMLIT_SERVER_BASE_URL_PATH.

root@1d1e0b2f6b03:/# export STREAMLIT_SERVER_BASE_URL_PATH=/abc
root@1d1e0b2f6b03:/# streamlit run st.py

  You can now view your Streamlit app in your browser.

  Network URL: http://172.17.0.3:8501/abc
  External URL: http://209.89.162.170:8501/abc

This is also shown in the help text for the run command.

root@1d1e0b2f6b03:/# streamlit run --help
Usage: streamlit run [OPTIONS] TARGET [ARGS]...

Options:
  --server.baseUrlPath TEXT       The base path for the URL where Streamlit
                                  should be served from.  [env var:
                                  STREAMLIT_SERVER_BASE_URL_PATH]

@dijitali
Copy link

Perfect, many thanks. Wasn't aware the --help command had all those details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants