SW개발/파이썬

AttributeError: module 'collections' has no attribute 'Iterable'

공무원 봉급 2022. 5. 19. 15:29

최신 파이썬 버전에서 collections.Iterable 속성이 deprecated 되었습니다. 이로 인해서 해당 속성값을 이용하려면 파이썬 2.7버전에서는 collections.Iterable로 사용해야 하고, 파이썬 3.10 버전에서는 collections.abc.Iterable로 사용해야 하는 문제가 있습니다.

본 페이지에서는 collections.Iterable 구문에서 발생하는 exception을 처리하는 방법에 대해서 설명하고자 합니다. 파이썬 버전에 따라서 호환되도록 처리해야 되기 때문에 try exception 구문을 할용하도록 하겠습니다.

문제의 상황

아래는 파이썬 3.10 버전에서 python-wordpress-xmlrpc 패키지를 설치해서 사용중에 발견된 런타임 에러입니다. 보시면 collections 모듈에 iterable이라는 속성이 없어서 발생했다는 것을 확인하실 수 있습니다.

Traceback (most recent call last):
  File "/home/parksejin/project/blog_automation/wordpress/./getPosts.py", line 18, in <module>
    getPosts( "https://www.webpage.com",
  File "/home/user/blog_automation/wordpress/getPosts.py", line 13, in getPosts
    postList = client.call(posts.GetPosts())
  File "/usr/local/lib/python3.10/dist-packages/wordpress_xmlrpc/base.py", line 46, in call
    return method.process_result(raw_result)
  File "/usr/local/lib/python3.10/dist-packages/wordpress_xmlrpc/base.py", line 128, in process_result
    elif isinstance(raw_result, collections.Iterable):
AttributeError: module 'collections' has no attribute 'Iterable'

 

Exception이 발생한 파일을 vi 편집기로 열어서 확인해보겠습니다.

$ vi /usr/local/lib/python3.10/dist-packages/wordpress_xmlrpc/base.py

 

해당 모듈의 스크립트를 확인해보면 파이썬 버전에 대한 고려 없이 collections.Iterable로 속성에 접근하고 있는 것을 알 수 있습니다.

import collections

#중략

    def process_result(self, raw_result):
        """
        Performs actions on the raw result from the XML-RPC response.

        If a `results_class` is defined, the response will be converted
        into one or more object instances of that class.
        """
        if self.results_class and raw_result:
            if isinstance(raw_result, dict_type):
                return self.results_class(raw_result)
            elif isinstance(raw_result, collections.Iterable):
                return [self.results_class(result) for result in raw_result]

        return raw_result

 

대책

대책은 파이썬 버전에 따라서 다르게 처리하도록 하는 방법이 있겠습니다만, 그것보다는 try-exception 구문으로 처리하면 좀 더 깔끔하게 해결할 수 있습니다.

import collections

try:
    collections = collections.abc
except AttributeError:
    pass

#중략

    def process_result(self, raw_result):
        """
        Performs actions on the raw result from the XML-RPC response.

        If a `results_class` is defined, the response will be converted
        into one or more object instances of that class.
        """
        if self.results_class and raw_result:
            if isinstance(raw_result, dict_type):
                return self.results_class(raw_result)
            elif isinstance(raw_result, collections.Iterable):
                return [self.results_class(result) for result in raw_result]

위와 같이 collections = collections.abc 구문을 실행하는데, 만약 collections.abc 속성이 없을 경우는 그냥 아무것도 처리하지 않도록 pass 시키면 깔끔하게 해결됩니다.

import collections

try:
    collections = collections.abc
except AttributeError:
    pass

즉, collections의 Iterable 속성을 사용하기 위해서는 위와 같은 방식으로 처리하면 되겠습니다. 제가 생각하는 best practice라고 생각됩니다. 다른 의견이 있으면 알려주시면 감사하겠습니다. 

 

인사이트를 얻은 링크

해당 내용은 아래의 링크에서 인사이트를 얻어서 작성했습니다.

 

How to use collections.abc from both Python 3.8+ and Python 2.7

In Python 3.3 "abstract base classes" in collections (like MutableMapping or MutableSequence) were moved to second-level module collections.abc. So in Python 3.3+ the real type is collections.abc.

stackoverflow.com

 

python-wordpress-xmlrpc 패키지 수정 관련

python-wordpress-xmlrpc 패키지에 해당 문제가 있어서 동일한 문제가 발생하고 있습니다. 아직 해당 패키지는 수정되지 않았고 현재 148번 pull request가 진행중에 있습니다. 아래 내용이 머지되면 이렇게 수동으로 모듈을 수정해주야되는 불편함이 사라지지 않을까 싶습니다.

관련 pull request는 아래 링크에서 확인하실 수 있습니다.

 

fix import for py3.10 compat: collections.Iterable -> collections.abc… by foormea · Pull Request #148 · maxcutler/python-wor

The collections.Iterable is broken in python 3.10, collections.abc.Iterable has to be used.

github.com

 

이상입니다.