binder.py 3.46 KB
Newer Older
1
2
3
4
# Tweepy
# Copyright 2009 Joshua Roesslein
# See LICENSE

5
import httplib
Josh Roesslein's avatar
Josh Roesslein committed
6
import urllib
7

Josh Roesslein's avatar
Josh Roesslein committed
8
9
from . parsers import parse_error
from . error import TweepError
10

11
12
def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False,
              timeout=None, host=None):
13

14
15
  def _call(api, *args, **kargs):
    # If require auth, throw exception if credentials not provided
16
    if require_auth and not api.auth_handler:
17
18
      raise TweepError('Authentication required!')

19
20
21
22
23
24
25
    # check for post_data parameter
    if 'post_data' in kargs:
      post_data = kargs['post_data']
      del kargs['post_data']
    else:
      post_data = None

26
27
28
29
30
31
32
    # check for headers
    if 'headers' in kargs:
      headers = dict(kargs['headers'])
      del kargs['headers']
    else:
      headers = {}

33
    # build parameter dict
34
    if allowed_param:
35
36
37
38
39
40
41
      parameters = {}
      for idx, arg in enumerate(args):
        try:
          parameters[allowed_param[idx]] = arg
        except IndexError:
          raise TweepError('Too many parameters supplied!')
      for k, arg in kargs.items():
42
43
        if arg is None:
          continue
44
45
        if k in parameters:
          raise TweepError('Multiple values for parameter %s supplied!' % k)
Josh Roesslein's avatar
Josh Roesslein committed
46
47
        if k not in allowed_param:
          raise TweepError('Invalid parameter %s supplied!' % k)
48
        parameters[k] = arg
49
    else:
Josh Roesslein's avatar
Josh Roesslein committed
50
51
      if len(args) > 0 or len(kargs) > 0:
        raise TweepError('This method takes no parameters!')
52
53
      parameters = None

54
55
    # Build url with parameters
    if parameters:
56
      url = '%s?%s' % (api.api_root + path, urllib.urlencode(parameters))
57
    else:
58
      url = api.api_root + path
59

60
61
62
63
64
65
66
67
68
69
70
    # get scheme and host
    if api.secure:
      scheme = 'https://'
    else:
      scheme = 'http://'
    _host = host or api.host

    # Apply authentication
    if api.auth_handler:
      api.auth_handler.apply_auth(scheme + _host + url, method, headers, parameters)

71
72
    # Check cache if caching enabled and method is GET
    if api.cache and method == 'GET':
73
      cache_result = api.cache.get(url, timeout)
74
75
      if cache_result:
        # if cache result found and not expired, return it
76
77
78
79
80
81
        # must restore api reference
        if isinstance(cache_result, list):
            for result in cache_result:
                result._api = api
        else:
            cache_result._api = api
82
83
        return cache_result

84
    # Open connection
Josh Roesslein's avatar
Josh Roesslein committed
85
    # FIXME: add timeout
86
    if api.secure:
Josh Roesslein's avatar
Josh Roesslein committed
87
      conn = httplib.HTTPSConnection(_host)
88
    else:
Josh Roesslein's avatar
Josh Roesslein committed
89
      conn = httplib.HTTPConnection(_host)
90
91

    # Build request
92
    conn.request(method, url, headers=headers, body=post_data)
93
94
95
96
97

    # Get response
    resp = conn.getresponse()

    # If an error was returned, throw an exception
Josh Roesslein's avatar
Josh Roesslein committed
98
99
100
101
102
103
    if resp.status != 200:
        try:
            error_msg = parse_error(resp.read())
        except Exception:
            error_msg = "Unkown twitter error response received: status=%s" % resp.status
        raise TweepError(error_msg)
104
105

    # Pass returned body into parser and return parser output
106
    out =  parser(resp.read(), api)
107
108
109
110
111
112
113
114
115
116
117
118
119
    conn.close()

    # validate result
    if api.validate:
      # list of results
      if isinstance(out, list) and len(out) > 0:
        if hasattr(out[0], 'validate'):
          for result in out:
            result.validate()
      # single result
      else:
        if hasattr(out, 'validate'):
          out.validate()
120

121
122
123
124
    # store result in cache
    if api.cache and method == 'GET':
      api.cache.store(url, out)

125
    return out
126

127
  return _call