From 9859189150958cbac257303296001894ac832666 Mon Sep 17 00:00:00 2001 From: pyro2927 Date: Sun, 17 Feb 2019 22:37:59 -0800 Subject: [PATCH] Restructuring folder structure --- .dockerignore | 2 + Makefile | 7 ++ checkin_test.py | 67 ---------- fixtures/checkin-get.json | 64 ---------- fixtures/checkin-post.json | 45 ------- fixtures/openflights.json | 1 - fixtures/view-reservation.json | 114 ------------------ southwest/__init__.py | 1 + openflights.py => southwest/openflights.py | 0 southwest.py => southwest/southwest.py | 0 tests/__init__.py | 0 tests/checkin_test.py | 37 ++++++ tests/fixtures/cassettes/test_checkin.yml | 107 ++++++++++++++++ .../cassettes/test_openflights_api.yml | 20 ++- tests/my_vcr.py | 43 +++++++ 15 files changed, 206 insertions(+), 302 deletions(-) create mode 100644 Makefile delete mode 100644 checkin_test.py delete mode 100644 fixtures/checkin-get.json delete mode 100644 fixtures/checkin-post.json delete mode 100644 fixtures/openflights.json delete mode 100644 fixtures/view-reservation.json create mode 100644 southwest/__init__.py rename openflights.py => southwest/openflights.py (100%) rename southwest.py => southwest/southwest.py (100%) create mode 100644 tests/__init__.py create mode 100644 tests/checkin_test.py create mode 100644 tests/fixtures/cassettes/test_checkin.yml rename test_openflights_api => tests/fixtures/cassettes/test_openflights_api.yml (58%) create mode 100644 tests/my_vcr.py diff --git a/.dockerignore b/.dockerignore index 7642b3f..5c4a3fb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,5 @@ *.pyc Dockerfile README.md +htmlcov/ +*.xml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..52d84f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +init: + pip install -r requirements.txt + +test: + pytest --cov=southwest/ --cov=checkin + +.PHONY: init test diff --git a/checkin_test.py b/checkin_test.py deleted file mode 100644 index d431400..0000000 --- a/checkin_test.py +++ /dev/null @@ -1,67 +0,0 @@ -import checkin -import json -import pytest -import requests -import southwest -import vcr -from datetime import datetime, timedelta -from pytz import timezone, utc -from tzlocal import get_localzone - - -def template_time(file_name): - in_string = open(file_name, 'r').read() - t = datetime.now() + timedelta(seconds=5) - in_string = in_string.replace('DATE_HERE', t.strftime('%Y-%m-%d')) - in_string = in_string.replace('TIME_HERE', t.strftime('%H:%M')) - return in_string - - -def test_checkin(requests_mock): - requests_mock.register_uri('GET', '/api/mobile-misc/v1/mobile-misc/page/view-reservation/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/view-reservation.json')) - requests_mock.register_uri('GET', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/checkin-get.json')) - requests_mock.register_uri('POST', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in', text=template_time('fixtures/checkin-post.json')) - requests_mock.register_uri('POST', '/php/apsearch.php', text=template_time('fixtures/openflights.json')) - try: - checkin.auto_checkin('XXXX', 'John', 'Smith') - except Exception: - pytest.fail("Error checking in") - - -def test_timezone_localization(): - tz = timezone('America/Los_Angeles') - date = tz.localize(datetime.strptime('2018-01-01 13:00', '%Y-%m-%d %H:%M')) - assert date.strftime('%z') == '-0800' - - -@vcr.use_cassette() -def test_openflights_api(): - tzrequest = {'iata': 'LAX', - 'country': 'ALL', - 'db': 'airports', - 'iatafilter': 'true', - 'action': 'SEARCH', - 'offset': '0'} - tzresult = requests.post("https://openflights.org/php/apsearch.php", tzrequest) - airport_tz = timezone(json.loads(tzresult.text)['airports'][0]['tz_id']) - assert airport_tz.zone == "America/Los_Angeles" - - -def test_notifications(requests_mock, mocker): - requests_mock.register_uri('GET', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/checkin-get.json')) - data = template_time('fixtures/checkin-post.json') - requests_mock.register_uri('POST', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in', text=data) - data = json.loads(data) - requests_mock.register_uri('POST', '/php/apsearch.php', text=template_time('fixtures/openflights.json')) - mocked_checkin = mocker.patch('southwest.Reservation.send_notification') - t = datetime.now(utc).astimezone(get_localzone()) + timedelta(minutes=5) - - try: - r = southwest.Reservation('XXXX', 'John', 'Smith') - checkin.schedule_checkin(t, r) - mocked_checkin.assert_not_called() - r.notifications = [{'mediaType': 'EMAIL', 'emailAddress': 'test@example.com'}] - checkin.schedule_checkin(t, r) - mocked_checkin.assert_called_once() - except Exception: - pytest.fail("Error checking in") diff --git a/fixtures/checkin-get.json b/fixtures/checkin-get.json deleted file mode 100644 index 7a78df0..0000000 --- a/fixtures/checkin-get.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "checkInSessionToken": "", - "checkInViewReservationPage": { - "_links": { - "checkIn": { - "body": { - "checkInSessionToken": "", - "firstName": "John", - "lastName": "Smith", - "recordLocator": "XXXX" - }, - "href": "/v1/mobile-air-operations/page/check-in", - "method": "POST" - }, - "travelDocuments": null - }, - "_v1_infoNeededToCheckin": { - "body": { - "names": [ - { - "firstName": "JOHN", - "lastName": "SMITH" - } - ] - }, - "href": "/v1/mobile/reservations/record-locator/XXXX/boarding-passes", - "method": "POST" - }, - "cards": [ - { - "arrivalAirport": "LAX", - "arrivalTime": "15:10", - "dates": { - "first": "2218-01-01", - "second": null - }, - "departureAirport": "SFO", - "departureDate": "2218-01-01", - "departureTime": "13:45", - "destinationDescription": "Los Angeles", - "flights": [ - { - "departureDate": "Jan 01", - "destinationAirportCode": "LAX", - "destinationStationName": "Los Angeles", - "flightNumber": "1234", - "hasWifi": true, - "originAirportCode": "SFO" - } - ], - "hazmatCheckInDisclaimer": "By tapping 'Check in' you acknowledge that you understand the hazardous materials restrictions and penalties.", - "travelTime": "1h 25m" - } - ], - "hazmatText": "Federal law forbids the carriage of hazardous materials such as aerosols, fireworks, lithium batteries and flammable liquids aboard the aircraft in your checked or carryon baggage. E-cigarettes are not permitted in checked baggage and must be transported in carryon baggage only.", - "pnr": { - "confirmationNumber": "XXXX", - "passengers": [ - "John Smith" - ] - } - }, - "prefillPassengerAPISDocuments": null -} \ No newline at end of file diff --git a/fixtures/checkin-post.json b/fixtures/checkin-post.json deleted file mode 100644 index e8b0422..0000000 --- a/fixtures/checkin-post.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "checkInConfirmationPage": { - "_links": { - "boardingPasses": { - "body": { - "checkInSessionToken": "XXXX", - "firstName": "JOHN", - "lastName": "SMITH", - "recordLocator": "XXXX" - }, - "href": "/v1/mobile-air-operations/page/check-in/view-boarding-pass", - "method": "POST" - } - }, - "_v1_infoNeededToViewBoardingPasses": { - "href": "/v1/mobile/record-locator/XXXX/mobile-boarding-passes", - "method": "GET", - "query": { - "first-name": "JOHN", - "last-name": "SMITH" - } - }, - "flights": [ - { - "boundIndex": 0, - "flightNumber": "1234", - "gate": null, - "hasWifi": true, - "passengers": [ - { - "boardingGroup": "A", - "boardingPosition": "31", - "checkedIn": true, - "confirmationNumber": "XXXX", - "hasPrecheck": true, - "mobileBoardingPassEligible": true, - "mobileBoardingPassIneligibilityErrorCode": "", - "name": "John Smith" - } - ], - "travelTime": "1h 25m" - } - ] - } -} \ No newline at end of file diff --git a/fixtures/openflights.json b/fixtures/openflights.json deleted file mode 100644 index f604a71..0000000 --- a/fixtures/openflights.json +++ /dev/null @@ -1 +0,0 @@ -{"status":1,"offset":0,"max":"1","airports":[{"name":"Los Angeles International Airport","city":"Los Angeles","country":"United States","iata":"LAX","icao":"KLAX","x":"-118.4079971","y":"33.94250107","elevation":"125","apid":"3484","timezone":"-8","dst":"A","tz_id":"America\/Los_Angeles","type":"airport","source":"OurAirports","ap_uid":null,"ap_name":"Los Angeles International. (LAX), United States"}]} \ No newline at end of file diff --git a/fixtures/view-reservation.json b/fixtures/view-reservation.json deleted file mode 100644 index edfa966..0000000 --- a/fixtures/view-reservation.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "viewReservationViewPage": { - "_links": { - "cancel": null, - "change": null, - "checkIn": null, - "checkInSessionToken": null, - "passportEmergencyContacts": null, - "viewBoardingPass": null, - "viewBoardingPositions": null, - "viewStandbyList": null - }, - "_v1_infoNeededToAddCompanion": null, - "_v1_infoNeededToCancel": { - "href": "/v1/mobile/reservations/record-locator/XXXX", - "method": "GET", - "query": { - "action": "CANCEL", - "first-name": "John", - "last-name": "Smith" - } - }, - "_v1_infoNeededToChange": { - "href": "/v1/mobile/reservations/record-locator/XXXX", - "method": "GET", - "query": { - "action": "CHANGE", - "first-name": "John", - "last-name": "Smith" - } - }, - "bounds": [ - { - "arrivalAirport": { - "code": "LAX", - "country": null, - "name": "Los Angeles", - "state": "CA" - }, - "arrivalStatus": null, - "arrivalStatusType": null, - "arrivalTime": "15:10", - "boundType": "DEPARTING", - "departureAirport": { - "code": "SFO", - "country": null, - "name": "San Francisco", - "state": "CA" - }, - "departureDate": "DATE_HERE", - "departureStatus": null, - "departureStatusType": null, - "departureTime": "TIME_HERE", - "fareType": "Companion", - "flights": [ - { - "number": "1234", - "wifiOnBoard": true - } - ], - "isNextDayArrival": false, - "passengerTypeCounts": { - "adult": 1, - "senior": 0 - }, - "stops": [], - "travelTime": "1h 25m" - } - ], - "checkInIneligibilityReason": null, - "companion": null, - "confirmationNumber": "XXXX", - "dates": { - "first": "2218-01-01", - "second": null - }, - "destinationAirport": { - "code": "LAX", - "country": null, - "name": "Los Angeles", - "state": "CA" - }, - "destinationDescription": "Los Angeles", - "hasAnyCancelledFlights": false, - "hasUnaccompaniedMinor": false, - "isCheckInEligible": false, - "isCheckedIn": false, - "isDynamicWaiver": false, - "isInternational": false, - "isNonRevPnr": false, - "originAirport": { - "code": "SFO", - "country": null, - "name": "San Francisco", - "state": "CA" - }, - "pageHeader": "SFO - LAX", - "passengers": [ - { - "accountNumber": "111111111", - "checkInIneligibilityReason": null, - "hasAnyEarlyBird": false, - "hasCompletePassportInfo": false, - "isCheckInEligible": false, - "isCheckedIn": false, - "isUnaccompaniedMinor": false, - "name": "John Smith", - "passengerReference": "2" - } - ], - "shouldShowAddEarlyBirdButton": false, - "standbyFlight": null - } -} \ No newline at end of file diff --git a/southwest/__init__.py b/southwest/__init__.py new file mode 100644 index 0000000..0c0a0a4 --- /dev/null +++ b/southwest/__init__.py @@ -0,0 +1 @@ +from .southwest import Reservation diff --git a/openflights.py b/southwest/openflights.py similarity index 100% rename from openflights.py rename to southwest/openflights.py diff --git a/southwest.py b/southwest/southwest.py similarity index 100% rename from southwest.py rename to southwest/southwest.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/checkin_test.py b/tests/checkin_test.py new file mode 100644 index 0000000..b80e044 --- /dev/null +++ b/tests/checkin_test.py @@ -0,0 +1,37 @@ +import json +import pytest +import requests +import southwest +from datetime import datetime, timedelta +from .my_vcr import custom_vcr +from pytz import timezone, utc +from tzlocal import get_localzone + +my_vcr = custom_vcr() + +@my_vcr.use_cassette() +def test_checkin(): + r = southwest.Reservation('XXXXXX', 'John', 'Smith') + try: + r.checkin() + except Exception: + pytest.fail("Error checking in") + + +def test_timezone_localization(): + tz = timezone('America/Los_Angeles') + date = tz.localize(datetime.strptime('2018-01-01 13:00', '%Y-%m-%d %H:%M')) + assert date.strftime('%z') == '-0800' + + +@my_vcr.use_cassette() +def test_openflights_api(): + tzrequest = {'iata': 'LAX', + 'country': 'ALL', + 'db': 'airports', + 'iatafilter': 'true', + 'action': 'SEARCH', + 'offset': '0'} + tzresult = requests.post("https://openflights.org/php/apsearch.php", tzrequest) + airport_tz = timezone(json.loads(tzresult.text)['airports'][0]['tz_id']) + assert airport_tz.zone == "America/Los_Angeles" diff --git a/tests/fixtures/cassettes/test_checkin.yml b/tests/fixtures/cassettes/test_checkin.yml new file mode 100644 index 0000000..8eb70e3 --- /dev/null +++ b/tests/fixtures/cassettes/test_checkin.yml @@ -0,0 +1,107 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Type: [application/json] + Host: [mobile.southwest.com] + User-Agent: [python-requests/2.21.0] + X-API-Key: [l7xxb3dcccc4a5674bada48fc6fcf0946bc8] + X-User-Experience-Id: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] + method: GET + uri: https://mobile.southwest.com/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXXXX + response: + body: {string: '{"checkInSessionToken": "[REDACTED]", "checkInViewReservationPage": + {"pnr": {"confirmationNumber": "XXXXXX", "passengers": "[REDACTED]"}, "cards": + [{"dates": {"first": "2019-02-18", "second": null}, "destinationDescription": + "Los Angeles", "departureDate": "2019-02-18", "departureAirport": "PDX", "departureTime": + "13:45", "arrivalAirport": "LAX", "arrivalTime": "16:05", "hazmatCheckInDisclaimer": + "By tapping ''Check in'' you acknowledge that you understand the hazardous + materials restrictions and penalties.", "flights": [{"flightNumber": "1614", + "hasWifi": true, "originAirportCode": "PDX", "destinationAirportCode": "LAX", + "destinationStationName": "Los Angeles", "departureDate": "Feb 18", "departureGate": + null, "departureTime": "13:45"}], "travelTime": "2h 20m"}], "hazmatText": + "Federal law forbids the carriage of hazardous materials such as aerosols, + fireworks, lithium batteries and flammable liquids aboard the aircraft in + your checked or carryon baggage. E-cigarettes are not permitted in checked + baggage and must be transported in carryon baggage only.", "_v1_infoNeededToCheckin": + {"href": "/v1/mobile/reservations/record-locator/XXXXXX/boarding-passes", + "method": "POST", "body": {"names": [{"firstName": "[REDACTED]", "lastName": + "[REDACTED]"}]}}, "_links": {"checkIn": {"href": "/v1/mobile-air-operations/page/check-in", + "method": "POST", "body": {"recordLocator": "[REDACTED]", "checkInSessionToken": + "[REDACTED]", "firstName": "[REDACTED]", "lastName": "[REDACTED]"}}, "travelDocuments": + null}}, "prefillPassengerAPISDocuments": null}'} + headers: + Access-Control-Allow-Credentials: ['true'] + Access-Control-Allow-Headers: ['origin, content-type, accept, authorization, + token, User-Agent, X-Forwarded-For, X-User-Experience-ID, X-Request-ID, + X-API-Key, X-Account-Number, X-Swa-Region, X-Channel-Id, X-Api-IDToken, + true-host'] + Access-Control-Allow-Methods: ['GET, POST, PUT, DELETE, OPTIONS, HEAD'] + Access-Control-Allow-Origin: [''] + Access-Control-Expose-Headers: ['X-User-Experience-ID, X-Request-ID'] + Access-Control-Max-Age: ['1'] + Cache-Control: ['max-age=0, no-cache, no-store'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Mon, 18 Feb 2019 06:29:03 GMT'] + Expires: ['Mon, 18 Feb 2019 06:29:03 GMT'] + Pragma: [no-cache] + Server: [Apache-Coyote/1.1] + Strict-Transport-Security: [max-age=60] + Vary: [Accept-Encoding] + X-Request-ID: [oMM1W3JIQrS_12lpUJIJdg] + X-User-Experience-ID: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] + content-length: ['13088'] + status: {code: 200, message: OK} +- request: + body: '{}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['5921'] + Content-Type: [application/json] + Host: [mobile.southwest.com] + User-Agent: [python-requests/2.21.0] + X-API-Key: [l7xxb3dcccc4a5674bada48fc6fcf0946bc8] + X-User-Experience-Id: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] + method: POST + uri: https://mobile.southwest.com/api/mobile-air-operations/v1/mobile-air-operations/page/check-in + response: + body: {string: '{"checkInConfirmationPage": {"messages": null, "flights": [{"boundIndex": + 0, "departureTime": "13:45", "gate": null, "passengers": "[REDACTED]", "flightNumber": + "1614", "hasWifi": true, "travelTime": "2h 20m"}], "_v1_infoNeededToViewBoardingPasses": + {"href": "/v1/mobile/record-locator/XXXXXX/mobile-boarding-passes", "method": + "GET", "query": {"first-name": "[REDACTED]", "last-name": "[REDACTED]"}}, + "_links": {"boardingPasses": {"href": "/v1/mobile-air-operations/page/check-in/view-boarding-pass", + "method": "POST", "body": {"recordLocator": "[REDACTED]", "firstName": "[REDACTED]", + "lastName": "[REDACTED]", "checkInSessionToken": "[REDACTED]", "travelerID": + "2005DBDA00087702"}}, "viewBoardingPassIssuance": {"href": "/v1/mobile-air-operations/page/check-in/mobile-issuance/XXXXXX", + "method": "POST", "body": {"passengers": "[REDACTED]"}}}}}'} + headers: + Access-Control-Allow-Credentials: ['true'] + Access-Control-Allow-Headers: ['origin, content-type, accept, authorization, + token, User-Agent, X-Forwarded-For, X-User-Experience-ID, X-Request-ID, + X-API-Key, X-Account-Number, X-Swa-Region, X-Channel-Id, X-Api-IDToken, + true-host'] + Access-Control-Allow-Methods: ['GET, POST, PUT, DELETE, OPTIONS, HEAD'] + Access-Control-Allow-Origin: [''] + Access-Control-Expose-Headers: ['X-User-Experience-ID, X-Request-ID'] + Access-Control-Max-Age: ['1'] + Cache-Control: ['max-age=0, no-cache, no-store'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Mon, 18 Feb 2019 06:29:03 GMT'] + Expires: ['Mon, 18 Feb 2019 06:29:03 GMT'] + Pragma: [no-cache] + Server: [Apache-Coyote/1.1] + Strict-Transport-Security: [max-age=60] + Vary: [Accept-Encoding] + X-Request-ID: [-UaFbua-QXu62S3ZInJ-WQ] + X-User-Experience-ID: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] + content-length: ['12674'] + status: {code: 200, message: OK} +version: 1 diff --git a/test_openflights_api b/tests/fixtures/cassettes/test_openflights_api.yml similarity index 58% rename from test_openflights_api rename to tests/fixtures/cassettes/test_openflights_api.yml index fa066a8..4e0c9df 100644 --- a/test_openflights_api +++ b/tests/fixtures/cassettes/test_openflights_api.yml @@ -11,26 +11,24 @@ interactions: method: POST uri: https://openflights.org/php/apsearch.php response: - body: - string: !!binary | - H4sIAAAAAAAAA4WQT2vDMAzFv4rRaYM0jduU/Ln5ODbYYQwG2wgmcYchsYMtj7Wl331SyjZ62vE9 - PUk/6QQRNaYIrczA7/fRILRFBpP+ghYkZKBtmH1ASryewOnJkP/go1Duw4wmijuHJjiN1js9CnVJ - U19v8XAdZdMnh4H9Z2fRDOKJti8Vq1FzXL2w6LUncX9RTLKSss7LomqaiqF4wnabN+VmV8iiIocW - fC4QjL3ZMfhsB46VdUkK7WSO3jH9qiY9RDoUFFeO3RJUkwm0+G1NyN0fMh5mbtK/h0WfQs/WYwrq - 5zm8rks8x6VxXNR/v8rFDd13m4nrV5zfz9+w9U2RlQEAAA== + body: {string: '{"status": 1, "offset": 0, "max": "1", "airports": [{"name": "[REDACTED]", + "city": "Los Angeles", "country": "United States", "iata": "LAX", "icao": + "KLAX", "x": "-118.4079971", "y": "33.94250107", "elevation": "125", "apid": + "3484", "timezone": "-8", "dst": "A", "tz_id": "America/Los_Angeles", "type": + "airport", "source": "OurAirports", "ap_uid": null, "ap_name": "Los Angeles + International. (LAX), United States"}]}'} headers: Cache-Control: ['no-store, no-cache, must-revalidate, post-check=0, pre-check=0'] Connection: [Keep-Alive] - Content-Encoding: [gzip] - Content-Length: ['262'] Content-Type: [text/html] - Date: ['Sat, 16 Feb 2019 22:42:03 GMT'] + Date: ['Mon, 18 Feb 2019 06:29:04 GMT'] Expires: ['Thu, 19 Nov 1981 08:52:00 GMT'] Keep-Alive: ['timeout=5, max=100'] Pragma: [no-cache] Server: [Apache/2.4.7 (Ubuntu)] - Set-Cookie: [PHPSESSID=g082si0ct41jj5gcp0a73p52u5; path=/] + Set-Cookie: [PHPSESSID=covu8plcltmotne4jvc976bk67; path=/] Vary: [Accept-Encoding] X-Powered-By: [PHP/5.5.9-1ubuntu4.26] + content-length: ['405'] status: {code: 200, message: OK} version: 1 diff --git a/tests/my_vcr.py b/tests/my_vcr.py new file mode 100644 index 0000000..96d3199 --- /dev/null +++ b/tests/my_vcr.py @@ -0,0 +1,43 @@ +from vcr import VCR +import json +import os + +# remove sensitive values from JSON response +bad_fields = [ + 'recordLocator', + 'checkInSessionToken', + 'name', + 'firstName', + 'lastName', + 'passengers', + 'first-name', + 'last-name' +] + +def redact(obj): + for k, v in list(obj.items()): + if k in bad_fields: + obj[k] = '[REDACTED]' + elif isinstance(v, list) and not isinstance(v, str): + for o in v: + redact(o) + elif isinstance(v, dict): + redact(v) + +def filter_payload(response): + string_body = response['body']['string'].decode('utf8') + body = json.loads(string_body) + redact(body) + response['body']['string'] = json.dumps(body).encode() + return response + +def custom_vcr(): + dirname = os.path.dirname(__file__) + return VCR( + decode_compressed_response=True, + cassette_library_dir=os.path.join(dirname, 'fixtures/cassettes'), + path_transformer=VCR.ensure_suffix('.yml'), + filter_query_parameters=bad_fields, + before_record_response=filter_payload, + filter_post_data_parameters=bad_fields + )