Python Forum

Full Version: Importing issues with base class for inheritance
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi, I'm trying to make a class that inherits from another one. The problem I'm having is related to imports, I'll try to explain as best as I can.

food_bot
├── __init__.py
├── price
│   ├── __init__.py
│   ├── item_pricing.py
│   └── pricing.py

This is the folder structure of the project (not complete, only the price folder is relevant for my problem).
In the __init__.py inside price I imported
from .item_pricing import ItemPricing
from .pricing import Pricing

__all__ = [
    'ItemPricing',
    'Pricing'
]
I need to import Pricing in the file item_pricing.py and I did that using the full path to the class Pricing:
from __future__ import annotations
from math import floor
from typing import TYPE_CHECKING

from food_bot.menu import MenuItem
from food_bot.exceptions import ParameterError
from food_bot.price.pricing import Pricing

class ItemPricing(Pricing): ...
I did this because, when importing Pricing like this from food_bot.price import Pricing (and not like this from food_bot.price.pricing import Pricing) a circular import begins; I then tried to put it under if TYPE_CHECKING:, the circular import was resolved but, because I use pricing for inheritance I got this error: NameError: name 'Pricing' is not defined even though it is defined.

In conclusion I want to be able to import Pricing like this, food_bot.price import Pricing as it is the point of my __init__.py AND use Pricing as base class for ItemPricing.
I might not be understanding all that well what TYPE_CHECKING is really useful for (same thing for __future__.annotations), I tried reading the documentation but it seems I got it wrong.
Can someone help me?
You could import pricing prior to item_pricing in init.py
# pricing/__init__.py
from .pricing import Pricing
from .item_pricing import ItemPricing
then in the item_pricing.py file
# pricing/item_pricing.py
from . import Pricing

class ItemPricing(Pricing):
    ....
I cannot answer about TYPE_CHECKING because I don't use it. The very word looks antipythonic to me.
(May-19-2021, 02:55 PM)Gribouillis Wrote: [ -> ]You could import pricing prior to item_pricing in init.py
# pricing/__init__.py
from .pricing import Pricing
from .item_pricing import ItemPricing
then in the item_pricing.py file
# pricing/item_pricing.py
from . import Pricing

class ItemPricing(Pricing):
    ....
I cannot answer about TYPE_CHECKING because I don't use it. The very word looks antipythonic to me.

Id tried and it works. Why does this work though?
To understand how it works you need to have some basic notions of how import statements work. When it executes say import food_bot.price, Python looks in the dictionary sys.modules if it already contains a module named food_bot.price. If it is not the case, a new empty module object is created an inserted immediately in sys.modules. Then Python starts executing in this module's namespace the code that in finds in __init__.py. There it encounters the line from .pricing import Pricing. It inserts immediately a module named food_bot.price.pricing in sys.modules and it executes the code of pricing.py in that module's namespace. After that, this module contains the class named Pricing and Python can complete the import. At that point, the module food_bot.price exists and contains the name Pricing.

Then Python runs from .item_pricing import ItemPricing. This executes the code from item_pricing.py in a new module's namespace. That code contains the line from . import Pricing. The . module here is food_bot.price which is already in sys.modules and already contains the symbol Pricing. Hence the line suceeds.
(May-19-2021, 04:26 PM)Gribouillis Wrote: [ -> ]To understand how it works you need to have some basic notions of how import statements work. When it executes say import food_bot.price, Python looks in the dictionary sys.modules if it already contains a module named food_bot.price. If it is not the case, a new empty module object is created an inserted immediately in sys.modules. Then Python starts executing in this module's namespace the code that in finds in __init__.py. There it encounters the line from .pricing import Pricing. It inserts immediately a module named food_bot.price.pricing in sys.modules and it executes the code of pricing.py in that module's namespace. After that, this module contains the class named Pricing and Python can complete the import. At that point, the module food_bot.price exists and contains the name Pricing.

Then Python runs from .item_pricing import ItemPricing. This executes the code from item_pricing.py in a new module's namespace. That code contains the line from . import Pricing. The . module here is food_bot.price which is already in sys.modules and already contains the symbol Pricing. Hence the line suceeds.

Thanks a lot!
Can also look at this post.
See in link how i take about simplify import(bye lifting sub-modules),so can have simpler import.

As a example when you use Requests the import is import requests (that's all).
Then with simple attribute call use it requests.get(), requests.head()...ect

My take on this that should try to make import simple for users,then do not need navigate your file tree with 3-4 import to use a package.
Usually is making a package the last step that most people have not looked much at before trying it out,then the result can be not optimal as eg under😵
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar