59 storage = []
60 storage.extend(getattr(bases[0] if bases else object, attr, ()))
61 storage.extend(d.get(attr, ()))
62 assert len(bases) <= 1, "multiple inheritance not allowed" 63 assert len(storage) == len(set(storage)), "layout conflict"
64 d[attr] = tuple(storage)
65 d.setdefault("abstract", False)
60 storage.extend(getattr(bases[0] if bases else object, attr, ()))
61 storage.extend(d.get(attr, ()))
62 assert len(bases) <= 1, "multiple inheritance not allowed"
63 assert len(storage) == len(set(storage)), "layout conflict" 64 d[attr] = tuple(storage)
65 d.setdefault("abstract", False)
66 return type.__new__(mcs, name, bases, d)
288 spec = importlib.util.find_spec(package_name)
289 assert spec is not None, "An import spec was not found for the package."
290 loader = spec.loader
291 assert loader is not None, "A loader was not found for the package."292 self._loader = loader
293 self._archive = None
294 template_root = None
286 # packages work, otherwise get_loader returns None.
287 import_module(package_name)
288 spec = importlib.util.find_spec(package_name)
289 assert spec is not None, "An import spec was not found for the package."290 loader = spec.loader
291 assert loader is not None, "A loader was not found for the package."
292 self._loader = loader
139}
140
141reverse_operators = {v: k for k, v in operators.items()}
142assert len(operators) == len(reverse_operators), "operators dropped"143operator_re = re.compile(
144 f"({'|'.join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))})"
145)
691 stack = ["root"]
692
693 if state is not None and state != "root":
694 assert state in ("variable", "block"), "invalid state"695 stack.append(state + "_begin")
696
697 statetokens = self.rules[stack[-1]]
135 continue
136
137 target = self.find_ref(name) # type: ignore
138 assert target is not None, "should not happen"139
140 if self.parent is not None:
141 outer_target = self.parent.find_ref(name)
887 if leeway is None:
888 leeway = env.policies["truncate.leeway"]
889
890 assert length >= len(end), f"expected length >= {len(end)}, got {length}" 891 assert leeway >= 0, f"expected leeway >= 0, got {leeway}"
892
893 if len(s) <= length + leeway:
888 leeway = env.policies["truncate.leeway"]
889
890 assert length >= len(end), f"expected length >= {len(end)}, got {length}"
891 assert leeway >= 0, f"expected leeway >= 0, got {leeway}" 892
893 if len(s) <= length + leeway:
894 return s
124
125def _environment_config_check(environment: "Environment") -> "Environment":
126 """Perform a sanity check on the environment."""
127 assert issubclass( 128 environment.undefined, Undefined 129 ), "'undefined' must be a subclass of 'jinja2.Undefined'." 130 assert (
131 environment.block_start_string
132 != environment.variable_start_string
127 assert issubclass(
128 environment.undefined, Undefined
129 ), "'undefined' must be a subclass of 'jinja2.Undefined'."
130 assert ( 131 environment.block_start_string 132 != environment.variable_start_string 133 != environment.comment_start_string 134 ), "block, variable and comment start strings must be different." 135 assert environment.newline_sequence in {
136 "\r",
137 "\r\n",
132 != environment.variable_start_string
133 != environment.comment_start_string
134 ), "block, variable and comment start strings must be different."
135 assert environment.newline_sequence in { 136 "\r", 137 "\r\n", 138 "\n", 139 }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." 140 return environment
141
142
834 def log_function(x: str) -> None:
835 pass
836
837 assert log_function is not None 838 assert self.loader is not None, "No loader configured."
839
840 def write_file(filename: str, data: str) -> None:
835 pass
836
837 assert log_function is not None
838 assert self.loader is not None, "No loader configured." 839
840 def write_file(filename: str, data: str) -> None:
841 if zip:
899
900 .. versionadded:: 2.4
901 """
902 assert self.loader is not None, "No loader configured." 903 names = self.loader.list_templates()
904
905 if extensions is not None:
825 def visit_Template(
826 self, node: nodes.Template, frame: t.Optional[Frame] = None
827 ) -> None:
828 assert frame is None, "no root frame allowed" 829 eval_ctx = EvalContext(self.environment, self.name)
830
831 from .runtime import exported, async_exported
Usage of assert
statement in application logic is discouraged. assert
is removed with compiling to optimized byte code. Consider raising an exception instead. Ideally, assert
statement should be used only in tests.
Python has an option to compile the optimized bytecode and create the respective .pyo
files by using the options -O
and -OO
. When used, these basic optimizations are done:
- All the assert statements are removed
- All docstrings are removed (when -OO is selected)
- Value of the
__debug__
built-in variable is set toFalse
It is recommended not to use assert
in non-test files. A better way for internal self-checks is to check explicitly and raise respective error using an if statement.
Tip: Make sure test_patterns
are defined in .deepsource.toml
to avoid false-positives. Please check the documentation to know more.
Consider this code snippet:
def read_secret(self):
assert self.is_admin, "You are unauthorized to read this"
return self._secret
If python
is run with the -O
flag, the check for self.is_admin
is
completely ignored, which can cause secrets to be leaked.
This is how you can ensure the code always works:
def read_secret(self):
if not self.is_admin:
raise AssertionError("You are unauthorized to read this")
return self._secret
Here's a more detailed example. Consider the following script foo.py
:
import sys
def run():
assert len(sys.argv) == 5 # Insecure, statement will be removed when compiled to optimized byte code
print("Argument variables are: ", sys.argv)
run()
When optimization is disabled:
$ python foo.py 1 2 3 4 5
Traceback (most recent call last):
File "foo.py", line 7, in <module>
run()
File "foo.py", line 4, in run
assert len(sys.argv) == 5 # Insecure, statement will be removed when compiled to optimized byte code
AssertionError
When optimization is enabled:
$ python -O foo.pyo 1 2 3 4 5 6
Argument variables are: ['foo.pyo', '1', '2', '3', '4', '5', '6']
Here, all the internal self-checks using the assert statements are removed, as we can see. Therefore, there's a chance for an application to behave strangely in this case. It is better do raise the Exception explicitly:
import sys
def run():
if not len(sys.argv) == 5:
raise ValueError
print("Argument variables are: ", sys.argv)
run()
Note: During autofix, DeepSource will change the assert
statements to if
statements raising AssertionError
.
This is done to replicate the existing behavior.
References:
- -O flag in python
- -OO flag in python
- Discuss blogpost - Using assert outside tests