3

This is my folder structure:

storage/
    __init__.py - contains class StorageAbstract, class DummyStorage, class STORE_TYPE
    file.py - contains class FileStorage
    db/
        __init__.py - contains class DbStorage, class DbStorageAbstract 
        pg.py - contains class PgStorage
        sqlite.py - contains class SQLiteStorage

Classes PgStorage and SQLiteStorage inherit from DbStorageAbstract so I need to import it. I do it like this (in pg.py and sqlite.py) :

from . import DbStorageAbstract

And that throws the following error:

ImportError: cannot import name 'DbStorageAbstract'

However, when I move DbStorageAbstract from storage/db/__init__py. to storage/__init__py and import it like this:

from .. import DbStorageAbstract

then it works fine. I have read this, this and many other resources but still can't figure out what is causing the problem. If it was circular dependence then moving the class to another file would not help I think.

If there is any more information needed, let me know in the comments and I will edit the question.

I am using Python 3.5

EDIT:

Although this question has been identified as a possible duplicate of this question I don't see how it answers my question. Unlike the other question, I already have init files in each folder. If I am wrong please point me to where I can find the answer.

EDIT 2: This is the db/init.py file:

##################################################################
# Copyright 2018 Open Source Geospatial Foundation and others    #
# licensed under MIT, Please consult LICENSE.txt for details     #
##################################################################

#import sys
#sys.path.append("/mnt/c/Users/Jan/Documents/GitHub/pywps")

import logging
from abc import ABCMeta, abstractmethod
from pywps import configuration as config
from .. import StorageAbstract
from . import sqlite
from . import pg


LOGGER = logging.getLogger('PYWPS')


class DbStorageAbstract(StorageAbstract):
    """Database storage abstract class
    """

    __metaclass__ = ABCMeta

    @abstractmethod
    def store(self, output):

        pass


    @abstractmethod
    def store_output(self, file_name, identifier):

        pass


class DbStorage(StorageAbstract):

    def __init__(self):

       self.storage = self.get_db_type()


    def store(self, output):

        assert(self.storage is not None)
        self.storage.store(output)


    def get_db_type(self):
        # get db_type from configuration 
        try:
            db_type = config.get_config_value('db', 'db_type')
        except KeyError:
            raise exception("Database type has not been specified")

        # create an instance of the appropriate class
        if db_type == "PG":
            storage = pg.PgStorage()
        elif db_type == "SQLITE":
            storage = sqlite.SQLiteStorage()
        else:
            raise exception("Unknown database type: '{}'".format(db_type))

        return storage
Jan Pisl
  • 1,043
  • 2
  • 14
  • 29

2 Answers2

3

Imports happens before class definition. In db/__init__.py you are importing pg.py, sqlite.py which are depends on classes defined here. To solve it move DbStorageAbstract to another file and if you are going to use it in the same file with pg.py, sqlite.py then make sure import is going to be like this:

from . import dbstorage # this file is the new one contains DbStorageAbstract class
from . import pg, sqlite

Note that if two modules are depends on each other try to create a third module so solve this problem.

metmirr
  • 4,234
  • 2
  • 21
  • 34
1

I believe you should create another file in your subdirectory

storage/
    __init__.py - contains class StorageAbstract, class DummyStorage, class STORE_TYPE
    file.py - contains class FileStorage
    db/
        __init__.py - 
        pg.py - contains class PgStorage
        sqlite.py - contains class SQLiteStorage
        base.py contains class DbStorage, class DbStorageAbstract

Then, the pg.py file and sqlite.py file will import the classes like:

from base import DbStorageAbstract

And the __init__.py file will also look like this

from base import DbStorageAbstract,  DbStorageAbstract
Nicolò Gasparini
  • 2,228
  • 2
  • 24
  • 53
  • Not sure if this is the most pythonic way, probably this might also help you: https://stackoverflow.com/questions/582723/how-to-import-classes-defined-in-init-py – Nicolò Gasparini Jun 06 '18 at 20:13
  • Yeah, I agree what you suggest would work but I am trying to keep the number of files to minimum so creating another file is exactly what I don't want to do (unless it is necessary). – Jan Pisl Jun 06 '18 at 20:20
  • Could you not use the full path to import then? from storage.db import DbStorageAbstract should work – Nicolò Gasparini Jun 06 '18 at 20:21