pdoc icon indicating copy to clipboard operation
pdoc copied to clipboard

Is there a way to determine if run/imported by pdoc at runtime?

Open lovetheguitar opened this issue 2 years ago • 8 comments

We have to deal with C# dlls and have some wrapper objects around those.

When run with pdoc we'd like to mock these objects to get descriptive documentation.

Is there a some environment variable or anything set by pdoc that would give us this information, e.g. like if TYPE_CHECKING.

Currently we are catching import errors and replacing it with mocks, which gives us nice documentation, but in case a dll is missing we loose valuable tracebacks.

Thanks a lot for maintaining this lovely piece of code. 😸

lovetheguitar avatar Nov 04 '22 13:11 lovetheguitar

I'm not sure if I understand what exactly your problem is. You want to detect if pdoc is running during import, is that correct?

If you have some weird import quirks, my general recommendation would be to write a Python script where you first do whatever you need to do for your imports to work, and then call pdoc programatically: https://github.com/mitmproxy/pdoc/blob/main/examples/library-usage/make.py

mhils avatar Nov 04 '22 14:11 mhils

I'm using pdoc only via command line and would like to keep it that way very much.

I have code like this:

try:
    from msl import loadlib

    for dll_name in _REQUIRED_DLLS:
        dll_path = PACKAGE_BIN_DIRECTORY / dll_name
        if not dll_path.exists:
            raise DllError(f'Dependency "{dll_path}" not found')
        loadlib.LoadLibrary(str(dll_path), "net")
    del dll_name, dll_path
    from Drivers import (  # noqa: E402
        MeasurementEquipment as _MeasurementEquipment,
    )
    from HP3458 import HP3458 as _HP3458  # noqa: E402
except ModuleNotFoundError:
    warnings.warn(
        "Could not load dlls"
        RuntimeWarning,
    )
    # The documentation is built on Ubuntu, therefore we need to mock the imports of the dll stuff.
    _HP3458 = mock.MagicMock()
    _MeasurementEquipment = mock.MagicMock()

I'd like to improve this to something like

if os.environ["PDOC_DOCUMENTATION_RUN"] == "True":
    _HP3458 = mock.MagicMock()
    _MeasurementEquipment = mock.MagicMock()
else:
    from msl import loadlib

    for dll_name in _REQUIRED_DLLS:
        dll_path = PACKAGE_BIN_DIRECTORY / dll_name
        if not dll_path.exists:
            raise DllError(f'Dependency "{dll_path}" not found')
        loadlib.LoadLibrary(str(dll_path), "net")
    del dll_name, dll_path
    from Drivers import (  # noqa: E402
        MeasurementEquipment as _MeasurementEquipment,
    )
    from HP3458 import HP3458 as _HP3458  # noqa: E402

lovetheguitar avatar Nov 04 '22 14:11 lovetheguitar

You could just set an env var and then run pdoc? If you are on Linux, that'd be

PDOC_DOCUMENTATION_RUN=1 pdoc ...

mhils avatar Nov 04 '22 21:11 mhils

Then I'd have to set and unset this variable any time I wanted to see/build the documentation or use the application/run tests on it.

I was thinking about something similar to this in pytest https://docs.pytest.org/en/7.1.x/example/simple.html#detect-if-running-from-within-a-pytest-run or https://docs.pytest.org/en/7.1.x/example/simple.html#pytest-current-test-environment-variable.

Maybe there is some other, more elegant way that would accomplish that?

Thanks a lot for for your help. 😺

lovetheguitar avatar Nov 04 '22 21:11 lovetheguitar

Maybe there is some other, more elegant way that would accomplish that?

I personally would use an environment variable as it makes things relatively clean, but if you are so inclined you can of course also do import sys; if "pdoc" in sys.modules: ...

mhils avatar Nov 05 '22 15:11 mhils

Would you be open to a PR adding that functionality, correctly setting & unsetting such an environment variable, and documenting it?

lovetheguitar avatar Nov 05 '22 22:11 lovetheguitar

I don't have a particular strong opinion here, but this feels very much like an edge case that doesn't warrant extra complexity in pdoc itself. I'm trying hard to not replicate Sphinx in terms of configurability, and this just may not pass the bar. If we find that more folks are chiming in here I'm more than willing to reconsider though. :)

mhils avatar Nov 10 '22 12:11 mhils

I actually have this exact problem when building documentation on Linux for a module designed to run using ctypes.WinDLL on windows. I currently have something like the code below, but I'm not a huge fan of it.

# Check the platform to allow for
plat = platform.platform()
if "Windows" not in plat:
    msg = "%s can't import WinDLL -- abstracting away for documentation purposes" % plat
    LOG.error(msg)
    ctypes.WinDLL = object
    import sys
    if not "pdoc" in sys.modules:
        raise EnvironmentError(msg)

jeinstei avatar Nov 30 '23 20:11 jeinstei