Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to config & run linter programmatically #246

Open
uvsmtid opened this issue Jan 5, 2025 · 6 comments
Open

Add support to config & run linter programmatically #246

uvsmtid opened this issue Jan 5, 2025 · 6 comments

Comments

@uvsmtid
Copy link

uvsmtid commented Jan 5, 2025

Configuring and running import-linter programmatically has multiple benefits:

  • Referencing modules by their imported names (instead of opaque string in configs)?

    This reliably survives refactoring (especialy if this code runs in tests - see below).

  • Generating rules instead of relying on static config files?

    It is still possible to generate config files and then load them, but it would:

    • pollute file system
    • make it cumbersome
  • Running import-linter via tests?

    It "lints" relationship between modules (not code as text).

    This should allow running it in the same Python runtime with those modules under tests.

@uvsmtid uvsmtid changed the title Add support to configure linter with direct in-memory config data to run it programmatically Add support to config & run linter programmatically Jan 5, 2025
@uvsmtid
Copy link
Author

uvsmtid commented Jan 5, 2025

I actully tried to hack it only to realize that import-linter tests already use FakeUserOptionReader for that purpose.

The issue can be reduced to exposing that FakeUserOptionReader as production code nicely - it is currently under test code.

@seddonym
Copy link
Owner

seddonym commented Jan 6, 2025

Thanks for the issue! I'd like to clarify what you are trying to achieve here.

  • If you need to, it's already possible to invoke Import Linter using a Python function - this is the entry point.
  • You can also write custom contract types - if you want to be able to do something more dynamic that Import Linter doesn't already support.

Are you looking for a way to dynamically generate the contract / configuration that Import Linter discovers?

@uvsmtid
Copy link
Author

uvsmtid commented Jan 6, 2025

@seddonym

Good example - let me explain...

I'm focusing on the 1st bullet only (with invocation entry point) - the 2nd one (custom contract types) is outside the scope for this issue.

The problem is config_filename argument to this entry point function - when it is specified (as I understand it), import-linter is forced to read actual config file on the file system.

The point is to avoid creating any config file (and simply pass config from code = from memory), for example, in my hack, I simply initialized some OptionReader with a data: dict which then passes its data for UserOptions:

        data = self.data.copy()
        session_options = data.get("session_options", {})
        contracts_options = data.get("contracts_options", [])
        return UserOptions(session_options=session_options, contracts_options=contracts_options)

That's all I want:

  • pass that data: dict
  • do not read any file

Tests of import-linter perform equivalent trick via FakeUserOptionReader (even simpler = just save given UserOptions directly instead of getting data: dict). However, FakeUserOptionReader is not accessible via import-linter package because it is part of the tests (not packaged).

@seddonym
Copy link
Owner

seddonym commented Jan 8, 2025

Got it. I think that importlinter.application.create_report should do what you need, as you can pass in the options directly as types, and it returns a Report object.

@uvsmtid
Copy link
Author

uvsmtid commented Jan 12, 2025

@seddonym

I created few rules as unit tests, for example, test_import_linter_assumptions.py.

And I am pretty happy with that. Thanks for the pointers!

You can see that I reference modules by their compiler-enforced names (instead of opaque strings) which makes it easier for the rule to survive refactoring. Also, unit tests are free to provide extra context and structure - they are free from specific config format.

I guess the issue can be closed unless you want to make a change to enforce stability of this API.
In fact, that use case makes import-linter:

  • more of a library (with API)
  • rather than a CLI tool (with config schema)

@seddonym
Copy link
Owner

There is already a Python API for reading configuration, so I'd be happy to have a similar thing for create_report. Happy to review a PR that adds docs for that (maybe for the time being we could just import create_report into the api module so it's available from there).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants