pythonpython-3.xabstract-factory

Python Abstract Factory Pattern With Multiple Files


in my project, I have 3 separated files as mainly. My project directory

Directory/
|-main.py
|-scrape/
  |--ScrapeFactory.py
  |--ScrapeFromAmazon.py

ScrapeFactory.py includes

from abc import ABC, abstractmethod
from .ScrapeFromAmazon import ScrapeFromAmazon

class Scrape(ABC):
    
    def __init__(self):
        print("ScrapeFactory initialized")

    """Abstract Factory Interface"""
    @abstractmethod
    def create_scrape_products_from_category(self, url, header):
        pass

class ScrapeFactory(ABC):
    """
    The factory represents combination of scrape product 
    from category and scrape product from product detail page.
    """

    @abstractmethod
    def create_scrape_products_from_category(self) -> Scrape:
        """
        Returns a new scrape product from 
        category belonging to this factory.
        """
        pass

Also, ScrapeFromAmazon.py includes

from bs4 import BeautifulSoup
import requests
import pandas as pd
import numpy as np
from .ScrapeFactory import ScrapeFactory

class ScrapeFromAmazon(ScrapeFactory):
    """
    Factory aimed at scraping products from Amazon
    """

    def calculate_iterate_page_count(self):
        response = requests.get(self.url, headers=self.header)
        soup = BeautifulSoup(response.content, 'html.parser')
        product_number_div = soup.find('div', class_='paginatorStyle-OQbSBb_oQve3e_k9LEg5').text
        product_number = product_number_div.split(" ")[3]
        if product_number.find("+"):
            product_number = product_number[:len(product_number)-1]
        self.iterate_page_count = int(int(product_number) / 48)

My python version:

Python 3.12.2

When i run the code, I have error:

ImportError: cannot import name 'ScrapeFactory' from partially initialized module 'scrape.ScrapeFactory' (most likely due to a circular import)

How to fix it?

I tried to init.py,


Solution

  • You are encountering a circular import.

    ScrapeFactory.py is importing ScrapeFromAmazon, but ScrapeFromAmazon.py is also importing from ScrapeFactory.py.

    This causes a circular dependency which python cannot resolve.

    The best practices is to structure your project such that circular imports are not needed. In your case, ScrapeFactory.py should not need to import ScrapeFromAmazon.

    If for some reason the circular import is required, you can delay the import to when a specific method is called.

    class ScrapeFactory(ABC):
        @abstractmethod
        def some_method(self) -> None:
            from .ScrapeFromAmazon import ScrapeFromAmazon
            # ...