github / codeql

CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security
https://codeql.github.com
MIT License
7.53k stars 1.5k forks source link

LGTM.com - false positive; The module 'urwid' imports itself #3429

Open abadger opened 4 years ago

abadger commented 4 years ago

Description of the false positive

Summary:

There seems to be a problem either with detecting Python3 namespace packages properly or with separation of Python3 absolute imports vs relative imports (or the combination of both) leading to false positives when a module, not at the toplevel imports a toplevel library of the same name.

URL to the alert on the project page on LGTM.com https://lgtm.com/projects/g/abadger/stellarmagnate/snapshot/fd6bd899321e58db828afcb0622275c867a6fa1e/files/magnate/ui/urwid/__init__.py?sort=name&dir=ASC&mode=heatmap#xba047dafaec728fd:1

Background:

There is a Python library named urwid which makes curses (screen-based, text-based user interfaces) easier to program. My application has plugins for different UIs. The plugin for urwid is named, urwid. So if my project and the urwid library were both installed in the same directory structure it would look like this:

site-packages
├── stellarmagnate
│   └── ui
│       └── urwid
│           └── __init__.py
└── urwid
    └── __init__.py

Now, I want plugins to be installable in different directories. For instance, stellarmagnate might come pre-installed on a Linux distro via rpm packages in /usr/lib/python3.8/site-packages/stellarmagnate. The user might then install a new ui plugin via pip install stellarmagnate-ui-kivy --user to ~/.local/lib/python3.8/site-packages/stellarmagnate.

To achieve that I use Python's Implicit namespace packages: https://www.python.org/dev/peps/pep-0420/ Which tell Python to allow importing non-conflicting python modules from multiple locations on the PYTHONPATH. As you can see in the directory structure above, only two directories have __init__.py files. The other directories are implicit namespace packages. So when stellarmagnate.ui.urwid is imported, Python will look in /usr/lib/python3.8/site-packages/stellarmagnate/ui/ for urwid. If it's not there, it will look in ~/.local/lib/python3.8/site-packages/stellarmagnate/ui/ for urwid, and so forth along all of the PYTHONPATH directories.

Specifics: My urwid plugin imports the urwid library using this code in stellarmagnate/ui/urwid/__init__.py:

import urwid

lgtm is flagging this as a python module importing itself. That would be true in Python2 (unless from __future__ import absolute_imports was specified, which gives Python2 the same behaviour as Python3) but in Python3, it is importing the toplevel urwid module from directly in the site-packages directory. If the plugin was importing itself it would either have to use a relative import:

from . import urwid

or it would have to be directly on the PYTHONPATH. (ie: if site-packages/urwid/__init__.py had a import urwid, then that would be an illegal self import.)

I'm not sure if relative imports or implicit namespaces are confusing the analysis but one or the other seems likely.

RasmusWL commented 4 years ago

Thanks for your detailed report @abadger :+1:

I know @tausbn has been looking at how we handle imports recently, so hopefully it will be useful information for him :blush:

kojiromike commented 1 year ago

We are still seeing this in 2023.