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

Module self-reference makes it impossible to access code in prettyprinter.py #93

Open
macdjord opened this issue Mar 6, 2023 · 0 comments

Comments

@macdjord
Copy link

macdjord commented Mar 6, 2023

  • PrettyPrinter version: 0.18.0
  • Python version: 3.11.2
  • Operating System: Win10

Description

I tried to import prettyprinter/prettyprinter.py so that I could properly type-hint the 'context' argument to my custom printer function. However, when I did so, I was informed that prettyprinter.prettyprinter did not contain any attribute PrettyContext.

On investigation, I discovered that prettyprinter (the package corresponding to prettyprinter/) contains, on initial import, already contains a member named prettyprinter, but this member is actually just a circular reference to the package itself. This makes it impossible to import prettyprinter.prettyprinter (the module corresponding to prettyprinter/prettyprinter.py).

What I Did

import prettyprinter as _prettyprinter
import prettyprinter.doctypes as __
import prettyprinter.prettyprinter as __


class Timestamp:
    ...


@_prettyprinter.register_pretty(Timestamp)
def pretty_timestamp(
        timestamp: Timestamp,
        ctx: _prettyprinter.prettyprinter.PrettyContext,
) -> _prettyprinter.doctypes.Doc:
    ...

Output:

Traceback (most recent call last):
  File "[REDACTED]/test.py", line 13, in <module>
    ctx: _prettyprinter.prettyprinter.PrettyContext,
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'prettyprinter' has no attribute 'PrettyContext'
import prettyprinter as _prettyprinter
print(f"{_prettyprinter=}")
print(f"{_prettyprinter.prettyprinter=}")
import prettyprinter.prettyprinter as _pp_pp
print(f"{_pp_pp=}")
print(f"{_pp_pp.prettyprinter=}")

Output:

_prettyprinter=<module 'prettyprinter' from 'C:\\Python311\\Lib\\site-packages\\prettyprinter\\__init__.py'>
_prettyprinter.prettyprinter=<module 'prettyprinter' from 'C:\\Python311\\Lib\\site-packages\\prettyprinter\\__init__.py'>
_pp_pp=<module 'prettyprinter' from 'C:\\Python311\\Lib\\site-packages\\prettyprinter\\__init__.py'>
_pp_pp.prettyprinter=<module 'prettyprinter' from 'C:\\Python311\\Lib\\site-packages\\prettyprinter\\__init__.py'>

The Fix

This is caused by the following line in prettyprinter/__init__.py:

import prettyprinter.pretty_stdlib

As well as actually importing the pretty_stdlib module, this also, as a side-effect, adds a member to package prettyprinter whose value is the package prettyprinter. (Actually, I'm amazed this doesn't cause an import cycle error.)

The fix is to change that line to:

from . import pretty_stdlib

Or:

import prettyprinter.pretty_stdlib as __

Workaround

Until this bug is fixed, this is a workaround:

import prettyprinter as _prettyprinter
del _prettyprinter.prettyprinter
import prettyprinter.prettyprinter as _pp_pp

Note that with this workaround you can only access the prettyprinter.py code using _pp_pp; trying to do _prettyprinter.prettyprinter will not work.

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

1 participant