Visitar URL original
Uninstalled linter packages stay registered in persist.linter_classes and keep linting until restart · Issue #1998 · SublimeLinter/SublimeLinter · GitHub
Skip to content

Uninstalled linter packages stay registered in persist.linter_classes and keep linting until restart #1998

Open

Description

@dpc00

After uninstalling a linter plugin (for example SublimeLinter-eslint) through Package Control, its linter class stays registered in persist.linter_classes and keeps linting every matching view until Sublime Text is restarted.

Repro (Sublime Text 4215 on Windows, Python 3.14 host, SublimeLinter from Package Control, SublimeLinter-eslint installed with eslint in a project node_modules):

  1. Open a .js file in that project; eslint results appear.
  2. Remove the linter package with Package Control ("Remove Package" > SublimeLinter-eslint). Package Control reports the removal as done and the .sublime-package file is deleted; the console prints unloading plugin SublimeLinter-eslint.linter.
  3. Open another .js file in the project.

Expected: no eslint results, the linter is gone.

Actual: the new view is still linted by eslint. In the console of the same session:

>>> from SublimeLinter.lint import persist
>>> sorted(persist.linter_classes)
['csslint', 'eslint', 'jshint', 'php']      # all four linter packages had already been removed

I saw the same thing when a package file was deleted directly (jshint, php, csslint) and when using Package Control's remove_package() (eslint): the class object of the removed package is still in persist.linter_classes and still assigned to buffers, and the linter binary is still executed.

Cause: linter.register_linter() does persist.linter_classes[name] = cls, and nothing removes the entry when the plugin module is unloaded. persist.py has no unregister function.

Suggested fix: drop entries from persist.linter_classes whose module is no longer loaded (in plugin_unloaded of the wrapper via a hook, or by checking cls.__module__ in sys.modules in assign_linters_to_buffer), and clear their errors from the store.

Activity

  1. kaste commented on Sep 29, 2026

    @kaste
    Member

    Ack, this is a long- (ever-) standing issue. Unsure about the best fix.

  2. kaste commented on Sep 29, 2026

    @kaste
    Member

    Actually, https://packages.sublimetext.io/packages/SublimeLinter-addon-toggler implements part of this by watching the settings/Preferences. That would mean a separate plugin on the root just for this feature; pulling the toggler code and extending it with the use case here.

  3. dpc00 commented on Sep 29, 2026

    @dpc00
    Author

    FWIW I opened a small PR for this, #1999: elect drops linters whose plugin module is no longer in sys.modules. Since Sublime pops the module when it unloads the plugin, this needs no extra plugin and no cooperation from the linter packages, and it works no matter how the package went away (removed, disabled, file deleted). Happy to rework it if you would rather go the toggler route.

  4. kaste commented on Sep 29, 2026

    @kaste
    Member

    The toggler runs once, as response/reaction to an event, and can call sublime_linter_config_changed which is semantically the right thing to do. Calling that while actually being in a "lint"-process seems more convoluted or brittle.

  5. dpc00 commented on Sep 29, 2026

    @dpc00
    Author

    Agreed on the design, thanks. I reworked #1999 that way: it now observes ignored_packages and Package Control's settings, and after a change forgets the linters of disabled or unloaded plugins and calls sublime_linter_config_changed once. Nothing runs in the lint path any more. I checked it live by removing SublimeLinter-json through Package Control: the linter was gone and the open view lost its errors without a restart.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions