ImportError: cannot import name 'ShopUI' from partially initialized module 'ui.shop'

0

Hej,

Poniższy kod nie chce mi działać:

# example_shop/example_shop.py
from ui.menu import Menu, UserChoice, quit_menu, do_nothing_choice
from ui.shop import ShopUI
from shop.shop import Shop


def main() -> None:
    shop = Shop()
    shop_ui = ShopUI(shop)
    main_menu = Menu('Main menu', items=(
        UserChoice('Product list', shop_ui.list_products),
        UserChoice('Shopping cart', do_nothing_choice),
        UserChoice('Your orders', do_nothing_choice),
        UserChoice('Quit', quit_menu)
    ))
    main_menu.loop()


if __name__ == '__main__':
    main()


# example_shop/ui/mwnu.py
import enum
from typing import Callable, Iterable, Sequence, NamedTuple, Optional
from user_input import read_number


@enum.uniqueclass BannerStyle(enum.IntEnum):
    FRAME_BOX = enum.auto()
    HASH = enum.auto()


class UserChoice(NamedTuple):
    name: str    invoke: Callable[[], Optional[bool]]

    def __str__(self) -> str:
        return self.name


def format_choices(choices: Sequence[UserChoice]) -> Iterable[str]:
    for idx, item in enumerate(choices, 1):
        yield f'{idx}) {item}'def read_choice(choices: Sequence[UserChoice]) -> UserChoice:
    prompt = '\n'.join((*format_choices(choices),
                        'Your choice (enter an integer): '))
    while True:
        index = read_number(prompt, int) - 1        if 0 <= index < len(choices):
            return choices[index]
        print('Choice out of range.')


class Menu(NamedTuple):
    title: str    items: Sequence[UserChoice]
    banner_style: BannerStyle = BannerStyle.FRAME_BOX

    def print_banner(self) -> None:
        top_char, edge_char = None, None        match self.banner_style:
            case BannerStyle.FRAME_BOX:
                top_char = '-'                edge_char = '|'            case BannerStyle.HASH:
                top_char = '#'                edge_char = '#'        print(top_char * (len(self.title) + 4))
        print(f'{edge_char} {self.title} {edge_char}')
        print(top_char * (len(self.title) + 4))

    def loop(self) -> None:
        while True:
            self.print_banner()
            choice = read_choice(self.items)
            if choice.invoke():
                break            print()


def wait_menu() -> None:
    input("Press the enter...")


def quit_menu() -> bool:
    return Truedef do_nothing_choice() -> None:
    """    The replacement function for lambda: None in UserChoice,    where UserChoice is the Menu element.    """    print('No action defined.')
    wait_menu()

# example_shop/ui/shop.py
from example_shop.shop.shop import Shop
from .menu import wait_menu


class ShopUI:
    def __init__(self, shop: Shop):
        self.shop = shop

    def list_products(self):
        if self.shop.available_products:
            print("Available products:")
            for idx, product in enumerate(self.shop.available_products):
                print(f"{idx}) {product.name}")
        else:
            print("No such any products")
        wait_menu()

# example_shop/shop/shop.py
from .products import Product
from .users import User


class Shop:
    def __init__(self):
        self.available_products = []
        self.users = []

    def count_product(self, product: Product):
        return self.available_products.count(product)

    def create_user(self, user: User):
        self.users.append(user)

    def remove_user(self, user: User):
        self.users.remove(user)

    def add_product(self, product: Product, qty=1):
        for _ in range(qty):
            self.available_products.append(product)

    def remove_product(self, product: Product):
        self.available_products.remove(product)

Błąd:

/home/lester29/PycharmProjects/example_shop/venv/bin/python /home/lester29/PycharmProjects/example_shop/example_shop/example_shop.py 
Traceback (most recent call last):
  File "/home/lester29/PycharmProjects/example_shop/example_shop/example_shop.py", line 2, in <module>
    from ui.shop import ShopUI
  File "/home/lester29/PycharmProjects/example_shop/example_shop/ui/shop.py", line 1, in <module>
    from example_shop.shop.shop import Shop
  File "/home/lester29/PycharmProjects/example_shop/example_shop/example_shop.py", line 2, in <module>
    from ui.shop import ShopUI
ImportError: cannot import name 'ShopUI' from partially initialized module 'ui.shop' (most likely due to a circular import) (/home/lester29/PycharmProjects/example_shop/example_shop/ui/shop.py)

Process finished with exit code 1

Po zmianie w example_shop/ui/shop.py pierwszej linijki na from ..shop.shop import Shop mam błąd

/home/lester29/PycharmProjects/example_shop/venv/bin/python /home/lester29/PycharmProjects/example_shop/example_shop/example_shop.py 
Traceback (most recent call last):
  File "/home/lester29/PycharmProjects/example_shop/example_shop/example_shop.py", line 2, in <module>
    from ui.shop import ShopUI
  File "/home/lester29/PycharmProjects/example_shop/example_shop/ui/shop.py", line 1, in <module>
    from ..shop.shop import Shop
ImportError: attempted relative import beyond top-level package

Process finished with exit code 1

Pomoże ktoś?

1

Jak masz jakiś bład z importem to najlepiej jeszcze daj structure folderów. łatwiej i szybciej jest znaleźć rozwiązanie. Ja skupie sie tutaj tylko na dwóch rzeczach dotyczących importu.

jeśli chodzi o drugi błąd to relatywny import działa tylko w pakietach. ..shop.shop aby to działało musisz zamienić to na pakiet i dodać do folderu __init__.py. Tak pisze w dokumentacji pythona "Pliki __init__.py są wymagane, aby Python traktował katalogi zawierające ten plik jako pakiety."

odpaliłem sobie twój kod ze struktura folderów taka jaka poniżej aby reprodukować blad i faktycznie dostaje ten sam bład. Aby to naprawić to zamieniłem to na pakiety i usunąłem example_shop z importu bo jest on tu niepotrzebny. i wszystko działa.

Rezultat dam poniżej (daje tylko elementy, które sa potrzebne do reprodukowania błędu, pomijam już inne pliki i kod, żeby to było bardziej czytelne)

struktura dla katalogów

example_shop/
│
│
├── example_shop/
│   ├── __init__.py
│   ├── example_shop.py
│   ├── shop/
│   │   ├── __init__.py
│   │   └── shop.py
│   │
│   └── ui/
│       ├── __init__.py
│       └── shop.py
│

plik z folderu shop/shop.py (bez zmian)

class Shop:
    def __init__(self):
        self.available_products = []
        self.users = []

plik z folderu ui/shop.py ( zmiana importu)

from shop.shop import Shop

class ShopUI:
    def __init__(self, shop: Shop):
        self.shop = shop

    def list_products(self):
        pass

plik example_shop.py (zmiana importu)

from ui.shop import ShopUI
from shop.shop import Shop

def main() -> None:
    shop = Shop()
    shop_ui = ShopUI(shop)
    print("started")

if __name__ == "__main__":
    main()

Mam nadzieje ze to Ci pomoże. "u mnie działa" ;-)

1
❯ tree example_shop
example_shop
├── __init__.py
├── main.py
├── __pycache__
│   └── __init__.cpython-311.pyc
├── shop
│   ├── __init__.py
│   ├── money.py
│   ├── orders.py
│   ├── payments.py
│   ├── products.py
│   ├── __pycache__
│   │   ├── __init__.cpython-311.pyc
│   │   ├── money.cpython-311.pyc
│   │   ├── orders.cpython-311.pyc
│   │   ├── payments.cpython-311.pyc
│   │   ├── products.cpython-311.pyc
│   │   ├── shop.cpython-311.pyc
│   │   └── users.cpython-311.pyc
│   ├── shop.py
│   └── users.py
└── ui
    ├── __init__.py
    ├── menu.py
    ├── products.py
    ├── __pycache__
    │   ├── __init__.cpython-311.pyc
    │   ├── menu.cpython-311.pyc
    │   └── user_input.cpython-311.pyc
    ├── shop.py
    └── user_input.py

6 directories, 25 file

0

widzę ze zmieniłeś plik example_shop.py na main.py, ale tez przykład powinien działać, dalej cos wyskakuje?

1 użytkowników online, w tym zalogowanych: 0, gości: 1