Python os.getenv 的类型提示导致下游不兼容的类型错误

Python typehint for os.getenv causes downstream incompatible type errors

使用 os.getenv 检索环境变量时,默认行为 return 是 Optional[str] 的一种类型。这是有问题的,因为使用这些变量的任何下游 methods/functions 都可能被定义为明确接受 str 类型。 是否有公认的用法来解决此问题或强制执行 str return 类型?

typeshedgetenv 的存根文件定义中,您可以发现 getenv 可以具有 return 类型的 Optional[str]Union[str, T_] 取决于 default kwarg 的用法。

目前我能看到的四个选项是:

  1. 定义任何下游操作以接受 Optional[str] 类型作为参数。这感觉不是特别正确,因为 function/method 的结构可能不符合 Optional 类型。即该操作没有理由将特定参数设为 None.
  2. getenv 使用 default kwarg 并提供 str 默认值。这似乎更正确,但需要为 getenv 的每次使用设置一个默认值。我能看到的唯一问题是这样做可能会混淆不同环境中的测试或使用。
  3. 定义某种变量检查函数。这可能是一个函数,它接受要加载的环境变量的名称,显式 returns 一个字符串,如果环境变量不存在则引发错误。
  4. getenv 编辑的值 return 的类型明确设置为 str。我真的不喜欢这样,因为它期望环境始终得到正确配置,根据我的经验,这不是一个好的假设。

在下面找到引发 mypy 错误的示例。

import os

SOME_VAR = os.getenv("SOME_VAR")


def some_func(val: str) -> None:
    print(f"Loaded env var: {val}")


some_func(SOME_VAR)

以上引发mypy错误:

error: Argument 1 to "some_func" has incompatible type "Optional[str]"; expected "str"

tl;dr 如果您确定它始终存在,请使用 os.environ['SOME_VAR']


os.getenv 可以而且确实如此 return None -- mypy 有助于显示您那里有一个错误:

>>> repr(os.getenv('DOES_NOT_EXIST'))
'None'
>>> repr(os.getenv('USER'))
"'asottile'"

或者,您可以通过两种不同的方式说服 mypy 它是您期望的类型:

  1. 利用断言:
x = os.getenv('SOME_VAR')
assert x is not None, x
# mypy will believe that it is non-None after this point
  1. 使用演员表:

    from typing import cast
    
    x = cast(str, os.getenv('SOME_VAR'))
    # mypy will believe that it is a `str` after this point
    

(转换有一些缺点,因为它永远不会被检查,而断言可能会导致测试失败)

我建议 不要 忽略这个错误/解决它,而是使用 os.environ['SOME_VAR'] 来处理你希望永远存在的东西,或者写一个条件来检查缺少时的错误情况

SOME_VAR 是可选的,因为它可以是 None

Return the value of the environment variable varname if it exists, or value if it doesn’t. value defaults to None.

Docs

如果环境变量不存在,您可以设置回退:

import os

SOME_VAR = os.getenv("SOME_VAR", "my fallback value")


def some_func(val: str) -> None:
    print(f"Loaded env var: {val}")

some_func(SOME_VAR)

这将使 SOME_VAR "not optional"