Skip to content

MF4Writer reports "asammdf package was not found" when asammdf is imported before can #2122

Open

Description

@nehalkpatel

Describe the bug

If asammdf is imported before can, and canopen is also installed, can.io.mf4 decides that
asammdf is missing. Every MF4Writer created later in that process raises:

NotImplementedError: The asammdf package was not found. Install python-can with the optional
dependency [mf4] to use the MF4Writer.

asammdf is installed. The message hides the real cause, which is a circular import.

To Reproduce

The environment needs python-can, asammdf (which pulls in canmatrix) and canopen.

import asammdf
from can.io import MF4Writer

MF4Writer("out.mf4")  # NotImplementedError: The asammdf package was not found...

Importing can first avoids the error:

import can
import asammdf
from can.io import MF4Writer

MF4Writer("out.mf4").stop()  # works

Cause

import asammdf pulls in can.io.mf4 before asammdf has finished initialising:

asammdf/blocks/types.py:5         from canmatrix import CanMatrix
canmatrix/formats/__init__.py:24  importlib.import_module("canmatrix.formats." + module)  # every format
canmatrix/formats/eds.py:4        import canopen.objectdictionary.eds
canopen/network.py:8              import can
can/__init__.py:100               from .io import (...)
can/io/logger.py:36               from .mf4 import MF4Writer
can/io/mf4.py                     from asammdf import Signal, Source   # asammdf partially initialised

The from asammdf import Signal, Source raises ImportError because asammdf is only partly
initialised. The optional-dependency guard catches it:

try:
    import asammdf
    ...
except ImportError:
    asammdf = None

This guard treats "asammdf is not installed" and "asammdf failed to import" as the same thing.
asammdf = None is then stored as a module global, so the wrong answer lasts for the whole
process, even after asammdf finishes importing.

Suggested Fix

Either of these would avoid the problem:

  1. Import asammdf lazily inside MF4Writer.__init__ / MF4Reader.__init__ instead of at module
    import. The cycle can no longer form, and import can gets cheaper too.
  2. Narrow the guard so that only a genuinely missing package counts as missing

Expected behavior

asammdf and can can be imported regardless of order.

Additional context

  • python-can 4.6.1. The same guard is in can/io/mf4.py on main.
  • asammdf 8.7.2, canmatrix 1.2, canopen 2.4.1
  • Python 3.13.11, Linux
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions