Please flatten the PyFPDF Namespace... to recover lost user-developer time due to a "warning" that stops execution and results in an error. #683
Replies: 2 comments 1 reply
-
Hi @richlysakowski! Thank you for the time you took to report this bad user experience.
Could you please mention what was the exact deprecation warning? And what was misleading?
What was the exact import you used?
This class is instantiated there: https://github.com/PyFPDF/fpdf2/blob/2.6.1/fpdf/__init__.py#L24 from fpdf import fpdf
fpdf() Was that the problem in your case?
As a maintainer, I consider backward compatibility a major goal & commitment toward the library users. For all those reasons, I'm not convinced by your suggestion for now.
from fpdf import FPDF
doc = FPDF() Would you have any suggestions @richlysakowski on how to make the import clearer? Just out of curiosity:
As mentioned in the documentation and in the code, this argument is deprecated and useless. As I mentioned above, the goal of the I hope I answer all your questions at this point. Again, thank you for your message! 😊 |
Beta Was this translation helpful? Give feedback.
-
Interesting. Thank you for the details.
I don't quite follow you there... What is the meaning of "did not apply" in this context? While you mentioned two kind of error messages,
This is a Python pattern from sir Guido Von Rossum: https://stackoverflow.com/a/72911884/636849
I opened PR #690 to improve the error message in case the |
Beta Was this translation helpful? Give feedback.
-
I appreciate the hard work that so many people have done on fpdf2 to develop and maintain it all these years. We picked it because it really is simpler than most other PDF generators / report writers.
I want to make a suggestion to simplify it even more, because we lost about 4 hours of time the past few days tracking down an error caused by an obscure and misleading deprecation "warning" Exception type. We were trying to apply fpdf2 within a Streamlit application. A poorly worded exception misled us for a long time.... fpdf simple examples worked in one environment and not another, then by itself, but not when called inside the Streamlit script.
We were in the process of completely removing the "deprecation.py" module and all references to it, when I asked the developer how he was importing and referencing the constructor. Then I parsed the namespace from installation to the final constructor function to get the shortest namespace path to reference the constructor. Tracing the full namespace path gave us the correct way to reference it. It was confusing to track down the names because there is an FPDF() inside "fpdf" inside "fpdf" inside "fpdf2" inside PyFPDF.
PROBLEM:
The full path to the FPDF class constructor is:
The full path through the package name, import and path reference is: PyFPDF.fpdf2.fpdf.fpdf.FPDF()
The class FPDF(GraphicsStateMixin) is located in github.com/PyFPDF/fpdf2/fpdf)/fpdf.py
When we finally got it working, the "bug" was due to a simple misnaming of imports.
Should it have been fpdf, fpdf2, FPDF, or "from fpdf2 import FPDF"? Or was it "from fpdf import FPDF"?
The error we got was "TypeError: 'WarnOnDeprecatedModuleAttributes' object is not callable".
The currently 3-level nested namespace path "fpdf2.fpdf.fpdf.FPDF()" made it easy to unwittingly rename / misname the imports and throw an exception error. The exception thrown is: "WarnOnDeprecatedModuleAttributes", which has nothing to do with improper imports or module naming.
POSSIBLE SOLUTION
Flatten the namespace. Take out the "hoisting" being done in init.py to get FPDF() to the top. Drop what you don't need any more. Make a break with the past (somewhere in PHP in ?)
Don't use init.py to try to flatten references to an overly nested namespace.
QUESTIONS:
The main fpdf.py module has this warning object in two places.
It is not clear why line 4508 reassigns WarnOnDeprecatedModuleAttributes (or why does it exist?)
52: from .deprecation import WarnOnDeprecatedModuleAttributes
4508: sys.modules[name].class = WarnOnDeprecatedModuleAttributes
What is the "font_cache_dir optional argument of the fpdf.FPDF constructor" and why does it exist? There are no instructions on how to use it?
MORE DETAIL
Inspecting the documentation for this custom Exception type gives the following code. It is not clear why and how getattr() exist and how to use them. What are "fpdf.FPDF_CACHE_DIR" and "fpdf.FPDF_CACHE_MODE" used for ??
There are no docstrings for this class or its functions.
Beta Was this translation helpful? Give feedback.
All reactions