Imports of forbidden external submodules incorrectly pass
I was trying to implement a "forbidden" contract like this:
[importlinter]
root_package = poliastro
include_external_packages=True
[importlinter:contract:1]
name=poliastro.core does not import astropy.units
type=forbidden
source_modules=
poliastro.core
forbidden_modules=
astropy.units
But, even though I have some files that do from astropy import units as u:
src/poliastro/core/elements.py: >>> from astropy import units as u
src/poliastro/core/iod.py: >>> from astropy import units as u
src/poliastro/core/perturbations.py:from astropy import units as u
This isn't properly detected by import-linter:
$ lint-imports --debug
=============
Import Linter
=============
---------
Contracts
---------
Analyzed 104 files, 301 dependencies.
-------------------------------------
poliastro.core does not import astropy.units KEPT
Contracts: 1 kept, 0 broken.
Notice that, if I write only astropy in the contract rather than astropy.units, it works:
$ lint-imports --debug
=============
Import Linter
=============
---------
Contracts
---------
Analyzed 104 files, 301 dependencies.
-------------------------------------
poliastro.core does not import astropy.units BROKEN
Contracts: 0 kept, 1 broken.
----------------
Broken contracts
----------------
poliastro.core does not import astropy.units
--------------------------------------------
poliastro.core is not allowed to import astropy:
- poliastro.core.perturbations -> astropy (l.2)
But this is not what I'm trying to check.
Thanks for raising this!
The issue here is that, since astropy is classified as an external package, it only appears in the graph that Import Linter analyses as a single node astropy. There's a simple thing that should fix it: include astropy as one of the packages under analysis:
[importlinter]
root_packages =
poliastro
astropy
include_external_packages=True
That being said, the current behaviour is confusing.
I think the simplest fix for the time being would be for Import Linter to treat the contract itself as malformed if a submodule of an external package is listed, since it will never be present in the graph. If we want to be able to drill down further into imports of external packages it would require a bit of a rethink of Grimp (the package that Import Linter uses for static analysis).
I'll think on it - but in the meantime let me know if adding astropy to root_packages solved your problem.
Works beautifully! There are just a few warnings:
$ lint-imports
Could not find astropy._dev.scm_version.version when scanning astropy.version. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.stats._fast_sigma_clip._sigma_clip_fast when scanning astropy.stats.sigma_clipping. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.wcs._wcs.__version__ when scanning astropy.wcs.wcsapi.tests.test_fitswcs. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.table._column_mixins._ColumnGetitemShim when scanning astropy.table.column. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.table._column_mixins._MaskedColumnGetitemShim when scanning astropy.table.column. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.io.fits._utils.parse_header when scanning astropy.io.fits.header. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.io.fits.compression.compress_hdu when scanning astropy.io.fits.tests.test_compression_failures. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.timeseries.periodograms.lombscargle.implementations.cython_impl.lombscargle_cython when scanning astropy.timeseries.periodograms.lombscargle.implementations.main. This may be due to a missing __init__.py file in the parent package.
Could not find astropy.timeseries.periodograms.bls._impl.bls_impl when scanning astropy.timeseries.periodograms.bls.methods. This may be due to a missing __init__.py file in the parent package.
=============
Import Linter
=============
---------
Contracts
---------
Analyzed 1060 files, 5617 dependencies.
---------------------------------------
poliastro.core does not import astropy.units KEPT
Contracts: 1 kept, 0 broken.
Great! Could this be because there are missing __init__.py files in the packages?
There is an open issue for allowing these, but in the meantime you could just add the init files if the warnings are bothering you.
They're not bothering me much, only interested in the exit code :) Thanks!
Closing as this should be fixed now there is support for namespace packages.
@seddonym Just chiming in to say I encountered this behavior as well (i.e. wondering why a forbidden external submodule didn't work).
It would have saved me some time to have a had a simple warning. A check if an external module name as a. in it, and link to this issue should save people a lot of time.
Thanks @ariebovenberg - I agree. I think I probably closed this ticket in error, reopening.
Import Linter 1.9.0, just released, now errors if you include an external subpackage in a forbidden module. Enjoy!
Thanks @seddonym for the quick fix!