Show More
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 |
|
2 | |||
3 | # Copyright (C) 2012-2020 RhodeCode GmbH |
|
3 | # Copyright (C) 2012-2020 RhodeCode GmbH | |
4 | # |
|
4 | # |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | Helper functions for use with :class:`Authomatic`. |
|
3 | Helper functions for use with :class:`Authomatic`. | |
4 |
|
4 |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | Adapters |
|
3 | Adapters | |
4 | -------- |
|
4 | -------- | |
@@ -271,6 +271,7 b' class WerkzeugAdapter(BaseAdapter):' | |||||
271 | self.response = response |
|
271 | self.response = response | |
272 |
|
272 | |||
273 | def write(self, value): |
|
273 | def write(self, value): | |
|
274 | #self.response.data = self.response.data.decode('utf-8') + value | |||
274 | self.response.data = self.response.data + value |
|
275 | self.response.data = self.response.data + value | |
275 |
|
276 | |||
276 | def set_header(self, key, value): |
|
277 | def set_header(self, key, value): |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 |
|
2 | |||
3 | import collections |
|
3 | import collections | |
4 | import copy |
|
4 | import copy | |
@@ -7,7 +7,10 b' import hashlib' | |||||
7 | import hmac |
|
7 | import hmac | |
8 | import json |
|
8 | import json | |
9 | import logging |
|
9 | import logging | |
10 | import pickle |
|
10 | try: | |
|
11 | import cPickle as pickle | |||
|
12 | except ImportError: | |||
|
13 | import pickle | |||
11 | import sys |
|
14 | import sys | |
12 | import threading |
|
15 | import threading | |
13 | import time |
|
16 | import time | |
@@ -914,7 +917,7 b' class Credentials(ReprMixin):' | |||||
914 |
|
917 | |||
915 | deserialized = Credentials(config) |
|
918 | deserialized = Credentials(config) | |
916 |
|
919 | |||
917 |
deserialized.provider_id = |
|
920 | deserialized.provider_id = int(split[0]) | |
918 | deserialized.provider_type = ProviderClass.get_type() |
|
921 | deserialized.provider_type = ProviderClass.get_type() | |
919 | deserialized.provider_type_id = split[1] |
|
922 | deserialized.provider_type_id = split[1] | |
920 | deserialized.provider_class = ProviderClass |
|
923 | deserialized.provider_class = ProviderClass | |
@@ -1141,8 +1144,8 b' class Response(ReprMixin):' | |||||
1141 | Return true if string is binary data. |
|
1144 | Return true if string is binary data. | |
1142 | """ |
|
1145 | """ | |
1143 |
|
1146 | |||
1144 |
textchars = (bytearray([7, 8, 9, 10, 12, 13, 27]) |
|
1147 | textchars = (bytearray([7, 8, 9, 10, 12, 13, 27]) | |
1145 | bytearray(range(0x20, 0x100))) |
|
1148 | + bytearray(range(0x20, 0x100))) | |
1146 | return bool(content.translate(None, textchars)) |
|
1149 | return bool(content.translate(None, textchars)) | |
1147 |
|
1150 | |||
1148 | @property |
|
1151 | @property | |
@@ -1156,6 +1159,7 b' class Response(ReprMixin):' | |||||
1156 | if self.is_binary_string(content): |
|
1159 | if self.is_binary_string(content): | |
1157 | self._content = content |
|
1160 | self._content = content | |
1158 | else: |
|
1161 | else: | |
|
1162 | #self._content = content.decode('utf-8') | |||
1159 | self._content = content |
|
1163 | self._content = content | |
1160 | return self._content |
|
1164 | return self._content | |
1161 |
|
1165 | |||
@@ -1714,7 +1718,7 b' class Authomatic(object):' | |||||
1714 | jsonp = params.get('callback') |
|
1718 | jsonp = params.get('callback') | |
1715 |
|
1719 | |||
1716 | # JSONP is possible only with GET method. |
|
1720 | # JSONP is possible only with GET method. | |
1717 |
if ProviderClass.supports_jsonp and method |
|
1721 | if ProviderClass.supports_jsonp and method == 'GET': | |
1718 | request_type = 'elements' |
|
1722 | request_type = 'elements' | |
1719 | else: |
|
1723 | else: | |
1720 | # Remove the JSONP callback |
|
1724 | # Remove the JSONP callback |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | Provides various exception types for the library. |
|
3 | Provides various exception types for the library. | |
4 | """ |
|
4 | """ |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | |flask| Extras |
|
3 | |flask| Extras | |
4 | -------------- |
|
4 | -------------- | |
@@ -8,7 +8,7 b' Utilities you can use when using this li' | |||||
8 | Thanks to `Mark Steve Samson <http://marksteve.com>`_. |
|
8 | Thanks to `Mark Steve Samson <http://marksteve.com>`_. | |
9 | """ |
|
9 | """ | |
10 |
|
10 | |||
11 |
|
11 | from __future__ import absolute_import | ||
12 | from functools import wraps |
|
12 | from functools import wraps | |
13 |
|
13 | |||
14 | from authomatic.adapters import WerkzeugAdapter |
|
14 | from authomatic.adapters import WerkzeugAdapter | |
@@ -44,4 +44,5 b' class FlaskAuthomatic(Authomatic):' | |||||
44 | return decorator |
|
44 | return decorator | |
45 |
|
45 | |||
46 | def session_saver(self): |
|
46 | def session_saver(self): | |
47 | session.modified = True |
|
47 | # FIXME: pylint false positive - see https://github.com/pallets/flask/issues/4020 | |
|
48 | session.modified = True # pylint: disable=assigning-non-slot |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | |gae| Extras |
|
3 | |gae| Extras | |
4 | ------------ |
|
4 | ------------ | |
@@ -6,13 +6,20 b'' | |||||
6 | Utilities you can use when using this library on |gae|_. |
|
6 | Utilities you can use when using this library on |gae|_. | |
7 | """ |
|
7 | """ | |
8 |
|
8 | |||
9 | from google.appengine.ext import ndb |
|
|||
10 | from webapp2_extras import sessions |
|
|||
11 |
|
9 | |||
12 | from authomatic import exceptions |
|
10 | from authomatic import exceptions | |
13 | from authomatic.extras import interfaces |
|
11 | from authomatic.extras import interfaces | |
14 | from authomatic.extras.gae.openid import NDBOpenIDStore |
|
12 | from authomatic.extras.gae.openid import NDBOpenIDStore | |
|
13 | import logging | |||
15 |
|
14 | |||
|
15 | logger = logging.getLogger(__name__) | |||
|
16 | ||||
|
17 | try: | |||
|
18 | from google.appengine.ext import ndb | |||
|
19 | from webapp2_extras import sessions | |||
|
20 | except ImportError: | |||
|
21 | logger.exception("FATAL: google.appengine 1st Gen. not installed!") | |||
|
22 | raise | |||
16 |
|
23 | |||
17 | __all__ = ['ndb_config', 'Webapp2Session'] |
|
24 | __all__ = ['ndb_config', 'Webapp2Session'] | |
18 |
|
25 |
@@ -1,13 +1,19 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 |
|
2 | |||
3 | # We need absolute import to import from openid library which has the same |
|
3 | # We need absolute import to import from openid library which has the same | |
4 | # name as this module |
|
4 | # name as this module | |
5 |
|
5 | from __future__ import absolute_import | ||
6 | import logging |
|
6 | import logging | |
7 | import datetime |
|
7 | import datetime | |
|
8 | import openid.store.interface | |||
8 |
|
9 | |||
9 | from google.appengine.ext import ndb |
|
10 | logger = logging.getLogger(__name__) | |
10 | import openid.store.interface |
|
11 | ||
|
12 | try: | |||
|
13 | from google.appengine.ext import ndb | |||
|
14 | except ImportError: | |||
|
15 | logger.exception("FATAL: google.appengine 1st Gen. not installed!") | |||
|
16 | raise | |||
11 |
|
17 | |||
12 |
|
18 | |||
13 | class NDBOpenIDStore(ndb.Expando, openid.store.interface.OpenIDStore): |
|
19 | class NDBOpenIDStore(ndb.Expando, openid.store.interface.OpenIDStore): |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | Interfaces |
|
3 | Interfaces | |
4 | ^^^^^^^^^^ |
|
4 | ^^^^^^^^^^ |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | Abstract Classes for Providers |
|
3 | Abstract Classes for Providers | |
4 | ------------------------------ |
|
4 | ------------------------------ | |
@@ -503,8 +503,10 b' class BaseProvider(object):' | |||||
503 | self.user.last_name)) |
|
503 | self.user.last_name)) | |
504 | else: |
|
504 | else: | |
505 | # Or use one of these. |
|
505 | # Or use one of these. | |
506 |
self.user.name = (self.user.username |
|
506 | self.user.name = (self.user.username | |
507 |
|
|
507 | or self.user.nickname | |
|
508 | or self.user.first_name | |||
|
509 | or self.user.last_name) | |||
508 |
|
510 | |||
509 | if not self.user.location: |
|
511 | if not self.user.location: | |
510 | if self.user.city and self.user.country: |
|
512 | if self.user.city and self.user.country: |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | Google App Engine OpenID Providers |
|
3 | Google App Engine OpenID Providers | |
4 | ---------------------------------- |
|
4 | ---------------------------------- | |
@@ -25,14 +25,20 b' Google App Engine OpenID Providers' | |||||
25 |
|
25 | |||
26 | """ |
|
26 | """ | |
27 |
|
27 | |||
28 | import logging |
|
|||
29 |
|
||||
30 | from google.appengine.api import users |
|
|||
31 |
|
||||
32 | import authomatic.core as core |
|
28 | import authomatic.core as core | |
33 | from authomatic import providers |
|
29 | from authomatic import providers | |
34 | from authomatic.exceptions import FailureError |
|
30 | from authomatic.exceptions import FailureError | |
35 |
|
31 | |||
|
32 | import logging | |||
|
33 | ||||
|
34 | logger = logging.getLogger(__name__) | |||
|
35 | ||||
|
36 | try: | |||
|
37 | from google.appengine.api import users | |||
|
38 | except ImportError: | |||
|
39 | logger.exception("FATAL: google.appengine 1st Gen. not installed!") | |||
|
40 | users = None | |||
|
41 | ||||
36 |
|
42 | |||
37 | __all__ = ['GAEOpenID', 'Yahoo', 'Google'] |
|
43 | __all__ = ['GAEOpenID', 'Yahoo', 'Google'] | |
38 |
|
44 |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | |oauth1| Providers |
|
3 | |oauth1| Providers | |
4 | -------------------- |
|
4 | -------------------- | |
@@ -358,7 +358,7 b' class OAuth1(providers.AuthorizationProv' | |||||
358 | params['oauth_consumer_key'] = consumer_key |
|
358 | params['oauth_consumer_key'] = consumer_key | |
359 | else: |
|
359 | else: | |
360 | raise OAuth1Error( |
|
360 | raise OAuth1Error( | |
361 |
'Credentials with valid consumer_key, ' |
|
361 | 'Credentials with valid consumer_key, ' | |
362 | 'consumer_secret, token and token_secret are required ' |
|
362 | 'consumer_secret, token and token_secret are required ' | |
363 | 'to create Protected Resources URL!') |
|
363 | 'to create Protected Resources URL!') | |
364 |
|
364 |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | |oauth2| Providers |
|
3 | |oauth2| Providers | |
4 | ------------------- |
|
4 | ------------------- | |
@@ -20,6 +20,7 b' Providers which implement the |oauth2|_ ' | |||||
20 | GitHub |
|
20 | GitHub | |
21 |
|
21 | |||
22 |
|
22 | |||
|
23 | MicrosoftOnline | |||
23 | PayPal |
|
24 | PayPal | |
24 |
|
25 | |||
25 | Viadeo |
|
26 | Viadeo | |
@@ -55,6 +56,7 b' import authomatic.core as core' | |||||
55 | 'GitHub', |
|
56 | 'GitHub', | |
56 | 'Google', |
|
57 | 'Google', | |
57 | 'LinkedIn', |
|
58 | 'LinkedIn', | |
|
59 | 'MicrosoftOnline', | |||
58 | 'PayPal', |
|
60 | 'PayPal', | |
59 | 'Reddit', |
|
61 | 'Reddit', | |
60 | 'Viadeo', |
|
62 | 'Viadeo', | |
@@ -298,7 +300,7 b' class OAuth2(providers.AuthorizationProv' | |||||
298 | # unquote Cast to str to void b64decode translation error. Base64 |
|
300 | # unquote Cast to str to void b64decode translation error. Base64 | |
299 | # should be str compatible. |
|
301 | # should be str compatible. | |
300 | return json.loads(base64.urlsafe_b64decode( |
|
302 | return json.loads(base64.urlsafe_b64decode( | |
301 | unquote(str(state))))[param] |
|
303 | unquote(str(state))).decode('utf-8'))[param] | |
302 | else: |
|
304 | else: | |
303 | return state if param == 'csrf' else '' |
|
305 | return state if param == 'csrf' else '' | |
304 |
|
306 | |||
@@ -490,9 +492,9 b' class OAuth2(providers.AuthorizationProv' | |||||
490 | url=self.user_authorization_url) |
|
492 | url=self.user_authorization_url) | |
491 |
|
493 | |||
492 | elif ( |
|
494 | elif ( | |
493 |
not self.params |
|
495 | not self.params | |
494 |
len(self.params) == 1 |
|
496 | or len(self.params) == 1 | |
495 | 'user_state' in self.params |
|
497 | and 'user_state' in self.params | |
496 | ): |
|
498 | ): | |
497 | # ================================================================= |
|
499 | # ================================================================= | |
498 | # Phase 1 before redirect |
|
500 | # Phase 1 before redirect | |
@@ -1214,6 +1216,7 b' class GitHub(OAuth2):' | |||||
1214 | 'consumer_key': '#####', |
|
1216 | 'consumer_key': '#####', | |
1215 | 'consumer_secret': '#####', |
|
1217 | 'consumer_secret': '#####', | |
1216 | 'access_headers': {'User-Agent': 'Awesome-Octocat-App'}, |
|
1218 | 'access_headers': {'User-Agent': 'Awesome-Octocat-App'}, | |
|
1219 | 'scope': ['user:email'] | |||
1217 | } |
|
1220 | } | |
1218 | } |
|
1221 | } | |
1219 |
|
1222 | |||
@@ -1272,6 +1275,38 b' class GitHub(OAuth2):' | |||||
1272 | credentials.token_type = cls.BEARER |
|
1275 | credentials.token_type = cls.BEARER | |
1273 | return credentials |
|
1276 | return credentials | |
1274 |
|
1277 | |||
|
1278 | def access(self, url, **kwargs): | |||
|
1279 | # https://developer.github.com/v3/#user-agent-required | |||
|
1280 | # GitHub requires that all API requests MUST include a valid ``User-Agent`` header. | |||
|
1281 | headers = kwargs["headers"] = kwargs.get("headers", {}) | |||
|
1282 | if not headers.get("User-Agent"): | |||
|
1283 | headers["User-Agent"] = self.settings.config[self.name]["consumer_key"] | |||
|
1284 | ||||
|
1285 | def parent_access(url): | |||
|
1286 | return super(GitHub, self).access(url, **kwargs) | |||
|
1287 | ||||
|
1288 | response = parent_access(url) | |||
|
1289 | ||||
|
1290 | # additional action to get email is required: | |||
|
1291 | # https://developer.github.com/v3/users/emails/ | |||
|
1292 | if response.status == 200: | |||
|
1293 | email_response = parent_access(url + "/emails") | |||
|
1294 | if email_response.status == 200: | |||
|
1295 | response.data["emails"] = email_response.data | |||
|
1296 | ||||
|
1297 | # find first or primary email | |||
|
1298 | primary_email = None | |||
|
1299 | for item in email_response.data: | |||
|
1300 | is_primary = item["primary"] | |||
|
1301 | if not primary_email or is_primary: | |||
|
1302 | primary_email = item["email"] | |||
|
1303 | ||||
|
1304 | if is_primary: | |||
|
1305 | break | |||
|
1306 | ||||
|
1307 | response.data["email"] = primary_email | |||
|
1308 | return response | |||
|
1309 | ||||
1275 |
|
1310 | |||
1276 | class Google(OAuth2): |
|
1311 | class Google(OAuth2): | |
1277 | """ |
|
1312 | """ | |
@@ -1487,13 +1522,89 b' class LinkedIn(OAuth2):' | |||||
1487 | return user |
|
1522 | return user | |
1488 |
|
1523 | |||
1489 |
|
1524 | |||
|
1525 | class MicrosoftOnline(OAuth2): | |||
|
1526 | """ | |||
|
1527 | Microsoft Online |oauth2| provider. | |||
|
1528 | ||||
|
1529 | Supported :class:`.User` properties: | |||
|
1530 | ||||
|
1531 | ||||
|
1532 | * first_name | |||
|
1533 | * id | |||
|
1534 | * last_name | |||
|
1535 | * location | |||
|
1536 | * name | |||
|
1537 | * phone | |||
|
1538 | * picture | |||
|
1539 | * username | |||
|
1540 | ||||
|
1541 | Unsupported :class:`.User` properties: | |||
|
1542 | ||||
|
1543 | * birth_date | |||
|
1544 | * city | |||
|
1545 | * country | |||
|
1546 | * gender | |||
|
1547 | * link | |||
|
1548 | * locale | |||
|
1549 | * nickname | |||
|
1550 | * postal_code | |||
|
1551 | * timezone | |||
|
1552 | ||||
|
1553 | """ | |||
|
1554 | ||||
|
1555 | user_authorization_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize' | |||
|
1556 | access_token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token' | |||
|
1557 | user_info_url = "https://graph.microsoft.com/v1.0/me" | |||
|
1558 | ||||
|
1559 | user_info_scope = ['openid profile'] | |||
|
1560 | ||||
|
1561 | supported_user_attributes = core.SupportedUserAttributes( | |||
|
1562 | id=True, | |||
|
1563 | email=True, | |||
|
1564 | first_name=True, | |||
|
1565 | last_name=True, | |||
|
1566 | location=True, | |||
|
1567 | name=True, | |||
|
1568 | phone=True, | |||
|
1569 | picture=True, | |||
|
1570 | username=True, | |||
|
1571 | ) | |||
|
1572 | ||||
|
1573 | def __init__(self, *args, **kwargs): | |||
|
1574 | super(MicrosoftOnline, self).__init__(*args, **kwargs) | |||
|
1575 | auth = args[0] | |||
|
1576 | provider_name = kwargs.get('provider_name') | |||
|
1577 | domain = auth.config.get(provider_name, {}).get('domain') | |||
|
1578 | if domain is not None: | |||
|
1579 | self.user_authorization_url = MicrosoftOnline.user_authorization_url.replace('/common/', '/%s/' % domain) | |||
|
1580 | self.access_token_url = MicrosoftOnline.access_token_url.replace('/common/', '/%s/' % domain) | |||
|
1581 | ||||
|
1582 | @classmethod | |||
|
1583 | def _x_credentials_parser(cls, credentials, data): | |||
|
1584 | if data.get('token_type') == 'bearer': | |||
|
1585 | credentials.token_type = cls.BEARER | |||
|
1586 | return credentials | |||
|
1587 | ||||
|
1588 | @staticmethod | |||
|
1589 | def _x_user_parser(user, data): | |||
|
1590 | user.id = data.get('id') | |||
|
1591 | user.name = data.get('displayName', '') | |||
|
1592 | user.first_name = data.get('givenName', '') | |||
|
1593 | user.last_name = data.get('surname', '') | |||
|
1594 | user.email = data.get('mail', '') | |||
|
1595 | user.location = data.get('officeLocation', '') | |||
|
1596 | user.phone = data.get('mobilePhone', '') | |||
|
1597 | user.picture = data.get('picture', '') | |||
|
1598 | user.username = data.get('userPrincipalName', '') | |||
|
1599 | return user | |||
|
1600 | ||||
|
1601 | ||||
1490 | class PayPal(OAuth2): |
|
1602 | class PayPal(OAuth2): | |
1491 | """ |
|
1603 | """ | |
1492 | PayPal |oauth2| provider. |
|
1604 | PayPal |oauth2| provider. | |
1493 |
|
1605 | |||
1494 | * Dashboard: https://developer.paypal.com/webapps/developer/applications |
|
1606 | * Dashboard: https://developer.paypal.com/webapps/developer/applications | |
1495 | * Docs: |
|
1607 | * Docs: https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/ | |
1496 | https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/ |
|
|||
1497 | * API reference: https://developer.paypal.com/webapps/developer/docs/api/ |
|
1608 | * API reference: https://developer.paypal.com/webapps/developer/docs/api/ | |
1498 |
|
1609 | |||
1499 | .. note:: |
|
1610 | .. note:: | |
@@ -1540,8 +1651,8 b' class Reddit(OAuth2):' | |||||
1540 |
|
1651 | |||
1541 | .. note:: |
|
1652 | .. note:: | |
1542 |
|
1653 | |||
1543 |
According to |
|
1654 | According to | |
1544 | `docs <https://github.com/reddit/reddit/wiki/API#rules>`_, |
|
1655 | `Reddit API docs <https://github.com/reddit/reddit/wiki/API#rules>`_, | |
1545 | you have to include a `User-Agent` header in each API call. |
|
1656 | you have to include a `User-Agent` header in each API call. | |
1546 |
|
1657 | |||
1547 | You can apply a default ``User-Agent`` header for all API calls in the |
|
1658 | You can apply a default ``User-Agent`` header for all API calls in the | |
@@ -1961,8 +2072,7 b' class Yandex(OAuth2):' | |||||
1961 | Yandex |oauth2| provider. |
|
2072 | Yandex |oauth2| provider. | |
1962 |
|
2073 | |||
1963 | * Dashboard: https://oauth.yandex.com/client/my |
|
2074 | * Dashboard: https://oauth.yandex.com/client/my | |
1964 | * Docs: |
|
2075 | * Docs: http://api.yandex.com/oauth/doc/dg/reference/obtain-access-token.xml | |
1965 | http://api.yandex.com/oauth/doc/dg/reference/obtain-access-token.xml |
|
|||
1966 | * API reference: |
|
2076 | * API reference: | |
1967 |
|
2077 | |||
1968 | Supported :class:`.User` properties: |
|
2078 | Supported :class:`.User` properties: | |
@@ -2042,6 +2152,7 b' PROVIDER_ID_MAP = [' | |||||
2042 | GitHub, |
|
2152 | GitHub, | |
2043 | Google, |
|
2153 | Google, | |
2044 | LinkedIn, |
|
2154 | LinkedIn, | |
|
2155 | MicrosoftOnline, | |||
2045 | OAuth2, |
|
2156 | OAuth2, | |
2046 | PayPal, |
|
2157 | PayPal, | |
2047 | Reddit, |
|
2158 | Reddit, |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """ |
|
2 | """ | |
3 | |openid| Providers |
|
3 | |openid| Providers | |
4 | ---------------------------------- |
|
4 | ---------------------------------- | |
@@ -20,7 +20,7 b' Providers which implement the |openid|_ ' | |||||
20 |
|
20 | |||
21 | # We need absolute import to import from openid library which has the same |
|
21 | # We need absolute import to import from openid library which has the same | |
22 | # name as this module |
|
22 | # name as this module | |
23 |
|
23 | from __future__ import absolute_import | ||
24 | import datetime |
|
24 | import datetime | |
25 | import logging |
|
25 | import logging | |
26 | import time |
|
26 | import time |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | from authomatic import providers |
|
2 | from authomatic import providers | |
3 |
|
3 | |||
4 |
|
4 |
@@ -1,4 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | ||
2 | """Utilities for writing code that runs on Python 2 and 3""" |
|
2 | """Utilities for writing code that runs on Python 2 and 3""" | |
3 |
|
3 | |||
4 | # Copyright (c) 2010-2015 Benjamin Peterson |
|
4 | # Copyright (c) 2010-2015 Benjamin Peterson | |
@@ -21,7 +21,7 b'' | |||||
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
22 | # SOFTWARE. |
|
22 | # SOFTWARE. | |
23 |
|
23 | |||
24 |
|
24 | from __future__ import absolute_import | ||
25 |
|
25 | |||
26 | import functools |
|
26 | import functools | |
27 | import itertools |
|
27 | import itertools | |
@@ -89,7 +89,7 b' class _LazyDescr(object):' | |||||
89 |
|
89 | |||
90 | def __get__(self, obj, tp): |
|
90 | def __get__(self, obj, tp): | |
91 | result = self._resolve() |
|
91 | result = self._resolve() | |
92 | setattr(obj, self.name, result) # Invokes __set__. |
|
92 | setattr(obj, self.name, result) # Invokes __set__. | |
93 | try: |
|
93 | try: | |
94 | # This is a bit ugly, but it avoids running this again by |
|
94 | # This is a bit ugly, but it avoids running this again by | |
95 | # removing this descriptor. |
|
95 | # removing this descriptor. | |
@@ -733,8 +733,8 b' if print_ is None:' | |||||
733 | want_unicode = True |
|
733 | want_unicode = True | |
734 | break |
|
734 | break | |
735 | if want_unicode: |
|
735 | if want_unicode: | |
736 |
newline = |
|
736 | newline = str("\n") | |
737 |
space = |
|
737 | space = str(" ") | |
738 | else: |
|
738 | else: | |
739 | newline = "\n" |
|
739 | newline = "\n" | |
740 | space = " " |
|
740 | space = " " |
General Comments 0
You need to be logged in to leave comments.
Login now