Skip to main content

Using Custom Option Types

Flask provides specialized Click option types in flask.cli to handle complex configuration scenarios, such as passing multiple file paths in a single string or configuring SSL certificates through various formats.

Parsing Multiple Paths with SeparatedPathType

When you need a CLI option to accept multiple file paths or patterns—such as when configuring the reloader—use SeparatedPathType. This type extends click.Path to split a single input string into a list of paths using the operating system's path separator (: on Linux/macOS, ; on Windows).

In the flask run command, this is used for the --extra-files and --exclude-patterns options:

import os
import click
from flask.cli import SeparatedPathType

@click.command("custom-run")
@click.option(
"--extra-files",
type=SeparatedPathType(),
help=f"Extra files separated by {os.path.pathsep!r}."
)
def custom_run(extra_files):
if extra_files:
for path in extra_files:
print(f"Monitoring: {path}")

Key Behaviors

  • Platform Specific: It uses os.pathsep internally via split_envvar_value. Users must use the separator appropriate for their OS.
  • Validation: Each individual path in the list is validated using standard click.Path logic.
  • Return Value: The option returns a list of strings (the validated paths) rather than a single string.

Configuring SSL with CertParamType

The CertParamType handles the polymorphic nature of the --cert option in Flask. It allows a user to provide an SSL configuration in three different ways: a file path, the string 'adhoc', or a dotted import path to an ssl.SSLContext object.

1. Using a Certificate File

If a path to an existing file is provided, CertParamType validates that the file exists. In Flask's run command, this is paired with a --key option.

@click.option(
"--cert",
type=CertParamType(),
is_eager=True, # Processed before --key
)
@click.option(
"--key",
type=click.Path(exists=True, dir_okay=False, resolve_path=True),
callback=_validate_key,
expose_value=False,
)

When a file path is used, the _validate_key callback ensures that a corresponding --key file is also provided. It then combines them into a tuple (cert_path, key_path) stored in the cert parameter.

2. Using Ad-hoc Certificates

Passing the literal string adhoc tells Flask to generate a temporary self-signed certificate.

flask run --cert adhoc

Requirement: This mode requires the cryptography library to be installed. If it is missing, CertParamType raises a click.BadParameter error.

3. Importing an SSLContext

You can provide a dotted import path to a pre-configured ssl.SSLContext object. CertParamType uses werkzeug.utils.import_string to load the object.

flask run --cert my_module.ssl_context_obj

If the imported object is an instance of ssl.SSLContext, it is returned directly.

Implementation Requirements

When using CertParamType in your own commands, follow these patterns found in Flask's implementation:

  1. Eager Evaluation: Always set is_eager=True on the --cert option. This ensures the certificate is processed and available in ctx.params before the --key option is validated.
  2. Key Validation: Use a callback like _validate_key to handle the dependencies between certs and keys. The callback should:
    • Check if cert is 'adhoc' or an SSLContext; if so, prevent the use of --key.
    • Ensure --key is present if cert is a file path.
    • Merge the two values into a single parameter if necessary.

Troubleshooting

  • Missing SSL Support: CertParamType will raise an error if Python was compiled without SSL support.
  • Key Conflicts: If you provide --key while using --cert adhoc or an imported SSLContext, Flask will raise a BadParameter error because those modes do not utilize external key files.