Skip to content
1 change: 1 addition & 0 deletions doc/data/messages/i/invalid-envvar-default/bad.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os

env = os.getenv("SECRET_KEY", 1) # [invalid-envvar-default]
env = os.environ.get("SECRET_KEY", 1) # [invalid-envvar-default]
1 change: 1 addition & 0 deletions doc/data/messages/i/invalid-envvar-default/good.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os

env = os.getenv("SECRET_KEY", "1")
env = os.environ.get("SECRET_KEY", "1")
1 change: 1 addition & 0 deletions doc/data/messages/i/invalid-envvar-value/bad.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os

os.getenv(1) # [invalid-envvar-value]
os.environ.get(1) # [invalid-envvar-value]
1 change: 1 addition & 0 deletions doc/data/messages/i/invalid-envvar-value/good.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os

os.getenv("1")
os.environ.get("1")
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/10092.false_negative
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix false negative for `invalid-envvar-default` to detect `os.environ.get`.

Closes #10092
51 changes: 47 additions & 4 deletions pylint/checkers/stdlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,14 @@ def visit_call(self, node: nodes.Call) -> None:
self._check_for_check_kw_in_run(node)
elif name in DEBUG_BREAKPOINTS:
self.add_message("forgotten-debug-statement", node=node)
elif (
isinstance(inferred, astroid.BoundMethod)
and self._is_os_environ_get(node)
and utils.is_builtin_object(inferred)
):
# when os.environ.get() is inferred it creates a "builtins.dict" and "_collections_abc.Mapping"
self._check_env_function(node, inferred)

self.check_deprecated_method(node, inferred)

@utils.only_required_for_messages("boolean-datetime")
Expand Down Expand Up @@ -892,7 +900,9 @@ def _check_open_call(
"unspecified-encoding", node=node, confidence=confidence
)

def _check_env_function(self, node: nodes.Call, infer: nodes.FunctionDef) -> None:
def _check_env_function(
self, node: nodes.Call, infer: nodes.FunctionDef | astroid.BoundMethod
) -> None:
env_name_kwarg = "key"
env_value_kwarg = "default"
if node.keywords:
Expand Down Expand Up @@ -934,14 +944,22 @@ def _check_env_function(self, node: nodes.Call, infer: nodes.FunctionDef) -> Non
def _check_invalid_envvar_value(
self,
node: nodes.Call,
infer: nodes.FunctionDef,
infer: nodes.FunctionDef | astroid.BoundMethod,
message: str,
call_arg: InferenceResult | None,
allow_none: bool,
) -> None:
if call_arg is None or isinstance(call_arg, util.UninferableBase):
return

if (
message == "invalid-envvar-default"
and isinstance(node.parent, nodes.Call)
and isinstance(node.parent.func, nodes.Name)
and node.parent.func.name in {"int", "float"}
):
return

name = infer.qname()
if isinstance(call_arg, nodes.Const):
emit = False
Expand All @@ -950,9 +968,34 @@ def _check_invalid_envvar_value(
elif not isinstance(call_arg.value, str):
emit = True
if emit:
self.add_message(message, node=node, args=(name, call_arg.pytype()))
self.add_message(
message,
node=node,
args=(
"os.environ.get" if self._is_os_environ_get(node) else name,
call_arg.pytype(),
),
)
else:
self.add_message(message, node=node, args=(name, call_arg.pytype()))
self.add_message(
message,
node=node,
args=(
"os.environ.get" if self._is_os_environ_get(node) else name,
call_arg.pytype(),
),
)

def _is_os_environ_get(self, node: nodes.Call) -> bool:
try:
return (
isinstance(node.func, nodes.Attribute)
and node.func.attrname == "get"
and node.func.expr.attrname == "environ"
and node.func.expr.expr.name == "os"
)
except AttributeError:
return False

def deprecated_methods(self) -> set[str]:
return self._deprecated_methods
Expand Down
72 changes: 72 additions & 0 deletions tests/functional/i/invalid/invalid_envvar_value.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# pylint: disable=useless-return,missing-docstring
import os
from os import getenv


Expand Down Expand Up @@ -57,6 +58,8 @@ def deep_function_returning_bytes():
getenv(key=function_returning_string())

getenv('TEST', "value")
int(getenv("TEST", 1))
float(getenv("TEST", 1.0))
getenv('TEST', []) # [invalid-envvar-default]
getenv('TEST', None)
getenv('TEST', b"123") # [invalid-envvar-default]
Expand All @@ -66,6 +69,8 @@ def deep_function_returning_bytes():
getenv('TEST', function_returning_bytes()) # [invalid-envvar-default]

getenv('TEST', default="value")
int(getenv("TEST", default=1))
float(getenv("TEST", default=1.0))
getenv('TEST', default=[]) # [invalid-envvar-default]
getenv('TEST', default=None)
getenv('TEST', default=b"123") # [invalid-envvar-default]
Expand All @@ -76,9 +81,76 @@ def deep_function_returning_bytes():

getenv(key='TEST')
getenv(key='TEST', default="value")
int(getenv(key="TEST", default=1))
float(getenv(key="TEST", default=1.0))
getenv(key='TEST', default=b"value") # [invalid-envvar-default]
getenv(key='TEST', default=["Crap"]) # [invalid-envvar-default]
getenv(key='TEST', default=function_returning_list()) # [invalid-envvar-default]
getenv(key='TEST', default=function_returning_none())
getenv(key='TEST', default=function_returning_string())
getenv(key='TEST', default=function_returning_bytes()) # [invalid-envvar-default]

os.environ.get() # pylint: disable=no-value-for-parameter

os.environ.get(b"TEST") # [invalid-envvar-value]
os.environ.get("TEST")
os.environ.get(None) # [invalid-envvar-value]
os.environ.get(["Crap"]) # [invalid-envvar-value]
os.environ.get(function_returning_bytes()) # [invalid-envvar-value]
os.environ.get(deep_function_returning_bytes()) # [invalid-envvar-value]
os.environ.get(function_returning_list()) # [invalid-envvar-value]
os.environ.get(function_returning_none()) # [invalid-envvar-value]
os.environ.get(function_returning_string())
os.environ.get(deep_function_returning_string())

os.environ.get(b"TEST", "default") # [invalid-envvar-value]
os.environ.get("TEST", "default")
os.environ.get(None, "default") # [invalid-envvar-value]
os.environ.get(["Crap"], "default") # [invalid-envvar-value]
os.environ.get(function_returning_bytes(), "default") # [invalid-envvar-value]
os.environ.get(function_returning_list(), "default") # [invalid-envvar-value]
os.environ.get(function_returning_none(), "default") # [invalid-envvar-value]
os.environ.get(function_returning_string(), "default")

os.environ.get(key=b"TEST") # [invalid-envvar-value]
os.environ.get(key="TEST")
os.environ.get(key=None) # [invalid-envvar-value]
os.environ.get(key=["Crap"]) # [invalid-envvar-value]
os.environ.get(key=function_returning_bytes()) # [invalid-envvar-value]
os.environ.get(key=function_returning_list()) # [invalid-envvar-value]
os.environ.get(key=function_returning_none()) # [invalid-envvar-value]
os.environ.get(key=function_returning_string())

os.environ.get('TEST', "value")
int(os.environ.get("TEST", 1))
float(os.environ.get("TEST", 1.0))
os.environ.get('TEST', []) # [invalid-envvar-default]
os.environ.get('TEST', None)
os.environ.get('TEST', b"123") # [invalid-envvar-default]
os.environ.get('TEST', function_returning_list()) # [invalid-envvar-default]
os.environ.get('TEST', function_returning_none())
os.environ.get('TEST', function_returning_string())
os.environ.get('TEST', function_returning_bytes()) # [invalid-envvar-default]

os.environ.get('TEST', default="value")
int(os.environ.get("TEST", default=1))
float(os.environ.get("TEST", default=1.0))
os.environ.get('TEST', default=[]) # [invalid-envvar-default]
os.environ.get('TEST', default=None)
os.environ.get('TEST', default=b"123") # [invalid-envvar-default]
os.environ.get('TEST', default=function_returning_list()) # [invalid-envvar-default]
os.environ.get('TEST', default=function_returning_none())
os.environ.get('TEST', default=function_returning_string())
os.environ.get('TEST', default=function_returning_bytes()) # [invalid-envvar-default]

os.environ.get(key='TEST')
os.environ.get(key='TEST', default="value")
int(os.environ.get(key="TEST", default=1))
float(os.environ.get(key="TEST", default=1.0))
os.environ.get(key='TEST', default=b"value") # [invalid-envvar-default]
os.environ.get(key='TEST', default=["Crap"]) # [invalid-envvar-default]
os.environ.get(key='TEST', default=function_returning_list()) # [invalid-envvar-default]
os.environ.get(key='TEST', default=function_returning_none())
os.environ.get(key='TEST', default=function_returning_string())
os.environ.get(key='TEST', default=function_returning_bytes()) # [invalid-envvar-default]
os.environ.get(key='TEST', default=function_returning_bytes()) # [invalid-envvar-default]
94 changes: 63 additions & 31 deletions tests/functional/i/invalid/invalid_envvar_value.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,63 @@
invalid-envvar-value:30:0:30:15::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:32:0:32:12::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:33:0:33:16::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:34:0:34:34::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:35:0:35:39::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:36:0:36:33::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:37:0:37:33::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:41:0:41:26::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:43:0:43:23::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:44:0:44:27::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:45:0:45:45::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:46:0:46:44::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:47:0:47:44::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:50:0:50:19::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:52:0:52:16::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:53:0:53:20::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:54:0:54:38::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:55:0:55:37::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:56:0:56:37::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-default:60:0:60:18::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:62:0:62:22::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:63:0:63:41::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:66:0:66:42::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:69:0:69:26::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:71:0:71:30::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:72:0:72:49::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:75:0:75:50::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:79:0:79:36::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:80:0:80:36::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:81:0:81:53::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:84:0:84:54::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-value:31:0:31:15::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:33:0:33:12::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:34:0:34:16::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:35:0:35:34::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:36:0:36:39::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:37:0:37:33::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:38:0:38:33::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:42:0:42:26::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:44:0:44:23::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:45:0:45:27::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:46:0:46:45::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:47:0:47:44::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:48:0:48:44::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:51:0:51:19::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:53:0:53:16::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:54:0:54:20::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:55:0:55:38::os.getenv does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:56:0:56:37::os.getenv does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:57:0:57:37::os.getenv does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-default:63:0:63:18::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:65:0:65:22::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:66:0:66:41::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:69:0:69:42::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:74:0:74:26::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:76:0:76:30::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:77:0:77:49::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:80:0:80:50::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:86:0:86:36::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:87:0:87:36::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:88:0:88:53::os.getenv default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:91:0:91:54::os.getenv default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-value:95:0:95:23::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:97:0:97:20::os.environ.get does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:98:0:98:24::os.environ.get does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:99:0:99:42::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:100:0:100:47::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:101:0:101:41::os.environ.get does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:102:0:102:41::os.environ.get does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:106:0:106:34::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:108:0:108:31::os.environ.get does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:109:0:109:35::os.environ.get does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:110:0:110:53::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:111:0:111:52::os.environ.get does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:112:0:112:52::os.environ.get does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:115:0:115:27::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:117:0:117:24::os.environ.get does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-value:118:0:118:28::os.environ.get does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:119:0:119:46::os.environ.get does not support builtins.bytes type argument:UNDEFINED
invalid-envvar-value:120:0:120:45::os.environ.get does not support builtins.list type argument:UNDEFINED
invalid-envvar-value:121:0:121:45::os.environ.get does not support builtins.NoneType type argument:UNDEFINED
invalid-envvar-default:127:0:127:26::os.environ.get default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:129:0:129:30::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:130:0:130:49::os.environ.get default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:133:0:133:50::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:138:0:138:34::os.environ.get default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:140:0:140:38::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:141:0:141:57::os.environ.get default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:144:0:144:58::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:150:0:150:44::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:151:0:151:44::os.environ.get default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:152:0:152:61::os.environ.get default type is builtins.list. Expected str or None.:UNDEFINED
invalid-envvar-default:155:0:155:62::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
invalid-envvar-default:156:0:156:62::os.environ.get default type is builtins.bytes. Expected str or None.:UNDEFINED
Loading