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.pathsepinternally viasplit_envvar_value. Users must use the separator appropriate for their OS. - Validation: Each individual path in the list is validated using standard
click.Pathlogic. - Return Value: The option returns a
listof 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:
- Eager Evaluation: Always set
is_eager=Trueon the--certoption. This ensures the certificate is processed and available inctx.paramsbefore the--keyoption is validated. - Key Validation: Use a callback like
_validate_keyto handle the dependencies between certs and keys. The callback should:- Check if
certis'adhoc'or anSSLContext; if so, prevent the use of--key. - Ensure
--keyis present ifcertis a file path. - Merge the two values into a single parameter if necessary.
- Check if
Troubleshooting
- Missing SSL Support:
CertParamTypewill raise an error if Python was compiled without SSL support. - Key Conflicts: If you provide
--keywhile using--cert adhocor an importedSSLContext, Flask will raise aBadParametererror because those modes do not utilize external key files.