├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── example ├── __init__.py ├── authorize_driver.py ├── authorize_rider.py ├── config.driver.yaml ├── config.rider.yaml ├── driver_dashboard.html ├── driver_dashboard.py ├── request_ride.py ├── rider_dashboard.html ├── rider_dashboard.py └── utils.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests ├── __init__.py ├── fixtures │ ├── test_auth_code_get_session │ ├── test_cancel_current_ride │ ├── test_cancel_ride │ ├── test_client_credential_get_session │ ├── test_estimate_ride │ ├── test_estimate_ride_with_places │ ├── test_estimate_shared_ride │ ├── test_get_business_receipt │ ├── test_get_business_trip_invoice_urls │ ├── test_get_business_trip_receipt_pdf_url │ ├── test_get_current_ride_details │ ├── test_get_current_shared_ride_details │ ├── test_get_driver_payments │ ├── test_get_driver_profile │ ├── test_get_driver_trips │ ├── test_get_home_address │ ├── test_get_payment_methods │ ├── test_get_pickup_time_estimates │ ├── test_get_price_estimates │ ├── test_get_products │ ├── test_get_promotions │ ├── test_get_ride_details │ ├── test_get_ride_map │ ├── test_get_ride_receipt │ ├── test_get_rider_profile │ ├── test_get_rider_trips │ ├── test_get_single_product │ ├── test_get_user_activity │ ├── test_get_user_profile │ ├── test_get_work_address │ ├── test_refresh_auth_code_access_token │ ├── test_refresh_client_credential_access_token │ ├── test_request_ride │ ├── test_request_ride_with_no_default_product │ ├── test_request_ride_with_places │ ├── test_request_ride_with_surge │ ├── test_request_shared_ride │ ├── test_set_home_address │ ├── test_set_work_address │ ├── test_update_ride_destination │ ├── test_update_ride_destination_with_places │ ├── test_update_sandbox_driver_trips │ ├── test_update_sandbox_product │ └── test_update_sandbox_ride ├── test_auth.py ├── test_client.py ├── test_errors.py ├── test_request_utils.py ├── test_session.py └── vcr_config.py └── uber_rides ├── __init__.py ├── auth.py ├── client.py ├── errors.py ├── request.py ├── session.py └── utils ├── __init__.py ├── auth.py ├── handlers.py ├── http.py └── request.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Local Environment # 2 | ##################### 3 | env/ 4 | 5 | # PyPi Dist Subdirectories # 6 | ############################ 7 | build/ 8 | dist/ 9 | *.egg-info/ 10 | 11 | # Examples 12 | example/oauth*_session_store.yaml 13 | 14 | 15 | # Backup Generated Files # 16 | ########################## 17 | __pycache__/ 18 | *.pyo 19 | *.pyc 20 | *~ 21 | *# 22 | 23 | # Compiled source # 24 | ################### 25 | *.com 26 | *.class 27 | *.dll 28 | *.exe 29 | *.o 30 | *.so 31 | 32 | # Packages # 33 | ############ 34 | *.7z 35 | *.dmg 36 | *.gz 37 | *.iso 38 | *.jar 39 | *.rar 40 | *.tar 41 | *.zip 42 | 43 | # Logs and databases # 44 | ###################### 45 | *.log 46 | *.sql 47 | *.sqlite 48 | 49 | # OS generated files # 50 | ###################### 51 | .DS_Store 52 | .DS_Store? 53 | ._* 54 | .Spotlight-V100 55 | .Trashes 56 | ehthumbs.db 57 | Thumbs.db 58 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.3" 5 | - "3.4" 6 | - "3.5" 7 | 8 | install: make bootstrap 9 | script: make 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | v0.6.0 - 14/9/2017 3 | ------------------- 4 | - Added support for Uber Driver Sandbox 5 | - BC Break: Renamed auth.CLIENT_CREDENTIAL_GRANT to auth.CLIENT_CREDENTIALS_GRANT 6 | 7 | v0.5.3 - 11/9/2017 8 | ------------------- 9 | - Added support for Uber for Business APIs 10 | 11 | v0.5.2 - 22/8/2017 12 | ------------------- 13 | - Added flask example apps for Rider + Driver Dashboards 14 | 15 | v0.5.1 - 18/8/2017 16 | ------------------- 17 | - Added better examples for Driver APIs 18 | - Added backwards compatibility proxies for legacy rider methods 19 | - Fixed SDK version # to v0.5.1 20 | 21 | v0.5.0 - 17/8/2017 22 | ------------------- 23 | - Added support Driver APIs 24 | 25 | v0.4.1 - 2/7/2017 26 | ------------------- 27 | - Made state token optional in authorization code grant 28 | 29 | v0.4.0 - 1/23/2017 30 | ------------------- 31 | - Upgrade OAuth endpoints to use v2. 32 | 33 | v0.3.1 - 11/12/2016 34 | ------------------- 35 | - Removal of rate limiting headers. The headers are deprecated with v1.2: X-Rate-Limit-Limit, X-Rate-Limit-Remaining, X-Rate-Limit-Reset. 36 | 37 | v0.3.0 - 11/12/2016 38 | ------------------- 39 | - Release of v1.2 endpoints for the Riders API. 40 | - API base URL would need to reflect the version bump: https://api.uber.com/v1.2/. 41 | 42 | v0.2.7 - 9/28/2016 43 | ------------------- 44 | - Added support for Python wheels 45 | 46 | v0.2.6 - 9/28/2016 47 | ------------------ 48 | - Added better support for python 2. 49 | 50 | v0.2.5 - 7/18/2016 51 | ------------------ 52 | - Add seat_count support to get_price_estimates 53 | 54 | v0.2.4 - 6/10/2016 55 | ------------------ 56 | - Added SDK Version header 57 | 58 | v0.2.3 - 6/8/2016 59 | ----------------- 60 | - Added Pool support 61 | 62 | v0.2.2 - 6/2/2016 63 | ----------------- 64 | - Fixed backwards compatibility setup support for Python 2 65 | - Allowed custom state tokens for authorizations 66 | - Improved ErrorDetails formatting 67 | 68 | v0.2.1 - 3/29/2016 69 | ------------------ 70 | - Added support for Python 3 71 | 72 | v0.2.0 - 2/20/2016 73 | ------------------ 74 | - Added places support 75 | - Added payment methods support 76 | - Added trip experiences support 77 | - Added optional destination (Fix for Issue #4) 78 | - Added update destinaion support 79 | - Added default product ID support for estimates and ride requests 80 | - Rides Client mode (Sandbox or Production) is explicitly set 81 | 82 | v0.1.0 - 9/26/2015 83 | ------------------ 84 | - Initial version. 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2017 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include uber_rides * 2 | recursive-include tests * 3 | recursive-include example * 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | test: 3 | @py.test -s tests/ 4 | 5 | .PHONY: clean 6 | clean: 7 | @find . -type f -name '*.pyc' -exec rm {} ';' 8 | 9 | .PHONY: bootstrap 10 | bootstrap: 11 | @pip install -r requirements.txt 12 | @pip install -e . 13 | -------------------------------------------------------------------------------- /example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/rides-python-sdk/76ecd75ab5235d792ec1010e36eca679ba285127/example/__init__.py -------------------------------------------------------------------------------- /example/authorize_driver.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """Initializes an UberRidesClient with OAuth 2.0 Credentials. 22 | 23 | This example demonstrates how to get an access token through the 24 | OAuth 2.0 Authorization Code Grant and use credentials to create 25 | an UberRidesClient. 26 | 27 | To run this example: 28 | 29 | (1) Set your app credentials in config.driver.yaml 30 | (2) Run `python authorize_driver.py` 31 | (3) A success message will print, 'Hello {YOUR_NAME}' 32 | (4) User OAuth 2.0 credentials are recorded in 33 | 'oauth_driver_session_store.yaml' 34 | """ 35 | 36 | from __future__ import absolute_import 37 | from __future__ import division 38 | from __future__ import print_function 39 | from __future__ import unicode_literals 40 | 41 | from builtins import input 42 | 43 | from yaml import safe_dump 44 | 45 | from example import utils # NOQA 46 | from example.utils import fail_print 47 | from example.utils import response_print 48 | from example.utils import success_print 49 | from example.utils import import_app_credentials 50 | 51 | from uber_rides.auth import AuthorizationCodeGrant 52 | from uber_rides.client import UberRidesClient 53 | from uber_rides.errors import ClientError 54 | from uber_rides.errors import ServerError 55 | from uber_rides.errors import UberIllegalState 56 | 57 | 58 | def authorization_code_grant_flow(credentials, storage_filename): 59 | """Get an access token through Authorization Code Grant. 60 | 61 | Parameters 62 | credentials (dict) 63 | All your app credentials and information 64 | imported from the configuration file. 65 | storage_filename (str) 66 | Filename to store OAuth 2.0 Credentials. 67 | 68 | Returns 69 | (UberRidesClient) 70 | An UberRidesClient with OAuth 2.0 Credentials. 71 | """ 72 | auth_flow = AuthorizationCodeGrant( 73 | credentials.get('client_id'), 74 | credentials.get('scopes'), 75 | credentials.get('client_secret'), 76 | credentials.get('redirect_url'), 77 | ) 78 | 79 | auth_url = auth_flow.get_authorization_url() 80 | login_message = 'Login as a driver and grant access by going to:\n\n{}\n' 81 | login_message = login_message.format(auth_url) 82 | response_print(login_message) 83 | 84 | redirect_url = 'Copy the URL you are redirected to and paste here:\n\n' 85 | result = input(redirect_url).strip() 86 | 87 | try: 88 | session = auth_flow.get_session(result) 89 | 90 | except (ClientError, UberIllegalState) as error: 91 | fail_print(error) 92 | return 93 | 94 | credential = session.oauth2credential 95 | 96 | credential_data = { 97 | 'client_id': credential.client_id, 98 | 'redirect_url': credential.redirect_url, 99 | 'access_token': credential.access_token, 100 | 'expires_in_seconds': credential.expires_in_seconds, 101 | 'scopes': list(credential.scopes), 102 | 'grant_type': credential.grant_type, 103 | 'client_secret': credential.client_secret, 104 | 'refresh_token': credential.refresh_token, 105 | } 106 | 107 | with open(storage_filename, 'w') as yaml_file: 108 | yaml_file.write(safe_dump(credential_data, default_flow_style=False)) 109 | 110 | return UberRidesClient(session, sandbox_mode=True) 111 | 112 | 113 | def hello_user(api_client): 114 | """Use an authorized client to fetch and print profile information. 115 | 116 | Parameters 117 | api_client (UberRidesClient) 118 | An UberRidesClient with OAuth 2.0 credentials. 119 | """ 120 | 121 | try: 122 | response = api_client.get_driver_profile() 123 | 124 | except (ClientError, ServerError) as error: 125 | fail_print(error) 126 | return 127 | 128 | else: 129 | profile = response.json 130 | first_name = profile.get('first_name') 131 | last_name = profile.get('last_name') 132 | email = profile.get('email') 133 | message = 'Hello, {} {}. Successfully granted access token to {}.' 134 | message = message.format(first_name, last_name, email) 135 | success_print(message) 136 | success_print(profile) 137 | 138 | success_print('---') 139 | response = api_client.get_driver_trips() 140 | trips = response.json 141 | success_print(trips) 142 | 143 | success_print('---') 144 | response = api_client.get_driver_payments() 145 | payments = response.json 146 | success_print(payments) 147 | 148 | 149 | if __name__ == '__main__': 150 | """Run the example. 151 | 152 | Get an access token through the OAuth 2.0 Authorization Code Grant 153 | and use credentials to create an UberRidesClient. 154 | """ 155 | credentials = import_app_credentials('config.driver.yaml') 156 | 157 | api_client = authorization_code_grant_flow( 158 | credentials, 159 | 'oauth_driver_session_store.yaml', 160 | ) 161 | 162 | hello_user(api_client) 163 | -------------------------------------------------------------------------------- /example/authorize_rider.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """Initializes an UberRidesClient with OAuth 2.0 Credentials. 22 | 23 | This example demonstrates how to get an access token through the 24 | OAuth 2.0 Authorization Code Grant and use credentials to create 25 | an UberRidesClient. 26 | 27 | To run this example: 28 | 29 | (1) Set your app credentials in config.yaml 30 | (2) Run `python authorize_rider.py` 31 | (3) A success message will print, 'Hello {YOUR_NAME}' 32 | (4) User OAuth 2.0 credentials are recorded in 33 | 'oauth_rider_session_store.yaml' 34 | """ 35 | 36 | from __future__ import absolute_import 37 | from __future__ import division 38 | from __future__ import print_function 39 | from __future__ import unicode_literals 40 | 41 | from builtins import input 42 | 43 | from yaml import safe_dump 44 | 45 | from example import utils # NOQA 46 | from example.utils import fail_print 47 | from example.utils import response_print 48 | from example.utils import success_print 49 | from example.utils import import_app_credentials 50 | 51 | from uber_rides.auth import AuthorizationCodeGrant 52 | from uber_rides.client import UberRidesClient 53 | from uber_rides.errors import ClientError 54 | from uber_rides.errors import ServerError 55 | from uber_rides.errors import UberIllegalState 56 | 57 | 58 | def authorization_code_grant_flow(credentials, storage_filename): 59 | """Get an access token through Authorization Code Grant. 60 | 61 | Parameters 62 | credentials (dict) 63 | All your app credentials and information 64 | imported from the configuration file. 65 | storage_filename (str) 66 | Filename to store OAuth 2.0 Credentials. 67 | 68 | Returns 69 | (UberRidesClient) 70 | An UberRidesClient with OAuth 2.0 Credentials. 71 | """ 72 | auth_flow = AuthorizationCodeGrant( 73 | credentials.get('client_id'), 74 | credentials.get('scopes'), 75 | credentials.get('client_secret'), 76 | credentials.get('redirect_url'), 77 | ) 78 | 79 | auth_url = auth_flow.get_authorization_url() 80 | login_message = 'Login as a rider and grant access by going to:\n\n{}\n' 81 | login_message = login_message.format(auth_url) 82 | response_print(login_message) 83 | 84 | redirect_url = 'Copy the URL you are redirected to and paste here: \n\n' 85 | result = input(redirect_url).strip() 86 | 87 | try: 88 | session = auth_flow.get_session(result) 89 | 90 | except (ClientError, UberIllegalState) as error: 91 | fail_print(error) 92 | return 93 | 94 | credential = session.oauth2credential 95 | 96 | credential_data = { 97 | 'client_id': credential.client_id, 98 | 'redirect_url': credential.redirect_url, 99 | 'access_token': credential.access_token, 100 | 'expires_in_seconds': credential.expires_in_seconds, 101 | 'scopes': list(credential.scopes), 102 | 'grant_type': credential.grant_type, 103 | 'client_secret': credential.client_secret, 104 | 'refresh_token': credential.refresh_token, 105 | } 106 | 107 | with open(storage_filename, 'w') as yaml_file: 108 | yaml_file.write(safe_dump(credential_data, default_flow_style=False)) 109 | 110 | return UberRidesClient(session, sandbox_mode=True) 111 | 112 | 113 | def hello_user(api_client): 114 | """Use an authorized client to fetch and print profile information. 115 | 116 | Parameters 117 | api_client (UberRidesClient) 118 | An UberRidesClient with OAuth 2.0 credentials. 119 | """ 120 | 121 | try: 122 | response = api_client.get_user_profile() 123 | 124 | except (ClientError, ServerError) as error: 125 | fail_print(error) 126 | return 127 | 128 | else: 129 | profile = response.json 130 | first_name = profile.get('first_name') 131 | last_name = profile.get('last_name') 132 | email = profile.get('email') 133 | message = 'Hello, {} {}. Successfully granted access token to {}.' 134 | message = message.format(first_name, last_name, email) 135 | success_print(message) 136 | success_print(profile) 137 | 138 | success_print('---') 139 | response = api_client.get_home_address() 140 | address = response.json 141 | success_print(address) 142 | 143 | success_print('---') 144 | response = api_client.get_user_activity() 145 | history = response.json 146 | success_print(history) 147 | 148 | 149 | if __name__ == '__main__': 150 | """Run the example. 151 | 152 | Get an access token through the OAuth 2.0 Authorization Code Grant 153 | and use credentials to create an UberRidesClient. 154 | """ 155 | credentials = import_app_credentials('config.rider.yaml') 156 | 157 | api_client = authorization_code_grant_flow( 158 | credentials, 159 | 'oauth_rider_session_store.yaml', 160 | ) 161 | 162 | hello_user(api_client) 163 | -------------------------------------------------------------------------------- /example/config.driver.yaml: -------------------------------------------------------------------------------- 1 | client_id: xxx 2 | client_secret: xxx 3 | redirect_url: http://localhost:8000/uber/connect 4 | scopes: 5 | - partner.accounts 6 | - partner.trips 7 | - partner.payments 8 | -------------------------------------------------------------------------------- /example/config.rider.yaml: -------------------------------------------------------------------------------- 1 | client_id: xxx 2 | client_secret: xxx 3 | redirect_url: http://localhost:8000/uber/connect 4 | scopes: 5 | - profile 6 | - history 7 | - places 8 | - request 9 | - request_receipt 10 | - all_trips 11 | -------------------------------------------------------------------------------- /example/driver_dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uber Driver Dashboard 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 30 | 31 | 33 | 34 |
35 | 36 |

Rating: {{ profile.rating }}

37 | 38 | {% if trips.0 %} 39 | 44 | {% else %} 45 |

No trips yet!

46 | {% endif %} 47 | 48 | {% if payments.0 %} 49 |

Earnings

50 |

51 | Made {{ payments | sum(attribute='amount') }}{{ payments.0.currency_code }} for driving {{ trips | sum(attribute='distance') }} miles. 52 |

53 | {% endif %} 54 | 55 |
56 | 57 | 59 | 60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /example/driver_dashboard.py: -------------------------------------------------------------------------------- 1 | 2 | from flask import Flask, redirect, request, render_template 3 | 4 | from example import utils # NOQA 5 | from example.utils import import_app_credentials 6 | 7 | from uber_rides.auth import AuthorizationCodeGrant 8 | from uber_rides.client import UberRidesClient 9 | 10 | import datetime 11 | 12 | app = Flask(__name__, template_folder="./") 13 | 14 | credentials = import_app_credentials('config.driver.yaml') 15 | 16 | auth_flow = AuthorizationCodeGrant( 17 | credentials.get('client_id'), 18 | credentials.get('scopes'), 19 | credentials.get('client_secret'), 20 | credentials.get('redirect_url'), 21 | ) 22 | 23 | 24 | @app.template_filter('date') 25 | def date(value, format='%b %d, %Y at %H:%M'): 26 | return datetime.datetime.fromtimestamp(value).strftime(format) 27 | 28 | 29 | @app.route('/') 30 | def index(): 31 | """Index controller to redirect user to sign in with uber.""" 32 | return redirect(auth_flow.get_authorization_url()) 33 | 34 | 35 | @app.route('/uber/connect') 36 | def connect(): 37 | """Connect controller to handle token exchange and query Uber API.""" 38 | 39 | # Exchange authorization code for acceess token and create session 40 | session = auth_flow.get_session(request.url) 41 | client = UberRidesClient(session) 42 | 43 | # Fetch profile for driver 44 | profile = client.get_driver_profile().json 45 | 46 | # Fetch last 50 trips and payments for driver 47 | trips = client.get_driver_trips(0, 50).json 48 | payments = client.get_driver_payments(0, 50).json 49 | 50 | return render_template('driver_dashboard.html', 51 | profile=profile, 52 | trips=trips['trips'], 53 | payments=payments['payments'] 54 | ) 55 | 56 | 57 | if __name__ == '__main__': 58 | app.run(host='0.0.0.0', port=8000, debug=True) 59 | -------------------------------------------------------------------------------- /example/rider_dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uber Rider Dashboard 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 29 | 30 | 32 | 33 |
34 | 35 |

You have traveled {{ total_distance_traveled|round|int }} miles in {{ total_rides }} Uber 36 | rides across {{ total_cities }} cities.

37 | 38 | 43 | 44 |
45 | 46 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /example/rider_dashboard.py: -------------------------------------------------------------------------------- 1 | 2 | from flask import Flask, redirect, request, render_template 3 | 4 | from example import utils # NOQA 5 | from example.utils import import_app_credentials 6 | 7 | from uber_rides.auth import AuthorizationCodeGrant 8 | from uber_rides.client import UberRidesClient 9 | 10 | from collections import OrderedDict, Counter 11 | 12 | app = Flask(__name__, template_folder="./") 13 | 14 | credentials = import_app_credentials('config.rider.yaml') 15 | 16 | auth_flow = AuthorizationCodeGrant( 17 | credentials.get('client_id'), 18 | credentials.get('scopes'), 19 | credentials.get('client_secret'), 20 | credentials.get('redirect_url'), 21 | ) 22 | 23 | 24 | @app.route('/') 25 | def index(): 26 | """Index controller to redirect user to sign in with uber.""" 27 | return redirect(auth_flow.get_authorization_url()) 28 | 29 | 30 | @app.route('/uber/connect') 31 | def connect(): 32 | """Connect controller to handle token exchange and query Uber API.""" 33 | 34 | # Exchange authorization code for acceess token and create session 35 | session = auth_flow.get_session(request.url) 36 | client = UberRidesClient(session) 37 | 38 | # Fetch profile for rider 39 | profile = client.get_rider_profile().json 40 | 41 | # Fetch all trips from history endpoint 42 | trips = [] 43 | i = 0 44 | while True: 45 | try: 46 | response = client.get_rider_trips( 47 | limit=50, 48 | offset=i) 49 | i += 50 50 | if len(response.json['history']) > 0: 51 | trips += response.json['history'] 52 | else: 53 | break 54 | except: 55 | break 56 | pass 57 | 58 | # Compute trip stats for # of rides and distance 59 | total_rides = 0 60 | total_distance_traveled = 0 61 | 62 | # Compute ranked list of # trips per city 63 | cities = list() 64 | for ride in trips: 65 | cities.append(ride['start_city']['display_name']) 66 | 67 | # only parse actually completed trips 68 | if ride['distance'] > 0: 69 | total_rides += 1 70 | total_distance_traveled += int(ride['distance']) 71 | 72 | total_cities = 0 73 | locations_counter = Counter(cities) 74 | locations = OrderedDict() 75 | cities_by_frequency = sorted(cities, key=lambda x: -locations_counter[x]) 76 | for city in list(cities_by_frequency): 77 | if city not in locations: 78 | total_cities += 1 79 | locations[city] = cities.count(city) 80 | 81 | return render_template('rider_dashboard.html', 82 | profile=profile, 83 | trips=trips, 84 | locations=locations, 85 | total_rides=total_rides, 86 | total_cities=total_cities, 87 | total_distance_traveled=total_distance_traveled 88 | ) 89 | 90 | 91 | if __name__ == '__main__': 92 | app.run(host='0.0.0.0', port=8000, debug=True) 93 | -------------------------------------------------------------------------------- /example/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """General utilities for command line examples.""" 22 | 23 | from __future__ import absolute_import 24 | from __future__ import division 25 | from __future__ import print_function 26 | from __future__ import unicode_literals 27 | 28 | from collections import namedtuple 29 | from yaml import safe_load 30 | 31 | from uber_rides.client import UberRidesClient 32 | from uber_rides.session import OAuth2Credential 33 | from uber_rides.session import Session 34 | 35 | 36 | # set your app credentials here 37 | CREDENTIALS_FILENAME = 'example/config.rider.yaml' 38 | 39 | # where your OAuth 2.0 credentials are stored 40 | STORAGE_FILENAME = 'example/oauth2_session_store.yaml' 41 | 42 | DEFAULT_CONFIG_VALUES = frozenset([ 43 | 'INSERT_CLIENT_ID_HERE', 44 | 'INSERT_CLIENT_SECRET_HERE', 45 | 'INSERT_REDIRECT_URL_HERE', 46 | ]) 47 | 48 | Colors = namedtuple('Colors', 'response, success, fail, end') 49 | COLORS = Colors( 50 | response='\033[94m', 51 | success='\033[92m', 52 | fail='\033[91m', 53 | end='\033[0m', 54 | ) 55 | 56 | 57 | def success_print(message): 58 | """Print a message in green text. 59 | 60 | Parameters 61 | message (str) 62 | Message to print. 63 | """ 64 | print(COLORS.success, message, COLORS.end) 65 | 66 | 67 | def response_print(message): 68 | """Print a message in blue text. 69 | 70 | Parameters 71 | message (str) 72 | Message to print. 73 | """ 74 | print(COLORS.response, message, COLORS.end) 75 | 76 | 77 | def fail_print(error): 78 | """Print an error in red text. 79 | 80 | Parameters 81 | error (HTTPError) 82 | Error object to print. 83 | """ 84 | print(COLORS.fail, error.message, COLORS.end) 85 | 86 | 87 | def paragraph_print(message): 88 | """Print message with padded newlines. 89 | 90 | Parameters 91 | message (str) 92 | Message to print. 93 | """ 94 | paragraph = '\n{}\n' 95 | print(paragraph.format(message)) 96 | 97 | 98 | def import_app_credentials(filename=CREDENTIALS_FILENAME): 99 | """Import app credentials from configuration file. 100 | 101 | Parameters 102 | filename (str) 103 | Name of configuration file. 104 | 105 | Returns 106 | credentials (dict) 107 | All your app credentials and information 108 | imported from the configuration file. 109 | """ 110 | with open(filename, 'r') as config_file: 111 | config = safe_load(config_file) 112 | 113 | client_id = config['client_id'] 114 | client_secret = config['client_secret'] 115 | redirect_url = config['redirect_url'] 116 | 117 | config_values = [client_id, client_secret, redirect_url] 118 | 119 | for value in config_values: 120 | if value in DEFAULT_CONFIG_VALUES: 121 | exit('Missing credentials in {}'.format(filename)) 122 | 123 | credentials = { 124 | 'client_id': client_id, 125 | 'client_secret': client_secret, 126 | 'redirect_url': redirect_url, 127 | 'scopes': set(config['scopes']), 128 | } 129 | 130 | return credentials 131 | 132 | 133 | def import_oauth2_credentials(filename=STORAGE_FILENAME): 134 | """Import OAuth 2.0 session credentials from storage file. 135 | 136 | Parameters 137 | filename (str) 138 | Name of storage file. 139 | 140 | Returns 141 | credentials (dict) 142 | All your app credentials and information 143 | imported from the configuration file. 144 | """ 145 | with open(filename, 'r') as storage_file: 146 | storage = safe_load(storage_file) 147 | 148 | # depending on OAuth 2.0 grant_type, these values may not exist 149 | client_secret = storage.get('client_secret') 150 | redirect_url = storage.get('redirect_url') 151 | refresh_token = storage.get('refresh_token') 152 | 153 | credentials = { 154 | 'access_token': storage['access_token'], 155 | 'client_id': storage['client_id'], 156 | 'client_secret': client_secret, 157 | 'expires_in_seconds': storage['expires_in_seconds'], 158 | 'grant_type': storage['grant_type'], 159 | 'redirect_url': redirect_url, 160 | 'refresh_token': refresh_token, 161 | 'scopes': storage['scopes'], 162 | } 163 | 164 | return credentials 165 | 166 | 167 | def create_uber_client(credentials): 168 | """Create an UberRidesClient from OAuth 2.0 credentials. 169 | 170 | Parameters 171 | credentials (dict) 172 | Dictionary of OAuth 2.0 credentials. 173 | 174 | Returns 175 | (UberRidesClient) 176 | An authorized UberRidesClient to access API resources. 177 | """ 178 | oauth2credential = OAuth2Credential( 179 | client_id=credentials.get('client_id'), 180 | access_token=credentials.get('access_token'), 181 | expires_in_seconds=credentials.get('expires_in_seconds'), 182 | scopes=credentials.get('scopes'), 183 | grant_type=credentials.get('grant_type'), 184 | redirect_url=credentials.get('redirect_url'), 185 | client_secret=credentials.get('client_secret'), 186 | refresh_token=credentials.get('refresh_token'), 187 | ) 188 | session = Session(oauth2credential=oauth2credential) 189 | return UberRidesClient(session, sandbox_mode=True) 190 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | appdirs==1.4.3 2 | certifi==2017.7.27.1 3 | chardet==3.0.4 4 | contextlib2==0.5.5 5 | funcsigs==1.0.2 6 | future==0.16.0 7 | futures==3.1.1 8 | idna==2.6 9 | mock==2.0.0 10 | packaging==16.8 11 | pbr==3.1.1 12 | py==1.4.34 13 | pyparsing==2.2.0 14 | pytest==3.2.1 15 | PyYAML==3.12 16 | requests==2.18.4 17 | six==1.10.0 18 | urllib3==1.22 19 | vcrpy==1.11.1 20 | wrapt==1.10.11 21 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | [bdist_wheel] 3 | universal = 1 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import absolute_import 3 | from __future__ import division 4 | from __future__ import print_function 5 | from __future__ import unicode_literals 6 | 7 | from setuptools import find_packages 8 | from setuptools import setup 9 | 10 | with open('README.rst') as f: 11 | readme = f.read() 12 | 13 | setup( 14 | name='uber_rides', 15 | version='0.6.0', 16 | packages=find_packages(), 17 | description='Official Uber API Python SDK', 18 | long_description=readme, 19 | url='https://github.com/uber/rides-python-sdk', 20 | license='MIT', 21 | author='Uber Technologies, Inc.', 22 | author_email='dev-advocates@uber.com', 23 | install_requires=['requests', 'pyyaml'], 24 | extras_require={ 25 | ':python_version == "2.7"': ['future'], 26 | }, 27 | tests_require=['pytest', 'mock', 'vcrpy'], 28 | keywords=['uber', 'api', 'sdk', 'rides', 'library'], 29 | ) 30 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/rides-python-sdk/76ecd75ab5235d792ec1010e36eca679ba285127/tests/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/test_auth_code_get_session: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode code=xxx&redirect_uri=https%3A%2F%2Flocalhost%3A8000%2Fapi%2Fv1%2Fuber%2Foauth&client_id=xxx&client_secret=xxx&grant_type=authorization_code 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | Content-Length: ['233'] 9 | Content-Type: [application/x-www-form-urlencoded] 10 | User-Agent: [python-requests/2.11.1] 11 | method: POST 12 | uri: https://login.uber.com/oauth/v2/token 13 | response: 14 | body: {string: !!python/unicode '{"last_authenticated":1485210848,"access_token":"xxx","expires_in":2592000,"token_type":"Bearer","scope":"profile 15 | history","refresh_token":"xxx"}'} 16 | headers: 17 | cache-control: [no-store, max-age=0] 18 | connection: [keep-alive] 19 | content-length: ['1017'] 20 | content-type: [application/json] 21 | date: ['Tue, 24 Jan 2017 00:04:56 GMT'] 22 | pragma: [no-cache] 23 | server: [nginx] 24 | set-cookie: [session=29afa247b81ce9ec_58869a28.WaWYr6GVd75geCKas-8FeDq2GxQ; 25 | Domain=login.uber.com; Secure; HttpOnly; Path=/] 26 | strict-transport-security: [max-age=604800, max-age=2592000] 27 | transfer-encoding: [chunked] 28 | x-content-type-options: [nosniff] 29 | x-frame-options: [SAMEORIGIN] 30 | x-uber-app: [login] 31 | x-xss-protection: [1; mode=block] 32 | status: {code: 200, message: OK} 33 | version: 1 34 | -------------------------------------------------------------------------------- /tests/fixtures/test_cancel_current_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Content-Length: ['0'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | method: DELETE 8 | uri: https://sandbox-api.uber.com/v1.2/requests/current 9 | response: 10 | body: {string: !!python/unicode ''} 11 | headers: 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-type: [text/html; charset=UTF-8] 15 | date: ['Thu, 20 Oct 2016 08:36:29 GMT'] 16 | server: [nginx] 17 | strict-transport-security: [max-age=0] 18 | x-content-type-options: [nosniff] 19 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 20 | x-xss-protection: [1; mode=block] 21 | status: {code: 204, message: No Content} 22 | - request: 23 | body: null 24 | headers: 25 | Content-Length: ['0'] 26 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 27 | method: DELETE 28 | uri: https://sandbox-api.uber.com/v1.2/requests/current 29 | response: 30 | body: {string: !!python/unicode ''} 31 | headers: 32 | connection: [keep-alive] 33 | content-language: [en] 34 | content-type: [text/html; charset=UTF-8] 35 | date: ['Thu, 20 Oct 2016 08:41:46 GMT'] 36 | server: [nginx] 37 | strict-transport-security: [max-age=0] 38 | x-content-type-options: [nosniff] 39 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 40 | x-xss-protection: [1; mode=block] 41 | status: {code: 204, message: No Content} 42 | - request: 43 | body: null 44 | headers: 45 | Content-Length: ['0'] 46 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 47 | method: DELETE 48 | uri: https://sandbox-api.uber.com/v1.2/requests/current 49 | response: 50 | body: {string: !!python/unicode ''} 51 | headers: 52 | connection: [keep-alive] 53 | content-language: [en] 54 | content-type: [text/html; charset=UTF-8] 55 | date: ['Thu, 20 Oct 2016 08:48:14 GMT'] 56 | server: [nginx] 57 | strict-transport-security: [max-age=0] 58 | x-content-type-options: [nosniff] 59 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 60 | x-xss-protection: [1; mode=block] 61 | status: {code: 204, message: No Content} 62 | - request: 63 | body: null 64 | headers: 65 | Content-Length: ['0'] 66 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 67 | method: DELETE 68 | uri: https://sandbox-api.uber.com/v1.2/requests/current 69 | response: 70 | body: {string: !!python/unicode ''} 71 | headers: 72 | connection: [keep-alive] 73 | content-language: [en] 74 | content-type: [text/html; charset=UTF-8] 75 | date: ['Thu, 20 Oct 2016 08:49:40 GMT'] 76 | server: [nginx] 77 | strict-transport-security: [max-age=0] 78 | x-content-type-options: [nosniff] 79 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 80 | x-xss-protection: [1; mode=block] 81 | status: {code: 204, message: No Content} 82 | version: 1 83 | -------------------------------------------------------------------------------- /tests/fixtures/test_cancel_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Content-Length: ['0'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | method: DELETE 8 | uri: https://sandbox-api.uber.com/v1.2/requests/9bdb3278-21bd-46b8-90fa-51404b0d6acf 9 | response: 10 | body: {string: !!python/unicode ''} 11 | headers: 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-type: [text/html; charset=UTF-8] 15 | date: ['Thu, 20 Oct 2016 08:36:29 GMT'] 16 | server: [nginx] 17 | strict-transport-security: [max-age=0] 18 | x-content-type-options: [nosniff] 19 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 20 | x-xss-protection: [1; mode=block] 21 | status: {code: 204, message: No Content} 22 | - request: 23 | body: null 24 | headers: 25 | Content-Length: ['0'] 26 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 27 | method: DELETE 28 | uri: https://sandbox-api.uber.com/v1.2/requests/610d868b-e21c-483a-9932-97e61b852fd2 29 | response: 30 | body: {string: !!python/unicode ''} 31 | headers: 32 | connection: [keep-alive] 33 | content-language: [en] 34 | content-type: [text/html; charset=UTF-8] 35 | date: ['Thu, 20 Oct 2016 08:41:45 GMT'] 36 | server: [nginx] 37 | strict-transport-security: [max-age=0] 38 | x-content-type-options: [nosniff] 39 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 40 | x-xss-protection: [1; mode=block] 41 | status: {code: 204, message: No Content} 42 | - request: 43 | body: null 44 | headers: 45 | Content-Length: ['0'] 46 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 47 | method: DELETE 48 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 49 | response: 50 | body: {string: !!python/unicode ''} 51 | headers: 52 | connection: [keep-alive] 53 | content-language: [en] 54 | content-type: [text/html; charset=UTF-8] 55 | date: ['Thu, 20 Oct 2016 08:48:14 GMT'] 56 | server: [nginx] 57 | strict-transport-security: [max-age=0] 58 | x-content-type-options: [nosniff] 59 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 60 | x-xss-protection: [1; mode=block] 61 | status: {code: 204, message: No Content} 62 | - request: 63 | body: null 64 | headers: 65 | Content-Length: ['0'] 66 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 67 | method: DELETE 68 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 69 | response: 70 | body: {string: !!python/unicode ''} 71 | headers: 72 | connection: [keep-alive] 73 | content-language: [en] 74 | content-type: [text/html; charset=UTF-8] 75 | date: ['Thu, 20 Oct 2016 08:49:39 GMT'] 76 | server: [nginx] 77 | strict-transport-security: [max-age=0] 78 | x-content-type-options: [nosniff] 79 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 80 | x-xss-protection: [1; mode=block] 81 | status: {code: 204, message: No Content} 82 | version: 1 83 | -------------------------------------------------------------------------------- /tests/fixtures/test_client_credential_get_session: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode client_id=xxx&scope=partner.referrals&client_secret=xxx&grant_type=client_credentials 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | Content-Length: ['151'] 9 | Content-Type: [application/x-www-form-urlencoded] 10 | User-Agent: [python-requests/2.11.1] 11 | method: POST 12 | uri: https://login.uber.com/oauth/v2/token 13 | response: 14 | body: {string: !!python/unicode '{"access_token":"xxx","token_type":"Bearer","last_authenticated":1485210848,"expires_in":2592000,"scope":"partner.referrals"}'} 15 | headers: 16 | cache-control: [no-store, max-age=0] 17 | connection: [keep-alive] 18 | content-length: ['864'] 19 | content-type: [application/json] 20 | date: ['Tue, 24 Jan 2017 00:01:05 GMT'] 21 | pragma: [no-cache] 22 | server: [nginx] 23 | set-cookie: [session=1b25e9fc5e9c4380_58869941.6C4QqAV6IdsPJqgrdPkjV46qJQo; 24 | Domain=login.uber.com; Secure; HttpOnly; Path=/] 25 | strict-transport-security: [max-age=604800, max-age=2592000] 26 | transfer-encoding: [chunked] 27 | x-content-type-options: [nosniff] 28 | x-frame-options: [SAMEORIGIN] 29 | x-uber-app: [login] 30 | x-xss-protection: [1; mode=block] 31 | status: {code: 200, message: OK} 32 | version: 1 33 | -------------------------------------------------------------------------------- /tests/fixtures/test_estimate_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"seat_count": null, "start_longitude": -122.4021253, 4 | "end_longitude": -122.4197513, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", 5 | "end_latitude": 37.775232, "end_place_id": null, "start_latitude": 37.7899886, 6 | "start_place_id": null}' 7 | headers: 8 | Content-Length: ['241'] 9 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 10 | content-type: [application/json] 11 | method: POST 12 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 13 | response: 14 | body: {string: !!python/unicode '{"fare":{"value":11.41,"fare_id":"254f6a83aaa08f12f505f5f75a4ade69f1fe62cd5092dfbc48f5388134681249","expires_at":1476952703,"display":"$11.41","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":540,"distance_estimate":1.96},"pickup_estimate":4}'} 15 | headers: 16 | connection: [keep-alive] 17 | content-geo-system: [wgs-84] 18 | content-language: [en] 19 | content-length: ['267'] 20 | content-type: [application/json] 21 | date: ['Thu, 20 Oct 2016 08:36:23 GMT'] 22 | server: [nginx] 23 | strict-transport-security: [max-age=0] 24 | x-content-type-options: [nosniff] 25 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 26 | x-xss-protection: [1; mode=block] 27 | status: {code: 200, message: OK} 28 | - request: 29 | body: !!python/unicode '{"seat_count": null, "start_longitude": -122.4021253, 30 | "end_longitude": -122.4197513, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", 31 | "end_latitude": 37.775232, "end_place_id": null, "start_latitude": 37.7899886, 32 | "start_place_id": null}' 33 | headers: 34 | Content-Length: ['241'] 35 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 36 | content-type: [application/json] 37 | method: POST 38 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 39 | response: 40 | body: {string: !!python/unicode '{"fare":{"value":10.8,"fare_id":"a93ccb928ed2d6896810030ba4dda0acb5a41c1782959e7bec1e03a8d5597136","expires_at":1476953019,"display":"$10.80","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":480,"distance_estimate":1.78},"pickup_estimate":4}'} 41 | headers: 42 | connection: [keep-alive] 43 | content-geo-system: [wgs-84] 44 | content-language: [en] 45 | content-length: ['266'] 46 | content-type: [application/json] 47 | date: ['Thu, 20 Oct 2016 08:41:39 GMT'] 48 | server: [nginx] 49 | strict-transport-security: [max-age=0] 50 | x-content-type-options: [nosniff] 51 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 52 | x-xss-protection: [1; mode=block] 53 | status: {code: 200, message: OK} 54 | - request: 55 | body: !!python/unicode '{"seat_count": null, "start_longitude": -122.4021253, 56 | "end_longitude": -122.4197513, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", 57 | "end_latitude": 37.775232, "end_place_id": null, "start_latitude": 37.7899886, 58 | "start_place_id": null}' 59 | headers: 60 | Content-Length: ['241'] 61 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 62 | content-type: [application/json] 63 | method: POST 64 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 65 | response: 66 | body: {string: !!python/unicode '{"fare":{"value":10.79,"fare_id":"a20f0156059f3bff78b048eb00093869184c4808220e3b42cb93a3470de0b2bd","expires_at":1476953407,"display":"$10.79","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":480,"distance_estimate":1.78},"pickup_estimate":4}'} 67 | headers: 68 | connection: [keep-alive] 69 | content-geo-system: [wgs-84] 70 | content-language: [en] 71 | content-length: ['267'] 72 | content-type: [application/json] 73 | date: ['Thu, 20 Oct 2016 08:48:07 GMT'] 74 | server: [nginx] 75 | strict-transport-security: [max-age=0] 76 | x-content-type-options: [nosniff] 77 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 78 | x-xss-protection: [1; mode=block] 79 | status: {code: 200, message: OK} 80 | - request: 81 | body: !!python/unicode '{"seat_count": null, "start_longitude": -122.4021253, 82 | "end_longitude": -122.4197513, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", 83 | "end_latitude": 37.775232, "end_place_id": null, "start_latitude": 37.7899886, 84 | "start_place_id": null}' 85 | headers: 86 | Content-Length: ['241'] 87 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 88 | content-type: [application/json] 89 | method: POST 90 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 91 | response: 92 | body: {string: !!python/unicode '{"fare":{"value":11.37,"fare_id":"cfc5e7aea155ab91e8b797ac595abe21f0e0bdb6fe48c8569f39e218a6a9326c","expires_at":1476953493,"display":"$11.37","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":540,"distance_estimate":1.96},"pickup_estimate":4}'} 93 | headers: 94 | connection: [keep-alive] 95 | content-geo-system: [wgs-84] 96 | content-language: [en] 97 | content-length: ['267'] 98 | content-type: [application/json] 99 | date: ['Thu, 20 Oct 2016 08:49:33 GMT'] 100 | server: [nginx] 101 | strict-transport-security: [max-age=0] 102 | x-content-type-options: [nosniff] 103 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 104 | x-xss-protection: [1; mode=block] 105 | status: {code: 200, message: OK} 106 | version: 1 107 | -------------------------------------------------------------------------------- /tests/fixtures/test_estimate_ride_with_places: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"seat_count": null, "start_longitude": null, "end_longitude": 4 | null, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "end_latitude": 5 | null, "end_place_id": "work", "start_latitude": null, "start_place_id": "home"}' 6 | headers: 7 | Content-Length: ['218'] 8 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 9 | content-type: [application/json] 10 | method: POST 11 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 12 | response: 13 | body: {string: !!python/unicode '{"fare":{"value":10.53,"fare_id":"0c00804e559af560519c820d1f16d5e87a71e9bcdc043ad005c3c77392e3e6da","expires_at":1476952704,"display":"$10.53","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":420,"distance_estimate":1.78},"pickup_estimate":3}'} 14 | headers: 15 | connection: [keep-alive] 16 | content-geo-system: [wgs-84] 17 | content-language: [en] 18 | content-length: ['267'] 19 | content-type: [application/json] 20 | date: ['Thu, 20 Oct 2016 08:36:24 GMT'] 21 | server: [nginx] 22 | strict-transport-security: [max-age=0] 23 | x-content-type-options: [nosniff] 24 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 25 | x-xss-protection: [1; mode=block] 26 | status: {code: 200, message: OK} 27 | - request: 28 | body: !!python/unicode '{"seat_count": null, "start_longitude": null, "end_longitude": 29 | null, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "end_latitude": 30 | null, "end_place_id": "work", "start_latitude": null, "start_place_id": "home"}' 31 | headers: 32 | Content-Length: ['218'] 33 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 34 | content-type: [application/json] 35 | method: POST 36 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 37 | response: 38 | body: {string: !!python/unicode '{"fare":{"value":10.49,"fare_id":"3b6a75714b629721743f87f288055bfa1da9dc3a460271a4d78cd727ccdaec0f","expires_at":1476953020,"display":"$10.49","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":420,"distance_estimate":1.78},"pickup_estimate":3}'} 39 | headers: 40 | connection: [keep-alive] 41 | content-geo-system: [wgs-84] 42 | content-language: [en] 43 | content-length: ['267'] 44 | content-type: [application/json] 45 | date: ['Thu, 20 Oct 2016 08:41:40 GMT'] 46 | server: [nginx] 47 | strict-transport-security: [max-age=0] 48 | x-content-type-options: [nosniff] 49 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 50 | x-xss-protection: [1; mode=block] 51 | status: {code: 200, message: OK} 52 | - request: 53 | body: !!python/unicode '{"seat_count": null, "start_longitude": null, "end_longitude": 54 | null, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "end_latitude": 55 | null, "end_place_id": "work", "start_latitude": null, "start_place_id": "home"}' 56 | headers: 57 | Content-Length: ['218'] 58 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 59 | content-type: [application/json] 60 | method: POST 61 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 62 | response: 63 | body: {string: !!python/unicode '{"fare":{"value":10.59,"fare_id":"f96b1c371386a8226d45547d25c3bf7d6982c9ba71b0903841ea88041e329627","expires_at":1476953409,"display":"$10.59","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":420,"distance_estimate":1.78},"pickup_estimate":3}'} 64 | headers: 65 | connection: [keep-alive] 66 | content-geo-system: [wgs-84] 67 | content-language: [en] 68 | content-length: ['267'] 69 | content-type: [application/json] 70 | date: ['Thu, 20 Oct 2016 08:48:09 GMT'] 71 | server: [nginx] 72 | strict-transport-security: [max-age=0] 73 | x-content-type-options: [nosniff] 74 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 75 | x-xss-protection: [1; mode=block] 76 | status: {code: 200, message: OK} 77 | - request: 78 | body: !!python/unicode '{"seat_count": null, "start_longitude": null, "end_longitude": 79 | null, "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "end_latitude": 80 | null, "end_place_id": "work", "start_latitude": null, "start_place_id": "home"}' 81 | headers: 82 | Content-Length: ['218'] 83 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 84 | content-type: [application/json] 85 | method: POST 86 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 87 | response: 88 | body: {string: !!python/unicode '{"fare":{"value":10.6,"fare_id":"0d789a6c6ef2c12ceb1bbbca8ec3ea88cb4e55cfdfb8a347ae7a20a003544966","expires_at":1476953494,"display":"$10.60","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":420,"distance_estimate":1.78},"pickup_estimate":3}'} 89 | headers: 90 | connection: [keep-alive] 91 | content-geo-system: [wgs-84] 92 | content-language: [en] 93 | content-length: ['266'] 94 | content-type: [application/json] 95 | date: ['Thu, 20 Oct 2016 08:49:34 GMT'] 96 | server: [nginx] 97 | strict-transport-security: [max-age=0] 98 | x-content-type-options: [nosniff] 99 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 100 | x-xss-protection: [1; mode=block] 101 | status: {code: 200, message: OK} 102 | version: 1 103 | -------------------------------------------------------------------------------- /tests/fixtures/test_estimate_shared_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"seat_count": 2, "start_longitude": -122.4021253, "end_longitude": 4 | -122.4197513, "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "end_latitude": 5 | 37.775232, "end_place_id": null, "start_latitude": 37.7899886, "start_place_id": 6 | null}' 7 | headers: 8 | Content-Length: ['238'] 9 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 10 | content-type: [application/json] 11 | method: POST 12 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 13 | response: 14 | body: {string: !!python/unicode '{"fare":{"value":7.3,"fare_id":"edff5663d5f237d2998568c68018055cee3cea732eee6dfcc13004f78e04ba29","expires_at":1476952702,"display":"$7.30","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":540,"distance_estimate":1.96},"pickup_estimate":3}'} 15 | headers: 16 | connection: [keep-alive] 17 | content-geo-system: [wgs-84] 18 | content-language: [en] 19 | content-length: ['264'] 20 | content-type: [application/json] 21 | date: ['Thu, 20 Oct 2016 08:36:22 GMT'] 22 | server: [nginx] 23 | strict-transport-security: [max-age=0] 24 | x-content-type-options: [nosniff] 25 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 26 | x-xss-protection: [1; mode=block] 27 | status: {code: 200, message: OK} 28 | - request: 29 | body: !!python/unicode '{"seat_count": 2, "start_longitude": -122.4021253, "end_longitude": 30 | -122.4197513, "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "end_latitude": 31 | 37.775232, "end_place_id": null, "start_latitude": 37.7899886, "start_place_id": 32 | null}' 33 | headers: 34 | Content-Length: ['238'] 35 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 36 | content-type: [application/json] 37 | method: POST 38 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 39 | response: 40 | body: {string: !!python/unicode '{"fare":{"value":6.99,"fare_id":"ca2326c28949fec46f7002f2a502de7ad8c70fb838c9ee0e0ebc12b242c652a9","expires_at":1476953018,"display":"$6.99","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":480,"distance_estimate":1.78},"pickup_estimate":3}'} 41 | headers: 42 | connection: [keep-alive] 43 | content-geo-system: [wgs-84] 44 | content-language: [en] 45 | content-length: ['265'] 46 | content-type: [application/json] 47 | date: ['Thu, 20 Oct 2016 08:41:38 GMT'] 48 | server: [nginx] 49 | strict-transport-security: [max-age=0] 50 | x-content-type-options: [nosniff] 51 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 52 | x-xss-protection: [1; mode=block] 53 | status: {code: 200, message: OK} 54 | - request: 55 | body: !!python/unicode '{"seat_count": 2, "start_longitude": -122.4021253, "end_longitude": 56 | -122.4197513, "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "end_latitude": 57 | 37.775232, "end_place_id": null, "start_latitude": 37.7899886, "start_place_id": 58 | null}' 59 | headers: 60 | Content-Length: ['238'] 61 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 62 | content-type: [application/json] 63 | method: POST 64 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 65 | response: 66 | body: {string: !!python/unicode '{"fare":{"value":6.9,"fare_id":"eb2c7950c4165007a2be115c898fe81bef06a68f8049069c5d4476c00def1212","expires_at":1476953407,"display":"$6.90","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":480,"distance_estimate":1.78},"pickup_estimate":4}'} 67 | headers: 68 | connection: [keep-alive] 69 | content-geo-system: [wgs-84] 70 | content-language: [en] 71 | content-length: ['264'] 72 | content-type: [application/json] 73 | date: ['Thu, 20 Oct 2016 08:48:07 GMT'] 74 | server: [nginx] 75 | strict-transport-security: [max-age=0] 76 | x-content-type-options: [nosniff] 77 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 78 | x-xss-protection: [1; mode=block] 79 | status: {code: 200, message: OK} 80 | - request: 81 | body: !!python/unicode '{"seat_count": 2, "start_longitude": -122.4021253, "end_longitude": 82 | -122.4197513, "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "end_latitude": 83 | 37.775232, "end_place_id": null, "start_latitude": 37.7899886, "start_place_id": 84 | null}' 85 | headers: 86 | Content-Length: ['238'] 87 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 88 | content-type: [application/json] 89 | method: POST 90 | uri: https://sandbox-api.uber.com/v1.2/requests/estimate 91 | response: 92 | body: {string: !!python/unicode '{"fare":{"value":7.22,"fare_id":"c2bf8adcb8004a67022642d0f8dfceebd888f1929156a7ca4c00eaf63e0310a7","expires_at":1476953492,"display":"$7.22","currency_code":"USD"},"trip":{"distance_unit":"mile","duration_estimate":540,"distance_estimate":1.96},"pickup_estimate":5}'} 93 | headers: 94 | connection: [keep-alive] 95 | content-geo-system: [wgs-84] 96 | content-language: [en] 97 | content-length: ['265'] 98 | content-type: [application/json] 99 | date: ['Thu, 20 Oct 2016 08:49:32 GMT'] 100 | server: [nginx] 101 | strict-transport-security: [max-age=0] 102 | x-content-type-options: [nosniff] 103 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 104 | x-xss-protection: [1; mode=block] 105 | status: {code: 200, message: OK} 106 | version: 1 107 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_business_receipt: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode 'Python Rides SDK v0.6.0'] 6 | method: GET 7 | uri: https://api.uber.com/v1/business/trips/5152dcc5-b88d-4754-8b33-975f4067c942/receipt 8 | response: 9 | body: {string: !!python/unicode '{"family_name":"Developer","employee_id":"UUID-01-UD","trip_uuid":"5152dcc5-b88d-4754-8b33-975f4067c942","transaction_history":[{"amount":6.61,"short_reference":"GYYTK","currency_code":"USD","utc_timestamp":"2017-05-07T01:32:39.740Z","transaction_type":"SALE"}],"vat_amount":null,"distance":1.65,"expense_memo":"Jam 10 | on life","distance_unit":"miles","dropoff":{"location":{"city":"San Francisco","country":"US","longitude":-122.4203,"state":"CA","address":"1255 11 | Polk St, San Francisco, CA 94109, USA","latitude":37.7886},"time":{"unix_timestamp":1494120748,"utc_offset":"-07:00","utc_timestamp":"2017-05-07T01:32:28.000Z"}},"total_owed":0.0,"email":"uber.developer@example.com","organization_uuid":"c615e84c-72ea-490e-a060-823f14532632","pickup":{"location":{"city":"San 12 | Francisco","country":"US","longitude":-122.3994,"state":"CA","address":"141 13 | New Montgomery St, San Francisco, CA 94105, USA","latitude":37.7865},"time":{"unix_timestamp":1494120043,"utc_offset":"-07:00","utc_timestamp":"2017-05-07T01:20:43.000Z"}},"expense_code":"JAM","given_name":"Uber","total_charged":6.61,"duration":"00:11:46","product_name":"uberX","currency_code":"USD"}'} 14 | headers: 15 | cache-control: [max-age=0] 16 | connection: [keep-alive] 17 | content-language: [en] 18 | content-length: ['1145'] 19 | content-type: [application/json] 20 | date: ['Thu, 14 Sep 2017 23:07:04 GMT'] 21 | etag: [W/"18e7d9bd82ca47a8ab264d1b0b2433eaef3b3c92"] 22 | server: [nginx] 23 | strict-transport-security: [max-age=604800, max-age=2592000] 24 | x-content-type-options: [nosniff] 25 | x-frame-options: [SAMEORIGIN] 26 | x-rate-limit-limit: ['2000'] 27 | x-rate-limit-remaining: ['1999'] 28 | x-rate-limit-reset: ['1505433600'] 29 | x-uber-app: [uberex-nonsandbox, optimus] 30 | x-xss-protection: [1; mode=block] 31 | status: {code: 200, message: OK} 32 | version: 1 33 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_business_trip_invoice_urls: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode 'Python Rides SDK v0.6.0'] 6 | method: GET 7 | uri: https://api.uber.com/v1/business/trips/5152dcc5-b88d-4754-8b33-975f4067c942/invoice_urls 8 | response: 9 | body: {string: !!python/unicode '{"invoices":[],"organization_uuid":"c615e84c-72ea-490e-a060-823f14532632","trip_uuid":"5152dcc5-b88d-4754-8b33-975f4067c942"}'} 10 | headers: 11 | cache-control: [max-age=0] 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-length: ['125'] 15 | content-type: [application/json] 16 | date: ['Thu, 14 Sep 2017 23:11:14 GMT'] 17 | etag: [W/"5fee7563ff5c9f335807fc73a9b4dcb7ef9d5964"] 18 | server: [nginx] 19 | strict-transport-security: [max-age=604800, max-age=2592000] 20 | x-content-type-options: [nosniff] 21 | x-frame-options: [SAMEORIGIN] 22 | x-rate-limit-limit: ['2000'] 23 | x-rate-limit-remaining: ['1997'] 24 | x-rate-limit-reset: ['1505433600'] 25 | x-uber-app: [uberex-nonsandbox, optimus] 26 | x-xss-protection: [1; mode=block] 27 | status: {code: 200, message: OK} 28 | version: 1 29 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_business_trip_receipt_pdf_url: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode 'Python Rides SDK v0.6.0'] 6 | method: GET 7 | uri: https://api.uber.com/v1/business/trips/5152dcc5-b88d-4754-8b33-975f4067c942/receipt/pdf_url 8 | response: 9 | body: {string: !!python/unicode '{"trip_uuid":"5152dcc5-b88d-4754-8b33-975f4067c942","organization_uuid":"c615e84c-72ea-490e-a060-823f14532632","resource_url": "https://uber-common-public.s3.amazonaws.com/hamlet/b0ecf463.pdf"}'} 10 | headers: 11 | cache-control: [max-age=0] 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-type: [application/json] 15 | date: ['Thu, 14 Sep 2017 23:11:14 GMT'] 16 | etag: [W/"5fee7563ff5c9f335807fc73a9b4dcb7ef9d5964"] 17 | server: [nginx] 18 | strict-transport-security: [max-age=604800, max-age=2592000] 19 | x-content-type-options: [nosniff] 20 | x-frame-options: [SAMEORIGIN] 21 | x-rate-limit-limit: ['2000'] 22 | x-rate-limit-remaining: ['1994'] 23 | x-rate-limit-reset: ['1505433400'] 24 | x-uber-app: [uberex-nonsandbox, optimus] 25 | x-xss-protection: [1; mode=block] 26 | status: {code: 200, message: OK} 27 | version: 1 28 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_current_ride_details: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/requests/current 8 | response: 9 | body: {string: !!python/unicode '{"status":"processing","product_id":"821415d8-3bd5-4e27-9604-194e4359a449","destination":{"latitude":37.775232,"longitude":-122.4197513},"driver":null,"pickup":{"latitude":37.7899886,"eta":1,"longitude":-122.4021253},"request_id":"610d868b-e21c-483a-9932-97e61b852fd2","location":null,"vehicle":null,"shared":false}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-geo-system: [wgs-84] 13 | content-language: [en] 14 | content-length: ['315'] 15 | content-type: [application/json] 16 | date: ['Thu, 20 Oct 2016 08:36:27 GMT'] 17 | etag: ['"ba4cb7f0193b2e0f8098077c09e82a4aef5cf8a5"'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 200, message: OK} 24 | - request: 25 | body: null 26 | headers: 27 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 28 | method: GET 29 | uri: https://sandbox-api.uber.com/v1.2/requests/current 30 | response: 31 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"no_current_trip","title":"User 32 | is not currently on a trip."}]}'} 33 | headers: 34 | connection: [keep-alive] 35 | content-length: ['105'] 36 | content-type: [application/json] 37 | date: ['Thu, 20 Oct 2016 08:41:43 GMT'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 404, message: Not Found} 44 | - request: 45 | body: null 46 | headers: 47 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 48 | method: GET 49 | uri: https://sandbox-api.uber.com/v1.2/requests/current 50 | response: 51 | body: {string: !!python/unicode '{"status":"processing","product_id":"26546650-e557-4a7b-86e7-6a3942445247","destination":{"latitude":37.7899886,"longitude":-122.4021253},"driver":null,"pickup":{"latitude":37.775232,"eta":3,"longitude":-122.4197513},"request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8","location":null,"vehicle":null,"shared":false}'} 52 | headers: 53 | connection: [keep-alive] 54 | content-geo-system: [wgs-84] 55 | content-language: [en] 56 | content-length: ['315'] 57 | content-type: [application/json] 58 | date: ['Thu, 20 Oct 2016 08:48:12 GMT'] 59 | etag: ['"c40a91960498f2fc6ba4e86530d640079cc012b0"'] 60 | server: [nginx] 61 | strict-transport-security: [max-age=0] 62 | x-content-type-options: [nosniff] 63 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 64 | x-xss-protection: [1; mode=block] 65 | status: {code: 200, message: OK} 66 | - request: 67 | body: null 68 | headers: 69 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 70 | method: GET 71 | uri: https://sandbox-api.uber.com/v1.2/requests/current 72 | response: 73 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"no_current_trip","title":"User 74 | is not currently on a trip."}]}'} 75 | headers: 76 | connection: [keep-alive] 77 | content-length: ['105'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:49:37 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 404, message: Not Found} 86 | version: 1 87 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_current_shared_ride_details: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/requests/current 8 | response: 9 | body: {string: !!python/unicode '{"status":"processing","product_id":"821415d8-3bd5-4e27-9604-194e4359a449","destination":{"latitude":37.775232,"longitude":-122.4197513},"driver":null,"pickup":{"latitude":37.7899886,"eta":1,"longitude":-122.4021253},"request_id":"610d868b-e21c-483a-9932-97e61b852fd2","location":null,"vehicle":null,"shared":false}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-geo-system: [wgs-84] 13 | content-language: [en] 14 | content-length: ['315'] 15 | content-type: [application/json] 16 | date: ['Thu, 20 Oct 2016 08:36:28 GMT'] 17 | etag: ['"ba4cb7f0193b2e0f8098077c09e82a4aef5cf8a5"'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 200, message: OK} 24 | - request: 25 | body: null 26 | headers: 27 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 28 | method: GET 29 | uri: https://sandbox-api.uber.com/v1.2/requests/current 30 | response: 31 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"no_current_trip","title":"User 32 | is not currently on a trip."}]}'} 33 | headers: 34 | connection: [keep-alive] 35 | content-length: ['105'] 36 | content-type: [application/json] 37 | date: ['Thu, 20 Oct 2016 08:41:43 GMT'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 404, message: Not Found} 44 | - request: 45 | body: null 46 | headers: 47 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 48 | method: GET 49 | uri: https://sandbox-api.uber.com/v1.2/requests/current 50 | response: 51 | body: {string: !!python/unicode '{"status":"processing","product_id":"26546650-e557-4a7b-86e7-6a3942445247","destination":{"latitude":37.7899886,"longitude":-122.4021253},"driver":null,"pickup":{"latitude":37.775232,"eta":3,"longitude":-122.4197513},"request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8","location":null,"vehicle":null,"shared":false}'} 52 | headers: 53 | connection: [keep-alive] 54 | content-geo-system: [wgs-84] 55 | content-language: [en] 56 | content-length: ['315'] 57 | content-type: [application/json] 58 | date: ['Thu, 20 Oct 2016 08:48:12 GMT'] 59 | etag: ['"c40a91960498f2fc6ba4e86530d640079cc012b0"'] 60 | server: [nginx] 61 | strict-transport-security: [max-age=0] 62 | x-content-type-options: [nosniff] 63 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 64 | x-xss-protection: [1; mode=block] 65 | status: {code: 200, message: OK} 66 | - request: 67 | body: null 68 | headers: 69 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 70 | method: GET 71 | uri: https://sandbox-api.uber.com/v1.2/requests/current 72 | response: 73 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"no_current_trip","title":"User 74 | is not currently on a trip."}]}'} 75 | headers: 76 | connection: [keep-alive] 77 | content-length: ['105'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:49:37 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 404, message: Not Found} 86 | version: 1 87 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_driver_payments: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://api.uber.com/v1/partners/payments 8 | response: 9 | body: {string: !!python/unicode '{"count":13,"limit":10,"payments":[{"payment_id":"5cb8304c-f3f0-4a46-b6e3-b55e020750d7","category":"fare","event_time":1502842757,"trip_id":"5cb8304c-f3f0-4a46-b6e3-b55e020750d7","cash_collected":0.0,"amount":3.12,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.16,"service_fee":-1.04},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"a9d1efa8-f2b1-46a2-acee-6847c752b0eb","category":"fare","event_time":1502841851,"trip_id":"a9d1efa8-f2b1-46a2-acee-6847c752b0eb","cash_collected":0.0,"amount":4.49,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":5.99,"service_fee":-1.5},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"da30d9ce-4592-40fe-9ba9-c9b970d1d391","category":"fare","event_time":1502841640,"trip_id":"da30d9ce-4592-40fe-9ba9-c9b970d1d391","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"b5613b6a-fe74-4704-a637-50f8d51a8bb1","category":"fare","event_time":1502843894,"trip_id":"b5613b6a-fe74-4704-a637-50f8d51a8bb1","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"50eebfa4-9985-41ca-bbd9-be0150e32d4c","category":"fare","event_time":1502842172,"trip_id":"50eebfa4-9985-41ca-bbd9-be0150e32d4c","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"ba950c43-c57a-4ab8-a8db-2057dd30756b","category":"fare","event_time":1502842655,"trip_id":"ba950c43-c57a-4ab8-a8db-2057dd30756b","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"9ffeb986-0a73-4312-bb5e-22a1cc13e495","category":"fare","event_time":1502842917,"trip_id":"9ffeb986-0a73-4312-bb5e-22a1cc13e495","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"4415e5f6-60f2-451f-ade1-c3d6ae286d76","category":"fare","event_time":1502843623,"trip_id":"4415e5f6-60f2-451f-ade1-c3d6ae286d76","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"43851410-34ba-4054-9a4e-711e4e6a8fe5","category":"fare","event_time":1502843338,"trip_id":"43851410-34ba-4054-9a4e-711e4e6a8fe5","cash_collected":0.0,"amount":3.0,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":4.0,"service_fee":-1.0},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"},{"payment_id":"020f251b-e8ac-4ad1-ae9f-543a0db6b294","category":"fare","event_time":1502830183,"trip_id":"020f251b-e8ac-4ad1-ae9f-543a0db6b294","cash_collected":0.0,"amount":4.34,"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","breakdown":{"other":5.79,"service_fee":-1.45},"rider_fees":{},"partner_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","currency_code":"USD"}],"offset":0}'} 10 | headers: 11 | cache-control: [max-age=0] 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-type: [application/json] 15 | date: ['Wed, 16 Aug 2017 22:54:50 GMT'] 16 | etag: [W/"a757f6e22e2dffdb1ccece2423b5f517f01ca791"] 17 | server: [nginx] 18 | strict-transport-security: [max-age=604800, max-age=2592000] 19 | transfer-encoding: [chunked] 20 | x-content-type-options: [nosniff] 21 | x-frame-options: [SAMEORIGIN] 22 | x-rate-limit-limit: ['2000'] 23 | x-rate-limit-remaining: ['1995'] 24 | x-rate-limit-reset: ['1502924400'] 25 | x-uber-app: [uberex-nonsandbox, optimus] 26 | x-xss-protection: [1; mode=block] 27 | status: {code: 200, message: OK} 28 | version: 1 29 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_driver_profile: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://api.uber.com/v1/partners/me 8 | response: 9 | body: {string: !!python/unicode '{"phone_number":"+14075550001","picture":"https:\/\/d1w2poirtb3as9.cloudfront.net\/16ce502f4767f17b120e.jpeg","first_name":"Uber","last_name":"Tester","promo_code":"ubert4544ue","rating":5.0,"activation_status":"active","driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","email":"uber.developer+tester@example.com"}'} 10 | headers: 11 | cache-control: [max-age=0] 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-length: ['419'] 15 | content-type: [application/json] 16 | date: ['Wed, 16 Aug 2017 22:54:50 GMT'] 17 | etag: [W/"d76d91610e42a7b0d6e551766905af177b466447"] 18 | server: [nginx] 19 | strict-transport-security: [max-age=604800, max-age=2592000] 20 | x-content-type-options: [nosniff] 21 | x-frame-options: [SAMEORIGIN] 22 | x-rate-limit-limit: ['2000'] 23 | x-rate-limit-remaining: ['1997'] 24 | x-rate-limit-reset: ['1502924400'] 25 | x-uber-app: [uberex-nonsandbox, optimus] 26 | x-xss-protection: [1; mode=block] 27 | status: {code: 200, message: OK} 28 | version: 1 29 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_driver_trips: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://api.uber.com/v1/partners/trips 8 | response: 9 | body: {string: !!python/unicode '{"count":13,"limit":10,"trips":[{"fare":6.2,"dropoff":{"timestamp":1502844378},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":0.37,"start_city":{"latitude":38.3498,"display_name":"Charleston, 10 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502843899},{"status":"driver_arrived","timestamp":1502843900},{"status":"trip_began","timestamp":1502843903},{"status":"completed","timestamp":1502844378}],"surge_multiplier":1.0,"pickup":{"timestamp":1502843903},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":475,"trip_id":"b5613b6a-fe74-4704-a637-50f8d51a8bb1","currency_code":"USD"},{"fare":6.4,"dropoff":{"timestamp":1502843883},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":0.96,"start_city":{"latitude":38.3498,"display_name":"Charleston, 11 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502843627},{"status":"driver_arrived","timestamp":1502843627},{"status":"trip_began","timestamp":1502843631},{"status":"completed","timestamp":1502843883}],"surge_multiplier":1.0,"pickup":{"timestamp":1502843631},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":253,"trip_id":"4415e5f6-60f2-451f-ade1-c3d6ae286d76","currency_code":"USD"},{"fare":6.2,"dropoff":{"timestamp":1502843563},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":0.0,"start_city":{"latitude":38.3498,"display_name":"Charleston, 12 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502843343},{"status":"driver_arrived","timestamp":1502843343},{"status":"trip_began","timestamp":1502843346},{"status":"completed","timestamp":1502843563}],"surge_multiplier":1.0,"pickup":{"timestamp":1502843346},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":217,"trip_id":"43851410-34ba-4054-9a4e-711e4e6a8fe5","currency_code":"USD"},{"fare":13.35,"dropoff":{"timestamp":1502843227},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":3.51,"start_city":{"latitude":38.3498,"display_name":"Charleston, 13 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502843039},{"status":"driver_arrived","timestamp":1502843040},{"status":"trip_began","timestamp":1502843043},{"status":"completed","timestamp":1502843227}],"surge_multiplier":1.0,"pickup":{"timestamp":1502843043},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":184,"trip_id":"fe8f00d9-2bd0-464a-82fe-8ce1ffd27057","currency_code":"USD"},{"fare":6.55,"dropoff":{"timestamp":1502843010},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":1.14,"start_city":{"latitude":38.3498,"display_name":"Charleston, 14 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502842919},{"status":"driver_arrived","timestamp":1502842919},{"status":"trip_began","timestamp":1502842922},{"status":"completed","timestamp":1502843010}],"surge_multiplier":1.0,"pickup":{"timestamp":1502842922},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":88,"trip_id":"9ffeb986-0a73-4312-bb5e-22a1cc13e495","currency_code":"USD"},{"fare":7.13,"dropoff":{"timestamp":1502842902},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":1.42,"start_city":{"latitude":38.3498,"display_name":"Charleston, 15 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502842761},{"status":"driver_arrived","timestamp":1502842761},{"status":"trip_began","timestamp":1502842763},{"status":"completed","timestamp":1502842902}],"surge_multiplier":1.0,"pickup":{"timestamp":1502842763},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":140,"trip_id":"5cb8304c-f3f0-4a46-b6e3-b55e020750d7","currency_code":"USD"},{"fare":6.53,"dropoff":null,"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":0.72,"start_city":{"latitude":38.3498,"display_name":"Charleston, 16 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502842659},{"status":"driver_arrived","timestamp":1502842660},{"status":"trip_began","timestamp":1502842662},{"status":"rider_canceled","timestamp":1502842731}],"surge_multiplier":1.0,"pickup":{"timestamp":1502842662},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"rider_canceled","duration":68,"trip_id":"ba950c43-c57a-4ab8-a8db-2057dd30756b","currency_code":"USD"},{"fare":9.68,"dropoff":{"timestamp":1502842611},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":3.82,"start_city":{"latitude":38.3498,"display_name":"Charleston, 17 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502842336},{"status":"driver_arrived","timestamp":1502842336},{"status":"trip_began","timestamp":1502842338},{"status":"completed","timestamp":1502842611}],"surge_multiplier":1.0,"pickup":{"timestamp":1502842338},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":273,"trip_id":"d80ea4dd-3eca-4215-8224-4162cd72eefb","currency_code":"USD"},{"fare":6.2,"dropoff":{"timestamp":1502842242},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":0.38,"start_city":{"latitude":38.3498,"display_name":"Charleston, 18 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502842176},{"status":"driver_arrived","timestamp":1502842177},{"status":"trip_began","timestamp":1502842180},{"status":"completed","timestamp":1502842242}],"surge_multiplier":1.0,"pickup":{"timestamp":1502842180},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":63,"trip_id":"50eebfa4-9985-41ca-bbd9-be0150e32d4c","currency_code":"USD"},{"fare":8.99,"dropoff":{"timestamp":1502842126},"vehicle_id":"0082b54a-6a5e-4f6b-b999-b0649f286381","distance":2.8,"start_city":{"latitude":38.3498,"display_name":"Charleston, 19 | WV","longitude":-81.6326},"status_changes":[{"status":"accepted","timestamp":1502841856},{"status":"driver_arrived","timestamp":1502841859},{"status":"trip_began","timestamp":1502841861},{"status":"completed","timestamp":1502842126}],"surge_multiplier":1.0,"pickup":{"timestamp":1502841861},"driver_id":"8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==","status":"completed","duration":264,"trip_id":"a9d1efa8-f2b1-46a2-acee-6847c752b0eb","currency_code":"USD"}],"offset":0}'} 20 | headers: 21 | cache-control: [max-age=0] 22 | connection: [keep-alive] 23 | content-language: [en] 24 | content-type: [application/json] 25 | date: ['Wed, 16 Aug 2017 22:54:50 GMT'] 26 | etag: [W/"7341e30342fe59d8119b66b04f314ce1a7ab275f"] 27 | server: [nginx] 28 | strict-transport-security: [max-age=604800, max-age=2592000] 29 | transfer-encoding: [chunked] 30 | x-content-type-options: [nosniff] 31 | x-frame-options: [SAMEORIGIN] 32 | x-rate-limit-limit: ['2000'] 33 | x-rate-limit-remaining: ['1996'] 34 | x-rate-limit-reset: ['1502924400'] 35 | x-uber-app: [uberex-nonsandbox, optimus] 36 | x-xss-protection: [1; mode=block] 37 | status: {code: 200, message: OK} 38 | version: 1 39 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_home_address: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/places/home 8 | response: 9 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 10 | 94105, USA"}'} 11 | headers: 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-length: ['57'] 15 | content-type: [application/json] 16 | date: ['Thu, 20 Oct 2016 08:36:31 GMT'] 17 | etag: ['"74feeed8e00d30505b9f97504dc53e839be347cc"'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 200, message: OK} 24 | - request: 25 | body: null 26 | headers: 27 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 28 | method: GET 29 | uri: https://sandbox-api.uber.com/v1.2/places/home 30 | response: 31 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 32 | 94105, USA"}'} 33 | headers: 34 | connection: [keep-alive] 35 | content-language: [en] 36 | content-length: ['57'] 37 | content-type: [application/json] 38 | date: ['Thu, 20 Oct 2016 08:41:47 GMT'] 39 | etag: ['"74feeed8e00d30505b9f97504dc53e839be347cc"'] 40 | server: [nginx] 41 | strict-transport-security: [max-age=0] 42 | x-content-type-options: [nosniff] 43 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 44 | x-xss-protection: [1; mode=block] 45 | status: {code: 200, message: OK} 46 | - request: 47 | body: null 48 | headers: 49 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 50 | method: GET 51 | uri: https://sandbox-api.uber.com/v1.2/places/home 52 | response: 53 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 54 | 94105, USA"}'} 55 | headers: 56 | connection: [keep-alive] 57 | content-language: [en] 58 | content-length: ['57'] 59 | content-type: [application/json] 60 | date: ['Thu, 20 Oct 2016 08:48:16 GMT'] 61 | etag: ['"74feeed8e00d30505b9f97504dc53e839be347cc"'] 62 | server: [nginx] 63 | strict-transport-security: [max-age=0] 64 | x-content-type-options: [nosniff] 65 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 66 | x-xss-protection: [1; mode=block] 67 | status: {code: 200, message: OK} 68 | - request: 69 | body: null 70 | headers: 71 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 72 | method: GET 73 | uri: https://sandbox-api.uber.com/v1.2/places/home 74 | response: 75 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 76 | 94105, USA"}'} 77 | headers: 78 | connection: [keep-alive] 79 | content-language: [en] 80 | content-length: ['57'] 81 | content-type: [application/json] 82 | date: ['Thu, 20 Oct 2016 08:49:42 GMT'] 83 | etag: ['"74feeed8e00d30505b9f97504dc53e839be347cc"'] 84 | server: [nginx] 85 | strict-transport-security: [max-age=0] 86 | x-content-type-options: [nosniff] 87 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 88 | x-xss-protection: [1; mode=block] 89 | status: {code: 200, message: OK} 90 | version: 1 91 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_payment_methods: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/payment-methods 8 | response: 9 | body: {string: !!python/unicode '{"last_used":"517a6c29-3a2b-45cb-94a3-35d679909a71","payment_methods":[{"type":"american_express","description":"***05","payment_method_id":"517a6c29-3a2b-45cb-94a3-35d679909a71"}]}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-language: [en] 13 | content-length: ['181'] 14 | content-type: [application/json] 15 | date: ['Thu, 20 Oct 2016 08:36:32 GMT'] 16 | etag: ['"2a24b71e77e897541be036fa1a578268e9df376c"'] 17 | server: [nginx] 18 | strict-transport-security: [max-age=0] 19 | x-content-type-options: [nosniff] 20 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 21 | x-xss-protection: [1; mode=block] 22 | status: {code: 200, message: OK} 23 | - request: 24 | body: null 25 | headers: 26 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 27 | method: GET 28 | uri: https://sandbox-api.uber.com/v1.2/payment-methods 29 | response: 30 | body: {string: !!python/unicode '{"last_used":"517a6c29-3a2b-45cb-94a3-35d679909a71","payment_methods":[{"type":"american_express","description":"***05","payment_method_id":"517a6c29-3a2b-45cb-94a3-35d679909a71"}]}'} 31 | headers: 32 | connection: [keep-alive] 33 | content-language: [en] 34 | content-length: ['181'] 35 | content-type: [application/json] 36 | date: ['Thu, 20 Oct 2016 08:41:48 GMT'] 37 | etag: ['"2a24b71e77e897541be036fa1a578268e9df376c"'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 200, message: OK} 44 | - request: 45 | body: null 46 | headers: 47 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 48 | method: GET 49 | uri: https://sandbox-api.uber.com/v1.2/payment-methods 50 | response: 51 | body: {string: !!python/unicode '{"last_used":"517a6c29-3a2b-45cb-94a3-35d679909a71","payment_methods":[{"type":"american_express","description":"***05","payment_method_id":"517a6c29-3a2b-45cb-94a3-35d679909a71"}]}'} 52 | headers: 53 | connection: [keep-alive] 54 | content-language: [en] 55 | content-length: ['181'] 56 | content-type: [application/json] 57 | date: ['Thu, 20 Oct 2016 08:48:17 GMT'] 58 | etag: ['"2a24b71e77e897541be036fa1a578268e9df376c"'] 59 | server: [nginx] 60 | strict-transport-security: [max-age=0] 61 | x-content-type-options: [nosniff] 62 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 63 | x-xss-protection: [1; mode=block] 64 | status: {code: 200, message: OK} 65 | - request: 66 | body: null 67 | headers: 68 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 69 | method: GET 70 | uri: https://sandbox-api.uber.com/v1.2/payment-methods 71 | response: 72 | body: {string: !!python/unicode '{"last_used":"517a6c29-3a2b-45cb-94a3-35d679909a71","payment_methods":[{"type":"american_express","description":"***05","payment_method_id":"517a6c29-3a2b-45cb-94a3-35d679909a71"}]}'} 73 | headers: 74 | connection: [keep-alive] 75 | content-language: [en] 76 | content-length: ['181'] 77 | content-type: [application/json] 78 | date: ['Thu, 20 Oct 2016 08:49:43 GMT'] 79 | etag: ['"2a24b71e77e897541be036fa1a578268e9df376c"'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 200, message: OK} 86 | version: 1 87 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_promotions: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 8 | response: 9 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-language: [en] 13 | content-length: ['118'] 14 | content-type: [application/json] 15 | date: ['Thu, 20 Oct 2016 08:22:37 GMT'] 16 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 17 | server: [nginx] 18 | strict-transport-security: [max-age=0] 19 | x-content-type-options: [nosniff] 20 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 21 | x-xss-protection: [1; mode=block] 22 | status: {code: 200, message: OK} 23 | - request: 24 | body: null 25 | headers: 26 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 27 | method: GET 28 | uri: https://api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 29 | response: 30 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 31 | headers: 32 | connection: [keep-alive] 33 | content-language: [en] 34 | content-length: ['118'] 35 | content-type: [application/json] 36 | date: ['Thu, 20 Oct 2016 08:22:37 GMT'] 37 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-nonsandbox, migrator-uberex-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 200, message: OK} 44 | - request: 45 | body: null 46 | headers: 47 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 48 | method: GET 49 | uri: https://sandbox-api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 50 | response: 51 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 52 | headers: 53 | connection: [keep-alive] 54 | content-language: [en] 55 | content-length: ['118'] 56 | content-type: [application/json] 57 | date: ['Thu, 20 Oct 2016 08:41:37 GMT'] 58 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 59 | server: [nginx] 60 | strict-transport-security: [max-age=0] 61 | x-content-type-options: [nosniff] 62 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 63 | x-xss-protection: [1; mode=block] 64 | status: {code: 200, message: OK} 65 | - request: 66 | body: null 67 | headers: 68 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 69 | method: GET 70 | uri: https://api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 71 | response: 72 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 73 | headers: 74 | connection: [keep-alive] 75 | content-language: [en] 76 | content-length: ['118'] 77 | content-type: [application/json] 78 | date: ['Thu, 20 Oct 2016 08:41:37 GMT'] 79 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-nonsandbox, migrator-uberex-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 200, message: OK} 86 | - request: 87 | body: null 88 | headers: 89 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 90 | method: GET 91 | uri: https://sandbox-api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 92 | response: 93 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 94 | headers: 95 | connection: [keep-alive] 96 | content-language: [en] 97 | content-length: ['118'] 98 | content-type: [application/json] 99 | date: ['Thu, 20 Oct 2016 08:48:05 GMT'] 100 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 101 | server: [nginx] 102 | strict-transport-security: [max-age=0] 103 | x-content-type-options: [nosniff] 104 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 105 | x-xss-protection: [1; mode=block] 106 | status: {code: 200, message: OK} 107 | - request: 108 | body: null 109 | headers: 110 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 111 | method: GET 112 | uri: https://api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 113 | response: 114 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 115 | headers: 116 | connection: [keep-alive] 117 | content-language: [en] 118 | content-length: ['118'] 119 | content-type: [application/json] 120 | date: ['Thu, 20 Oct 2016 08:48:05 GMT'] 121 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 122 | server: [nginx] 123 | strict-transport-security: [max-age=0] 124 | x-content-type-options: [nosniff] 125 | x-uber-app: [uberex-nonsandbox, migrator-uberex-optimus] 126 | x-xss-protection: [1; mode=block] 127 | status: {code: 200, message: OK} 128 | - request: 129 | body: null 130 | headers: 131 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 132 | method: GET 133 | uri: https://sandbox-api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 134 | response: 135 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 136 | headers: 137 | connection: [keep-alive] 138 | content-language: [en] 139 | content-length: ['118'] 140 | content-type: [application/json] 141 | date: ['Thu, 20 Oct 2016 08:49:31 GMT'] 142 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 143 | server: [nginx] 144 | strict-transport-security: [max-age=0] 145 | x-content-type-options: [nosniff] 146 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 147 | x-xss-protection: [1; mode=block] 148 | status: {code: 200, message: OK} 149 | - request: 150 | body: null 151 | headers: 152 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 153 | method: GET 154 | uri: https://api.uber.com/v1.2/promotions?start_latitude=37.7899886&start_longitude=-122.4021253&end_latitude=37.775232&end_longitude=-122.4197513 155 | response: 156 | body: {string: !!python/unicode '{"display_text":"Free ride up to $15","localized_value":"$15","type":"trip_credit","value":15.0,"currency_code":"USD"}'} 157 | headers: 158 | connection: [keep-alive] 159 | content-language: [en] 160 | content-length: ['118'] 161 | content-type: [application/json] 162 | date: ['Thu, 20 Oct 2016 08:49:31 GMT'] 163 | etag: ['"2e4fdbfb8dcaa81fadf58188042048488eef7538"'] 164 | server: [nginx] 165 | strict-transport-security: [max-age=0] 166 | x-content-type-options: [nosniff] 167 | x-uber-app: [uberex-nonsandbox, migrator-uberex-optimus] 168 | x-xss-protection: [1; mode=block] 169 | status: {code: 200, message: OK} 170 | version: 1 171 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_ride_details: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/requests/9bdb3278-21bd-46b8-90fa-51404b0d6acf 8 | response: 9 | body: {string: !!python/unicode '{"message":"cannot find trip","code":"not_found"}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-length: ['49'] 13 | content-type: [application/json] 14 | date: ['Thu, 20 Oct 2016 08:36:27 GMT'] 15 | server: [nginx] 16 | strict-transport-security: [max-age=0] 17 | x-content-type-options: [nosniff] 18 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 19 | x-xss-protection: [1; mode=block] 20 | status: {code: 404, message: Not Found} 21 | - request: 22 | body: null 23 | headers: 24 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 25 | method: GET 26 | uri: https://sandbox-api.uber.com/v1.2/requests/610d868b-e21c-483a-9932-97e61b852fd2 27 | response: 28 | body: {string: !!python/unicode '{"status":"rider_canceled","request_id":"610d868b-e21c-483a-9932-97e61b852fd2","driver":null,"location":null,"vehicle":null,"shared":false}'} 29 | headers: 30 | connection: [keep-alive] 31 | content-language: [en] 32 | content-length: ['139'] 33 | content-type: [application/json] 34 | date: ['Thu, 20 Oct 2016 08:41:43 GMT'] 35 | etag: ['"6fe60292e1aacfced16eb479e34f8998c099fac0"'] 36 | server: [nginx] 37 | strict-transport-security: [max-age=0] 38 | x-content-type-options: [nosniff] 39 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 40 | x-xss-protection: [1; mode=block] 41 | status: {code: 200, message: OK} 42 | - request: 43 | body: null 44 | headers: 45 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 46 | method: GET 47 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 48 | response: 49 | body: {string: !!python/unicode '{"status":"processing","product_id":"26546650-e557-4a7b-86e7-6a3942445247","destination":{"latitude":37.7899886,"longitude":-122.4021253},"driver":null,"pickup":{"latitude":37.775232,"longitude":-122.4197513},"request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8","location":null,"vehicle":null,"shared":false}'} 50 | headers: 51 | connection: [keep-alive] 52 | content-geo-system: [wgs-84] 53 | content-language: [en] 54 | content-length: ['307'] 55 | content-type: [application/json] 56 | date: ['Thu, 20 Oct 2016 08:48:11 GMT'] 57 | etag: ['"0472dd46bc441b9471f36592774c7b544d7aca13"'] 58 | server: [nginx] 59 | strict-transport-security: [max-age=0] 60 | x-content-type-options: [nosniff] 61 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 62 | x-xss-protection: [1; mode=block] 63 | status: {code: 200, message: OK} 64 | - request: 65 | body: null 66 | headers: 67 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 68 | method: GET 69 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 70 | response: 71 | body: {string: !!python/unicode '{"status":"rider_canceled","request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8","driver":null,"location":null,"vehicle":null,"shared":false}'} 72 | headers: 73 | connection: [keep-alive] 74 | content-language: [en] 75 | content-length: ['139'] 76 | content-type: [application/json] 77 | date: ['Thu, 20 Oct 2016 08:49:37 GMT'] 78 | etag: ['"e2040920cf35ec4f320fc0a04592f2541397bea9"'] 79 | server: [nginx] 80 | strict-transport-security: [max-age=0] 81 | x-content-type-options: [nosniff] 82 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 83 | x-xss-protection: [1; mode=block] 84 | status: {code: 200, message: OK} 85 | version: 1 86 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_ride_map: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8/map 8 | response: 9 | body: {string: !!python/unicode '{"href":"https:\/\/sandbox-api.uber.com\/v1\/sandbox\/map","request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8"}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-language: [en] 13 | content-length: ['111'] 14 | content-type: [application/json] 15 | date: ['Fri, 21 Oct 2016 01:15:00 GMT'] 16 | etag: ['"0843ec9a5bf0314e51a0e83b2de31b5d3ac21f47"'] 17 | server: [nginx] 18 | strict-transport-security: [max-age=0] 19 | x-content-type-options: [nosniff] 20 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 21 | x-xss-protection: [1; mode=block] 22 | status: {code: 200, message: OK} 23 | version: 1 24 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_ride_receipt: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8/receipt 8 | response: 9 | body: {string: !!python/unicode '{"distance":"1.87","charge_adjustments":[{"amount":"2.25","type":"booking_fee","name":"Booking 10 | Fee"}],"total_owed":null,"distance_label":"miles","total_charged":"$9.00","request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8","duration":"00:11:32","total_fare":"$9.00","subtotal":"$9.00","currency_code":"USD"}'} 11 | headers: 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-length: ['305'] 15 | content-type: [application/json] 16 | date: ['Fri, 21 Oct 2016 01:17:15 GMT'] 17 | etag: ['"7f5216c11382891ac55db6557ec37f174b17637f"'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 200, message: OK} 24 | version: 1 25 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_rider_profile: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode 'Python Rides SDK v0.6.0'] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/me 8 | response: 9 | body: {string: !!python/unicode '{"picture":"https:\/\/d1w2poirtb3as9.cloudfront.net\/16ce502f4767f17b120e.png","first_name":"Uber","last_name":"Tester","promo_code":"uber_tester","rider_id":"8LvXuRBq254Ogmr8EMkovekFNa2848lyMaQevIto-aXmdbbwlDSvy50HMoiAHsFc8N7WW3gdo6smNKnmT2uJIlirAkhUmtNdzDytTda9qGwWHQiswLMo5jHET7k4RQsEPw==","email":"uber.developer+tester@example.com","mobile_verified":true,"uuid":"5cbc8ff1-29bb-469d-b31d-71126648bbb0"}'} 10 | headers: 11 | cache-control: [max-age=0] 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-length: ['395'] 15 | content-type: [application/json] 16 | date: ['Fri, 18 Aug 2017 00:04:24 GMT'] 17 | etag: [W/"bbb14deefec4704ee540ccc25c838f833f9f9689"] 18 | server: [nginx] 19 | strict-transport-security: [max-age=604800, max-age=2592000] 20 | x-content-type-options: [nosniff] 21 | x-frame-options: [SAMEORIGIN] 22 | x-uber-app: [uberex-sandbox, optimus] 23 | x-xss-protection: [1; mode=block] 24 | status: {code: 200, message: OK} 25 | version: 1 26 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_rider_trips: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode 'Python Rides SDK v0.6.0'] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/history 8 | response: 9 | body: {string: !!python/unicode '{"count":1678,"history":[{"status":"completed","distance":1.2917022901,"product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d","start_time":1502994399,"start_city":{"latitude":37.7749295,"display_name":"San 10 | Francisco","longitude":-122.4194155},"fare":8.02,"end_time":1502994827,"request_id":"d903203a-da02-45a3-964d-dd402174e3ae","currency_code":"USD","request_time":1502994212},{"status":"completed","distance":1.4490403973,"product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d","start_time":1502935226,"start_city":{"latitude":37.7749295,"display_name":"San 11 | Francisco","longitude":-122.4194155},"fare":7.34,"end_time":1502935773,"request_id":"f09af6aa-816d-4356-b5ed-98749cbcb145","currency_code":"USD","request_time":1502935075},{"status":"completed","distance":1.2886012532,"product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d","start_time":1502908015,"start_city":{"latitude":37.7749295,"display_name":"San 12 | Francisco","longitude":-122.4194155},"fare":8.1,"end_time":1502908400,"request_id":"dafa189b-747e-4273-bbc6-178a62b8046c","currency_code":"USD","request_time":1502907880},{"status":"completed","distance":1.4457831309,"product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d","start_time":1502845436,"start_city":{"latitude":37.7749295,"display_name":"San 13 | Francisco","longitude":-122.4194155},"fare":1.23,"end_time":1502846061,"request_id":"5f40ed6a-2654-4b1b-802c-80b578bb14cd","currency_code":"USD","request_time":1502845218},{"status":"completed","distance":1.3627998333,"product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d","start_time":1502819334,"start_city":{"latitude":37.7749295,"display_name":"San 14 | Francisco","longitude":-122.4194155},"fare":6.89,"end_time":1502819720,"request_id":"ad1f6cff-3587-41d9-905e-c80d7b0b9de1","currency_code":"USD","request_time":1502819209}],"limit":5,"offset":0}'} 15 | headers: 16 | cache-control: [max-age=0] 17 | connection: [keep-alive] 18 | content-language: [en] 19 | content-length: ['1796'] 20 | content-type: [application/json] 21 | date: ['Fri, 18 Aug 2017 00:04:24 GMT'] 22 | etag: [W/"710a1952efbc2724739c986c6b34c9e5ae3eaf46"] 23 | server: [nginx] 24 | strict-transport-security: [max-age=604800, max-age=2592000] 25 | x-content-type-options: [nosniff] 26 | x-frame-options: [SAMEORIGIN] 27 | x-rate-limit-limit: ['2000'] 28 | x-rate-limit-remaining: ['1999'] 29 | x-rate-limit-reset: ['1503018000'] 30 | x-uber-app: [uberex-sandbox, optimus] 31 | x-xss-protection: [1; mode=block] 32 | status: {code: 200, message: OK} 33 | version: 1 34 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_user_profile: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/me 8 | response: 9 | body: {string: !!python/unicode '{"picture":"https:\/\/d1w2poirtb3as9.cloudfront.net\/f3be498cb0bbf570aa3d.jpeg","first_name":"Uber","last_name":"Developer","uuid":"f4a416e3-6016-4623-8ec9-d5ee105a6e27","rider_id":"8OlTlUG1TyeAQf1JiBZZdkKxuSSOUwu2IkO0Hf9d2HV52Pm25A0NvsbmbnZr85tLVi-s8CckpBK8Eq0Nke4X-no3AcSHfeVh6J5O6LiQt5LsBZDSi4qyVUdSLeYDnTtirw==","email":"uberdevelopers@gmail.com","mobile_verified":true,"promo_code":"uberd340ue"}'} 10 | headers: 11 | connection: [keep-alive] 12 | content-language: [en] 13 | content-length: ['400'] 14 | content-type: [application/json] 15 | date: ['Thu, 20 Oct 2016 08:28:33 GMT'] 16 | etag: ['"97ce42cf42a0c9c030421237f8ce7a28c0c1494f"'] 17 | server: [nginx] 18 | strict-transport-security: [max-age=0] 19 | x-content-type-options: [nosniff] 20 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 21 | x-xss-protection: [1; mode=block] 22 | status: {code: 200, message: OK} 23 | - request: 24 | body: null 25 | headers: 26 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 27 | method: GET 28 | uri: https://sandbox-api.uber.com/v1.2/me 29 | response: 30 | body: {string: !!python/unicode '{"picture":"https:\/\/d1w2poirtb3as9.cloudfront.net\/f3be498cb0bbf570aa3d.jpeg","first_name":"Uber","last_name":"Developer","uuid":"f4a416e3-6016-4623-8ec9-d5ee105a6e27","rider_id":"8OlTlUG1TyeAQf1JiBZZdkKxuSSOUwu2IkO0Hf9d2HV52Pm25A0NvsbmbnZr85tLVi-s8CckpBK8Eq0Nke4X-no3AcSHfeVh6J5O6LiQt5LsBZDSi4qyVUdSLeYDnTtirw==","email":"uberdevelopers@gmail.com","mobile_verified":true,"promo_code":"uberd340ue"}'} 31 | headers: 32 | connection: [keep-alive] 33 | content-language: [en] 34 | content-length: ['400'] 35 | content-type: [application/json] 36 | date: ['Thu, 20 Oct 2016 08:41:38 GMT'] 37 | etag: ['"97ce42cf42a0c9c030421237f8ce7a28c0c1494f"'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 200, message: OK} 44 | - request: 45 | body: null 46 | headers: 47 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 48 | method: GET 49 | uri: https://sandbox-api.uber.com/v1.2/me 50 | response: 51 | body: {string: !!python/unicode '{"picture":"https:\/\/d1w2poirtb3as9.cloudfront.net\/f3be498cb0bbf570aa3d.jpeg","first_name":"Uber","last_name":"Developer","uuid":"f4a416e3-6016-4623-8ec9-d5ee105a6e27","rider_id":"8OlTlUG1TyeAQf1JiBZZdkKxuSSOUwu2IkO0Hf9d2HV52Pm25A0NvsbmbnZr85tLVi-s8CckpBK8Eq0Nke4X-no3AcSHfeVh6J5O6LiQt5LsBZDSi4qyVUdSLeYDnTtirw==","email":"uberdevelopers@gmail.com","mobile_verified":true,"promo_code":"uberd340ue"}'} 52 | headers: 53 | connection: [keep-alive] 54 | content-language: [en] 55 | content-length: ['400'] 56 | content-type: [application/json] 57 | date: ['Thu, 20 Oct 2016 08:48:06 GMT'] 58 | etag: ['"97ce42cf42a0c9c030421237f8ce7a28c0c1494f"'] 59 | server: [nginx] 60 | strict-transport-security: [max-age=0] 61 | x-content-type-options: [nosniff] 62 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 63 | x-xss-protection: [1; mode=block] 64 | status: {code: 200, message: OK} 65 | - request: 66 | body: null 67 | headers: 68 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 69 | method: GET 70 | uri: https://sandbox-api.uber.com/v1.2/me 71 | response: 72 | body: {string: !!python/unicode '{"picture":"https:\/\/d1w2poirtb3as9.cloudfront.net\/f3be498cb0bbf570aa3d.jpeg","first_name":"Uber","last_name":"Developer","uuid":"f4a416e3-6016-4623-8ec9-d5ee105a6e27","rider_id":"8OlTlUG1TyeAQf1JiBZZdkKxuSSOUwu2IkO0Hf9d2HV52Pm25A0NvsbmbnZr85tLVi-s8CckpBK8Eq0Nke4X-no3AcSHfeVh6J5O6LiQt5LsBZDSi4qyVUdSLeYDnTtirw==","email":"uberdevelopers@gmail.com","mobile_verified":true,"promo_code":"uberd340ue"}'} 73 | headers: 74 | connection: [keep-alive] 75 | content-language: [en] 76 | content-length: ['400'] 77 | content-type: [application/json] 78 | date: ['Thu, 20 Oct 2016 08:49:31 GMT'] 79 | etag: ['"97ce42cf42a0c9c030421237f8ce7a28c0c1494f"'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 200, message: OK} 86 | version: 1 87 | -------------------------------------------------------------------------------- /tests/fixtures/test_get_work_address: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 6 | method: GET 7 | uri: https://sandbox-api.uber.com/v1.2/places/work 8 | response: 9 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 10 | 94103, USA"}'} 11 | headers: 12 | connection: [keep-alive] 13 | content-language: [en] 14 | content-length: ['58'] 15 | content-type: [application/json] 16 | date: ['Thu, 20 Oct 2016 08:36:32 GMT'] 17 | etag: ['"9bc62a15a6f4b45bf80257930416c505b9cde3cd"'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 200, message: OK} 24 | - request: 25 | body: null 26 | headers: 27 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 28 | method: GET 29 | uri: https://sandbox-api.uber.com/v1.2/places/work 30 | response: 31 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 32 | 94103, USA"}'} 33 | headers: 34 | connection: [keep-alive] 35 | content-language: [en] 36 | content-length: ['58'] 37 | content-type: [application/json] 38 | date: ['Thu, 20 Oct 2016 08:41:48 GMT'] 39 | etag: ['"9bc62a15a6f4b45bf80257930416c505b9cde3cd"'] 40 | server: [nginx] 41 | strict-transport-security: [max-age=0] 42 | x-content-type-options: [nosniff] 43 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 44 | x-xss-protection: [1; mode=block] 45 | status: {code: 200, message: OK} 46 | - request: 47 | body: null 48 | headers: 49 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 50 | method: GET 51 | uri: https://sandbox-api.uber.com/v1.2/places/work 52 | response: 53 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 54 | 94103, USA"}'} 55 | headers: 56 | connection: [keep-alive] 57 | content-language: [en] 58 | content-length: ['58'] 59 | content-type: [application/json] 60 | date: ['Thu, 20 Oct 2016 08:48:16 GMT'] 61 | etag: ['"9bc62a15a6f4b45bf80257930416c505b9cde3cd"'] 62 | server: [nginx] 63 | strict-transport-security: [max-age=0] 64 | x-content-type-options: [nosniff] 65 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 66 | x-xss-protection: [1; mode=block] 67 | status: {code: 200, message: OK} 68 | - request: 69 | body: null 70 | headers: 71 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 72 | method: GET 73 | uri: https://sandbox-api.uber.com/v1.2/places/work 74 | response: 75 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 76 | 94103, USA"}'} 77 | headers: 78 | connection: [keep-alive] 79 | content-language: [en] 80 | content-length: ['58'] 81 | content-type: [application/json] 82 | date: ['Thu, 20 Oct 2016 08:49:42 GMT'] 83 | etag: ['"9bc62a15a6f4b45bf80257930416c505b9cde3cd"'] 84 | server: [nginx] 85 | strict-transport-security: [max-age=0] 86 | x-content-type-options: [nosniff] 87 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 88 | x-xss-protection: [1; mode=block] 89 | status: {code: 200, message: OK} 90 | version: 1 91 | -------------------------------------------------------------------------------- /tests/fixtures/test_refresh_auth_code_access_token: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode redirect_uri=https%3A%2F%2Flocalhost%3A8000%2Fapi%2Fv1%2Fuber%2Foauth&client_id=xxx&client_secret=xxx&grant_type=refresh_token&refresh_token=xxx 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | Content-Length: ['235'] 9 | Content-Type: [application/x-www-form-urlencoded] 10 | User-Agent: [python-requests/2.11.1] 11 | method: POST 12 | uri: https://login.uber.com/oauth/v2/token 13 | response: 14 | body: {string: !!python/unicode '{"last_authenticated":1485210848,"access_token":"xxx","expires_in":2592000,"token_type":"Bearer","scope":"profile 15 | history","refresh_token":"xxx"}'} 16 | headers: 17 | cache-control: [no-store, max-age=0] 18 | connection: [keep-alive] 19 | content-length: ['911'] 20 | content-type: [application/json] 21 | date: ['Tue, 24 Jan 2017 01:14:57 GMT'] 22 | pragma: [no-cache] 23 | server: [nginx] 24 | set-cookie: [session=e5b4c855402bec82_5886aa91.wNBLxxu2Z074BTuO-EP8DhuIY2U; 25 | Domain=login.uber.com; Secure; HttpOnly; Path=/] 26 | strict-transport-security: [max-age=604800, max-age=2592000] 27 | transfer-encoding: [chunked] 28 | x-content-type-options: [nosniff] 29 | x-frame-options: [SAMEORIGIN] 30 | x-uber-app: [login] 31 | x-xss-protection: [1; mode=block] 32 | status: {code: 200, message: OK} 33 | version: 1 34 | -------------------------------------------------------------------------------- /tests/fixtures/test_refresh_client_credential_access_token: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode client_id=xxx&scope=partner.referrals&client_secret=xxx&grant_type=client_credentials 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | Content-Length: ['151'] 9 | Content-Type: [application/x-www-form-urlencoded] 10 | User-Agent: [python-requests/2.11.1] 11 | method: POST 12 | uri: https://login.uber.com/oauth/v2/token 13 | response: 14 | body: {string: !!python/unicode '{"access_token":"xxx","token_type":"Bearer","last_authenticated":1485210848,"expires_in":2592000,"scope":"partner.referrals"}'} 15 | headers: 16 | cache-control: [no-store, max-age=0] 17 | connection: [keep-alive] 18 | content-length: ['864'] 19 | content-type: [application/json] 20 | date: ['Mon, 23 Jan 2017 22:57:35 GMT'] 21 | pragma: [no-cache] 22 | server: [nginx] 23 | set-cookie: [session=bcbf256d4922c558_58868a5f.wJPhMqR1PV7dIs_zelHBTAesgY8; 24 | Domain=login.uber.com; Secure; HttpOnly; Path=/] 25 | strict-transport-security: [max-age=604800, max-age=2592000] 26 | transfer-encoding: [chunked] 27 | x-content-type-options: [nosniff] 28 | x-frame-options: [SAMEORIGIN] 29 | x-uber-app: [login] 30 | x-xss-protection: [1; mode=block] 31 | status: {code: 200, message: OK} 32 | version: 1 33 | -------------------------------------------------------------------------------- /tests/fixtures/test_request_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 4 | null, "start_address": null, "end_place_id": null, "fare_id": "8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c", 5 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 6 | "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": 7 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 8 | "start_latitude": 37.7899886}' 9 | headers: 10 | Content-Length: ['468'] 11 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 12 | content-type: [application/json] 13 | method: POST 14 | uri: https://sandbox-api.uber.com/v1.2/requests 15 | response: 16 | body: {string: !!python/unicode '{"status":"processing","product_id":"821415d8-3bd5-4e27-9604-194e4359a449","destination":{"latitude":37.775232,"longitude":-122.4197513},"driver":null,"pickup":{"latitude":37.7899886,"longitude":-122.4021253},"request_id":"610d868b-e21c-483a-9932-97e61b852fd2","eta":null,"location":null,"vehicle":null,"shared":false}'} 17 | headers: 18 | connection: [keep-alive] 19 | content-geo-system: [wgs-84] 20 | content-language: [en] 21 | content-length: ['318'] 22 | content-type: [application/json] 23 | date: ['Thu, 20 Oct 2016 08:36:25 GMT'] 24 | server: [nginx] 25 | strict-transport-security: [max-age=0] 26 | x-content-type-options: [nosniff] 27 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 28 | x-xss-protection: [1; mode=block] 29 | status: {code: 202, message: Accepted} 30 | - request: 31 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 32 | null, "start_address": null, "end_place_id": null, "fare_id": "8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c", 33 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 34 | "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": 35 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 36 | "start_latitude": 37.7899886}' 37 | headers: 38 | Content-Length: ['468'] 39 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 40 | content-type: [application/json] 41 | method: POST 42 | uri: https://sandbox-api.uber.com/v1.2/requests 43 | response: 44 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 45 | fare id: 8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c"}]}'} 46 | headers: 47 | connection: [keep-alive] 48 | content-geo-system: [wgs-84] 49 | content-length: ['154'] 50 | content-type: [application/json] 51 | date: ['Thu, 20 Oct 2016 08:41:41 GMT'] 52 | server: [nginx] 53 | strict-transport-security: [max-age=0] 54 | x-content-type-options: [nosniff] 55 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 56 | x-xss-protection: [1; mode=block] 57 | status: {code: 422, message: Unprocessable Entity} 58 | - request: 59 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 60 | null, "start_address": null, "end_place_id": null, "fare_id": "7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264", 61 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 62 | "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": 63 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 64 | "start_latitude": 37.7899886}' 65 | headers: 66 | Content-Length: ['468'] 67 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 68 | content-type: [application/json] 69 | method: POST 70 | uri: https://sandbox-api.uber.com/v1.2/requests 71 | response: 72 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 73 | fare id: 7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264"}]}'} 74 | headers: 75 | connection: [keep-alive] 76 | content-geo-system: [wgs-84] 77 | content-length: ['154'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:48:09 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 422, message: Unprocessable Entity} 86 | - request: 87 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 88 | null, "start_address": null, "end_place_id": null, "fare_id": "7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264", 89 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 90 | "product_id": "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": 91 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 92 | "start_latitude": 37.7899886}' 93 | headers: 94 | Content-Length: ['468'] 95 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 96 | content-type: [application/json] 97 | method: POST 98 | uri: https://sandbox-api.uber.com/v1.2/requests 99 | response: 100 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 101 | fare id: 7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264"}]}'} 102 | headers: 103 | connection: [keep-alive] 104 | content-geo-system: [wgs-84] 105 | content-length: ['154'] 106 | content-type: [application/json] 107 | date: ['Thu, 20 Oct 2016 08:49:35 GMT'] 108 | server: [nginx] 109 | strict-transport-security: [max-age=0] 110 | x-content-type-options: [nosniff] 111 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 112 | x-xss-protection: [1; mode=block] 113 | status: {code: 422, message: Unprocessable Entity} 114 | version: 1 115 | -------------------------------------------------------------------------------- /tests/fixtures/test_request_ride_with_no_default_product: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 4 | null, "start_address": null, "end_place_id": null, "fare_id": "8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c", 5 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 6 | "product_id": null, "seat_count": null, "end_address": null, "end_nickname": 7 | null, "start_place_id": null, "start_longitude": -122.4021253, "start_latitude": 8 | 37.7899886}' 9 | headers: 10 | Content-Length: ['434'] 11 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 12 | content-type: [application/json] 13 | method: POST 14 | uri: https://sandbox-api.uber.com/v1.2/requests 15 | response: 16 | body: {string: !!python/unicode '{"status":"processing","product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d","destination":{"latitude":37.775232,"longitude":-122.4197513},"driver":null,"pickup":{"latitude":37.7899886,"longitude":-122.4021253},"request_id":"610d868b-e21c-483a-9932-97e61b852fd2","eta":null,"location":null,"vehicle":null,"shared":false}'} 17 | headers: 18 | connection: [keep-alive] 19 | content-geo-system: [wgs-84] 20 | content-language: [en] 21 | content-length: ['318'] 22 | content-type: [application/json] 23 | date: ['Thu, 20 Oct 2016 08:36:26 GMT'] 24 | server: [nginx] 25 | strict-transport-security: [max-age=0] 26 | x-content-type-options: [nosniff] 27 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 28 | x-xss-protection: [1; mode=block] 29 | status: {code: 202, message: Accepted} 30 | - request: 31 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 32 | null, "start_address": null, "end_place_id": null, "fare_id": "8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c", 33 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 34 | "product_id": null, "seat_count": null, "end_address": null, "end_nickname": 35 | null, "start_place_id": null, "start_longitude": -122.4021253, "start_latitude": 36 | 37.7899886}' 37 | headers: 38 | Content-Length: ['434'] 39 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 40 | content-type: [application/json] 41 | method: POST 42 | uri: https://sandbox-api.uber.com/v1.2/requests 43 | response: 44 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 45 | fare id: 8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c"}]}'} 46 | headers: 47 | connection: [keep-alive] 48 | content-geo-system: [wgs-84] 49 | content-length: ['154'] 50 | content-type: [application/json] 51 | date: ['Thu, 20 Oct 2016 08:41:42 GMT'] 52 | server: [nginx] 53 | strict-transport-security: [max-age=0] 54 | x-content-type-options: [nosniff] 55 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 56 | x-xss-protection: [1; mode=block] 57 | status: {code: 422, message: Unprocessable Entity} 58 | - request: 59 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 60 | null, "start_address": null, "end_place_id": null, "fare_id": "7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264", 61 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 62 | "product_id": null, "seat_count": null, "end_address": null, "end_nickname": 63 | null, "start_place_id": null, "start_longitude": -122.4021253, "start_latitude": 64 | 37.7899886}' 65 | headers: 66 | Content-Length: ['434'] 67 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 68 | content-type: [application/json] 69 | method: POST 70 | uri: https://sandbox-api.uber.com/v1.2/requests 71 | response: 72 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 73 | fare id: 7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264"}]}'} 74 | headers: 75 | connection: [keep-alive] 76 | content-geo-system: [wgs-84] 77 | content-length: ['154'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:48:10 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 422, message: Unprocessable Entity} 86 | - request: 87 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 88 | null, "start_address": null, "end_place_id": null, "fare_id": "7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264", 89 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 90 | "product_id": null, "seat_count": null, "end_address": null, "end_nickname": 91 | null, "start_place_id": null, "start_longitude": -122.4021253, "start_latitude": 92 | 37.7899886}' 93 | headers: 94 | Content-Length: ['434'] 95 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 96 | content-type: [application/json] 97 | method: POST 98 | uri: https://sandbox-api.uber.com/v1.2/requests 99 | response: 100 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 101 | fare id: 7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264"}]}'} 102 | headers: 103 | connection: [keep-alive] 104 | content-geo-system: [wgs-84] 105 | content-length: ['154'] 106 | content-type: [application/json] 107 | date: ['Thu, 20 Oct 2016 08:49:36 GMT'] 108 | server: [nginx] 109 | strict-transport-security: [max-age=0] 110 | x-content-type-options: [nosniff] 111 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 112 | x-xss-protection: [1; mode=block] 113 | status: {code: 422, message: Unprocessable Entity} 114 | version: 1 115 | -------------------------------------------------------------------------------- /tests/fixtures/test_request_ride_with_places: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_longitude": null, "surge_confirmation_id": null, 4 | "start_address": null, "end_place_id": "work", "fare_id": "8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c", 5 | "start_nickname": null, "end_latitude": null, "payment_method_id": null, "product_id": 6 | "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": null, 7 | "end_nickname": null, "start_place_id": "home", "start_longitude": null, "start_latitude": 8 | null}' 9 | headers: 10 | Content-Length: ['445'] 11 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 12 | content-type: [application/json] 13 | method: POST 14 | uri: https://sandbox-api.uber.com/v1.2/requests 15 | response: 16 | body: {string: !!python/unicode '{"status":"processing","product_id":"821415d8-3bd5-4e27-9604-194e4359a449","destination":{"latitude":37.775232,"longitude":-122.4197513},"driver":null,"pickup":{"latitude":37.7899886,"longitude":-122.4021253},"request_id":"610d868b-e21c-483a-9932-97e61b852fd2","eta":null,"location":null,"vehicle":null,"shared":false}'} 17 | headers: 18 | connection: [keep-alive] 19 | content-geo-system: [wgs-84] 20 | content-language: [en] 21 | content-length: ['318'] 22 | content-type: [application/json] 23 | date: ['Thu, 20 Oct 2016 08:36:27 GMT'] 24 | server: [nginx] 25 | strict-transport-security: [max-age=0] 26 | x-content-type-options: [nosniff] 27 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 28 | x-xss-protection: [1; mode=block] 29 | status: {code: 202, message: Accepted} 30 | - request: 31 | body: !!python/unicode '{"end_longitude": null, "surge_confirmation_id": null, 32 | "start_address": null, "end_place_id": "work", "fare_id": "8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c", 33 | "start_nickname": null, "end_latitude": null, "payment_method_id": null, "product_id": 34 | "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": null, 35 | "end_nickname": null, "start_place_id": "home", "start_longitude": null, "start_latitude": 36 | null}' 37 | headers: 38 | Content-Length: ['445'] 39 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 40 | content-type: [application/json] 41 | method: POST 42 | uri: https://sandbox-api.uber.com/v1.2/requests 43 | response: 44 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 45 | fare id: 8692d3a4e304b6071b1f6a8b64efa9546e327e79de1ba428a4829a00246d527c"}]}'} 46 | headers: 47 | connection: [keep-alive] 48 | content-geo-system: [wgs-84] 49 | content-length: ['154'] 50 | content-type: [application/json] 51 | date: ['Thu, 20 Oct 2016 08:41:42 GMT'] 52 | server: [nginx] 53 | strict-transport-security: [max-age=0] 54 | x-content-type-options: [nosniff] 55 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 56 | x-xss-protection: [1; mode=block] 57 | status: {code: 422, message: Unprocessable Entity} 58 | - request: 59 | body: !!python/unicode '{"end_longitude": null, "surge_confirmation_id": null, 60 | "start_address": null, "end_place_id": "work", "fare_id": "7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264", 61 | "start_nickname": null, "end_latitude": null, "payment_method_id": null, "product_id": 62 | "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": null, 63 | "end_nickname": null, "start_place_id": "home", "start_longitude": null, "start_latitude": 64 | null}' 65 | headers: 66 | Content-Length: ['445'] 67 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 68 | content-type: [application/json] 69 | method: POST 70 | uri: https://sandbox-api.uber.com/v1.2/requests 71 | response: 72 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 73 | fare id: 7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264"}]}'} 74 | headers: 75 | connection: [keep-alive] 76 | content-geo-system: [wgs-84] 77 | content-length: ['154'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:48:11 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 422, message: Unprocessable Entity} 86 | - request: 87 | body: !!python/unicode '{"end_longitude": null, "surge_confirmation_id": null, 88 | "start_address": null, "end_place_id": "work", "fare_id": "7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264", 89 | "start_nickname": null, "end_latitude": null, "payment_method_id": null, "product_id": 90 | "821415d8-3bd5-4e27-9604-194e4359a449", "seat_count": null, "end_address": null, 91 | "end_nickname": null, "start_place_id": "home", "start_longitude": null, "start_latitude": 92 | null}' 93 | headers: 94 | Content-Length: ['445'] 95 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 96 | content-type: [application/json] 97 | method: POST 98 | uri: https://sandbox-api.uber.com/v1.2/requests 99 | response: 100 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 101 | fare id: 7dad38f13eab3124621d16604c35fb26e30395e76937c507565fb1b4aa4a8264"}]}'} 102 | headers: 103 | connection: [keep-alive] 104 | content-geo-system: [wgs-84] 105 | content-length: ['154'] 106 | content-type: [application/json] 107 | date: ['Thu, 20 Oct 2016 08:49:37 GMT'] 108 | server: [nginx] 109 | strict-transport-security: [max-age=0] 110 | x-content-type-options: [nosniff] 111 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 112 | x-xss-protection: [1; mode=block] 113 | status: {code: 422, message: Unprocessable Entity} 114 | version: 1 115 | -------------------------------------------------------------------------------- /tests/fixtures/test_request_ride_with_surge: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_longitude": -43.1925661, "surge_confirmation_id": 4 | null, "start_address": null, "end_place_id": null, "fare_id": null, "start_nickname": 5 | null, "end_latitude": -22.9883286, "payment_method_id": null, "product_id": 6 | "d5ef01d9-7d54-413e-b265-425948d06e92", "seat_count": null, "end_address": null, 7 | "end_nickname": null, "start_place_id": null, "start_longitude": -43.1801978, 8 | "start_latitude": -22.9674153}' 9 | headers: 10 | Content-Length: ['407'] 11 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 12 | content-type: [application/json] 13 | method: POST 14 | uri: https://sandbox-api.uber.com/v1.2/requests 15 | response: 16 | body: {string: !!python/unicode '{"meta":{"surge_confirmation":{"href":"https:\/\/sandbox-api.uber.com\/surge-confirmations\/2674678f-c07e-4161-b4c8-17b13a985036","expires_at":1476953606,"multiplier":2.0,"surge_confirmation_id":"2674678f-c07e-4161-b4c8-17b13a985036"}},"errors":[{"status":409,"code":"surge","title":"Surge 17 | pricing is currently in effect for this product."}]}'} 18 | headers: 19 | connection: [keep-alive] 20 | content-geo-system: [wgs-84] 21 | content-length: ['342'] 22 | content-type: [application/json] 23 | date: ['Thu, 20 Oct 2016 08:51:26 GMT'] 24 | server: [nginx] 25 | strict-transport-security: [max-age=0] 26 | x-content-type-options: [nosniff] 27 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 28 | x-xss-protection: [1; mode=block] 29 | status: {code: 409, message: Conflict} 30 | version: 1 31 | -------------------------------------------------------------------------------- /tests/fixtures/test_request_shared_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 4 | null, "start_address": null, "end_place_id": null, "fare_id": "eab9a73fe7f9bf7e9c4e0df27c112635a195b8b00b1305766ebd91132fa47719", 5 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 6 | "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "seat_count": 2, "end_address": 7 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 8 | "start_latitude": 37.7899886}' 9 | headers: 10 | Content-Length: ['465'] 11 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 12 | content-type: [application/json] 13 | method: POST 14 | uri: https://sandbox-api.uber.com/v1.2/requests 15 | response: 16 | body: {string: !!python/unicode '{"status":"processing","product_id":"26546650-e557-4a7b-86e7-6a3942445247","destination":{"latitude":37.775232,"longitude":-122.4197513},"driver":null,"pickup":{"latitude":37.7899886,"longitude":-122.4021253},"request_id":"610d868b-e21c-483a-9932-97e61b852fd2","eta":null,"location":null,"vehicle":null,"shared":false}'} 17 | headers: 18 | connection: [keep-alive] 19 | content-geo-system: [wgs-84] 20 | content-language: [en] 21 | content-length: ['318'] 22 | content-type: [application/json] 23 | date: ['Thu, 20 Oct 2016 08:36:25 GMT'] 24 | server: [nginx] 25 | strict-transport-security: [max-age=0] 26 | x-content-type-options: [nosniff] 27 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 28 | x-xss-protection: [1; mode=block] 29 | status: {code: 202, message: Accepted} 30 | - request: 31 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 32 | null, "start_address": null, "end_place_id": null, "fare_id": "eab9a73fe7f9bf7e9c4e0df27c112635a195b8b00b1305766ebd91132fa47719", 33 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 34 | "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "seat_count": 2, "end_address": 35 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 36 | "start_latitude": 37.7899886}' 37 | headers: 38 | Content-Length: ['465'] 39 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 40 | content-type: [application/json] 41 | method: POST 42 | uri: https://sandbox-api.uber.com/v1.2/requests 43 | response: 44 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 45 | fare id: eab9a73fe7f9bf7e9c4e0df27c112635a195b8b00b1305766ebd91132fa47719"}]}'} 46 | headers: 47 | connection: [keep-alive] 48 | content-geo-system: [wgs-84] 49 | content-length: ['154'] 50 | content-type: [application/json] 51 | date: ['Thu, 20 Oct 2016 08:41:41 GMT'] 52 | server: [nginx] 53 | strict-transport-security: [max-age=0] 54 | x-content-type-options: [nosniff] 55 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 56 | x-xss-protection: [1; mode=block] 57 | status: {code: 422, message: Unprocessable Entity} 58 | - request: 59 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 60 | null, "start_address": null, "end_place_id": null, "fare_id": "d30e732b8bba22c9cdc10513ee86380087cb4a6f89e37ad21ba2a39f3a1ba960", 61 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 62 | "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "seat_count": 2, "end_address": 63 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 64 | "start_latitude": 37.7899886}' 65 | headers: 66 | Content-Length: ['465'] 67 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 68 | content-type: [application/json] 69 | method: POST 70 | uri: https://sandbox-api.uber.com/v1.2/requests 71 | response: 72 | body: {string: !!python/unicode '{"status":"processing","product_id":"26546650-e557-4a7b-86e7-6a3942445247","destination":{"latitude":37.7899886,"longitude":-122.4021253},"driver":null,"pickup":{"latitude":37.775232,"longitude":-122.4197513},"request_id":"0aec0061-1e20-4239-a0b7-78328e9afec8","eta":null,"location":null,"vehicle":null,"shared":false}'} 73 | headers: 74 | connection: [keep-alive] 75 | content-geo-system: [wgs-84] 76 | content-language: [en] 77 | content-length: ['318'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:48:09 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 202, message: Accepted} 86 | - request: 87 | body: !!python/unicode '{"end_longitude": -122.4197513, "surge_confirmation_id": 88 | null, "start_address": null, "end_place_id": null, "fare_id": "d30e732b8bba22c9cdc10513ee86380087cb4a6f89e37ad21ba2a39f3a1ba960", 89 | "start_nickname": null, "end_latitude": 37.775232, "payment_method_id": null, 90 | "product_id": "26546650-e557-4a7b-86e7-6a3942445247", "seat_count": 2, "end_address": 91 | null, "end_nickname": null, "start_place_id": null, "start_longitude": -122.4021253, 92 | "start_latitude": 37.7899886}' 93 | headers: 94 | Content-Length: ['465'] 95 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 96 | content-type: [application/json] 97 | method: POST 98 | uri: https://sandbox-api.uber.com/v1.2/requests 99 | response: 100 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":422,"code":"invalid_fare_id","title":"Invalid 101 | fare id: d30e732b8bba22c9cdc10513ee86380087cb4a6f89e37ad21ba2a39f3a1ba960"}]}'} 102 | headers: 103 | connection: [keep-alive] 104 | content-geo-system: [wgs-84] 105 | content-length: ['154'] 106 | content-type: [application/json] 107 | date: ['Thu, 20 Oct 2016 08:49:35 GMT'] 108 | server: [nginx] 109 | strict-transport-security: [max-age=0] 110 | x-content-type-options: [nosniff] 111 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 112 | x-xss-protection: [1; mode=block] 113 | status: {code: 422, message: Unprocessable Entity} 114 | version: 1 115 | -------------------------------------------------------------------------------- /tests/fixtures/test_set_home_address: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"address": "555 Market Street, SF"}' 4 | headers: 5 | Content-Length: ['36'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | content-type: [application/json] 8 | method: PUT 9 | uri: https://sandbox-api.uber.com/v1.2/places/home 10 | response: 11 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 12 | 94105, USA"}'} 13 | headers: 14 | connection: [keep-alive] 15 | content-language: [en] 16 | content-length: ['57'] 17 | content-type: [application/json] 18 | date: ['Thu, 20 Oct 2016 08:36:31 GMT'] 19 | server: [nginx] 20 | strict-transport-security: [max-age=0] 21 | x-content-type-options: [nosniff] 22 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 23 | x-xss-protection: [1; mode=block] 24 | status: {code: 200, message: OK} 25 | - request: 26 | body: !!python/unicode '{"address": "555 Market Street, SF"}' 27 | headers: 28 | Content-Length: ['36'] 29 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 30 | content-type: [application/json] 31 | method: PUT 32 | uri: https://sandbox-api.uber.com/v1.2/places/home 33 | response: 34 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 35 | 94105, USA"}'} 36 | headers: 37 | connection: [keep-alive] 38 | content-language: [en] 39 | content-length: ['57'] 40 | content-type: [application/json] 41 | date: ['Thu, 20 Oct 2016 08:41:47 GMT'] 42 | server: [nginx] 43 | strict-transport-security: [max-age=0] 44 | x-content-type-options: [nosniff] 45 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 46 | x-xss-protection: [1; mode=block] 47 | status: {code: 200, message: OK} 48 | - request: 49 | body: !!python/unicode '{"address": "555 Market Street, SF"}' 50 | headers: 51 | Content-Length: ['36'] 52 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 53 | content-type: [application/json] 54 | method: PUT 55 | uri: https://sandbox-api.uber.com/v1.2/places/home 56 | response: 57 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 58 | 94105, USA"}'} 59 | headers: 60 | connection: [keep-alive] 61 | content-language: [en] 62 | content-length: ['57'] 63 | content-type: [application/json] 64 | date: ['Thu, 20 Oct 2016 08:48:15 GMT'] 65 | server: [nginx] 66 | strict-transport-security: [max-age=0] 67 | x-content-type-options: [nosniff] 68 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 69 | x-xss-protection: [1; mode=block] 70 | status: {code: 200, message: OK} 71 | - request: 72 | body: !!python/unicode '{"address": "555 Market Street, SF"}' 73 | headers: 74 | Content-Length: ['36'] 75 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 76 | content-type: [application/json] 77 | method: PUT 78 | uri: https://sandbox-api.uber.com/v1.2/places/home 79 | response: 80 | body: {string: !!python/unicode '{"address":"555 Market St, San Francisco, CA 81 | 94105, USA"}'} 82 | headers: 83 | connection: [keep-alive] 84 | content-language: [en] 85 | content-length: ['57'] 86 | content-type: [application/json] 87 | date: ['Thu, 20 Oct 2016 08:49:41 GMT'] 88 | server: [nginx] 89 | strict-transport-security: [max-age=0] 90 | x-content-type-options: [nosniff] 91 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 92 | x-xss-protection: [1; mode=block] 93 | status: {code: 200, message: OK} 94 | version: 1 95 | -------------------------------------------------------------------------------- /tests/fixtures/test_set_work_address: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"address": "1455 Market Street, SF"}' 4 | headers: 5 | Content-Length: ['37'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | content-type: [application/json] 8 | method: PUT 9 | uri: https://sandbox-api.uber.com/v1.2/places/work 10 | response: 11 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 12 | 94103, USA"}'} 13 | headers: 14 | connection: [keep-alive] 15 | content-language: [en] 16 | content-length: ['58'] 17 | content-type: [application/json] 18 | date: ['Thu, 20 Oct 2016 08:36:31 GMT'] 19 | server: [nginx] 20 | strict-transport-security: [max-age=0] 21 | x-content-type-options: [nosniff] 22 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 23 | x-xss-protection: [1; mode=block] 24 | status: {code: 200, message: OK} 25 | - request: 26 | body: !!python/unicode '{"address": "1455 Market Street, SF"}' 27 | headers: 28 | Content-Length: ['37'] 29 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 30 | content-type: [application/json] 31 | method: PUT 32 | uri: https://sandbox-api.uber.com/v1.2/places/work 33 | response: 34 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 35 | 94103, USA"}'} 36 | headers: 37 | connection: [keep-alive] 38 | content-language: [en] 39 | content-length: ['58'] 40 | content-type: [application/json] 41 | date: ['Thu, 20 Oct 2016 08:41:48 GMT'] 42 | server: [nginx] 43 | strict-transport-security: [max-age=0] 44 | x-content-type-options: [nosniff] 45 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 46 | x-xss-protection: [1; mode=block] 47 | status: {code: 200, message: OK} 48 | - request: 49 | body: !!python/unicode '{"address": "1455 Market Street, SF"}' 50 | headers: 51 | Content-Length: ['37'] 52 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 53 | content-type: [application/json] 54 | method: PUT 55 | uri: https://sandbox-api.uber.com/v1.2/places/work 56 | response: 57 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 58 | 94103, USA"}'} 59 | headers: 60 | connection: [keep-alive] 61 | content-language: [en] 62 | content-length: ['58'] 63 | content-type: [application/json] 64 | date: ['Thu, 20 Oct 2016 08:48:16 GMT'] 65 | server: [nginx] 66 | strict-transport-security: [max-age=0] 67 | x-content-type-options: [nosniff] 68 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 69 | x-xss-protection: [1; mode=block] 70 | status: {code: 200, message: OK} 71 | - request: 72 | body: !!python/unicode '{"address": "1455 Market Street, SF"}' 73 | headers: 74 | Content-Length: ['37'] 75 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 76 | content-type: [application/json] 77 | method: PUT 78 | uri: https://sandbox-api.uber.com/v1.2/places/work 79 | response: 80 | body: {string: !!python/unicode '{"address":"1455 Market St, San Francisco, CA 81 | 94103, USA"}'} 82 | headers: 83 | connection: [keep-alive] 84 | content-language: [en] 85 | content-length: ['58'] 86 | content-type: [application/json] 87 | date: ['Thu, 20 Oct 2016 08:49:42 GMT'] 88 | server: [nginx] 89 | strict-transport-security: [max-age=0] 90 | x-content-type-options: [nosniff] 91 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 92 | x-xss-protection: [1; mode=block] 93 | status: {code: 200, message: OK} 94 | version: 1 95 | -------------------------------------------------------------------------------- /tests/fixtures/test_update_ride_destination: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_longitude": -122.4197515, "end_latitude": 37.775234}' 4 | headers: 5 | Content-Length: ['58'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | content-type: [application/json] 8 | method: PATCH 9 | uri: https://sandbox-api.uber.com/v1.2/requests/9bdb3278-21bd-46b8-90fa-51404b0d6acf 10 | response: 11 | body: {string: !!python/unicode '{"message":"Forbidden","code":"forbidden"}'} 12 | headers: 13 | connection: [keep-alive] 14 | content-geo-system: [wgs-84] 15 | content-length: ['42'] 16 | content-type: [application/json] 17 | date: ['Thu, 20 Oct 2016 08:36:28 GMT'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 403, message: Forbidden} 24 | - request: 25 | body: !!python/unicode '{"end_longitude": -122.4197515, "end_latitude": 37.775234}' 26 | headers: 27 | Content-Length: ['58'] 28 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 29 | content-type: [application/json] 30 | method: PATCH 31 | uri: https://sandbox-api.uber.com/v1.2/requests/610d868b-e21c-483a-9932-97e61b852fd2 32 | response: 33 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"trip_not_found","title":"Trip 34 | not found."}]}'} 35 | headers: 36 | connection: [keep-alive] 37 | content-geo-system: [wgs-84] 38 | content-length: ['87'] 39 | content-type: [application/json] 40 | date: ['Thu, 20 Oct 2016 08:41:44 GMT'] 41 | server: [nginx] 42 | strict-transport-security: [max-age=0] 43 | x-content-type-options: [nosniff] 44 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 45 | x-xss-protection: [1; mode=block] 46 | status: {code: 404, message: Not Found} 47 | - request: 48 | body: !!python/unicode '{"end_longitude": -122.4197515, "end_latitude": 37.775234}' 49 | headers: 50 | Content-Length: ['58'] 51 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 52 | content-type: [application/json] 53 | method: PATCH 54 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 55 | response: 56 | body: {string: !!python/unicode ''} 57 | headers: 58 | connection: [keep-alive] 59 | content-language: [en] 60 | content-type: [text/html; charset=UTF-8] 61 | date: ['Thu, 20 Oct 2016 08:48:12 GMT'] 62 | server: [nginx] 63 | strict-transport-security: [max-age=0] 64 | x-content-type-options: [nosniff] 65 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 66 | x-xss-protection: [1; mode=block] 67 | status: {code: 204, message: No Content} 68 | - request: 69 | body: !!python/unicode '{"end_longitude": -122.4197515, "end_latitude": 37.775234}' 70 | headers: 71 | Content-Length: ['58'] 72 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 73 | content-type: [application/json] 74 | method: PATCH 75 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 76 | response: 77 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"trip_not_found","title":"Trip 78 | not found."}]}'} 79 | headers: 80 | connection: [keep-alive] 81 | content-geo-system: [wgs-84] 82 | content-length: ['87'] 83 | content-type: [application/json] 84 | date: ['Thu, 20 Oct 2016 08:49:38 GMT'] 85 | server: [nginx] 86 | strict-transport-security: [max-age=0] 87 | x-content-type-options: [nosniff] 88 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 89 | x-xss-protection: [1; mode=block] 90 | status: {code: 404, message: Not Found} 91 | version: 1 92 | -------------------------------------------------------------------------------- /tests/fixtures/test_update_ride_destination_with_places: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"end_place_id": "work"}' 4 | headers: 5 | Content-Length: ['24'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | content-type: [application/json] 8 | method: PATCH 9 | uri: https://sandbox-api.uber.com/v1.2/requests/9bdb3278-21bd-46b8-90fa-51404b0d6acf 10 | response: 11 | body: {string: !!python/unicode '{"message":"Forbidden","code":"forbidden"}'} 12 | headers: 13 | connection: [keep-alive] 14 | content-geo-system: [wgs-84] 15 | content-length: ['42'] 16 | content-type: [application/json] 17 | date: ['Thu, 20 Oct 2016 08:36:28 GMT'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=0] 20 | x-content-type-options: [nosniff] 21 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 22 | x-xss-protection: [1; mode=block] 23 | status: {code: 403, message: Forbidden} 24 | - request: 25 | body: !!python/unicode '{"end_place_id": "work"}' 26 | headers: 27 | Content-Length: ['24'] 28 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 29 | content-type: [application/json] 30 | method: PATCH 31 | uri: https://sandbox-api.uber.com/v1.2/requests/610d868b-e21c-483a-9932-97e61b852fd2 32 | response: 33 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"trip_not_found","title":"Trip 34 | not found."}]}'} 35 | headers: 36 | connection: [keep-alive] 37 | content-geo-system: [wgs-84] 38 | content-length: ['87'] 39 | content-type: [application/json] 40 | date: ['Thu, 20 Oct 2016 08:41:44 GMT'] 41 | server: [nginx] 42 | strict-transport-security: [max-age=0] 43 | x-content-type-options: [nosniff] 44 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 45 | x-xss-protection: [1; mode=block] 46 | status: {code: 404, message: Not Found} 47 | - request: 48 | body: !!python/unicode '{"end_place_id": "work"}' 49 | headers: 50 | Content-Length: ['24'] 51 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 52 | content-type: [application/json] 53 | method: PATCH 54 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 55 | response: 56 | body: {string: !!python/unicode ''} 57 | headers: 58 | connection: [keep-alive] 59 | content-language: [en] 60 | content-type: [text/html; charset=UTF-8] 61 | date: ['Thu, 20 Oct 2016 08:48:13 GMT'] 62 | server: [nginx] 63 | strict-transport-security: [max-age=0] 64 | x-content-type-options: [nosniff] 65 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 66 | x-xss-protection: [1; mode=block] 67 | status: {code: 204, message: No Content} 68 | - request: 69 | body: !!python/unicode '{"end_place_id": "work"}' 70 | headers: 71 | Content-Length: ['24'] 72 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 73 | content-type: [application/json] 74 | method: PATCH 75 | uri: https://sandbox-api.uber.com/v1.2/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 76 | response: 77 | body: {string: !!python/unicode '{"meta":{},"errors":[{"status":404,"code":"trip_not_found","title":"Trip 78 | not found."}]}'} 79 | headers: 80 | connection: [keep-alive] 81 | content-geo-system: [wgs-84] 82 | content-length: ['87'] 83 | content-type: [application/json] 84 | date: ['Thu, 20 Oct 2016 08:49:38 GMT'] 85 | server: [nginx] 86 | strict-transport-security: [max-age=0] 87 | x-content-type-options: [nosniff] 88 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 89 | x-xss-protection: [1; mode=block] 90 | status: {code: 404, message: Not Found} 91 | version: 1 92 | -------------------------------------------------------------------------------- /tests/fixtures/test_update_sandbox_driver_trips: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"trips": []}' 4 | headers: 5 | Content-Length: ['13'] 6 | X-Uber-User-Agent: [!!python/unicode 'Python Rides SDK v0.6.0'] 7 | content-type: [application/json] 8 | method: PUT 9 | uri: https://sandbox-api.uber.com/v1/sandbox/partners/trips 10 | response: 11 | body: {string: !!python/unicode ''} 12 | headers: 13 | cache-control: [max-age=0] 14 | connection: [keep-alive] 15 | content-language: [en] 16 | content-type: [text/html; charset=UTF-8] 17 | date: ['Fri, 15 Sep 2017 00:09:51 GMT'] 18 | server: [nginx] 19 | strict-transport-security: [max-age=604800, max-age=2592000] 20 | x-content-type-options: [nosniff] 21 | x-frame-options: [SAMEORIGIN] 22 | x-rate-limit-limit: ['2000'] 23 | x-rate-limit-remaining: ['1992'] 24 | x-rate-limit-reset: ['1505437200'] 25 | x-uber-app: [uberex-sandbox, optimus] 26 | x-xss-protection: [1; mode=block] 27 | status: {code: 204, message: No Content} 28 | version: 1 29 | -------------------------------------------------------------------------------- /tests/fixtures/test_update_sandbox_product: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"surge_multiplier": 2, "drivers_available": null}' 4 | headers: 5 | Content-Length: ['50'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | content-type: [application/json] 8 | method: PUT 9 | uri: https://sandbox-api.uber.com/v1.2/sandbox/products/d5ef01d9-7d54-413e-b265-425948d06e92 10 | response: 11 | body: {string: !!python/unicode ''} 12 | headers: 13 | connection: [keep-alive] 14 | content-language: [en] 15 | content-type: [text/html; charset=UTF-8] 16 | date: ['Thu, 20 Oct 2016 08:36:30 GMT'] 17 | server: [nginx] 18 | strict-transport-security: [max-age=0] 19 | x-content-type-options: [nosniff] 20 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 21 | x-xss-protection: [1; mode=block] 22 | status: {code: 204, message: No Content} 23 | - request: 24 | body: !!python/unicode '{"surge_multiplier": 2, "drivers_available": null}' 25 | headers: 26 | Content-Length: ['50'] 27 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 28 | content-type: [application/json] 29 | method: PUT 30 | uri: https://sandbox-api.uber.com/v1.2/sandbox/products/d5ef01d9-7d54-413e-b265-425948d06e92 31 | response: 32 | body: {string: !!python/unicode ''} 33 | headers: 34 | connection: [keep-alive] 35 | content-language: [en] 36 | content-type: [text/html; charset=UTF-8] 37 | date: ['Thu, 20 Oct 2016 08:41:46 GMT'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 204, message: No Content} 44 | - request: 45 | body: !!python/unicode '{"surge_multiplier": 2, "drivers_available": null}' 46 | headers: 47 | Content-Length: ['50'] 48 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 49 | content-type: [application/json] 50 | method: PUT 51 | uri: https://sandbox-api.uber.com/v1.2/sandbox/products/d5ef01d9-7d54-413e-b265-425948d06e92 52 | response: 53 | body: {string: !!python/unicode ''} 54 | headers: 55 | connection: [keep-alive] 56 | content-language: [en] 57 | content-type: [text/html; charset=UTF-8] 58 | date: ['Thu, 20 Oct 2016 08:48:14 GMT'] 59 | server: [nginx] 60 | strict-transport-security: [max-age=0] 61 | x-content-type-options: [nosniff] 62 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 63 | x-xss-protection: [1; mode=block] 64 | status: {code: 204, message: No Content} 65 | - request: 66 | body: !!python/unicode '{"surge_multiplier": 2, "drivers_available": null}' 67 | headers: 68 | Content-Length: ['50'] 69 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 70 | content-type: [application/json] 71 | method: PUT 72 | uri: https://sandbox-api.uber.com/v1.2/sandbox/products/d5ef01d9-7d54-413e-b265-425948d06e92 73 | response: 74 | body: {string: !!python/unicode ''} 75 | headers: 76 | connection: [keep-alive] 77 | content-language: [en] 78 | content-type: [text/html; charset=UTF-8] 79 | date: ['Thu, 20 Oct 2016 08:49:40 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 204, message: No Content} 86 | version: 1 87 | -------------------------------------------------------------------------------- /tests/fixtures/test_update_sandbox_ride: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: !!python/unicode '{"status": "accepted"}' 4 | headers: 5 | Content-Length: ['22'] 6 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 7 | content-type: [application/json] 8 | method: PUT 9 | uri: https://sandbox-api.uber.com/v1.2/sandbox/requests/9bdb3278-21bd-46b8-90fa-51404b0d6acf 10 | response: 11 | body: {string: !!python/unicode '{"message":"No trip with id=9bdb3278-21bd-46b8-90fa-51404b0d6acf","code":"not_found"}'} 12 | headers: 13 | connection: [keep-alive] 14 | content-length: ['85'] 15 | content-type: [application/json] 16 | date: ['Thu, 20 Oct 2016 08:36:29 GMT'] 17 | server: [nginx] 18 | strict-transport-security: [max-age=0] 19 | x-content-type-options: [nosniff] 20 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 21 | x-xss-protection: [1; mode=block] 22 | status: {code: 404, message: Not Found} 23 | - request: 24 | body: !!python/unicode '{"status": "accepted"}' 25 | headers: 26 | Content-Length: ['22'] 27 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 28 | content-type: [application/json] 29 | method: PUT 30 | uri: https://sandbox-api.uber.com/v1.2/sandbox/requests/610d868b-e21c-483a-9932-97e61b852fd2 31 | response: 32 | body: {string: !!python/unicode '{"message":"No trip with id=610d868b-e21c-483a-9932-97e61b852fd2","code":"not_found"}'} 33 | headers: 34 | connection: [keep-alive] 35 | content-length: ['85'] 36 | content-type: [application/json] 37 | date: ['Thu, 20 Oct 2016 08:41:45 GMT'] 38 | server: [nginx] 39 | strict-transport-security: [max-age=0] 40 | x-content-type-options: [nosniff] 41 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 42 | x-xss-protection: [1; mode=block] 43 | status: {code: 404, message: Not Found} 44 | - request: 45 | body: !!python/unicode '{"status": "accepted"}' 46 | headers: 47 | Content-Length: ['22'] 48 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 49 | content-type: [application/json] 50 | method: PUT 51 | uri: https://sandbox-api.uber.com/v1.2/sandbox/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 52 | response: 53 | body: {string: !!python/unicode ''} 54 | headers: 55 | connection: [keep-alive] 56 | content-language: [en] 57 | content-type: [text/html; charset=UTF-8] 58 | date: ['Thu, 20 Oct 2016 08:48:13 GMT'] 59 | server: [nginx] 60 | strict-transport-security: [max-age=0] 61 | x-content-type-options: [nosniff] 62 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 63 | x-xss-protection: [1; mode=block] 64 | status: {code: 204, message: No Content} 65 | - request: 66 | body: !!python/unicode '{"status": "accepted"}' 67 | headers: 68 | Content-Length: ['22'] 69 | X-Uber-User-Agent: [!!python/unicode Python Rides SDK v0.6.0] 70 | content-type: [application/json] 71 | method: PUT 72 | uri: https://sandbox-api.uber.com/v1.2/sandbox/requests/0aec0061-1e20-4239-a0b7-78328e9afec8 73 | response: 74 | body: {string: !!python/unicode '{"message":"No trip with id=0aec0061-1e20-4239-a0b7-78328e9afec8","code":"not_found"}'} 75 | headers: 76 | connection: [keep-alive] 77 | content-length: ['85'] 78 | content-type: [application/json] 79 | date: ['Thu, 20 Oct 2016 08:49:39 GMT'] 80 | server: [nginx] 81 | strict-transport-security: [max-age=0] 82 | x-content-type-options: [nosniff] 83 | x-uber-app: [uberex-sandbox, migrator-uberex-sandbox-optimus] 84 | x-xss-protection: [1; mode=block] 85 | status: {code: 404, message: Not Found} 86 | version: 1 87 | -------------------------------------------------------------------------------- /tests/test_request_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import 22 | from __future__ import division 23 | from __future__ import print_function 24 | from __future__ import unicode_literals 25 | 26 | from collections import OrderedDict 27 | 28 | from pytest import fixture 29 | 30 | from uber_rides.utils.request import build_url 31 | from uber_rides.utils.request import generate_data 32 | 33 | 34 | LAT = 37.775232 35 | LNG = -122.4197513 36 | HOST = 'api.uber.com' 37 | DEFAULT_TARGET = 'v1.2/products' 38 | SPECIAL_CHAR_TARGET = 'v1.2/~products' 39 | DEFAULT_BASE_URL = 'https://api.uber.com/v1.2/products' 40 | 41 | 42 | @fixture 43 | def default_http_arguments_as_json(): 44 | return OrderedDict([ 45 | ('latitude', LAT), 46 | ('longitude', LNG), 47 | ]) 48 | 49 | 50 | @fixture 51 | def default_http_arguments_as_string(): 52 | return '{{"latitude": {}, "longitude": {}}}'.format(LAT, LNG) 53 | 54 | 55 | def test_generate_data_with_POST( 56 | default_http_arguments_as_json, 57 | default_http_arguments_as_string, 58 | ): 59 | """Assign arguments to body of request in POST.""" 60 | data, params = generate_data('POST', default_http_arguments_as_json) 61 | assert not params 62 | assert data == default_http_arguments_as_string 63 | 64 | 65 | def test_generate_data_with_PATCH( 66 | default_http_arguments_as_json, 67 | default_http_arguments_as_string, 68 | ): 69 | """Assign arguments to body of request in PATCH.""" 70 | data, params = generate_data('PATCH', default_http_arguments_as_json) 71 | assert not params 72 | assert data == default_http_arguments_as_string 73 | 74 | 75 | def test_generate_data_with_PUT( 76 | default_http_arguments_as_json, 77 | default_http_arguments_as_string, 78 | ): 79 | """Assign arguments to body of request in PUT.""" 80 | data, params = generate_data('PUT', default_http_arguments_as_json) 81 | assert not params 82 | assert data == default_http_arguments_as_string 83 | 84 | 85 | def test_generate_data_with_GET(default_http_arguments_as_json): 86 | """Assign arguments to querystring params in GET.""" 87 | data, params = generate_data('GET', default_http_arguments_as_json) 88 | assert params == default_http_arguments_as_json 89 | assert not data 90 | 91 | 92 | def test_generate_data_with_DELETE(default_http_arguments_as_json,): 93 | """Assign arguments to querystring params in DELETE.""" 94 | data, params = generate_data('DELETE', default_http_arguments_as_json) 95 | assert params == default_http_arguments_as_json 96 | assert not data 97 | 98 | 99 | def test_build_url_no_params(): 100 | """Build URL with no parameters.""" 101 | url = build_url(HOST, DEFAULT_TARGET) 102 | assert url == DEFAULT_BASE_URL 103 | 104 | 105 | def test_build_url_with_scheme(): 106 | """Build URL with https scheme.""" 107 | url = build_url(HOST, DEFAULT_TARGET) 108 | assert url == DEFAULT_BASE_URL 109 | 110 | 111 | def test_build_special_char_url(): 112 | """Build URL special characters.""" 113 | url = build_url(HOST, SPECIAL_CHAR_TARGET) 114 | assert url == 'https://api.uber.com/v1.2/%7Eproducts' 115 | 116 | 117 | def test_build_url_params(default_http_arguments_as_json): 118 | """Build URL with querystring parameters.""" 119 | url = build_url(HOST, DEFAULT_TARGET, default_http_arguments_as_json) 120 | url_with_params = '{}?latitude={}&longitude={}' 121 | assert url == url_with_params.format(DEFAULT_BASE_URL, LAT, LNG) 122 | -------------------------------------------------------------------------------- /tests/vcr_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """Configure vcr to record test fixtures. 22 | 23 | This file overrides vcrpy's default settings. 24 | You can set options individually. Such per-cassette 25 | overrides will take precedent over the global 26 | configuration below. 27 | """ 28 | 29 | from __future__ import absolute_import 30 | from __future__ import division 31 | from __future__ import print_function 32 | from __future__ import unicode_literals 33 | 34 | import vcr 35 | 36 | uber_vcr = vcr.VCR( 37 | serializer='yaml', 38 | cassette_library_dir='tests/fixtures', 39 | 40 | # disable gzip 41 | decode_compressed_response=True, 42 | 43 | # you can record_mode='all' to force re-record all cassettes 44 | record_mode='once', 45 | 46 | # configure matching features that vcr uses to identify identical requests 47 | match_on=['uri', 'method'], 48 | 49 | # scrub sensitive information from cassette files 50 | filter_headers=['Authorization'], 51 | ) 52 | -------------------------------------------------------------------------------- /uber_rides/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/rides-python-sdk/76ecd75ab5235d792ec1010e36eca679ba285127/uber_rides/__init__.py -------------------------------------------------------------------------------- /uber_rides/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import 22 | from __future__ import division 23 | from __future__ import print_function 24 | from __future__ import unicode_literals 25 | 26 | 27 | class APIError(Exception): 28 | """Parent class of all Uber API errors.""" 29 | pass 30 | 31 | 32 | class HTTPError(APIError): 33 | """Parent class of all HTTP errors.""" 34 | 35 | def _adapt_response(self, response): 36 | """Convert error responses to standardized ErrorDetails.""" 37 | if response.headers['content-type'] == 'application/json': 38 | body = response.json() 39 | status = response.status_code 40 | 41 | if body.get('errors'): 42 | return self._complex_response_to_error_adapter(body) 43 | 44 | elif body.get('code') and body.get('message'): 45 | return self._simple_response_to_error_adapter(status, body) 46 | 47 | elif body.get('error'): 48 | code = response.reason 49 | return self._message_to_error_adapter(status, code, body) 50 | 51 | raise UnknownHttpError(response) 52 | 53 | def _complex_response_to_error_adapter(self, body): 54 | """Convert a list of error responses.""" 55 | meta = body.get('meta') 56 | errors = body.get('errors') 57 | e = [] 58 | 59 | for error in errors: 60 | status = error['status'] 61 | code = error['code'] 62 | title = error['title'] 63 | 64 | e.append(ErrorDetails(status, code, title)) 65 | 66 | return e, meta 67 | 68 | def _simple_response_to_error_adapter(self, status, original_body): 69 | """Convert a single error response.""" 70 | body = original_body.copy() 71 | code = body.pop('code') 72 | title = body.pop('message') 73 | meta = body # save whatever is left in the response 74 | 75 | e = [ErrorDetails(status, code, title)] 76 | 77 | return e, meta 78 | 79 | def _message_to_error_adapter(self, status, code, original_body): 80 | """Convert single string message to error response.""" 81 | body = original_body.copy() 82 | title = body.pop('error') 83 | meta = body # save whatever is left in the response 84 | 85 | e = [ErrorDetails(status, code, title)] 86 | 87 | return e, meta 88 | 89 | 90 | class ClientError(HTTPError): 91 | """Raise for 4XX Errors. 92 | 93 | Contains an array of ErrorDetails objects. 94 | """ 95 | 96 | def __init__(self, response, message=None): 97 | """ 98 | Parameters 99 | response 100 | The 4XX HTTP response. 101 | message 102 | An error message string. If one is not provided, the 103 | default message is used. 104 | """ 105 | if not message: 106 | message = ( 107 | 'The request contains bad syntax or cannot be filled ' 108 | 'due to a fault from the client sending the request.' 109 | ) 110 | 111 | super(ClientError, self).__init__(message) 112 | errors, meta = super(ClientError, self)._adapt_response(response) 113 | self.errors = errors 114 | self.meta = meta 115 | 116 | 117 | class ServerError(HTTPError): 118 | """Raise for 5XX Errors. 119 | 120 | Contains a single ErrorDetails object. 121 | """ 122 | 123 | def __init__(self, response, message=None): 124 | """ 125 | Parameters 126 | response 127 | The 5XX HTTP response. 128 | message 129 | An error message string. If one is not provided, the 130 | default message is used. 131 | """ 132 | if not message: 133 | message = ( 134 | 'The server encounter an error or is ' 135 | 'unable to process the request.' 136 | ) 137 | 138 | super(ServerError, self).__init__(message) 139 | self.error, self.meta = self._adapt_response(response) 140 | 141 | def _adapt_response(self, response): 142 | """Convert various error responses to standardized ErrorDetails.""" 143 | errors, meta = super(ServerError, self)._adapt_response(response) 144 | return errors[0], meta # single error instead of array 145 | 146 | 147 | class ErrorDetails(object): 148 | """Class to standardize all errors.""" 149 | 150 | def __init__(self, status, code, title): 151 | self.status = status 152 | self.code = code 153 | self.title = title 154 | 155 | def __repr__(self): 156 | return "ErrorDetails: {} {} {}".format( 157 | str(self.status), 158 | str(self.code), 159 | str(self.title) 160 | ) 161 | 162 | 163 | class UnknownHttpError(APIError): 164 | """Throw when an unknown HTTP error occurs. 165 | 166 | Thrown when a previously unseen error is 167 | received and there is no standard schema to convert 168 | it into a well-formed HttpError. 169 | """ 170 | 171 | def __init__(self, response): 172 | super(UnknownHttpError, self).__init__() 173 | self.response = response 174 | 175 | 176 | class UberIllegalState(APIError): 177 | """Raise for Illegal State Errors. 178 | 179 | Thrown when the environment or class is not in an 180 | appropriate state for the requested operation. 181 | """ 182 | pass 183 | -------------------------------------------------------------------------------- /uber_rides/request.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | """Internal module for HTTP Requests and Responses.""" 22 | 23 | from __future__ import absolute_import 24 | from __future__ import division 25 | from __future__ import print_function 26 | from __future__ import unicode_literals 27 | 28 | from requests import Session 29 | from string import ascii_letters 30 | from string import digits 31 | 32 | from uber_rides.errors import UberIllegalState 33 | from uber_rides.utils import http 34 | from uber_rides.utils.request import build_url 35 | from uber_rides.utils.request import generate_data 36 | from uber_rides.utils.request import generate_prepared_request 37 | 38 | 39 | LIB_VERSION = '0.6.0' 40 | 41 | 42 | class Response(object): 43 | """The response from an HTTP request.""" 44 | 45 | def __init__(self, response): 46 | """Initialize a Response. 47 | 48 | Parameters 49 | response (requests.Response) 50 | The HTTP response from an API request. 51 | """ 52 | self.status_code = response.status_code 53 | self.request = response.request 54 | self.headers = response.headers 55 | 56 | try: 57 | self.json = response.json() 58 | except: 59 | self.json = None 60 | 61 | 62 | class Request(object): 63 | """Request containing information to send to server.""" 64 | 65 | def __init__( 66 | self, 67 | auth_session, 68 | api_host, 69 | method, 70 | path, 71 | handlers=None, 72 | args=None, 73 | ): 74 | """Initialize a Request. 75 | 76 | Parameters 77 | auth_session (Session) 78 | Session object containing OAuth 2.0 credentials. Optional 79 | for any HTTP Requests that don't need access headers. 80 | api_host (str) 81 | Base URL of the Uber Server that handles API calls. 82 | method (str) 83 | HTTP Method (e.g. 'POST'). 84 | path (str) 85 | The endpoint path. (e.g. 'v1.2/products') 86 | handlers (list[handler]) 87 | Optional list of error handlers to attach to the request. 88 | args (dict) 89 | Optional dictionary of arguments to add to the request. 90 | """ 91 | self.auth_session = auth_session 92 | self.api_host = api_host 93 | self.path = path 94 | self.method = method 95 | self.handlers = handlers or [] 96 | self.args = args 97 | 98 | def _prepare(self): 99 | """Builds a URL and return a PreparedRequest. 100 | 101 | Returns 102 | (requests.PreparedRequest) 103 | 104 | Raises 105 | UberIllegalState (APIError) 106 | """ 107 | if self.method not in http.ALLOWED_METHODS: 108 | raise UberIllegalState('Unsupported HTTP Method.') 109 | 110 | api_host = self.api_host 111 | headers = self._build_headers(self.method, self.auth_session) 112 | url = build_url(api_host, self.path) 113 | data, params = generate_data(self.method, self.args) 114 | 115 | return generate_prepared_request( 116 | self.method, 117 | url, 118 | headers, 119 | data, 120 | params, 121 | self.handlers, 122 | ) 123 | 124 | def _send(self, prepared_request): 125 | """Send a PreparedRequest to the server. 126 | 127 | Parameters 128 | prepared_request (requests.PreparedRequest) 129 | 130 | Returns 131 | (Response) 132 | A Response object, whichcontains a server's 133 | response to an HTTP request. 134 | """ 135 | session = Session() 136 | response = session.send(prepared_request) 137 | return Response(response) 138 | 139 | def execute(self): 140 | """Prepare and send the Request, return a Response. 141 | 142 | Returns 143 | (Response) 144 | The HTTP Response from an API Request 145 | to the server. 146 | 147 | Example 148 | request = Request(session, 'api.uber.com', 'GET', 'v1.2/profile') 149 | response = request.execute() 150 | """ 151 | prepared_request = self._prepare() 152 | return self._send(prepared_request) 153 | 154 | def _build_headers(self, method, auth_session): 155 | """Create headers for the request. 156 | 157 | Parameters 158 | method (str) 159 | HTTP method (e.g. 'POST'). 160 | auth_session (Session) 161 | The Session object containing OAuth 2.0 credentials. 162 | 163 | Returns 164 | headers (dict) 165 | Dictionary of access headers to attach to request. 166 | 167 | Raises 168 | UberIllegalState (ApiError) 169 | Raised if headers are invalid. 170 | """ 171 | token_type = auth_session.token_type 172 | 173 | if auth_session.server_token: 174 | token = auth_session.server_token 175 | else: 176 | token = auth_session.oauth2credential.access_token 177 | 178 | if not self._authorization_headers_valid(token_type, token): 179 | message = 'Invalid token_type or token.' 180 | raise UberIllegalState(message) 181 | 182 | headers = { 183 | 'Authorization': ' '.join([token_type, token]), 184 | 'X-Uber-User-Agent': 'Python Rides SDK v{}'.format(LIB_VERSION), 185 | } 186 | 187 | if method in http.BODY_METHODS: 188 | headers.update(http.DEFAULT_CONTENT_HEADERS) 189 | 190 | return headers 191 | 192 | def _authorization_headers_valid(self, token_type, token): 193 | """Verify authorization headers for a request. 194 | 195 | Parameters 196 | token_type (str) 197 | Type of token to access resources. 198 | token (str) 199 | Server Token or OAuth 2.0 Access Token. 200 | 201 | Returns 202 | (bool) 203 | True iff token_type and token are valid. 204 | """ 205 | if token_type not in http.VALID_TOKEN_TYPES: 206 | return False 207 | 208 | allowed_chars = ascii_letters + digits + '.' + '_' + '-' + '=' 209 | 210 | # True if token only contains allowed_chars 211 | return all(characters in allowed_chars for characters in token) 212 | -------------------------------------------------------------------------------- /uber_rides/session.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import 22 | from __future__ import division 23 | from __future__ import print_function 24 | from __future__ import unicode_literals 25 | 26 | from requests import codes 27 | from time import time 28 | 29 | from uber_rides.errors import ClientError 30 | from uber_rides.errors import UberIllegalState 31 | from uber_rides.utils import auth 32 | 33 | 34 | EXPIRES_THRESHOLD_SECONDS = 500 35 | 36 | 37 | class Session(object): 38 | """A class to store credentials. 39 | 40 | A Session can be initialized with a Server Token or with a set of 41 | OAuth 2.0 Credentials, but not with both. A Session uses credentials 42 | to properly construct requests to Uber and access protected resources. 43 | """ 44 | 45 | def __init__( 46 | self, 47 | server_token=None, 48 | oauth2credential=None, 49 | ): 50 | """Initialize a Session. 51 | 52 | Parameters 53 | sever_token (str) 54 | Your application's server token. Available at 55 | developer.uber.com. 56 | oauth2credential (OAuth2Credential) 57 | Access token and additional OAuth 2.0 credentials used 58 | to access protected resources. 59 | 60 | Raises 61 | UberIllegalState (APIError) 62 | Raised if there is an attempt to create session with 63 | both server token and access token. 64 | """ 65 | if server_token and oauth2credential: 66 | message = ( 67 | 'Session cannot have both Server ' 68 | 'and OAuth 2.0 Credentials.' 69 | ) 70 | raise UberIllegalState(message) 71 | 72 | if server_token is None and oauth2credential is None: 73 | message = ( 74 | 'Session must have either Server ' 75 | 'Token or OAuth 2.0 Credentials.' 76 | ) 77 | raise UberIllegalState(message) 78 | 79 | if server_token: 80 | self.server_token = server_token 81 | self.token_type = auth.SERVER_TOKEN_TYPE 82 | self.oauth2credential = None 83 | 84 | elif oauth2credential: 85 | self.oauth2credential = oauth2credential 86 | self.token_type = auth.OAUTH_TOKEN_TYPE 87 | self.server_token = None 88 | 89 | 90 | class OAuth2Credential(object): 91 | """A class to store OAuth 2.0 credentials. 92 | 93 | OAuth 2.0 credentials are used to properly construct requests 94 | to Uber and access protected resources. The class also stores 95 | app information (such as client_id) to refresh or request new 96 | access tokens if they expire or are revoked. 97 | """ 98 | 99 | def __init__( 100 | self, 101 | client_id, 102 | access_token, 103 | expires_in_seconds, 104 | scopes, 105 | grant_type, 106 | redirect_url=None, 107 | client_secret=None, 108 | refresh_token=None, 109 | ): 110 | """Initialize an OAuth2Credential. 111 | 112 | Parameters 113 | client_id (str) 114 | Your app's Client ID. 115 | access_token (str) 116 | Access token received from OAuth 2.0 Authorization. 117 | expires_in_seconds (int) 118 | Seconds after initial grant when access token will expire. 119 | scopes (set) 120 | Set of permission scopes to request. 121 | (e.g. {'profile', 'history'}) Keep this list minimal so 122 | users feel safe granting your app access to their information. 123 | grant_type (str) 124 | Type of OAuth 2.0 Grant used to obtain access token. 125 | (e.g. 'authorization_code') 126 | redirect_url (str) 127 | The URL that the Uber server will redirect to. 128 | client_secret (str) 129 | Your app's Client Secret. 130 | refresh_token (str) 131 | Optional refresh token used to get a new access token. 132 | Only used for Authorization Code Grant. 133 | """ 134 | self.client_id = client_id 135 | self.access_token = access_token 136 | self.expires_in_seconds = self._now() + int(expires_in_seconds) 137 | self.scopes = scopes 138 | self.grant_type = grant_type 139 | self.redirect_url = redirect_url 140 | self.client_secret = client_secret 141 | self.refresh_token = refresh_token 142 | 143 | @classmethod 144 | def make_from_response( 145 | cls, 146 | response, 147 | grant_type, 148 | client_id, 149 | client_secret=None, 150 | redirect_url=None, 151 | ): 152 | """Alternate constructor for OAuth2Credential(). 153 | 154 | Create an OAuth2Credential from an HTTP Response. 155 | 156 | Parameters 157 | response (Response) 158 | HTTP Response containing OAuth 2.0 credentials. 159 | grant_type (str) 160 | Type of OAuth 2.0 Grant used to obtain access token. 161 | (e.g. 'authorization_code') 162 | client_id (str) 163 | Your app's Client ID. 164 | client_secret (str) 165 | Your app's Client Secret. 166 | redirect_url (str) 167 | The URL that the Uber server will redirect to. 168 | 169 | Returns 170 | (OAuth2Credential) 171 | 172 | Raises 173 | ClientError (APIError) 174 | Raised if the response is invalid. 175 | """ 176 | if response.status_code != codes.ok: 177 | message = 'Error with Access Token Request: {}' 178 | message = message.format(response.reason) 179 | raise ClientError(response, message) 180 | 181 | response = response.json() 182 | 183 | # convert space delimited string to set 184 | scopes = response.get('scope') 185 | scopes_set = {scope for scope in scopes.split()} 186 | 187 | return cls( 188 | client_id=client_id, 189 | client_secret=client_secret, 190 | redirect_url=redirect_url, 191 | access_token=response.get('access_token'), 192 | expires_in_seconds=response.get('expires_in'), 193 | scopes=scopes_set, 194 | grant_type=grant_type, 195 | refresh_token=response.get('refresh_token', None), 196 | ) 197 | 198 | def is_stale(self): 199 | """Check whether the session's current access token is about to expire. 200 | 201 | Returns 202 | (bool) 203 | True if access_token expires within threshold 204 | """ 205 | expires_in_seconds = self.expires_in_seconds - self._now() 206 | return expires_in_seconds < EXPIRES_THRESHOLD_SECONDS 207 | 208 | def _now(self): 209 | return int(time()) 210 | -------------------------------------------------------------------------------- /uber_rides/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/rides-python-sdk/76ecd75ab5235d792ec1010e36eca679ba285127/uber_rides/utils/__init__.py -------------------------------------------------------------------------------- /uber_rides/utils/auth.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | SERVER_TOKEN_TYPE = 'Token' 22 | OAUTH_TOKEN_TYPE = 'Bearer' 23 | AUTHORIZATION_CODE_GRANT = 'authorization_code' 24 | CLIENT_CREDENTIALS_GRANT = 'client_credentials' 25 | IMPLICIT_GRANT = 'implicit' 26 | REFRESH_TOKEN = 'refresh_token' 27 | AUTH_HOST = 'login.uber.com' 28 | ACCESS_TOKEN_PATH = 'oauth/v2/token' 29 | AUTHORIZE_PATH = 'oauth/v2/authorize' 30 | REVOKE_PATH = 'oauth/v2/revoke' 31 | CODE_RESPONSE_TYPE = 'code' 32 | TOKEN_RESPONSE_TYPE = 'token' 33 | VALID_RESPONSE_TYPES = frozenset([ 34 | CODE_RESPONSE_TYPE, 35 | TOKEN_RESPONSE_TYPE, 36 | ]) 37 | -------------------------------------------------------------------------------- /uber_rides/utils/handlers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import 22 | from __future__ import division 23 | from __future__ import print_function 24 | from __future__ import unicode_literals 25 | 26 | from uber_rides.errors import ClientError 27 | from uber_rides.errors import ServerError 28 | 29 | 30 | def error_handler(response, **kwargs): 31 | """Error Handler to surface 4XX and 5XX errors. 32 | 33 | Attached as a callback hook on the Request object. 34 | 35 | Parameters 36 | response (requests.Response) 37 | The HTTP response from an API request. 38 | **kwargs 39 | Arbitrary keyword arguments. 40 | 41 | Raises 42 | ClientError (ApiError) 43 | Raised if response contains a 4XX status code. 44 | ServerError (ApiError) 45 | Raised if response contains a 5XX status code. 46 | 47 | Returns 48 | response (requests.Response) 49 | The original HTTP response from the API request. 50 | """ 51 | try: 52 | body = response.json() 53 | except ValueError: 54 | body = {} 55 | status_code = response.status_code 56 | message = body.get('message', '') 57 | fields = body.get('fields', '') 58 | error_message = str(status_code) + ': ' + message + ' ' + str(fields) 59 | if 400 <= status_code <= 499: 60 | raise ClientError(response, error_message) 61 | 62 | elif 500 <= status_code <= 599: 63 | raise ServerError(response, error_message) 64 | 65 | return response 66 | -------------------------------------------------------------------------------- /uber_rides/utils/http.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | URL_SCHEME = 'https://' 22 | 23 | ALLOWED_METHODS = frozenset(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']) 24 | BODY_METHODS = frozenset(['POST', 'PUT', 'PATCH']) 25 | QUERY_METHODS = frozenset(['GET', 'DELETE']) 26 | 27 | DEFAULT_CONTENT_HEADERS = {'content-type': 'application/json'} 28 | 29 | STATUS_OK = 200 30 | STATUS_UNAUTHORIZED = 401 31 | STATUS_CONFLICT = 409 32 | STATUS_UNPROCESSABLE_ENTITY = 422 33 | STATUS_INTERNAL_SERVER_ERROR = 500 34 | STATUS_SERVICE_UNAVAILABLE = 503 35 | 36 | ERROR_CODE_DESCRIPTION_DICT = { 37 | 'distance_exceeded': 'Distance between two points exceeds 100 miles.', 38 | 'unauthorized': 'Invalid OAuth 2.0 credentials provided.', 39 | 'validation_failed': 'Invalid request.', 40 | 'internal_server_error': 'Unexpected internal server error occurred.', 41 | 'service_unavailable': 'Service temporarily unavailable.', 42 | 'surge': 'Surge pricing is in effect.', 43 | 'same_pickup_dropoff': 'Pickup and Dropoff can\'t be the same.', 44 | } 45 | 46 | VALID_TOKEN_TYPES = frozenset(['Token', 'Bearer']) 47 | -------------------------------------------------------------------------------- /uber_rides/utils/request.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 Uber Technologies, Inc. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | # THE SOFTWARE. 20 | 21 | from __future__ import absolute_import 22 | from __future__ import division 23 | from __future__ import print_function 24 | from __future__ import unicode_literals 25 | 26 | from json import dumps 27 | from requests import Request 28 | 29 | try: 30 | from urllib.parse import quote 31 | from urllib.parse import urlencode 32 | from urllib.parse import urljoin 33 | except ImportError: 34 | from urllib import quote 35 | from urllib import urlencode 36 | from urlparse import urljoin 37 | 38 | from uber_rides.utils.handlers import error_handler 39 | from uber_rides.utils import http 40 | 41 | 42 | def generate_data(method, args): 43 | """Assign arguments to body or URL of an HTTP request. 44 | 45 | Parameters 46 | method (str) 47 | HTTP Method. (e.g. 'POST') 48 | args (dict) 49 | Dictionary of data to attach to each Request. 50 | e.g. {'latitude': 37.561, 'longitude': -122.742} 51 | 52 | Returns 53 | (str or dict) 54 | Either params containing the dictionary of arguments 55 | or data containing arugments in JSON-formatted string. 56 | """ 57 | data = {} 58 | params = {} 59 | 60 | if method in http.BODY_METHODS: 61 | data = dumps(args) 62 | else: 63 | params = args 64 | return data, params 65 | 66 | 67 | def generate_prepared_request(method, url, headers, data, params, handlers): 68 | """Add handlers and prepare a Request. 69 | 70 | Parameters 71 | method (str) 72 | HTTP Method. (e.g. 'POST') 73 | headers (dict) 74 | Headers to send. 75 | data (JSON-formatted str) 76 | Body to attach to the request. 77 | params (dict) 78 | Dictionary of URL parameters to append to the URL. 79 | handlers (list) 80 | List of callback hooks, for error handling. 81 | 82 | Returns 83 | (requests.PreparedRequest) 84 | The fully mutable PreparedRequest object, 85 | containing the exact bytes to send to the server. 86 | """ 87 | request = Request( 88 | method=method, 89 | url=url, 90 | headers=headers, 91 | data=data, 92 | params=params, 93 | ) 94 | 95 | handlers.append(error_handler) 96 | 97 | for handler in handlers: 98 | request.register_hook('response', handler) 99 | 100 | return request.prepare() 101 | 102 | 103 | def build_url(host, path, params=None): 104 | """Build a URL. 105 | 106 | This method encodes the parameters and adds them 107 | to the end of the base URL, then adds scheme and hostname. 108 | 109 | Parameters 110 | host (str) 111 | Base URL of the Uber Server that handles API calls. 112 | path (str) 113 | Target path to add to the host (e.g. 'v1.2/products'). 114 | params (dict) 115 | Optional dictionary of parameters to add to the URL. 116 | 117 | Returns 118 | (str) 119 | The fully formed URL. 120 | """ 121 | path = quote(path) 122 | params = params or {} 123 | 124 | if params: 125 | path = '/{}?{}'.format(path, urlencode(params)) 126 | else: 127 | path = '/{}'.format(path) 128 | 129 | if not host.startswith(http.URL_SCHEME): 130 | host = '{}{}'.format(http.URL_SCHEME, host) 131 | 132 | return urljoin(host, path) 133 | --------------------------------------------------------------------------------