From 151f7d338330753cbf8080dd19a0f1144a52d408 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Fri, 7 Nov 2025 10:53:21 -0700 Subject: [PATCH 1/3] feat: adds verify_carrier address param --- CHANGELOG.md | 3 +- easypost/constant.py | 2 +- easypost/services/address_service.py | 3 + setup.py | 2 +- .../test_address_create_verify_carrier.yaml | 82 +++++++++++++++++++ tests/test_address.py | 14 ++++ 6 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 tests/cassettes/test_address_create_verify_carrier.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 12f534ce..95d0385d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # CHANGELOG -## Next Release +## v10.2.0 (2025-11-10) - Adds `UspsShipAccount` support to the create carrier method - Adds `tracker.retrieve_batch` function +- Adds `verify_carrier` address param ## v10.1.0 (2025-06-18) diff --git a/easypost/constant.py b/easypost/constant.py index bd8cec8d..372e62e0 100644 --- a/easypost/constant.py +++ b/easypost/constant.py @@ -1,6 +1,6 @@ # flake8: noqa # Library version -VERSION = "10.1.0" +VERSION = "10.2.0" VERSION_INFO = [str(number) for number in VERSION.split(".")] # Client defaults diff --git a/easypost/services/address_service.py b/easypost/services/address_service.py index 42db7fe8..58eda071 100644 --- a/easypost/services/address_service.py +++ b/easypost/services/address_service.py @@ -21,6 +21,7 @@ def create( self, verify: Optional[bool] = None, verify_strict: Optional[bool] = None, + verify_carrier: Optional[str] = None, **params, ) -> Address: """Create an Address.""" @@ -31,6 +32,8 @@ def create( wrapped_params["verify"] = verify if verify_strict: wrapped_params["verify_strict"] = verify_strict + if verify_carrier: + wrapped_params["verify_carrier"] = verify_carrier response = Requestor(self._client).request(method=RequestMethod.POST, url=url, params=wrapped_params) diff --git a/setup.py b/setup.py index 9dc284cf..d4147550 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( name="easypost", - version="10.1.0", + version="10.2.0", description="EasyPost Shipping API Client Library for Python", author="EasyPost", author_email="support@easypost.com", diff --git a/tests/cassettes/test_address_create_verify_carrier.yaml b/tests/cassettes/test_address_create_verify_carrier.yaml new file mode 100644 index 00000000..61aa9523 --- /dev/null +++ b/tests/cassettes/test_address_create_verify_carrier.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + body: '{"address": {"company": "EasyPost", "street1": "000 unknown street", "city": + "Not A City", "state": "ZZ", "zip": "00001", "country": "US", "email": "test@example.com", + "phone": "5555555555"}, "verify": true, "verify_carrier": "UPS"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '232' + Content-Type: + - application/json + authorization: + - + user-agent: + - + method: POST + uri: https://api.easypost.com/v2/addresses + response: + body: + string: '{"id": "adr_6bbec015bb5011f082233cecef1b359e", "object": "Address", + "created_at": "2025-11-06T20:37:32Z", "updated_at": "2025-11-06T20:37:32Z", + "name": null, "company": "EASYPOST", "street1": "000 UNKNOWN STREET", "street2": + "", "city": "NOT A CITY", "state": "ZZ", "zip": "00001", "country": "US", + "phone": "", "email": "", "mode": "test", "carrier_facility": + null, "residential": null, "federal_tax_id": null, "state_tax_id": null, "verifications": + {"zip4": {"success": true, "errors": [{"code": "E.ADDRESS.NOT_FOUND", "field": + "address", "message": "Address not found", "suggestion": null}], "details": + null}, "delivery": {"success": true, "errors": [{"code": "E.ADDRESS.NOT_FOUND", + "field": "address", "message": "Address not found", "suggestion": null}], + "details": {"latitude": null, "longitude": null, "time_zone": null}}, "verify_carrier": + "ups"}}' + headers: + cache-control: + - private, no-cache, no-store + content-length: + - '808' + content-type: + - application/json; charset=utf-8 + expires: + - '0' + location: + - /api/v2/addresses/adr_6bbec015bb5011f082233cecef1b359e + pragma: + - no-cache + referrer-policy: + - strict-origin-when-cross-origin + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-backend: + - easypost + x-content-type-options: + - nosniff + x-download-options: + - noopen + x-ep-request-uuid: + - bcd43725690d070be2b85def014ed69a + x-frame-options: + - SAMEORIGIN + x-node: + - bigweb66nuq + x-permitted-cross-domain-policies: + - none + x-proxied: + - intlb4nuq c0061e0a2e + - extlb2nuq cbbd141214 + x-runtime: + - '0.837269' + x-version-label: + - easypost-202511061930-711db047b0-master + x-xss-protection: + - 1; mode=block + status: + code: 201 + message: Created +version: 1 diff --git a/tests/test_address.py b/tests/test_address.py index b05f640e..7dfaee4f 100644 --- a/tests/test_address.py +++ b/tests/test_address.py @@ -1,4 +1,5 @@ import pytest + from easypost.constant import ( _FILTERS_KEY, _TEST_FAILED_INTENTIONALLY_ERROR, @@ -155,3 +156,16 @@ def test_address_verify_invalid_address(test_client): test_client.address.verify(address.id) assert str(error.value) == "Unable to verify address." + + +@pytest.mark.vcr() +def test_address_create_verify_carrier(incorrect_address, test_client): + """Test creating an address with the `verify_carrier` param.""" + incorrect_address["verify"] = True + incorrect_address["verify_carrier"] = "UPS" + address = test_client.address.create(**incorrect_address) + + assert isinstance(address, Address) + + assert address.verifications.delivery.errors[0].message == "Address not found" + assert address.verifications.zip4.errors[0].message == "Address not found" From 6046a5048e24944d484e586d7ac86e4d61f3e5a7 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:02:03 -0700 Subject: [PATCH 2/3] feat: add verify_carrier to create_and_verify also --- easypost/services/address_service.py | 7 +- ...est_address_create_and_verify_carrier.yaml | 82 +++++++++++++++++++ tests/test_address.py | 12 +++ 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 tests/cassettes/test_address_create_and_verify_carrier.yaml diff --git a/easypost/services/address_service.py b/easypost/services/address_service.py index 58eda071..bea69baa 100644 --- a/easypost/services/address_service.py +++ b/easypost/services/address_service.py @@ -51,10 +51,13 @@ def retrieve(self, id) -> Address: """Retrieve an Address.""" return self._retrieve_resource(self._model_class, id) - def create_and_verify(self, **params) -> Address: + def create_and_verify(self, verify_carrier: Optional[str] = None, **params) -> Address: """Create and verify an Address in one call.""" url = f"{self._class_url('address')}/create_and_verify" - wrapped_params = {self._snakecase_name(self._model_class): params} + wrapped_params = {self._snakecase_name(self._model_class): params} # type: dict[str, Any] + + if verify_carrier: + wrapped_params["verify_carrier"] = verify_carrier response = Requestor(self._client).request(method=RequestMethod.POST, url=url, params=wrapped_params) diff --git a/tests/cassettes/test_address_create_and_verify_carrier.yaml b/tests/cassettes/test_address_create_and_verify_carrier.yaml new file mode 100644 index 00000000..065e80db --- /dev/null +++ b/tests/cassettes/test_address_create_and_verify_carrier.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + body: '{"address": {"company": "EasyPost", "street1": "000 unknown street", "city": + "Not A City", "state": "ZZ", "zip": "00001", "country": "US", "email": "test@example.com", + "phone": "5555555555"}, "verify_carrier": "UPS"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '216' + Content-Type: + - application/json + authorization: + - + user-agent: + - + method: POST + uri: https://api.easypost.com/v2/addresses/create_and_verify + response: + body: + string: '{"address": {"id": "adr_b532f4f1bc0311f0b86eac1f6bc539aa", "object": + "Address", "created_at": "2025-11-07T18:00:55Z", "updated_at": "2025-11-07T18:00:55Z", + "name": null, "company": "EASYPOST", "street1": "000 UNKNOWN STREET", "street2": + "", "city": "NOT A CITY", "state": "ZZ", "zip": "00001", "country": "US", + "phone": "", "email": "", "mode": "test", "carrier_facility": + null, "residential": null, "federal_tax_id": null, "state_tax_id": null, "verifications": + {"zip4": {"success": true, "errors": [{"code": "E.ADDRESS.NOT_FOUND", "field": + "address", "message": "Address not found", "suggestion": null}], "details": + null}, "delivery": {"success": true, "errors": [{"code": "E.ADDRESS.NOT_FOUND", + "field": "address", "message": "Address not found", "suggestion": null}], + "details": {"latitude": null, "longitude": null, "time_zone": null}}, "verify_carrier": + "ups"}}}' + headers: + cache-control: + - private, no-cache, no-store + content-length: + - '820' + content-type: + - application/json; charset=utf-8 + expires: + - '0' + location: + - /api/v2/addresses/adr_b532f4f1bc0311f0b86eac1f6bc539aa + pragma: + - no-cache + referrer-policy: + - strict-origin-when-cross-origin + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + x-backend: + - easypost + x-content-type-options: + - nosniff + x-download-options: + - noopen + x-ep-request-uuid: + - bcd43723690e33d7e786a7bd02a1cbd9 + x-frame-options: + - SAMEORIGIN + x-node: + - bigweb42nuq + x-permitted-cross-domain-policies: + - none + x-proxied: + - intlb3nuq c0061e0a2e + - extlb2nuq cbbd141214 + x-runtime: + - '0.492859' + x-version-label: + - easypost-202511071655-85836cab32-master + x-xss-protection: + - 1; mode=block + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_address.py b/tests/test_address.py index 7dfaee4f..ff2a71ac 100644 --- a/tests/test_address.py +++ b/tests/test_address.py @@ -169,3 +169,15 @@ def test_address_create_verify_carrier(incorrect_address, test_client): assert address.verifications.delivery.errors[0].message == "Address not found" assert address.verifications.zip4.errors[0].message == "Address not found" + + +@pytest.mark.vcr() +def test_address_create_and_verify_carrier(incorrect_address, test_client): + """Test creating and verifying an address with the `verify_carrier` param.""" + incorrect_address["verify_carrier"] = "UPS" + address = test_client.address.create_and_verify(**incorrect_address) + + assert isinstance(address, Address) + + assert address.verifications.delivery.errors[0].message == "Address not found" + assert address.verifications.zip4.errors[0].message == "Address not found" From 92a279afeb53bbb631bc5985f46fcf2d686d1020 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:39:50 -0700 Subject: [PATCH 3/3] fix: lint --- tests/test_address.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_address.py b/tests/test_address.py index ff2a71ac..346a9309 100644 --- a/tests/test_address.py +++ b/tests/test_address.py @@ -1,5 +1,4 @@ import pytest - from easypost.constant import ( _FILTERS_KEY, _TEST_FAILED_INTENTIONALLY_ERROR,