conda config
和上下文#
context
对象是 conda
代码库中许多部分的核心。它充当设置的集中式存储库。通常情况下,您会导入单例并直接访问其(众多)属性。
from conda.base.context import context
context.quiet
# False
此单例从多个可能的来源级联初始化。从优先级最低到最高
在
Context
类中硬编码的默认值。这些值通过类属性定义。在配置文件 (
.condarc
) 中定义的值,它们有自己的 优先级.由相应的命令行参数设置的值(如果有)。
由相应的
CONDA_*
环境变量定义的值(如果存在)。
实现这种行为的机制是一个包含多种类型对象的复杂对象。
Context
类的解剖#
conda.base.context.Context
是与应用程序无关的 conda.common.configuration.Configuration
类的 conda 特定子类。此类实现了用于实例化每个定义属性的优先级顺序,以及整体验证逻辑和帮助消息报告。但仅此而已,它仅仅是 ParameterLoader
对象的存储,这些对象反过来在每个属性中实例化相关的 Parameter
子类。大致来说
class MyConfiguration(Configuration):
string_field = ParameterLoader(PrimitiveParameter("default", str))
list_of_int_field = ParameterLoader(SequenceParameter([1, 2, 3], int))
map_of_foat_values_field = ParameterLoader(MapParameter({"key": 1.0}, float))
当实例化 MyConfiguration
时,这些类属性将由已使用来自上述优先级链的值填充的 .raw_data
字典填充。 raw_data
字典包含 RawParameter
对象,这些对象被子类化以处理其来源的具体细节(YAML 文件、环境变量、命令行标志)。每个 ParameterLoader
对象将 RawParameter
对象传递给其相关 Parameter
子类的 .load()
方法,这些方法被设计为返回其相应的 LoadedParameter
对象对应物。
这有点令人困惑,但委托方式如下
Configuration
子类解析可能来源的原始值,并将它们存储为相关的RawParameter
对象,这些对象可以是EnvRawParameter
:用于来自环境变量的值ArgParseRawParameter
:用于来自命令行标志的值YamlRawParameter
:用于来自配置文件的值DefaultValueRawParameter
:用于来自传递给ParameterLoader
的默认值的值
每个
Configuration
属性都是一个ParameterLoader
,它通过__get__
实现property
协议。这意味着,在访问属性时(例如MyConfiguration.string_field
),ParameterLoader
可以执行加载逻辑。这意味着在原始数据中查找潜在的类型匹配,将它们加载为LoadedParameter
对象,并将它们与适当的优先级顺序合并。
合并策略取决于 (Loaded)Parameter
子类型。以下是可用子类型的列表
PrimitiveParameter
:保存一个类型为str
、int
、float
、complex
、bool
或NoneType
的单个标量值。SequenceParameter
:保存其他Parameter
对象的可迭代项(list
)。MapParameter
:保存其他Parameter
对象的映射(dict
)。ObjectParameter
:保存一个对象,其属性设置为Parameter
对象。
Parameter
对象的主要目标是实现如何对原始值进行类型化并将其转换为其 Loaded
对应项。这些实现了验证例程并定义了如何合并相同键的参数。
PrimitiveLoadedParameter
:优先级最高的 value 将替换现有的 value。SequenceLoadedParameter
:扩展,不重复,保持优先级。MapLoadedParameter
:级联更新,保留最高优先级。ObjectLoadedParameter
:与Map
相同。
完成所有这些步骤后,LoadedParameter
对象将被类型化:此时将执行类型验证。如果一切顺利,您将获得您的值。如果没有,将引发验证错误。
请注意,结果会被缓存以加快后续访问速度。这意味着,即使您更改了负责特定设置的环境变量的值,也不会反映在 context
对象中,直到您使用 conda.base.context.reset_context()
刷新它。
请勿修改 Context 对象!
ParameterLoader
并未实现 property
协议的 __set__
方法,因此您可以自由地覆盖在 Configuration
子类中定义的属性。您可能会认为这将在经过验证机制后重新定义 value,但事实并非如此。您将只是用原始 value 完全覆盖它,这可能不是您想要的。
相反,请将 context
对象视为不可变的。如果您需要在运行时更改设置,这可能是一个不好的主意。唯一可以接受这种情况的是在测试期间。
在不同来源中设置值#
设置值可能的来源背后有一些魔法。这些是如何与最终的 Configuration
对象关联的,可能一开始并不明显。对于每个 RawParameter
子类,情况都有所不同。
DefaultValueRawParameter
:用户永远不会看到这个。它只是包装传递给ParameterLoader
类的默认值。可以忽略。YamlRawParameter
:这个从 YAML 文件获取并将其解析为字典。此文件中的键必须与Configuration
类中的属性名称完全匹配(或其别名之一)。一旦正确设置,匹配就会自动发生。如何解析值取决于 YAML 加载器,由conda
在内部设置。EnvRawParameter
:来自某些环境变量的值可以进入Configuration
实例,前提是它们以<APP_NAME>_<PARAMETER_NAME>
格式,全部大写。应用程序名称由Configuration
子类定义。参数名称由类中的属性名称定义,转换为大写。例如,context.ignore_pinned
可以用CONDA_IGNORE_PINNED
设置。变量的值根据类型以不同的方式解析。PrimitiveParameter
很容易。环境变量字符串被解析为预期的类型。布尔值有点不同,因为有几个字符串被识别为布尔值,并且以不区分大小写的方式。True
可以用true
、yes
、on
和y
设置。False
可以用false
、off
、n
、no
、non
、none
和""
(空字符串)设置。
SequenceParameter
可以指定自己的分隔符(例如,
),因此环境变量字符串被处理成列表。MapParameter
和ObjectParameter
不支持用环境变量设置。
ArgParseRawParameter
:这些有点不同,因为没有自动机制将给定的命令行标志绑定到 context 对象。这意味着,如果您向Context
类添加了一个新设置,并且您希望在 CLI 中将其作为命令行标志使用,您必须自己添加它。如果是这种情况,请参考conda.cli.conda_argparse
并确保您argparse.Argument
的dest
值与Context
中的属性名称匹配。这样,Configuration.__init__
可以获取argparse.Namespace
对象,将其转换为字典,并使其通过加载机制。