웹페이지 운영/워드프레스

워드프레스 API로 getPosts 실행시 AttributeError: module 'collections' has not attribute 'Iterable' 에러 발생시 조치 방법

공무원 봉급 2022. 5. 19. 17:06

본 페이지에서는 워드프레스 API를 통해서 getPosts 실행시에 AttributeError: module 'collections' has not attribute 'Iterable' 에러가 발생할 경우 조치하는 방법에 대해서 설명합니다.

 

워드프레스 API와 getPosts()

이 글을 검색해서 읽고 계신 분들이라면 기본적으로 워드프레스, API, 파이썬 등의 개념에 대해서 어느정도 알고 계신 분일 것이라고 추측됩니다. 워드프레스는 웹으로 할 수 있는 거의 모든 작업들을 API로 제공합니다. 이를 통해서 우리는 웹페이지를 손쉽게 관리할 수도 있고, 글을 자동으로 발행하는 등의 블로그 자동화를 이룰 수 있습니다.

그 중에서도 getPosts() 메쏘드는 가장 빈번하게 사용되어지는 API 중의 하나입니다. getPosts()를 RPC로 호출함으로써 웹 페이지에 있는 모든 글들의 목록을 가져올 수 있습니다. 이를 통해서 블로그 글들의 번호 목록을 가져올 수 있습니다. 글의 ID를 가지고 우리는 다시 getPost() 메쏘드를 호출해서 포스트 콘텐츠를 가져올 수 있습니다.

즉, getPosts() 호출로 글의 목록을 가져온 이후에, 다시 getPost() 호출로 글의 내용을 가져올 수 있는 구조입니다.

 

getPosts() 파이썬 예제

아래는 글의 목록을 받아오는 아주 간단한 파이썬 예제입니다.

#!/usr/bin/python3

from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods import posts

def getPosts(url, id, pw):
  print("id :", id) 
  print("pw :", pw) 
  url = url + "/xmlrpc.php"
  print("url :", url)
  client = Client(url, id, pw) 

  postList = client.call(posts.GetPosts())
  for post in postList:
    print("ID :", post.id)

if __name__ == '__main__':
  getPosts( "https://www.webpage.com",
                  'id',
                  'pw')

 

위의 예제를 실행하기 위해서는 몇가지 패키지가 설치되어 있어야 합니다.

  • 파이썬 패키지
  • python-wordpress-xmlrpc 패키지

 

관련 내용은 제가 작성한 아래의 글을 참고하시기 바랍니다.

2022.05.19 - [워드프레스] - 워드프레스 API를 통한 자동 글쓰기 예제 (파이썬 버전)

 

워드프레스 API를 통한 자동 글쓰기 예제 (파이썬 버전)

블로그 자동화를 위해서는 네이버 블로그나 티스토리 블로그로는 한계가 있습니다. 하루에 발행할 수 있는 글의 개수에 제한이 있기 때문입니다. 그래서 GitHub Pages나 워드프레스로 블로그를 옮

worldclassproduct.tistory.com

 

'collections' has no attribute 'Iterable' 에러 발생

위와 예제를 실행했더니 런타임 에러가 발생했습니다. 보시면 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/parksejin/project/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 시키면 깔끔하게 해결됩니다.

 

getPosts() 예제를 실행시켜보면 아래와 같이 포스트 ID들이 정상적으로 표시됩니다.

ID : 91
ID : 79
ID : 72
ID : 68
ID : 45
ID : 33
ID : 18
ID : 6

위의 ID를 토대로 getPost() API를 호출하면 되겠습니다.

 

인사이트를 얻은 링크

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

https://stackoverflow.com/questions/53978542/how-to-use-collections-abc-from-both-python-3-8-and-python-2-7/53978543#53978543

 

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는 아래 링크에서 확인하실 수 있습니다.

https://github.com/maxcutler/python-wordpress-xmlrpc/pull/148

 

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

 

이상입니다.