
Security News
Browserslist-rs Gets Major Refactor, Cutting Binary Size by Over 1MB
Browserslist-rs now uses static data to reduce binary size by over 1MB, improving memory use and performance for Rust-based frontend tools.
A base CLI entrypoint supporting Anaconda CLI plugins using Typer.
To develop a subcommand in a third-party package, first create a typer.Typer()
app with one or more commands.
See this example. The commands defined in your package will be prefixed
with the subcommand you define when you register the plugin.
In your pyproject.toml
subcommands can be registered as follows:
# In pyproject.toml
[project.entry-points."anaconda_cli.subcommand"]
auth = "anaconda_cloud_auth.cli:app"
In the example above:
"anaconda_cloud_cli.subcommand"
is the required string to use for registration. The quotes are important.auth
is the name of the new subcommand, i.e. anaconda auth
typer.Typer
commands you define in your package are accessible the registered subcommandanaconda auth <command>
.anaconda_cloud_auth.cli:app
signifies the object named app
in the anaconda_cloud_auth.cli
module is the entry point for the subcommand.By default any exception raised during CLI execution in your registered plugin will be caught and only a minimal message will be displayed to the user.
You can define a custom callback for individual exceptions that may be thrown from your subcommand. You can register handlers for standard library exceptions or custom defined exceptions. It may be best to use custom exceptions to avoid unintended consequences for other plugins.
To register the callback decorate a function that takes an exception as input, and return an integer error code. The error code will be sent back through the CLI and your subcommand will exit with that error code.
from typing import Type
from anaconda_cli_base.exceptions import register_error_handler
@register_error_handler(MyCustomException)
def better_exception_handling(e: Type[Exception]) -> int:
# do something or print useful information
return 1
@register_error_handler(AnotherException)
def just_ignore_it(e: Type[Exception])
# ignore the error and let the CLI exit successfully
return 0
@register_error_handler(YetAnotherException)
def fix_the_error_and_try_again(e: Type[Exception]) -> int:
# do something and retry the CLI command
return -1
In the second example the handler returns -1
. This means that the handler has attempted to correct the error
and the CLI subcommand should be re-tried. The handler could call another interactive command, like a login action,
before attempting the CLI subcommand again.
See the anaconda-cloud-auth plugin for an example custom handler.
If your plugin wants to utilize the Anaconda config file, default location ~/.anaconda/config.toml
, to read configuration
parameters you can derive from anaconda_cli_base.config.AnacondaBaseSettings
to add a section in the config file for
your plugin.
Each subclass of AnacondaBaseSettings
defines the section header. The base class is configured so that parameters defined in subclasses can be read in the
following priority from lowest to highest.
AnacondaBaseSettings
ANACONDA_<PLUGIN-NAME>_<FIELD>
variables defined in the .env file in your working directoryANACONDA_<PLUGIN-NAME>_<FIELD>
env variables set in your shell or on command invocationNotes:
AnacondaBaseSettings
is a subclass of BaseSettings
from pydantic-settings.Here's an example subclass
from anaconda_cli_base.config import AnacondaBaseSettings
class MyPluginConfig(AnacondaBaseSettings, plugin_name="my_plugin"):
foo: str = "bar"
To read the config value in your plugin according to the above priority:
config = MyPluginConfig()
assert config.foo == "bar"
Since there is no value of foo
in the config file it assumes the default value from the subclass definition.
The value of foo
can now be written to the config file under the section my_plugin
# ~/.anaconda/config.toml
[plugin.my_plugin]
foo = "baz"
Now that the config file has been written, the value of foo
is read from the
config.toml file:
config = MyPluginConfig()
assert config.foo == "baz"
The AnacondaBaseSettings supports nested Pydantic models.
from anaconda_cli_base.config import AnacondaBaseSettings
from pydantic import BaseModel
class Nested(BaseModel):
n1: int = 0
n2: int = 0
class MyPluginConfig(AnacondaBaseSettings, plugin_name="my_plugin"):
foo: str = "bar"
nested: Nested = Nested()
In the ~/.anaconda/config.toml
you can set values of nested fields as an in-line table
# ~/.anaconda/config.toml
[plugin.my_plugin]
foo = "baz"
nested = { n1 = 1, n2 = 2}
Or as a separate table entry
# ~/.anaconda/config.toml
[plugin.my_plugin]
foo = "baz"
[plugin.my_plugin.nested]
n1 = 1
n2 = 2
To set environment variables use the __
delimiter
ANACONDA_MY_PLUGIN_NESTED__N1=1
ANACONDA_MY_PLUGIN_NESTED__N2=2
You can pass a tuple to plugin_name=
in subclasses of AnacondaBaseSettings
to nest whole plugins,
which may be defined in separate packages.
class Nested(BaseModel):
n1: int = 0
n2: int = 0
class MyPluginConfig(AnacondaBaseSettings, plugin_name="my_plugin"):
foo: str = "bar"
nested: Nested = Nested()
Then in another package you can nest a new config into my_plugin
.
class MyPluginExtrasConfig(AnacondaBaseSettings, plugin_name=("my_plugin", "extras")):
field: str = "default"
The new config table is now nested in the config.toml
# ~/.anaconda/config.toml
[plugin.my_plugin]
foo = "baz"
nested = { n1 = 1, n2 = 2}
[plugin.my_plugin.extras]
field = "value"
And can be set by env variable using the concatenation of plugin_name
ANACONDA_MY_PLUGIN_EXTRAS_FIELD="value"
See the tests for more examples.
Ensure you have conda
installed.
Then run:
make setup
make test
make tox
FAQs
A base CLI entrypoint supporting Anaconda CLI plugins
We found that anaconda-cli-base demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Browserslist-rs now uses static data to reduce binary size by over 1MB, improving memory use and performance for Rust-based frontend tools.
Research
Security News
Eight new malicious Firefox extensions impersonate games, steal OAuth tokens, hijack sessions, and exploit browser permissions to spy on users.
Security News
The official Go SDK for the Model Context Protocol is in development, with a stable, production-ready release expected by August 2025.