forked from sigmavirus24/github3.py
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecorators.py
More file actions
151 lines (109 loc) · 4.17 KB
/
decorators.py
File metadata and controls
151 lines (109 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# -*- coding: utf-8 -*-
"""This module provides decorators to the rest of the library."""
from functools import wraps
from requests.models import Response
import os
try: # (No coverage)
# python2
from StringIO import StringIO # (No coverage)
except ImportError: # (No coverage)
# python3
from io import BytesIO as StringIO
class RequestsStringIO(StringIO):
"""Shim compatibility for string IO."""
def read(self, n=-1, *args, **kwargs):
"""Ignore extra args and kwargs."""
# StringIO is an old-style class, so can't use super
return StringIO.read(self, n)
def requires_auth(func):
"""Decorator to note which object methods require authorization."""
@wraps(func)
def auth_wrapper(self, *args, **kwargs):
if hasattr(self, "session") and self.session.has_auth():
return func(self, *args, **kwargs)
else:
from .exceptions import error_for
# Mock a 401 response
r = generate_fake_error_response(
'{"message": "Requires authentication"}'
)
raise error_for(r)
return auth_wrapper
def requires_basic_auth(func):
"""Specific (basic) authentication decorator.
This is used to note which object methods require username/password
authorization and won't work with token based authorization.
"""
@wraps(func)
def auth_wrapper(self, *args, **kwargs):
if hasattr(self, "session") and self.session.auth:
return func(self, *args, **kwargs)
else:
from .exceptions import error_for
# Mock a 401 response
r = generate_fake_error_response(
'{"message": "Requires username/password authentication"}'
)
raise error_for(r)
return auth_wrapper
def requires_app_credentials(func):
"""Require client_id and client_secret to be associated.
This is used to note and enforce which methods require a client_id and
client_secret to be used.
"""
@wraps(func)
def auth_wrapper(self, *args, **kwargs):
client_id, client_secret = self.session.retrieve_client_credentials()
if client_id and client_secret:
return func(self, *args, **kwargs)
else:
from .exceptions import error_for
# Mock a 401 response
r = generate_fake_error_response(
'{"message": "Requires username/password authentication"}'
)
raise error_for(r)
return auth_wrapper
def requires_app_bearer_auth(func):
"""Require the use of application authentication.
.. versionadded:: 1.2.0
"""
@wraps(func)
def auth_wrapper(self, *args, **kwargs):
from . import session
if isinstance(self.session.auth, session.AppBearerTokenAuth):
return func(self, *args, **kwargs)
else:
from . import exceptions
raise exceptions.MissingAppBearerAuthentication(
"This method requires GitHub App authentication."
)
return auth_wrapper
def requires_app_installation_auth(func):
"""Require the use of App's installation authentication.
.. versionadded:: 1.2.0
"""
@wraps(func)
def auth_wrapper(self, *args, **kwargs):
from . import session
if isinstance(self.session.auth, session.AppInstallationTokenAuth):
return func(self, *args, **kwargs)
else:
from . import exceptions
raise exceptions.MissingAppInstallationAuthentication(
"This method requires GitHub App authentication."
)
return auth_wrapper
def generate_fake_error_response(msg, status_code=401, encoding="utf-8"):
"""Generate a fake Response from requests."""
r = Response()
r.status_code = status_code
r.encoding = encoding
r.raw = RequestsStringIO(msg.encode())
r._content_consumed = True
r._content = r.raw.read()
return r
# Use mock decorators when generating documentation, so all functino signatures
# are displayed correctly
if os.getenv("GENERATING_DOCUMENTATION", None) == "github3":
requires_auth = requires_basic_auth = lambda x: x # noqa # (No coverage)