Permalink
Browse files

updated sections, python3 support, added __repr__ methods

  • Loading branch information...
1 parent 0ef15b0 commit 5b8180a099bab7410e31790a8796a1cb991202d6 @d1ffuz0r committed Dec 17, 2012
Showing with 159 additions and 129 deletions.
  1. +1 −0 MANIFEST.in
  2. +104 −87 api2ch.py
  3. +19 −16 setup.py
  4. +35 −26 tests/tests.py
View
1 MANIFEST.in
@@ -0,0 +1 @@
+include README.rst
View
191 api2ch.py
@@ -1,73 +1,89 @@
# -*- coding:utf-8 -*-
+
"""2ch.so API"""
-__author__ = "d1ffuz0r"
-__version__ = "0.0.1"
-__all__ = ("Api", "Thread", "Post", "Captcha",
- "Settings", "BOARDS", "BOARDS_ALL")
+
+__author__ = 'd1ffuz0r'
+__version__ = '0.0.2'
+__all__ = ('Api', 'Thread', 'Post', 'Captcha',
+ 'Settings', 'BOARDS', 'BOARDS_ALL')
import json
-import urllib2
-from urllib import urlencode
+import os
+try:
+ from urllib2 import urlopen
+ from urllib import urlencode
+except ImportError:
+ from urllib.request import urlopen
+ from urllib.parse import urlencode
+ from functools import reduce
+
# List sections on board
BOARDS = {
- "thematics": ["au", "gd", "bi", "biz", "bo", "c", "em", "ew", "fa", "fiz",
- "fl", "hi", "hw", "me", "mlp", "mo", "mu", "ne", "ph",
- "po", "pr", "psy", "ra", "re", "s", "sf", "sci", "sn",
- "sp", "t", "tr", "tv", "un", "w", "wh", "wm", "mg"],
- "creation": ["di", "de", "diy", "f", "pa", "p", "wp", "td", "spc"],
- "games": ["bg", "mc", "mmo", "gb", "vg", "wr", "tes"],
- "japanese": ["a", "aa", "fd", "ma", "vn", "to"],
- "other": ["b", "soc", "r", "abu", "int", "fag"],
- "adults": ["fg", "fur", "g", "ga", "h", "ho", "per", "sex", "ls"],
- "test": ["rm", "pvc", "trv", "izd", "cg"]
+ 'thematics': ['app', 'au', 'bi', 'biz', 'bo', 'c', 'em', 'ew',
+ 'fa', 'fiz', 'fl', 'ftb', 'gd', 'hh', 'hi', 'hw',
+ 'me', 'mg', 'mlp', 'mo', 'mu', 'ne', 'pvc', 'ph',
+ 'po', 'pr', 'psy', 'ra', 're', 's', 'sf', 'sci',
+ 'sn', 'sp', 'spc', 't', 'tr', 'tv', 'un', 'w',
+ 'web', 'wh', 'wm'],
+ 'creation': ['di', 'de', 'diy', 'dom', 'f', 'izd', 'mus', 'o',
+ 'pa', 'p', 'wp', 'td'],
+ 'games': ['bg ,cg ,gb', 'mc', 'mmo', 'tes', 'vg', 'wr'],
+ 'japanese': ['a', 'aa', 'fd', 'ja', 'ma', 'rm', 'to', 'vn'],
+ 'other': ['d', 'b', 'fag', 'soc', 'r', 'cp', 'abu', '@', 'int', 'mdk'],
+ 'adults': ['fg', 'fur', 'g', 'ga', 'h', 'ho', 'per', 'sex'],
+ 'test': ['gif', 'mov']
}
+
listmerge = lambda s: reduce(lambda d, el: d.extend(el) or d, s, [])
BOARDS_ALL = listmerge(BOARDS)
class Post(object):
"""Post object"""
- __rows__ = ("lasthit", "comment", "name", "parent", "timestamp",
- "banned", "sticky", "height", "width", "num",
- "video", "tn_height", "closed", "tn_width", "date",
- "subject", "image", "thumbnail", "op", "size")
+ __rows__ = ('lasthit', 'comment', 'name', 'parent', 'timestamp',
+ 'banned', 'sticky', 'height', 'width', 'num',
+ 'video', 'tn_height', 'closed', 'tn_width', 'date',
+ 'subject', 'image', 'thumbnail', 'op', 'size')
def __init__(self, post):
"""
Create object from dict with post info
@param post: dict with post info
"""
- for arg in post.keys():
- self.__setattr__(arg, post[arg])
+ for key, value in post.items():
+ setattr(self, key, value)
def __repr__(self):
- return "<Post: {num}>".format(num=self.num)
+ return '<Post: {num}>'.format(num=self.num)
class Message(object):
"""Message object"""
- def __init__(self, parent="", comment="", subject=""):
+ def __init__(self, parent='', comment='', subject=''):
"""
@param parent: parent id (№ OP post)
@param comment: text your comment
@param subject: subject message example( SAGE )
@return:
"""
- self.captcha_key = ""
- self.video = ""
- self.nofile = ""
+ self.captcha_key = ''
+ self.video = ''
+ self.nofile = ''
self.subject = subject
self.parent = parent
- self.submit = ""
- self.file = ""
- self.name = ""
- self.task = "pоst"
- self.captcha = ""
- self.email = ""
+ self.submit = ''
+ self.file = ''
+ self.name = ''
+ self.task = 'pоst'
+ self.captcha = ''
+ self.email = ''
self.comment = comment
+ def __repr__(self):
+ return '<Message: "{comment}...">'.format(comment=self.comment[:10])
+
class Thread(object):
"""Thread object"""
@@ -76,12 +92,12 @@ def __init__(self, thread):
Create object from dict with thread info
@param thread: dict with thread info
"""
- self.reply_count = int(thread[u"reply_count"])
- self.post = Post(thread[u"posts"][0][0])
+ self.reply_count = int(thread['reply_count'])
+ self.post = Post(thread['posts'][0][0])
self.num = self.post.num
def __repr__(self):
- return "<Thread: {num}>".format(num=self.num)
+ return '<Thread: {num}>'.format(num=self.num)
class Captcha(object):
@@ -91,54 +107,51 @@ def __init__(self, captcha):
Create object from dict with captcha info
@param captcha: dict with captcha info
"""
- self.key = captcha[u"key"]
- self.url = captcha[u"url"]
+ self.key = captcha['key']
+ self.url = captcha['url']
+
+ def __repr__(self):
+ return '<Captcha: {key}>'.format(key=self.key)
class Settings(object):
"""Settings object"""
- __postfields__ = ("captcha_key", "video", "nofile", "subject", "submit",
- "file", "name", "task", "captcha", "email", "comment")
- __board__ = ("thumb_dir", "shortname", "wakaba_version",
- "enable_wakabamark", "imagesize", "favicon", "name",
- "charset", "max_comment_length", "enable_bbcode",
- "threads_per_page", "img_dir", "page_ext", "image_h",
- "image_w", "max_field_lengt", "res_dir",)
+ __postfields__ = ('captcha_key', 'video', 'nofile', 'subject', 'submit',
+ 'file', 'name', 'task', 'captcha', 'email', 'comment')
+ __board__ = ('thumb_dir', 'shortname', 'wakaba_version',
+ 'enable_wakabamark', 'imagesize', 'favicon', 'name',
+ 'charset', 'max_comment_length', 'enable_bbcode',
+ 'threads_per_page', 'img_dir', 'page_ext', 'image_h',
+ 'image_w', 'max_field_lengt', 'res_dir',)
def __init__(self, settings):
"""
Create object from dict with settings info
@param settings: dict with settings info
"""
- self.query_interval = settings[u"query_interval"]
- self.query_limit = settings[u"query_limit"]
- self.ban_time = settings[u"ban_time"]
-
- postfields = settings[u"postfields"]
- self.postfields = {}
+ self.query_interval = settings['query_interval']
+ self.query_limit = settings['query_limit']
+ self.ban_time = settings['ban_time']
- for arg in postfields.keys():
- self.postfields[arg] = postfields[arg]
+ postfields = settings['postfields']
+ self.postfields = {key: value for key, value in postfields.items()}
- board = settings[u"board"]
- self.board = {}
-
- for arg in board.keys():
- self.board[arg] = board[arg]
+ board = settings['board']
+ self.board = {key: value for key, value in board.items()}
def __repr__(self): # pragma: no cover
- return "<Settings: %s>" % self.board["shortname"]
+ return '<Settings: {board}>'.format(board=self.board['shortname'])
class Api(object):
"""Api object"""
def __init__(self, board=None):
"""
- @param board: board code example( "b" )
+ @param board: board code example( 'b' )
"""
self.logging = False
self.board = board
- self._url = "http://2ch.so/"
+ self._url = 'http://2ch.hk/'
self.settings = None
self.captcha_key = None
self.thread = None
@@ -149,7 +162,7 @@ def __init__(self, board=None):
def board_exist(self, board):
"""
Checking exist section on board or not
- @param board: name section. example( "b" )
+ @param board: name section. example( 'b' )
@return: boolean
"""
return True if board in BOARDS_ALL else False
@@ -163,9 +176,9 @@ def get_board(self, board=None):
if board and self.board_exist(board): # pragma: no cover
self.board = board
- threads = self._get(url="wakaba.json")[u'threads']
+ threads = self._get(url='wakaba.json')['threads']
- return [Thread(thread) for thread in threads]
+ return (Thread(thread) for thread in threads)
def _get(self, url):
"""
@@ -174,11 +187,11 @@ def _get(self, url):
@return: raise or json object
"""
if not self.board:
- raise ValueError("Board is not selected")
+ raise ValueError('Board is not selected')
else:
- return json.load(
- urllib2.urlopen(self._url + self.board + "/" + url)
- )
+ url = os.path.join(self._url, self.board, url)
+ js = urlopen(url).read().decode('utf8')
+ return json.loads(js)
def get_thread(self, thread):
"""
@@ -190,25 +203,25 @@ def get_thread(self, thread):
thread = thread.num
self.thread = thread
- posts = self._get("res/" + str(self.thread) + ".json")[u"thread"]
+ posts = self._get('res/' + str(self.thread) + '.json')[u'thread']
- return [Post(post[0]) for post in posts]
+ return (Post(post[0]) for post in posts)
def get_captcha(self): # pragma: no cover
"""
Fetching captcha
@return: captcha info object
"""
captcha = Captcha(
- self._get("/wakaba.pl?task=api&code=getcaptcha")
+ self._get('/wakaba.pl?task=api&code=getcaptcha')
)
self.captcha_key = captcha.key
return captcha
def get_settings(self): # pragma: no cover
"""Fetching settings"""
self.settings = Settings(
- self._get("/wakaba.pl?task=api&code=getsettings")
+ self._get('/wakaba.pl?task=api&code=getsettings')
)
def send_post(self, msg): # pragma: no cover
@@ -219,22 +232,26 @@ def send_post(self, msg): # pragma: no cover
"""
params = self.settings.postfields
post = urlencode({
- "parent": msg.parent,
- params["captcha_key"]: self.captcha_key,
- params["video"]: msg.video,
- params["nofile"]: msg.nofile,
- params["subject"]: msg.subject,
- params["submit"]: msg.submit,
- params["file"]: msg.file,
- params["name"]: msg.name,
- "task": msg.task,
- params["captcha"]: msg.captcha,
- params["email"]: msg.email,
- params["comment"]: msg.comment
+ 'parent': msg.parent,
+ params['captcha_key']: self.captcha_key,
+ params['video']: msg.video,
+ params['nofile']: msg.nofile,
+ params['subject']: msg.subject,
+ params['submit']: msg.submit,
+ params['file']: msg.file,
+ params['name']: msg.name,
+ 'task': msg.task,
+ params['captcha']: msg.captcha,
+ params['email']: msg.email,
+ params['comment']: msg.comment
})
try:
- urllib2.urlopen(self._url + self.board + "/wakaba.pl", data=post)
+ print(self._url, self.board)
+ urllib2.urlopen(self._url + self.board + '/wakaba.pl', data=post)
return True
- except urllib2.HTTPError:
- print "Error send post"
+ except urllib2.HTTPError as e:
+ print('Error send post: {msg}'.format(msg=e))
+
+ def __repr__(self):
+ return '<Api: {board}>'.format(board=self.board)
View
35 setup.py
@@ -1,23 +1,26 @@
#!/usr/bin/env python
-try:
- from setuptools import setup, find_packages
-except ImportError:
- from ez_setup import use_setuptools
- use_setuptools()
+
+from setuptools import setup
import api2ch
+import sys
+
+test_require = ['mock'] if sys.version_info.major == 2 else []
-setup(name="api2ch",
- description="Object oriented wrapper for 2ch.so json-api",
- long_description=open("README.rst").read(),
+setup(name='api2ch',
+ description='Object oriented wrapper for 2ch.so json-api',
+ long_description=open('README.rst').read(),
author=api2ch.__author__,
version=api2ch.__version__,
- author_email="d1fffuz0r@gmail.com",
- py_modules=["api2ch"],
- url="https://github.com/d1ffuz0r/2ch-API",
+ author_email='d1fffuz0r@gmail.com',
+ py_modules=['api2ch'],
+ url='https://github.com/d1ffuz0r/2ch-API',
classifiers=[
- "Operating System :: OS Independent",
- "Programming Language :: Python",
- "Topic :: Internet :: API",
- "Topic :: Software Development :: Libraries :: Python Modules"
- ])
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: API',
+ 'Topic :: Software Development :: Libraries :: Python Modules'
+ ],
+ zip_safe=False,
+ tests_require=test_require,
+ test_suite='tests')
View
61 tests/tests.py
@@ -1,71 +1,80 @@
import os
import json
import unittest
-from mock import Mock
import api2ch
+try:
+ from mock import Mock
+except ImportError:
+ from unittest.mock import Mock
+
DIR = os.path.dirname(__file__)
-class MyTestCase(unittest.TestCase):
+class ApiTests(unittest.TestCase):
def setUp(self):
- self.api = api2ch.Api("pr")
- self.api._url = "file:///" + os.path.join(DIR) + "/"
+ self.api = api2ch.Api('pr')
+ self.api._url = 'file:///{path}/'.format(path=os.path.join(DIR))
def test_api(self):
self.assertIsInstance(self.api, object)
+ self.assertEqual(self.api.__repr__(), '<Api: pr>')
def test_set_board(self):
- self.assertEqual(self.api.board, "pr")
+ self.assertEqual(self.api.board, 'pr')
def test_get_board_true(self):
- threads = self.api.get_board("pr")
+ threads = list(self.api.get_board('pr'))
thread = threads[0]
self.assertIsInstance(threads, list)
self.assertIsInstance(thread, api2ch.Thread)
- self.assertEqual(thread.__repr__(), "<Thread: 87848>")
+ self.assertEqual(thread.__repr__(), '<Thread: 87848>')
def test_get_board_false(self):
self.api.board = None
self.assertRaises(ValueError, self.api.get_board)
def test_get_thread_id_true(self):
- posts = self.api.get_thread(87848)
+ posts = list(self.api.get_thread(87848))
post = posts[0]
- self.assertIsInstance(posts, list)
self.assertIsInstance(post, api2ch.Post)
self.assertEqual(post.__repr__(), "<Post: 87848>")
def test_get_thread_object_true(self):
- threads = self.api.get_board()
- posts = self.api.get_thread(threads[0])
+ threads = list(self.api.get_board())
+ posts = list(self.api.get_thread(threads[0]))
post = posts[0]
- self.assertIsInstance(posts, list)
self.assertIsInstance(post, api2ch.Post)
self.assertEqual(post.__repr__(), "<Post: 87848>")
def test_get_capcha(self):
- CAPTH_MOCK_DATA = file(os.path.join(DIR, "pr", "captcha.json"))
+ with open(os.path.join(DIR, "pr", "captcha.json")) as CAPTH_MOCK_DATA:
- api = Mock()
- api.get_captcha.return_value = api2ch.Captcha(json.load(CAPTH_MOCK_DATA))
- captcha = api.get_captcha()
+ api = Mock()
+ api.get_captcha.return_value = api2ch.Captcha(
+ json.load(CAPTH_MOCK_DATA)
+ )
+ captcha = api.get_captcha()
- self.assertIsInstance(captcha, api2ch.Captcha)
- self.assertIsNotNone(captcha.url)
- self.assertIsNotNone(captcha.key)
+ self.assertIsInstance(captcha, api2ch.Captcha)
+ self.assertIsNotNone(captcha.url)
+ self.assertIsNotNone(captcha.key)
+ self.assertEqual(captcha.__repr__(),
+ '<Captcha: {0}>'.format(captcha.key))
def test_get_settings(self):
- SETT_MOCK_DATA = file(os.path.join(DIR, "pr", "settings.json"))
+ with open(os.path.join(DIR, "pr", "settings.json")) as SETT_MOCK_DATA:
- api = Mock()
- api.get_settings.return_value = api2ch.Settings(json.load(SETT_MOCK_DATA))
- settings = api.get_settings()
+ api = Mock()
+ api.get_settings.return_value = api2ch.Settings(
+ json.load(SETT_MOCK_DATA)
+ )
+ settings = api.get_settings()
- self.assertIsInstance(settings, api2ch.Settings)
- self.assertIsNotNone(settings.query_interval)
- self.assertIsNotNone(settings.postfields)
+ self.assertIsInstance(settings, api2ch.Settings)
+ self.assertIsNotNone(settings.query_interval)
+ self.assertIsNotNone(settings.postfields)
def test_message_create(self):
message = api2ch.Message("1", "test comment", "SAGE")

0 comments on commit 5b8180a

Please sign in to comment.