PyPI / sqlalchemy / 2.1.6

sqlalchemy 2.1.6

Source
https://github.com/sqlalchemy/sqlalchemy
Artifact scanned
sqlalchemy-2.1.6-py3-none-any.whl (wheel · 2.0 MB · SHA-256 106878cf3795…)
Compared with
sqlalchemy-2.1.5-py3-none-any.whl (0 signals introduced since)
Files
260 scanned, 8 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 28 info
Scan time
19.6 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 24 of 24 warn and critical signals; 24 demoted to info.
Disclude version
4.3.0
Scanned (UTC)
2026-10-23 03:30

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. info critical → info by review dynamic-import sqlalchemy/dialects/__init__.py:48:22

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

            else:
                module = __import__("sqlalchemy.dialects.%s" % (dialect,)).dialects
                module = getattr(module, dialect)
        except ImportError:
    likely benign LLM, confidence 0.93 Loads a SQLAlchemy dialect module by name from the URL scheme.
    Reasoning

    The dialect name comes from the URL scheme parsed by SQLAlchemy and is used to load a bundled dialect package under sqlalchemy.dialects. This is the documented plugin-loading mechanism, and the ImportError handling is ordinary.

  2. info critical → info by review dynamic-import sqlalchemy/dialects/mysql/mariadb.py:49:19

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

    def loader(driver: str) -> type[MariaDBDialect]:
        dialect_mod = __import__(
            "sqlalchemy.dialects.mysql.%s" % driver
        ).dialects.mysql
    likely benign LLM, confidence 0.93 Imports a MariaDB driver submodule chosen by driver name.
    Reasoning

    The driver name selects one of the bundled MySQL/MariaDB driver submodules. The namespace is fixed to the sqlalchemy package, so this is ordinary dialect dispatch.

  3. info critical → info by review dynamic-import sqlalchemy/dialects/mysql/mariadbconnector.py:210:32

    `__import__` called on a non-literal expression (ast pass, confidence 0.90)

                try:
                    CLIENT_FLAGS = __import__(
                        self.dbapi.__name__ + ".constants.CLIENT"
                    ).constants.CLIENT
    likely benign LLM, confidence 0.93 Imports the driver's constants.CLIENT module to read client flags.
    Reasoning

    The module is the DBAPI's own name plus a fixed suffix, used to fetch client flag constants. This is a standard way to locate a driver's constants module.

  4. info critical → info by review dynamic-import sqlalchemy/dialects/mysql/mysqldb.py:260:32

    `__import__` called on a non-literal expression (ast pass, confidence 0.90)

                try:
                    CLIENT_FLAGS = __import__(
                        self.dbapi.__name__ + ".constants.CLIENT"
                    ).constants.CLIENT
    likely benign LLM, confidence 0.93 Imports the MySQLdb constants.CLIENT module to read client flags.
    Reasoning

    Same pattern as the MariaDB connector: the DBAPI's own module name plus a fixed suffix to read CLIENT flags. Nothing here reaches outside the driver package.

  5. info critical → info by review dynamic-import sqlalchemy/engine/default.py:742:13

    `__import__` called on a non-literal expression (ast pass, confidence 0.90)

            try:
                __import__(package + ".provision")
            except ImportError:
                pass
    likely benign LLM, confidence 0.90 Optionally imports a dialect's provision submodule, ignoring ImportError.
    Reasoning

    Imports an optional provisioning helper package for a dialect, and ImportError is suppressed. This is test-support plumbing with no sign of malicious intent.

  6. info warn → info by review dynamic-attribute sqlalchemy/event/base.py:335:9

    reach-by-name through `globals` (ast pass, confidence 0.60)

            # establish pickle capability by adding it to this module
            globals()[klass.__name__] = klass
    likely benign LLM, confidence 0.88 Registers a generated event class in module globals to support pickling.
    Reasoning

    Assigns the class into module globals so it can be pickled, a documented technique for making dynamically created classes picklable. It does not execute anything.

  7. info warn → info by review dynamic-execution sqlalchemy/orm/clsregistry.py:592:21

    `eval` called on a non-literal expression (ast pass, confidence 0.70)

                try:
                    x = eval(self.arg, globals(), self._dict)
    
                    if isinstance(x, _GetColumns):
    likely benign LLM, confidence 0.88 Evaluates declarative string expressions for relationship arguments.
    Reasoning

    eval is applied to string expressions from mapper configuration such as relationship primaryjoin strings, with an explicit namespace. This is a known and intentional feature of declarative configuration, and the input is developer-supplied model code.

  8. info warn → info by review dynamic-attribute sqlalchemy/sql/annotation.py:562:5

    reach-by-name through `globals` (ast pass, confidence 0.60)

        )
        globals()["Annotated%s" % cls.__name__] = anno_cls
    
        if "_traverse_internals" in cls.__dict__:
    likely benign LLM, confidence 0.88 Generates and registers an Annotated class variant in module globals.
    Reasoning

    Creates an Annotated<ClassName> class and stores it in globals, derived from a class already in the codebase. This is internal class generation with no external input.

  9. info warn → info by review dynamic-attribute sqlalchemy/sql/coercions.py:1366:20

    reach-by-name through `globals` (ast pass, confidence 0.60)

            if name in globals():
                impl = globals()[name](cls)
                _impl_lookup[cls] = impl
    likely benign LLM, confidence 0.88 Instantiates a coercion implementation class looked up by name in globals.
    Reasoning

    Looks up a coercion implementation class by name from a fixed set of module-defined classes. The lookup is internal and does not come from untrusted input.

  10. info warn → info by review dynamic-execution sqlalchemy/sql/lambdas.py:1264:9

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

            vars_ = {"o%d" % i: cell_values[i] for i in argrange}
            exec(code, vars_, vars_)
            closure = vars_["make_cells"]()
    likely benign LLM, confidence 0.85 Executes internally generated code to rebuild closure cells for lambda caching.
    Reasoning

    exec runs generated code that builds closure cells for SQL lambda caching. The code is produced by SQLAlchemy from its own templates, and the values are the lambda's captured closure variables, not external input.

  11. info critical → info by review dynamic-import sqlalchemy/testing/engines.py:250:17

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

                mod = getattr(
                    __import__("sqlalchemy.dialects.%s" % name).dialects, name
                )
            yield mod.dialect()
    likely benign LLM, confidence 0.90 Imports a dialect module by name in the test engine helper.
    Reasoning

    Imports a dialect module by name for the test engine helper. The name is a test parameter, and the code is test-only.

  12. info warn → info by review frame-introspection sqlalchemy/testing/fixtures/mypy.py:118:27

    `inspect.stack` — call-stack frame introspection (ast pass, confidence 0.70)

            else:
                caller_path = inspect.stack()[1].filename
                path = os.path.join(os.path.dirname(caller_path), dirname)
            files = list(Path(path).glob("**/*.py"))
    likely benign LLM, confidence 0.88 Uses the caller's stack frame to resolve a test-fixture directory.
    Reasoning

    Inspects the caller's file path to locate test fixture files for mypy checks. This is a common test-suite pattern with no network, exec, or persistence behavior.

  13. info critical → info by review dynamic-import sqlalchemy/testing/plugin/plugin_base.py:487:11

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

        # late
        mod = __import__(modname)
        for component in modname.split(".")[1:]:
            mod = getattr(mod, component)
    likely benign LLM, confidence 0.90 Imports a test module from a dotted name in the pytest plugin.
    Reasoning

    Imports a test module from a dotted name taken from the test configuration. The code is pytest plugin plumbing with no external input path to it.

  14. info warn → info by review dynamic-execution sqlalchemy/testing/plugin/pytestplugin.py:671:9

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

            # in format_argpsec_plus()
            exec(code, env)
            return env[fn_name]
    likely benign LLM, confidence 0.87 Executes generated source to build a test function with a matching signature.
    Reasoning

    exec compiles a generated function signature for test argument handling, which is the standard approach used to preserve argspecs. The code is produced internally.

  15. info warn → info by review frame-introspection sqlalchemy/testing/schema.py:192:18

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

        try:
            module = sys._getframe(1).f_globals.get("__name__", "__main__")
        except (AttributeError, ValueError):
            pass
    likely benign LLM, confidence 0.88 Reads the caller's module name from the stack frame in a test schema helper.
    Reasoning

    Reads the caller's module name from the frame to set a table's schema module. This is a benign introspection pattern in test helpers.

  16. identifier `é試蛇ẟΩ` mixes scripts: Latin + Han + Greek (in string/comment) (raw pass, confidence 0.40)

                metadata,
                Column("unicode", Integer, comment="é試蛇ẟΩ"),
                Column("emoji", Integer, comment="☁⟨U+FE0F⟩✨"),
                comment="試蛇ẟΩ✨",
  17. identifier `試蛇ẟΩ` mixes scripts: Han + Latin + Greek (in string/comment) (raw pass, confidence 0.40)

                Column("emoji", Integer, comment="☁⟨U+FE0F⟩✨"),
                comment="試蛇ẟΩ✨",
            )
  18. identifier `試蛇ẟΩ` mixes scripts: Han + Latin + Greek (in string/comment) (raw pass, confidence 0.40)

            tc = insp.get_table_comment("unicode_comments")
            eq_(tc, {"text": "試蛇ẟΩ✨"})
    
            cols = insp.get_columns("unicode_comments")
  19. identifier `é試蛇ẟΩ` mixes scripts: Latin + Han + Greek (in string/comment) (raw pass, confidence 0.40)

            value = {c["name"]: c["comment"] for c in cols}
            exp = {"unicode": "é試蛇ẟΩ", "emoji": "☁⟨U+FE0F⟩✨"}
            eq_(value, exp)
  20. info warn → info by review dynamic-execution sqlalchemy/util/langhelpers.py:453:16

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

                linecache_cache[filename] = entry
            code = compile(code, filename, "exec")
    
        exec(code, env)
    likely benign LLM, confidence 0.88 Compiles and executes generated function source to create a decorated wrapper.
    Reasoning

    Compiles and execs generated function source. The filename is registered in linecache for tracebacks, and the code comes from SQLAlchemy's own decorator generation, which is a standard metaprogramming technique.

  21. info warn → info by review dynamic-execution sqlalchemy/util/langhelpers.py:455:5

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

    
        exec(code, env)
        fn = env[fn_name]
    likely benign LLM, confidence 0.85 exec of generated function source in SQLAlchemy's decorator helper.
    Reasoning

    SQLAlchemy's langhelpers uses exec to generate function bodies from templated source (decorator generation, self-compiled wrappers), then pulls the named function out of env. This is a known, documented metaprogramming pattern in the library; the code is generated internally rather than fetched from outside.

  22. info critical → info by review dynamic-import sqlalchemy/util/langhelpers.py:507:19

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

            def load():
                mod = __import__(modulepath)
                for token in modulepath.split(".")[1:]:
                    mod = getattr(mod, token)
    likely benign LLM, confidence 0.85 Deferred module import helper that imports a dotted path and walks attributes.
    Reasoning

    Lazy-loading a module by dotted path via __import__ followed by getattr traversal is a standard deferred-import idiom (e.g. the dependency-loading helper for optional modules). The modulepath comes from library-internal constants, not untrusted input or network data.

  23. info critical → info by review frame-introspection sqlalchemy/util/langhelpers.py:2066:17

    `sys._getframe` — call-stack frame introspection — file also calls `sys.exit`/`exec`/`eval` (anti-analysis shape) (ast pass, confidence 0.85)

        try:
            frame = sys._getframe(stacklevel)
        except ValueError:
            # being called from less than 3 (or given) stacklevels, weird,
    likely benign LLM, confidence 0.80 Call-stack frame lookup used to find the caller for warning attribution.
    Reasoning

    sys._getframe with a stacklevel is used to determine the caller's module for warnings/deprecation messages, a common legitimate pattern. The 'anti-analysis' shape is a heuristic match only; the snippet shows no evasion or hiding behavior.

  24. info warn → info by review dynamic-execution sqlalchemy/util/langhelpers.py:2169:5

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

        env = locals().copy()
        exec(code, env)
        return env["set"]
    likely benign LLM, confidence 0.85 exec used to build a compatibility function returned as env['set'].
    Reasoning

    Exec of a generated code string with a copied locals dict to return a constructed function (the 'set' builtin shadowing pattern) is an internal code-generation idiom used in SQLAlchemy for Python-version compatibility shims. No external input or obfuscation is evident.

  25. info critical → info by review dynamic-import sqlalchemy/util/preloaded.py:142:17

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

                ) and key not in self.__dict__:
                    __import__(module, globals(), locals())
                    self.__dict__[key] = globals()[key] = sys.modules[module]
    likely benign LLM, confidence 0.85 Lazy import of a named module cached into the module namespace on first attribute access.
    Reasoning

    The preloaded module implements lazy module attribute loading: it imports a named module on first access and caches it in __dict__ and globals. This is a known, legitimate lazy-import design in SQLAlchemy.

  26. info warn → info by review dynamic-attribute sqlalchemy/util/preloaded.py:143:38

    reach-by-name through `globals` (ast pass, confidence 0.60)

                    __import__(module, globals(), locals())
                    self.__dict__[key] = globals()[key] = sys.modules[module]
    likely benign LLM, confidence 0.80 Caches lazily imported module into globals and instance dict.
    Reasoning

    Caching the imported module via globals() is part of the same lazy-loading mechanism; reaching by name through globals is ordinary Python for module-level caching and carries no malicious indication.

  27. info warn → info by review dynamic-execution sqlalchemy/util/typing.py:265:26

    `eval` called on a non-literal expression (ast pass, confidence 0.70)

    
                annotation = eval(expression, cls_namespace, locals_)
            else:
                annotation = eval(expression, base_globals, locals_)
    likely benign LLM, confidence 0.85 eval used to resolve string type annotations against a namespace.
    Reasoning

    eval of type annotation strings with class and module namespaces is how typing.get_type_hints-style resolution works; SQLAlchemy uses it to resolve forward-reference annotations from its own source. The input is annotation text, not attacker-controlled data in this context.

  28. info warn → info by review dynamic-execution sqlalchemy/util/typing.py:267:26

    `eval` called on a non-literal expression (ast pass, confidence 0.70)

            else:
                annotation = eval(expression, base_globals, locals_)
        except Exception as err:
            raise NameError(
    likely benign LLM, confidence 0.85 eval fallback resolving string annotations against base globals.
    Reasoning

    Same annotation-resolution eval in the fallback branch with base globals; it is the standard forward-reference resolution technique and is wrapped to raise NameError on failure, consistent with legitimate typing introspection.

Reproduce This Scan

Run disclude locally to verify. These commands scan the published file; the "new in this release" marks come from comparing it with the previous release's file, which they don't repeat. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.3.0
curl -fsSL -o sqlalchemy-2.1.6-py3-none-any.whl https://files.pythonhosted.org/packages/c1/69/c75534e336b06b3fd3f76de73d89736510800e60c77c58d4e4ce18389018/sqlalchemy-2.1.6-py3-none-any.whl
printf '%s  %s\n' 106878cf3795cd3d357e2e858609f9e44f20f19b2d8e48a3532bef3f90b03fbe sqlalchemy-2.1.6-py3-none-any.whl | shasum -a 256 -c -
unzip -q sqlalchemy-2.1.6-py3-none-any.whl -d pkg
disclude scan --untrusted --severity info pkg