0

Context:

I am trying to build a Django app that uses this package:django-minio-storage. I am trying to extend a certain class in the package with the following class:

@deconstructible
class MinioStoreStorage(MinioStorage):
    def __init__(self, bucket_name):
        client = create_minio_client_from_settings()
        base_url = bucket_name
        # base_url = get_setting("MINIO_STORAGE_STATIC_URL", None)
        bucket_name = bucket_name
        auto_create_bucket = True
        presign_urls = True

        super(MinioStoreStorage, self).__init__(
            client,
            bucket_name,
            auto_create_bucket=auto_create_bucket,
            base_url=base_url,
            presign_urls=presign_urls
        )

Problem:

I can not import the function create_minio_client_from_settings. This function resides in the file storage.py of the package. The same file where resides the class MinioStorage. I can also import successfully another function (get_setting) that is in the same file and use it with no problem, but trying to do the same for create_minio_client_from_settings raises an ImportError. Here are the import I am using:

from minio_storage.storage import get_setting
# Succeeds
from minio_storage.storage import create_minio_client_from_settings
Traceback (most recent call last):
  File "<console>", line 1, in <module>
ImportError: cannot import name 'create_minio_client_from_settings'

storage.py

Here is a snippet of the code of the package:

@deconstructible
class MinioStorage(Storage):
    """An implementation of Django's file storage using the minio client.

    The implementation should comply with
    https://docs.djangoproject.com/en/dev/ref/files/storage/.

    """
    ...
    ...
    ...

def get_setting(name, default=_NoValue, ):
    result = getattr(settings, name, default)
    if result is _NoValue:
        print("Attr {} : {}".format(name, getattr(settings, name,                     default)))
        raise ImproperlyConfigured
    else:
        return result


def create_minio_client_from_settings():
    endpoint = get_setting("MINIO_STORAGE_ENDPOINT")
    access_key = get_setting("MINIO_STORAGE_ACCESS_KEY")
    secret_key = get_setting("MINIO_STORAGE_SECRET_KEY")
    secure = get_setting("MINIO_STORAGE_USE_HTTPS", True)
    client = minio.Minio(endpoint,
                         access_key=access_key,
                         secret_key=secret_key,
                         secure=secure)
    return client

Questions:

  • How can I import the create_minio_client_from_settings function?
  • Is there a workaround to solve this problem? (I know I can simply copy it as a helper function straight into my project)
  • What can be the reasons to not being able ti import a function from a package, while I can do the same for a function that is in the same file?

Further investigation:

I have been looking into this problem more, and here is some remarks and a more reproducible way of seeing the anomaly. After creating a Django project and installing the package in question, I fired up the shell using : python manage.py shell and used the following commands:

>>> import minio_storage
>>> dir(minio_storage)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__',         '__name__', '__package__', '__path__', '__spec__', '__version__',     'storage']
>>> help(minio_storage.storage)

The help(minio_storage.storage) will show a manual page that describes the Classes and Functions provided by the package. Under functions category, only one function is available and it's the get_setting() function.

  • Why the create_minio_client_from_settings() does not show up the same way get_setting() does?
  • Is it possible for a package developer to hide some of his functions?

Versions and dependencies

Here is the result of the command: pipenv graph

django-minio-storage==0.1.0
  - django [required: >=1.9, installed: 1.11.6]
    - pytz [required: Any, installed: 2017.2]
  - minio [required: >=1.0.2, installed: 2.2.5]
    - certifi [required: Any, installed: 2017.7.27.1]
    - pytz [required: Any, installed: 2017.2]
    - urllib3 [required: Any, installed: 1.22]
djangorestframework==3.7.1
flake8==3.5.0
  - mccabe [required: >=0.6.0,<0.7.0, installed: 0.6.1]
  - pycodestyle [required: >=2.0.0,<2.4.0, installed: 2.3.1]
  - pyflakes [required: >=1.5.0,<1.7.0, installed: 1.6.0]
Pillow==4.3.0
  - olefile [required: Any, installed: 0.44]
Anas Tiour
  • 1,344
  • 3
  • 17
  • 33

2 Answers2

2

Your django-minio-storage package is out of date, but it's not really your fault - at the time of this writing the PyPi package itself is outdated.

The version you're running does not contain the function you're looking for. Download the source code for the package from GitHub, and run it from there - you will get the behavior you want: https://github.com/py-pa/django-minio-storage

souldeux
  • 3,615
  • 3
  • 23
  • 35
  • Yes, I admit that integrating the source code directly into my project allows me to bypass all these problems. I was just trying to integrate it in a better way. Still this behaviour is intriguing. Thanks – Anas Tiour Oct 31 '17 at 13:42
  • You can also download the (up-to-date) source code, then install it as a package to get it to behave as it would had you installed it with `pip`: https://stackoverflow.com/questions/36014334/how-to-install-python-packages-from-the-tar-gz-file-without-using-pip-install – souldeux Oct 31 '17 at 13:44
-1

Solved

As the user souldeux pointed, my package is out-of-date. I installed it using pipenv, which is not a version that matches the latest one. I was working on my outdated package on one side, and the fresh code from github on the other side.

The link he provided was useful, but I ended installing the package directly from github using another SO answer. More specifically in my case:

pipenv install git+https://github.com/py-pa/django-minio-storage.git#egg=django-minio-storage
Anas Tiour
  • 1,344
  • 3
  • 17
  • 33