From e82a450e2f710f0924279e47659cb1eb3938641d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 23 Apr 2026 11:10:17 -0600 Subject: [PATCH 01/11] Fixed the way we import the python sdk. --- .gitignore | 1 + requirements.txt | 1 + smarty/Makefile | 5 +- smarty/__init__.py | 4 + .../RECORD | 149 -- .../WHEEL | 5 - .../INSTALLER | 0 .../METADATA | 24 +- .../RECORD | 165 +++ .../REQUESTED | 0 .../WHEEL | 5 + .../licenses/LICENSE.md} | 2 +- .../top_level.txt | 0 smarty/smartystreets_python_sdk/__init__.py | 6 +- .../basic_auth_credentials.py | 13 + smarty/smartystreets_python_sdk/batch.py | 2 +- .../client_builder.py | 208 ++- .../custom_header_sender.py | 18 +- .../custom_query_sender.py | 10 + smarty/smartystreets_python_sdk/errors.py | 3 +- .../international_autocomplete/candidate.py | 6 + .../international_autocomplete/client.py | 23 +- .../international_autocomplete/lookup.py | 14 +- .../__init__.py | 2 +- .../international_postal_code/candidate.py | 14 + .../international_postal_code/client.py | 39 + .../international_postal_code/lookup.py | 27 + .../international_street/analysis.py | 2 +- .../international_street/candidate.py | 6 +- .../international_street/changes.py | 4 +- .../international_street/client.py | 8 +- .../international_street/components.py | 13 + .../international_street/lookup.py | 20 +- .../international_street/metadata.py | 2 + smarty/smartystreets_python_sdk/request.py | 2 + .../requests_sender.py | 50 +- smarty/smartystreets_python_sdk/response.py | 9 +- .../smartystreets_python_sdk/retry_sender.py | 27 +- .../status_code_sender.py | 29 +- .../url_prefix_sender.py | 6 +- .../us_autocomplete/client.py | 62 - .../us_autocomplete/geolocation_type.py | 5 - .../us_autocomplete/lookup.py | 36 - .../us_autocomplete/suggestion.py | 9 - .../us_autocomplete_pro/client.py | 9 +- .../us_autocomplete_pro/lookup.py | 10 +- .../us_enrichment/__init__.py | 2 + .../us_enrichment/client.py | 158 +++ .../us_enrichment/lookup.py | 54 + .../us_enrichment/response.py | 1205 +++++++++++++++++ .../us_extract/address.py | 2 +- .../us_extract/client.py | 15 +- .../us_extract/lookup.py | 13 +- .../us_extract/result.py | 4 +- .../us_reverse_geo/address.py | 2 + .../us_reverse_geo/client.py | 8 +- .../us_reverse_geo/lookup.py | 8 +- .../us_reverse_geo/response.py | 2 +- .../us_reverse_geo/result.py | 4 +- .../us_street/analysis.py | 23 + .../us_street/candidate.py | 29 + .../us_street/client.py | 34 +- .../us_street/component_analysis.py | 40 + .../us_street/components.py | 24 + .../us_street/lookup.py | 44 +- .../us_street/match_info.py | 14 + .../us_street/match_type.py | 10 +- .../us_street/metadata.py | 27 + .../us_street/output_format.py | 6 + .../us_zipcode/client.py | 7 +- .../us_zipcode/lookup.py | 4 + .../us_zipcode/result.py | 2 +- .../us_zipcode/zipcode.py | 2 +- .../__init__.py | 2 +- vendor.sh | 21 + 75 files changed, 2377 insertions(+), 444 deletions(-) create mode 100644 requirements.txt delete mode 100644 smarty/smartystreets_python_sdk-4.10.10.dist-info/RECORD delete mode 100644 smarty/smartystreets_python_sdk-4.10.10.dist-info/WHEEL rename smarty/{smartystreets_python_sdk-4.10.10.dist-info => smartystreets_python_sdk-5.7.0.dist-info}/INSTALLER (100%) rename smarty/{smartystreets_python_sdk-4.10.10.dist-info => smartystreets_python_sdk-5.7.0.dist-info}/METADATA (68%) create mode 100644 smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD create mode 100644 smarty/smartystreets_python_sdk-5.7.0.dist-info/REQUESTED create mode 100644 smarty/smartystreets_python_sdk-5.7.0.dist-info/WHEEL rename smarty/{smartystreets_python_sdk-4.10.10.dist-info/LICENSE.txt => smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md} (99%) rename smarty/{smartystreets_python_sdk-4.10.10.dist-info => smartystreets_python_sdk-5.7.0.dist-info}/top_level.txt (100%) create mode 100644 smarty/smartystreets_python_sdk/basic_auth_credentials.py create mode 100644 smarty/smartystreets_python_sdk/custom_query_sender.py rename smarty/smartystreets_python_sdk/{us_autocomplete => international_postal_code}/__init__.py (60%) create mode 100644 smarty/smartystreets_python_sdk/international_postal_code/candidate.py create mode 100644 smarty/smartystreets_python_sdk/international_postal_code/client.py create mode 100644 smarty/smartystreets_python_sdk/international_postal_code/lookup.py delete mode 100644 smarty/smartystreets_python_sdk/us_autocomplete/client.py delete mode 100644 smarty/smartystreets_python_sdk/us_autocomplete/geolocation_type.py delete mode 100644 smarty/smartystreets_python_sdk/us_autocomplete/lookup.py delete mode 100644 smarty/smartystreets_python_sdk/us_autocomplete/suggestion.py create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/__init__.py create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/client.py create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/lookup.py create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/response.py create mode 100644 smarty/smartystreets_python_sdk/us_street/component_analysis.py create mode 100644 smarty/smartystreets_python_sdk/us_street/match_info.py create mode 100644 smarty/smartystreets_python_sdk/us_street/output_format.py create mode 100755 vendor.sh diff --git a/.gitignore b/.gitignore index 0d20b64..d646835 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.pyc +__pycache__/ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e4eb672 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +smartystreets-python-sdk==5.7.0 diff --git a/smarty/Makefile b/smarty/Makefile index 7a821ea..75f9f34 100644 --- a/smarty/Makefile +++ b/smarty/Makefile @@ -77,7 +77,7 @@ PLUGIN_UPLOAD = $(c)/plugin_upload.py RESOURCE_SRC=$(shell grep '^ *@@g;s/.*>//g' | tr '\n' ' ') -.PHONY: default +.PHONY: default vendor default: @echo While you can use make to build and deploy your plugin, pb_tool @echo is a much better solution. @@ -86,6 +86,9 @@ default: @echo You can install pb_tool using: pip install pb_tool @echo See https://g-sherman.github.io/plugin_build_tool/ for info. +vendor: + cd .. && ./vendor.sh + compile: $(COMPILED_RESOURCE_FILES) %.py : %.qrc $(RESOURCES_SRC) diff --git a/smarty/__init__.py b/smarty/__init__.py index baae3bc..279c38e 100644 --- a/smarty/__init__.py +++ b/smarty/__init__.py @@ -25,6 +25,10 @@ import subprocess import platform import os +import sys + +# Allow the vendored SDK to use absolute imports (e.g. import smartystreets_python_sdk) +sys.path.insert(0, os.path.dirname(__file__)) # noinspection PyPep8Naming def classFactory(iface): # pylint: disable=invalid-name diff --git a/smarty/smartystreets_python_sdk-4.10.10.dist-info/RECORD b/smarty/smartystreets_python_sdk-4.10.10.dist-info/RECORD deleted file mode 100644 index 40d0e4c..0000000 --- a/smarty/smartystreets_python_sdk-4.10.10.dist-info/RECORD +++ /dev/null @@ -1,149 +0,0 @@ -smartystreets_python_sdk-4.10.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -smartystreets_python_sdk-4.10.10.dist-info/LICENSE.txt,sha256=wfFs8UMp4X4YdzbdTPLC2p3HIdbsxJprokwf7FZ26lQ,11339 -smartystreets_python_sdk-4.10.10.dist-info/METADATA,sha256=NKwEpde27w01vQy6JEXGiJeAcEA17znQC3g-mJaARC4,886 -smartystreets_python_sdk-4.10.10.dist-info/RECORD,, -smartystreets_python_sdk-4.10.10.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -smartystreets_python_sdk-4.10.10.dist-info/WHEEL,sha256=pqI-DBMA-Z6OTNov1nVxs7mwm6Yj2kHZGNp_6krVn1E,92 -smartystreets_python_sdk-4.10.10.dist-info/top_level.txt,sha256=uPitCujTcHdnUQwzTZKMfb1GoYxgM5Evyq_CJrhfVnU,58 -smartystreets_python_sdk/__init__.py,sha256=-fHaa1wOejp58OA3agPoLSyrin98Hnvky2SkFQY1wbg,697 -smartystreets_python_sdk/__init__.pyc,, -smartystreets_python_sdk/batch.py,sha256=FafhYEGpTbHIb6oGkBozblsf00PNfMQsCVT_EY0c-aw,1371 -smartystreets_python_sdk/batch.pyc,, -smartystreets_python_sdk/client_builder.py,sha256=BAgUBBzBfxPRD1c8KWtei82yFS7fRrzBIPFmviR3LGQ,7385 -smartystreets_python_sdk/client_builder.pyc,, -smartystreets_python_sdk/custom_header_sender.py,sha256=62XL5jCFgMD4r-dhhcsQ6VBpyWEGBYOIEpFJMD0KEaA,654 -smartystreets_python_sdk/custom_header_sender.pyc,, -smartystreets_python_sdk/errors.py,sha256=jiuvem4dCo-A0uB7OURpFEi4IBIClGnpisYdNnEbrcU,1197 -smartystreets_python_sdk/errors.pyc,, -smartystreets_python_sdk/exceptions.py,sha256=8hel1fr7kYHOL3DSUCL06RwKNJf-DQgxqc8NFTyYZKg,652 -smartystreets_python_sdk/exceptions.pyc,, -smartystreets_python_sdk/international_autocomplete/__init__.py,sha256=zmHkBQ4bBdQRXgA98Luey4xGgAOYUD0j8_nMcz-1kDw,87 -smartystreets_python_sdk/international_autocomplete/__init__.pyc,, -smartystreets_python_sdk/international_autocomplete/candidate.py,sha256=VkWko9Z5DxFw2WOs9d1W4BVO-F5VB567I1MSZT9IihI,333 -smartystreets_python_sdk/international_autocomplete/candidate.pyc,, -smartystreets_python_sdk/international_autocomplete/client.py,sha256=yRttLwMoV88NKvZxfKojyKcMcWH8w-B6b4b_LIsJbbE,1879 -smartystreets_python_sdk/international_autocomplete/client.pyc,, -smartystreets_python_sdk/international_autocomplete/lookup.py,sha256=vZ9-W_RFsp0DBkW-qZIbvN3UGu2LJslIeiGnQ9OThMk,944 -smartystreets_python_sdk/international_autocomplete/lookup.pyc,, -smartystreets_python_sdk/international_street/__init__.py,sha256=lCUAdOYSQ4vKvcSRvmGIjElHWPE188CXrGtHEMUnbWg,184 -smartystreets_python_sdk/international_street/__init__.pyc,, -smartystreets_python_sdk/international_street/analysis.py,sha256=va5FCw0oCR_d7eME-8fvQ2ErwFvHnwB6ZLxt_jUuOgM,437 -smartystreets_python_sdk/international_street/analysis.pyc,, -smartystreets_python_sdk/international_street/candidate.py,sha256=vV3jAYYRQZTHi9LKzbs4_02gtdsuVoGYecK6y2dmKwc,672 -smartystreets_python_sdk/international_street/candidate.pyc,, -smartystreets_python_sdk/international_street/changes.py,sha256=qBUYwl90FKppDLLg1j4VG4yi6GzYAeVracwEO5I9Yu0,226 -smartystreets_python_sdk/international_street/changes.pyc,, -smartystreets_python_sdk/international_street/client.py,sha256=Eu79399Q0I4C3kB4SjAnQHXq1XuAV5WLu5cGH0MwrFU,2155 -smartystreets_python_sdk/international_street/client.pyc,, -smartystreets_python_sdk/international_street/components.py,sha256=EycQ70Y4O-8uX-22zziF4HNu92Jw8USb0flJuq65cug,2957 -smartystreets_python_sdk/international_street/components.pyc,, -smartystreets_python_sdk/international_street/language_mode.py,sha256=zf45F-2Y-RCYdE88JcRnN8R2HPs_EbP6A2chYTKvhbk,35 -smartystreets_python_sdk/international_street/language_mode.pyc,, -smartystreets_python_sdk/international_street/lookup.py,sha256=BaJ-Dhkk0BZ6CySFpWc-AjhRgdQngSmQuSA1s676VS0,2719 -smartystreets_python_sdk/international_street/lookup.pyc,, -smartystreets_python_sdk/international_street/metadata.py,sha256=R3hsaddRnTCvUDxrBCHFbF02UxEhTrMpbnOjrmq4aI8,462 -smartystreets_python_sdk/international_street/metadata.pyc,, -smartystreets_python_sdk/international_street/rootlevel.py,sha256=ZeErBuBhNkgD7-nEOXa4EDYN-EOYvlKqPiaycz_J_08,759 -smartystreets_python_sdk/international_street/rootlevel.pyc,, -smartystreets_python_sdk/license_sender.py,sha256=hAPSejluaFcAjhG2B5nt910Q474hnbtMnbb2FPUXi3c,313 -smartystreets_python_sdk/license_sender.pyc,, -smartystreets_python_sdk/native_serializer.py,sha256=QpN2-woD1Muu3bzr-LVzF4n3l-0Ae2OtynVCW4YxoIc,225 -smartystreets_python_sdk/native_serializer.pyc,, -smartystreets_python_sdk/proxy.py,sha256=2asS-F-v_rikgPQvVJh10oI5Wp8ezprS1E10tZUFKXc,506 -smartystreets_python_sdk/proxy.pyc,, -smartystreets_python_sdk/request.py,sha256=KimKG7na_LM9K-2VQlsmojxtrxuibSlx8GYQ39zPcoM,251 -smartystreets_python_sdk/request.pyc,, -smartystreets_python_sdk/requests_sender.py,sha256=Ts5_KLKrNFi5FXl1-fifyI2qFlSeHjyDD3l35kszvGY,2795 -smartystreets_python_sdk/requests_sender.pyc,, -smartystreets_python_sdk/response.py,sha256=53o9VM65SUScD2FMOuoxS8K6OxxG6KGLP7EelgbBt8c,171 -smartystreets_python_sdk/response.pyc,, -smartystreets_python_sdk/retry_sender.py,sha256=rf4BDETABJ3ntZ_nCACq2xBMJ9VthwJ0l3Kvrs1RVA4,914 -smartystreets_python_sdk/retry_sender.pyc,, -smartystreets_python_sdk/shared_credentials.py,sha256=YJTE3_089mTqB2OlLSfxUfp9s33MoiHG3DB65zTxoNs,248 -smartystreets_python_sdk/shared_credentials.pyc,, -smartystreets_python_sdk/signing_sender.py,sha256=g5USdC86_HnL5t2oH2oyCqEevakcqdVhedML-ws4OEI,220 -smartystreets_python_sdk/signing_sender.pyc,, -smartystreets_python_sdk/static_credentials.py,sha256=BHx34sjh-QKqjGziAaYASFSblG0WpvEnAqNwz1BQe58,280 -smartystreets_python_sdk/static_credentials.pyc,, -smartystreets_python_sdk/status_code_sender.py,sha256=bkAyaEISpRXIEG0FOocnKEKTAKAs7wJBXRmfx32Y1S8,1731 -smartystreets_python_sdk/status_code_sender.pyc,, -smartystreets_python_sdk/url_prefix_sender.py,sha256=KpheftpOBKz23LA_ZqOv4xvQDcPbnMNOrOzlZjEUYhk,246 -smartystreets_python_sdk/url_prefix_sender.pyc,, -smartystreets_python_sdk/us_autocomplete/__init__.py,sha256=l4m1GmSshTs5jtUVwrGIwFZ0FaPUwjhPzOpgVg6udDs,89 -smartystreets_python_sdk/us_autocomplete/__init__.pyc,, -smartystreets_python_sdk/us_autocomplete/client.py,sha256=NGvZuztUIKWQcsNQXRjkSo8TOjTskyJQ61Z1kEpbpqI,2367 -smartystreets_python_sdk/us_autocomplete/client.pyc,, -smartystreets_python_sdk/us_autocomplete/geolocation_type.py,sha256=3TKIUY4ZcCT3qPa04Sb_xFmGCrgSmS9X4CeENQbHSbw,46 -smartystreets_python_sdk/us_autocomplete/geolocation_type.pyc,, -smartystreets_python_sdk/us_autocomplete/lookup.py,sha256=eq14oFMebMGGoopN4FhUTFRyj-c9CIrQ9XQamvhle6o,1783 -smartystreets_python_sdk/us_autocomplete/lookup.pyc,, -smartystreets_python_sdk/us_autocomplete/suggestion.py,sha256=RYTb38g8mNJP6lCcPjvUREjDm6nLqKY0i2Ww6LSwJnE,345 -smartystreets_python_sdk/us_autocomplete/suggestion.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/__init__.py,sha256=l4m1GmSshTs5jtUVwrGIwFZ0FaPUwjhPzOpgVg6udDs,89 -smartystreets_python_sdk/us_autocomplete_pro/__init__.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/client.py,sha256=TxlMnZKRAswzCjgjt2hFh_yh-Sca8YJ7EgHx4Z-nob0,2751 -smartystreets_python_sdk/us_autocomplete_pro/client.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/geolocation_type.py,sha256=Y3Dl2fYDyCnEZY6e39CV8v5iLFfdoo7y3BxkdXZBHCI,29 -smartystreets_python_sdk/us_autocomplete_pro/geolocation_type.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/lookup.py,sha256=M1b-zZQmfMwXsZUADEipdr5cjxgF9tVw6PbveCfzwiY,3825 -smartystreets_python_sdk/us_autocomplete_pro/lookup.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/suggestion.py,sha256=eMr4BDL0XK5wwCIt1Ijt1RJVtDrKKCdnmZe-HAOb3xU,451 -smartystreets_python_sdk/us_autocomplete_pro/suggestion.pyc,, -smartystreets_python_sdk/us_extract/__init__.py,sha256=Fc_OZTtDwP5lE1HXFnbrcGXmEa6pNU4MJxvXlgAUuSU,141 -smartystreets_python_sdk/us_extract/__init__.pyc,, -smartystreets_python_sdk/us_extract/address.py,sha256=vtMzxoocQGISehKm78Bzqm-hqif-o-_-P0OB-Q2AZO4,613 -smartystreets_python_sdk/us_extract/address.pyc,, -smartystreets_python_sdk/us_extract/client.py,sha256=kJISbQqJrtZEaEKVN8q5JXAmoysgo45t-5vMd4hYOSc,1789 -smartystreets_python_sdk/us_extract/client.pyc,, -smartystreets_python_sdk/us_extract/lookup.py,sha256=yvTvGSDsyuWuGJ7dDvCKAe5ZFQE3PUSMAk-CEwdkIr0,664 -smartystreets_python_sdk/us_extract/lookup.pyc,, -smartystreets_python_sdk/us_extract/metadata.py,sha256=4j898o9Wp_QxCgGqVxGUkHn7Hm2Lb35lHQv98bZhfHo,478 -smartystreets_python_sdk/us_extract/metadata.pyc,, -smartystreets_python_sdk/us_extract/result.py,sha256=yPnmrotiq5-DHU1x6FxRkpjo6KiACWpOrjG-U2eIrMw,619 -smartystreets_python_sdk/us_extract/result.pyc,, -smartystreets_python_sdk/us_reverse_geo/__init__.py,sha256=ePdvUgk-y-6jTZzGmDPiyPgpi6u_dSmF5mWHJLXezD4,176 -smartystreets_python_sdk/us_reverse_geo/__init__.pyc,, -smartystreets_python_sdk/us_reverse_geo/address.py,sha256=KLhbzoCZ5xfm1BpvLM0oRlqrj3BbVQ1oAXvYWzsi4w8,352 -smartystreets_python_sdk/us_reverse_geo/address.pyc,, -smartystreets_python_sdk/us_reverse_geo/client.py,sha256=ysUswSzKnlB5-HdIfih1_kcfRRvOp-KQxsQL3zkML00,1195 -smartystreets_python_sdk/us_reverse_geo/client.pyc,, -smartystreets_python_sdk/us_reverse_geo/coordinate.py,sha256=qlnkLnV3nsCP_5s91UoovBgdsmQHLxGmvrmHLFk1BqQ,507 -smartystreets_python_sdk/us_reverse_geo/coordinate.pyc,, -smartystreets_python_sdk/us_reverse_geo/lookup.py,sha256=PKXh5CQdUZZscMdDJ5S9z7wU2xCDHL8aSv9VJ-HQBO4,456 -smartystreets_python_sdk/us_reverse_geo/lookup.pyc,, -smartystreets_python_sdk/us_reverse_geo/response.py,sha256=lyI8XRkzvnMFgvK7ndGj0GSzwOERChrw5FY3wBZl0ps,194 -smartystreets_python_sdk/us_reverse_geo/response.pyc,, -smartystreets_python_sdk/us_reverse_geo/result.py,sha256=5sRFUwoJsBqMRmZ5JhqD_VBCv3kcLarXSYNV1A07aCc,379 -smartystreets_python_sdk/us_reverse_geo/result.pyc,, -smartystreets_python_sdk/us_street/__init__.py,sha256=f_baQcNCWCTLwH9uGO_xsFPdfgK10gT7aA1sItGLCuA,185 -smartystreets_python_sdk/us_street/__init__.pyc,, -smartystreets_python_sdk/us_street/analysis.py,sha256=dmCBbr0kk6lgBjXAlzaO9ad-s9ZHvNW-aGv68eeVM2w,846 -smartystreets_python_sdk/us_street/analysis.pyc,, -smartystreets_python_sdk/us_street/candidate.py,sha256=-YEgvktqj-TZ8BPA9MPLRpZmXIkytZtlflh6aILBDZs,1109 -smartystreets_python_sdk/us_street/candidate.pyc,, -smartystreets_python_sdk/us_street/client.py,sha256=rhSvysBFXRo_YTbEx78v4goDnLclRlCModHmG5KDTfE,2778 -smartystreets_python_sdk/us_street/client.pyc,, -smartystreets_python_sdk/us_street/components.py,sha256=3i1LjfMZN6RjKaouvIbG3_EYnL1OZfH6yLPBOTHwCKs,1479 -smartystreets_python_sdk/us_street/components.pyc,, -smartystreets_python_sdk/us_street/lookup.py,sha256=zBOoj_T-4w4Y5P9X2d61knyMVWcKFtVzeRGceZJLLMM,1036 -smartystreets_python_sdk/us_street/lookup.pyc,, -smartystreets_python_sdk/us_street/match_type.py,sha256=6Y8nyFiTRs57lv8-6226tOZpv1luYeGXUNdAstLVyMA,93 -smartystreets_python_sdk/us_street/match_type.pyc,, -smartystreets_python_sdk/us_street/metadata.py,sha256=levNpe-PKRrvwqS0OJ73wRJX100V0BcqJ5JZnc8_Fhg,1098 -smartystreets_python_sdk/us_street/metadata.pyc,, -smartystreets_python_sdk/us_zipcode/__init__.py,sha256=Yw0343wwUaSD0FTS5GfTEgsK3lsqr-1OqOX7KGLrCsc,179 -smartystreets_python_sdk/us_zipcode/__init__.pyc,, -smartystreets_python_sdk/us_zipcode/alternate_county.py,sha256=j1ya-Dosx_ZbxBE9reTHK23meavitEsH2FpzIa5o-qE,353 -smartystreets_python_sdk/us_zipcode/alternate_county.pyc,, -smartystreets_python_sdk/us_zipcode/city.py,sha256=0SAnjWOli2t38wsQSSb28JkdSTMWctWToMljeiIXYzw,411 -smartystreets_python_sdk/us_zipcode/city.pyc,, -smartystreets_python_sdk/us_zipcode/client.py,sha256=20FBgBUv2obzOulkW2hRq9jvdcALChm2Wse8TC40lNI,2055 -smartystreets_python_sdk/us_zipcode/client.pyc,, -smartystreets_python_sdk/us_zipcode/lookup.py,sha256=BVeH2Lk4iDaHkZ2upIrDB7UCKLsUo_9zqpiXkI7b7i0,536 -smartystreets_python_sdk/us_zipcode/lookup.pyc,, -smartystreets_python_sdk/us_zipcode/result.py,sha256=HZiLJ6xmJ6jdFwNCmBJDPA4uH5kNHIjpZ2Rj2cCw4Io,938 -smartystreets_python_sdk/us_zipcode/result.pyc,, -smartystreets_python_sdk/us_zipcode/zipcode.py,sha256=gHJAv6nObkKi8hdcRgOgEfTOazEmXB6uAFr2rWhbqao,852 -smartystreets_python_sdk/us_zipcode/zipcode.pyc,, -smartystreets_python_sdk_version/__init__.py,sha256=eoQ06I4YmaZFSv1QIjpQ-vN4AvbZXHMYft3SesIP80k,124 -smartystreets_python_sdk_version/__init__.pyc,, diff --git a/smarty/smartystreets_python_sdk-4.10.10.dist-info/WHEEL b/smarty/smartystreets_python_sdk-4.10.10.dist-info/WHEEL deleted file mode 100644 index 32b6cef..0000000 --- a/smarty/smartystreets_python_sdk-4.10.10.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.1) -Root-Is-Purelib: true -Tag: py2-none-any - diff --git a/smarty/smartystreets_python_sdk-4.10.10.dist-info/INSTALLER b/smarty/smartystreets_python_sdk-5.7.0.dist-info/INSTALLER similarity index 100% rename from smarty/smartystreets_python_sdk-4.10.10.dist-info/INSTALLER rename to smarty/smartystreets_python_sdk-5.7.0.dist-info/INSTALLER diff --git a/smarty/smartystreets_python_sdk-4.10.10.dist-info/METADATA b/smarty/smartystreets_python_sdk-5.7.0.dist-info/METADATA similarity index 68% rename from smarty/smartystreets_python_sdk-4.10.10.dist-info/METADATA rename to smarty/smartystreets_python_sdk-5.7.0.dist-info/METADATA index bc9ca68..2644bfe 100644 --- a/smarty/smartystreets_python_sdk-4.10.10.dist-info/METADATA +++ b/smarty/smartystreets_python_sdk-5.7.0.dist-info/METADATA @@ -1,22 +1,30 @@ -Metadata-Version: 2.1 -Name: smartystreets-python-sdk -Version: 4.10.10 +Metadata-Version: 2.4 +Name: smartystreets_python_sdk +Version: 5.7.0 Summary: An official library to help Python developers easily access the SmartyStreets APIs Home-page: https://github.com/smartystreets/smartystreets-python-sdk +Download-URL: https://github.com/smartystreets/smartystreets-python-sdk/tarball/5.7.0 Author: SmartyStreets SDK Team Author-email: support@smartystreets.com License: Apache 2 -Download-URL: https://github.com/smartystreets/smartystreets-python-sdk/tarball/4.10.10 Keywords: smartystreets,smarty,address,validation,verification,street,sdk,library,geocode -Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Natural Language :: English -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 +License-File: LICENSE.md Requires-Dist: requests +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: download-url +Dynamic: home-page +Dynamic: keywords +Dynamic: license +Dynamic: license-file +Dynamic: requires-dist +Dynamic: summary Official Python library for SmartyStreets - - diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD b/smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD new file mode 100644 index 0000000..882ad3f --- /dev/null +++ b/smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD @@ -0,0 +1,165 @@ +smartystreets_python_sdk-5.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +smartystreets_python_sdk-5.7.0.dist-info/METADATA,sha256=9o091ZFO6l87lmmH0z4OO7EgWlOdDtJI8i2mya2Ctg0,1054 +smartystreets_python_sdk-5.7.0.dist-info/RECORD,, +smartystreets_python_sdk-5.7.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +smartystreets_python_sdk-5.7.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91 +smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md,sha256=Cu67SvL5YQlDIEaH0UOH2rlm4LIPiCfdO4hlAACCWl4,11332 +smartystreets_python_sdk-5.7.0.dist-info/top_level.txt,sha256=uPitCujTcHdnUQwzTZKMfb1GoYxgM5Evyq_CJrhfVnU,58 +smartystreets_python_sdk/__init__.py,sha256=cJpR9L-R1gDD7b4-L3QJltQOacFe8Sdom586X3feFJo,805 +smartystreets_python_sdk/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/basic_auth_credentials.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/batch.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/client_builder.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/custom_header_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/custom_query_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/errors.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/exceptions.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/license_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/native_serializer.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/proxy.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/request.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/requests_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/response.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/retry_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/shared_credentials.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/signing_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/static_credentials.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/status_code_sender.cpython-311.pyc,, +smartystreets_python_sdk/__pycache__/url_prefix_sender.cpython-311.pyc,, +smartystreets_python_sdk/basic_auth_credentials.py,sha256=-9vCG8z0Mr8GR-7Zl8UuXWbfzposXc9aIRa1Ynjz2Ek,401 +smartystreets_python_sdk/batch.py,sha256=FafhYEGpTbHIb6oGkBozblsf00PNfMQsCVT_EY0c-aw,1371 +smartystreets_python_sdk/client_builder.py,sha256=g-hhGVT9xSzFEZnkApabmITcpJe8K0I8ZXLQnZ5047A,12787 +smartystreets_python_sdk/custom_header_sender.py,sha256=fH0b1_fvxa1q5dePM3Wa8QQBwpeJhnjPvBz4ydVv9yU,1166 +smartystreets_python_sdk/custom_query_sender.py,sha256=q238mqAOh3nK26HS5mHUmeucT3_ki6ue5PFJtOAcTMw,364 +smartystreets_python_sdk/errors.py,sha256=aJz6de55P4IJQkaVmz4EApywhEjsVV0lP1yKzoRRqos,1091 +smartystreets_python_sdk/exceptions.py,sha256=8hel1fr7kYHOL3DSUCL06RwKNJf-DQgxqc8NFTyYZKg,652 +smartystreets_python_sdk/international_autocomplete/__init__.py,sha256=zmHkBQ4bBdQRXgA98Luey4xGgAOYUD0j8_nMcz-1kDw,87 +smartystreets_python_sdk/international_autocomplete/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/international_autocomplete/__pycache__/candidate.cpython-311.pyc,, +smartystreets_python_sdk/international_autocomplete/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/international_autocomplete/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/international_autocomplete/candidate.py,sha256=SMy274DXAIwA7Gp4jQ_-oFbAzPU7vuYQaDrpvHVNrKQ,679 +smartystreets_python_sdk/international_autocomplete/client.py,sha256=ejuGxnrt6C2-jHlvq5QOanzOlssdOOoPqaAzhEQaGNs,2339 +smartystreets_python_sdk/international_autocomplete/lookup.py,sha256=HZdbDW3DpfUuuSa8yU9zuIBxYHm6rApV6YU_qNFjcCM,1268 +smartystreets_python_sdk/international_postal_code/__init__.py,sha256=zmHkBQ4bBdQRXgA98Luey4xGgAOYUD0j8_nMcz-1kDw,87 +smartystreets_python_sdk/international_postal_code/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/international_postal_code/__pycache__/candidate.cpython-311.pyc,, +smartystreets_python_sdk/international_postal_code/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/international_postal_code/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/international_postal_code/candidate.py,sha256=cOEHsemaWzOfPoUE21BdqLMvqE4LgR_zkKuWBtdt8fM,829 +smartystreets_python_sdk/international_postal_code/client.py,sha256=MoWTqqwN0xuiQdoOduYL2UiwW8YeUY27cAxIddjLR_8,1570 +smartystreets_python_sdk/international_postal_code/lookup.py,sha256=J55Hi62-nvRTpjNHrNOnOdNeh-mb-Ed3De1v1jmLyVs,945 +smartystreets_python_sdk/international_street/__init__.py,sha256=lCUAdOYSQ4vKvcSRvmGIjElHWPE188CXrGtHEMUnbWg,184 +smartystreets_python_sdk/international_street/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/analysis.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/candidate.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/changes.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/components.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/language_mode.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/metadata.cpython-311.pyc,, +smartystreets_python_sdk/international_street/__pycache__/rootlevel.cpython-311.pyc,, +smartystreets_python_sdk/international_street/analysis.py,sha256=va5FCw0oCR_d7eME-8fvQ2ErwFvHnwB6ZLxt_jUuOgM,437 +smartystreets_python_sdk/international_street/candidate.py,sha256=vV3jAYYRQZTHi9LKzbs4_02gtdsuVoGYecK6y2dmKwc,672 +smartystreets_python_sdk/international_street/changes.py,sha256=qBUYwl90FKppDLLg1j4VG4yi6GzYAeVracwEO5I9Yu0,226 +smartystreets_python_sdk/international_street/client.py,sha256=gtJcIjrRcvfhUuxnNjE8n19SO3M2ZGdDce87U60DA48,2370 +smartystreets_python_sdk/international_street/components.py,sha256=Q8VbHv5jTaOJ_gYAoTxFpKZHibNYz3fQLBqKPnD7Az0,3812 +smartystreets_python_sdk/international_street/language_mode.py,sha256=zf45F-2Y-RCYdE88JcRnN8R2HPs_EbP6A2chYTKvhbk,35 +smartystreets_python_sdk/international_street/lookup.py,sha256=qmYEEAwXI85mcG5CoPPBKmOt51SVaAdf7l1L4IkYPY4,2679 +smartystreets_python_sdk/international_street/metadata.py,sha256=DM9VJAxrUV5czeOwxt3ea6171-xBupUSVZRFWGsKEWw,598 +smartystreets_python_sdk/international_street/rootlevel.py,sha256=ZeErBuBhNkgD7-nEOXa4EDYN-EOYvlKqPiaycz_J_08,759 +smartystreets_python_sdk/license_sender.py,sha256=hAPSejluaFcAjhG2B5nt910Q474hnbtMnbb2FPUXi3c,313 +smartystreets_python_sdk/native_serializer.py,sha256=QpN2-woD1Muu3bzr-LVzF4n3l-0Ae2OtynVCW4YxoIc,225 +smartystreets_python_sdk/proxy.py,sha256=2asS-F-v_rikgPQvVJh10oI5Wp8ezprS1E10tZUFKXc,506 +smartystreets_python_sdk/request.py,sha256=YbgBBmJuAKpcDAfeskk8BkSe_5EUuO8W3pPvI-LJ0cg,311 +smartystreets_python_sdk/requests_sender.py,sha256=x3Ltx2ykmZVHOwdvO39SFqKI61dMiS0zwhqWbuJ0LuQ,3253 +smartystreets_python_sdk/response.py,sha256=0lh6bn471YekUSVKOPKvK3sQy-6dFc3Qw9F2729nOlM,361 +smartystreets_python_sdk/retry_sender.py,sha256=8V2_a1PKKvILKhUMrvQINXc5CIa7JhWOnOrb5HBnHG4,1257 +smartystreets_python_sdk/shared_credentials.py,sha256=YJTE3_089mTqB2OlLSfxUfp9s33MoiHG3DB65zTxoNs,248 +smartystreets_python_sdk/signing_sender.py,sha256=g5USdC86_HnL5t2oH2oyCqEevakcqdVhedML-ws4OEI,220 +smartystreets_python_sdk/static_credentials.py,sha256=BHx34sjh-QKqjGziAaYASFSblG0WpvEnAqNwz1BQe58,280 +smartystreets_python_sdk/status_code_sender.py,sha256=7n1OWEoXBvQJMh4bcdkizy66uuBLasG10NFsWYvm1e0,2444 +smartystreets_python_sdk/url_prefix_sender.py,sha256=_NGjV9fNbaQI9zRfsVHpmIraXE0L6nC6AygNNbbsHS4,372 +smartystreets_python_sdk/us_autocomplete_pro/__init__.py,sha256=l4m1GmSshTs5jtUVwrGIwFZ0FaPUwjhPzOpgVg6udDs,89 +smartystreets_python_sdk/us_autocomplete_pro/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_autocomplete_pro/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/us_autocomplete_pro/__pycache__/geolocation_type.cpython-311.pyc,, +smartystreets_python_sdk/us_autocomplete_pro/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/us_autocomplete_pro/__pycache__/suggestion.cpython-311.pyc,, +smartystreets_python_sdk/us_autocomplete_pro/client.py,sha256=6emfu5NqeIgIEnAsLKDYuuCdgqWBCkdqgnVXqpP1cEM,2901 +smartystreets_python_sdk/us_autocomplete_pro/geolocation_type.py,sha256=Y3Dl2fYDyCnEZY6e39CV8v5iLFfdoo7y3BxkdXZBHCI,29 +smartystreets_python_sdk/us_autocomplete_pro/lookup.py,sha256=aDJ5Fhu8m2O6C_vmj8EzOVTDzPr3Hc576PEuRDsLzMo,4314 +smartystreets_python_sdk/us_autocomplete_pro/suggestion.py,sha256=eMr4BDL0XK5wwCIt1Ijt1RJVtDrKKCdnmZe-HAOb3xU,451 +smartystreets_python_sdk/us_enrichment/__init__.py,sha256=ZllT-z0eZvAYEnscXzsEAEFBlVHXE1GytW2Z95Xy9UA,50 +smartystreets_python_sdk/us_enrichment/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/__pycache__/response.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/client.py,sha256=wFBEWoH8a0MWdNUjZYzbWXhb-sYEvOd3EfyO_zzfdmg,5445 +smartystreets_python_sdk/us_enrichment/lookup.py,sha256=pjPNkHj0YPowYlF_nxWDiKPBYQYtALRait_CfXFz2bI,1935 +smartystreets_python_sdk/us_enrichment/response.py,sha256=zqQBPMTFkYDJ-wI6iDt2bfz4aeHnTSGs7utnuLD_Hq0,62925 +smartystreets_python_sdk/us_extract/__init__.py,sha256=Fc_OZTtDwP5lE1HXFnbrcGXmEa6pNU4MJxvXlgAUuSU,141 +smartystreets_python_sdk/us_extract/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_extract/__pycache__/address.cpython-311.pyc,, +smartystreets_python_sdk/us_extract/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/us_extract/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/us_extract/__pycache__/metadata.cpython-311.pyc,, +smartystreets_python_sdk/us_extract/__pycache__/result.cpython-311.pyc,, +smartystreets_python_sdk/us_extract/address.py,sha256=vtMzxoocQGISehKm78Bzqm-hqif-o-_-P0OB-Q2AZO4,613 +smartystreets_python_sdk/us_extract/client.py,sha256=k4KMcFohAnMZ_hO-ciyC5rzoFmNMOgOZ-DuCb7uMoHg,2207 +smartystreets_python_sdk/us_extract/lookup.py,sha256=6xnVgkT_nbz5eGtZWYhorOH-_RbSAY1o7tX89bmuzbI,945 +smartystreets_python_sdk/us_extract/metadata.py,sha256=4j898o9Wp_QxCgGqVxGUkHn7Hm2Lb35lHQv98bZhfHo,478 +smartystreets_python_sdk/us_extract/result.py,sha256=yPnmrotiq5-DHU1x6FxRkpjo6KiACWpOrjG-U2eIrMw,619 +smartystreets_python_sdk/us_reverse_geo/__init__.py,sha256=ePdvUgk-y-6jTZzGmDPiyPgpi6u_dSmF5mWHJLXezD4,176 +smartystreets_python_sdk/us_reverse_geo/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/__pycache__/address.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/__pycache__/coordinate.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/__pycache__/response.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/__pycache__/result.cpython-311.pyc,, +smartystreets_python_sdk/us_reverse_geo/address.py,sha256=9ImBpoVsI-CSkntZsELiDwY3_FHhK0VLdmxLghe4RVs,451 +smartystreets_python_sdk/us_reverse_geo/client.py,sha256=gsGAaXsbkDPE9ma6gEilbhjO6FeSKfnVKmXEG-WXoQc,1406 +smartystreets_python_sdk/us_reverse_geo/coordinate.py,sha256=qlnkLnV3nsCP_5s91UoovBgdsmQHLxGmvrmHLFk1BqQ,507 +smartystreets_python_sdk/us_reverse_geo/lookup.py,sha256=4EwaqCpsBRAuUpVkN8gevTK7FVzGiJU34YJ8rvxgZhw,647 +smartystreets_python_sdk/us_reverse_geo/response.py,sha256=lyI8XRkzvnMFgvK7ndGj0GSzwOERChrw5FY3wBZl0ps,194 +smartystreets_python_sdk/us_reverse_geo/result.py,sha256=5sRFUwoJsBqMRmZ5JhqD_VBCv3kcLarXSYNV1A07aCc,379 +smartystreets_python_sdk/us_street/__init__.py,sha256=f_baQcNCWCTLwH9uGO_xsFPdfgK10gT7aA1sItGLCuA,185 +smartystreets_python_sdk/us_street/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/analysis.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/candidate.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/component_analysis.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/components.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/match_info.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/match_type.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/metadata.cpython-311.pyc,, +smartystreets_python_sdk/us_street/__pycache__/output_format.cpython-311.pyc,, +smartystreets_python_sdk/us_street/analysis.py,sha256=y4tnZ-K9acqWtfAKkkS7EaMDpJdNjY8Z-yTcmEgb3g4,1802 +smartystreets_python_sdk/us_street/candidate.py,sha256=O7YCz-rz3wu20pblQ0AnwaYeBLWhRIFkuQvMBGwAqFY,2284 +smartystreets_python_sdk/us_street/client.py,sha256=qSZo3Wv1wOGPqwpMVwwUbPAZdj8cfNFbPBKngsubnJ4,3780 +smartystreets_python_sdk/us_street/component_analysis.py,sha256=SCNHra9OGVR-DZmSDuRuE1t4Ff8ZLSbj1QSt-9JrMIQ,3162 +smartystreets_python_sdk/us_street/components.py,sha256=uG5UCNxcxeGvHtca9aixt2tk5LF7sXDne6yVB_t3nww,2630 +smartystreets_python_sdk/us_street/lookup.py,sha256=_PZhl9T-UBrsMQq-XFXefHzMn37mLDu7augUMYb9BeY,2245 +smartystreets_python_sdk/us_street/match_info.py,sha256=IlrotWKFgbU2Ea3_F4j2ttuv2-L4cQCtb323JGbQauE,428 +smartystreets_python_sdk/us_street/match_type.py,sha256=Y_MlddxylUgBmW_f20HmfEqoyJfp4TiVzaXxXEsTWG4,124 +smartystreets_python_sdk/us_street/metadata.py,sha256=VWlTYqfaeMlJeDvyjIGwS2ZV_dS0GZyBnlOhJ6mdu1o,2294 +smartystreets_python_sdk/us_street/output_format.py,sha256=YuFLP81dRw43gwae2CO28FE4z8zoH2GlzCEkJhJu4qQ,111 +smartystreets_python_sdk/us_zipcode/__init__.py,sha256=Yw0343wwUaSD0FTS5GfTEgsK3lsqr-1OqOX7KGLrCsc,179 +smartystreets_python_sdk/us_zipcode/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/__pycache__/alternate_county.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/__pycache__/city.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/__pycache__/client.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/__pycache__/lookup.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/__pycache__/result.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/__pycache__/zipcode.cpython-311.pyc,, +smartystreets_python_sdk/us_zipcode/alternate_county.py,sha256=j1ya-Dosx_ZbxBE9reTHK23meavitEsH2FpzIa5o-qE,353 +smartystreets_python_sdk/us_zipcode/city.py,sha256=0SAnjWOli2t38wsQSSb28JkdSTMWctWToMljeiIXYzw,411 +smartystreets_python_sdk/us_zipcode/client.py,sha256=9UJzNvk7BM3DC00wltIdmDyLA-0fHsSiguceES_jcDo,2205 +smartystreets_python_sdk/us_zipcode/lookup.py,sha256=SYlMExfKS9clDrDOdE7RX69XAUK3yjPeIIQ_gfBvXDQ,687 +smartystreets_python_sdk/us_zipcode/result.py,sha256=HZiLJ6xmJ6jdFwNCmBJDPA4uH5kNHIjpZ2Rj2cCw4Io,938 +smartystreets_python_sdk/us_zipcode/zipcode.py,sha256=gHJAv6nObkKi8hdcRgOgEfTOazEmXB6uAFr2rWhbqao,852 +smartystreets_python_sdk_version/__init__.py,sha256=pkujCwAzmEFZh_I47UMkNRFvSaqfWtBlzTM7TgqvB5E,122 +smartystreets_python_sdk_version/__pycache__/__init__.cpython-311.pyc,, diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/REQUESTED b/smarty/smartystreets_python_sdk-5.7.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/WHEEL b/smarty/smartystreets_python_sdk-5.7.0.dist-info/WHEEL new file mode 100644 index 0000000..14a883f --- /dev/null +++ b/smarty/smartystreets_python_sdk-5.7.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (82.0.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/smarty/smartystreets_python_sdk-4.10.10.dist-info/LICENSE.txt b/smarty/smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md similarity index 99% rename from smarty/smartystreets_python_sdk-4.10.10.dist-info/LICENSE.txt rename to smarty/smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md index 28577e6..6611688 100644 --- a/smarty/smartystreets_python_sdk-4.10.10.dist-info/LICENSE.txt +++ b/smarty/smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright SmartyStreets + Copyright Smarty Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/smarty/smartystreets_python_sdk-4.10.10.dist-info/top_level.txt b/smarty/smartystreets_python_sdk-5.7.0.dist-info/top_level.txt similarity index 100% rename from smarty/smartystreets_python_sdk-4.10.10.dist-info/top_level.txt rename to smarty/smartystreets_python_sdk-5.7.0.dist-info/top_level.txt diff --git a/smarty/smartystreets_python_sdk/__init__.py b/smarty/smartystreets_python_sdk/__init__.py index 61d2bfc..c1b66e8 100644 --- a/smarty/smartystreets_python_sdk/__init__.py +++ b/smarty/smartystreets_python_sdk/__init__.py @@ -4,14 +4,16 @@ from .native_serializer import NativeSerializer from .static_credentials import StaticCredentials from .shared_credentials import SharedCredentials +from .basic_auth_credentials import BasicAuthCredentials from .status_code_sender import StatusCodeSender from .signing_sender import SigningSender from .license_sender import LicenseSender from .custom_header_sender import CustomHeaderSender from .retry_sender import RetrySender from .url_prefix_sender import URLPrefixSender +from .custom_query_sender import CustomQuerySender from .batch import Batch from .client_builder import ClientBuilder from .proxy import Proxy -# import smartystreets_python_sdk.errors -# import smartystreets_python_sdk.exceptions +import smartystreets_python_sdk.errors +import smartystreets_python_sdk.exceptions diff --git a/smarty/smartystreets_python_sdk/basic_auth_credentials.py b/smarty/smartystreets_python_sdk/basic_auth_credentials.py new file mode 100644 index 0000000..d965c58 --- /dev/null +++ b/smarty/smartystreets_python_sdk/basic_auth_credentials.py @@ -0,0 +1,13 @@ +class CredentialsRequired(Exception): + pass + + +class BasicAuthCredentials: + def __init__(self, auth_id, auth_token): + if not auth_id or not auth_token: + raise CredentialsRequired("credentials (auth_id, auth_token) required") + self.auth_id = auth_id + self.auth_token = auth_token + + def sign(self, request): + request.auth = (self.auth_id, self.auth_token) diff --git a/smarty/smartystreets_python_sdk/batch.py b/smarty/smartystreets_python_sdk/batch.py index 3443843..9476ec4 100644 --- a/smarty/smartystreets_python_sdk/batch.py +++ b/smarty/smartystreets_python_sdk/batch.py @@ -1,4 +1,4 @@ -from .exceptions import BatchFullError +from smartystreets_python_sdk.exceptions import BatchFullError class Batch: diff --git a/smarty/smartystreets_python_sdk/client_builder.py b/smarty/smartystreets_python_sdk/client_builder.py index 6a7235c..c89b987 100644 --- a/smarty/smartystreets_python_sdk/client_builder.py +++ b/smarty/smartystreets_python_sdk/client_builder.py @@ -1,13 +1,13 @@ -# import smartystreets_python_sdk as smarty -from . import * -from .us_street import Client as USStreetClient -from .us_zipcode import Client as USZIPClient -from .us_extract import Client as USExtractClient -from .us_autocomplete import Client as USAutocompleteClient -from .us_autocomplete_pro import Client as USAutocompleteProClient -from .us_reverse_geo import Client as USReverseGeoClient -from .international_street import Client as InternationalStreetClient -from .international_autocomplete import Client as InternationalAutocompleteClient +import smartystreets_python_sdk as smarty +from smartystreets_python_sdk.us_street import Client as USStreetClient +from smartystreets_python_sdk.us_zipcode import Client as USZIPClient +from smartystreets_python_sdk.us_extract import Client as USExtractClient +from smartystreets_python_sdk.us_autocomplete_pro import Client as USAutocompleteProClient +from smartystreets_python_sdk.us_reverse_geo import Client as USReverseGeoClient +from smartystreets_python_sdk.international_street import Client as InternationalStreetClient +from smartystreets_python_sdk.international_autocomplete import Client as InternationalAutocompleteClient +from smartystreets_python_sdk.us_enrichment import Client as USEnrichmentClient +from smartystreets_python_sdk.international_postal_code import Client as InternationalPostalCodeClient class ClientBuilder: @@ -18,23 +18,28 @@ def __init__(self, signer): These methods are chainable, so you can usually get set up with one line of code. """ self.signer = signer - self.serializer = NativeSerializer() # TODO: + self.serializer = smarty.NativeSerializer() self.http_sender = None self.max_retries = 5 - self.max_timeout = 10000 + self.max_timeout = 10 self.url_prefix = None self.proxy = None + self.ip = None self.debug = None self.header = None + self.append_headers = {} self.licenses = [] - self.INTERNATIONAL_STREET_API_URL = "https://international-street.api.smartystreets.com/verify" - self.INTERNATIONAL_AUTOCOMPLETE_API_URL = "https://international-autocomplete.api.smartystreets.com/lookup" - self.US_AUTOCOMPLETE_API_URL = "https://us-autocomplete.api.smartystreets.com/suggest" - self.US_AUTOCOMPLETE_PRO_API_URL = "https://us-autocomplete-pro.api.smartystreets.com/lookup" - self.US_EXTRACT_API_URL = "https://us-extract.api.smartystreets.com" - self.US_STREET_API_URL = "https://us-street.api.smartystreets.com/street-address" - self.US_ZIP_CODE_API_URL = "https://us-zipcode.api.smartystreets.com/lookup" - self.US_REVERSE_GEO_API_URL = "https://us-reverse-geo.api.smartystreets.com/lookup" + self.pool_size = None + self.custom_queries = None + self.INTERNATIONAL_STREET_API_URL = "https://international-street.api.smarty.com/verify" + self.INTERNATIONAL_AUTOCOMPLETE_API_URL = "https://international-autocomplete.api.smarty.com/v2/lookup" + self.US_AUTOCOMPLETE_PRO_API_URL = "https://us-autocomplete-pro.api.smarty.com/lookup" + self.US_EXTRACT_API_URL = "https://us-extract.api.smarty.com" + self.US_STREET_API_URL = "https://us-street.api.smarty.com/street-address" + self.US_ZIP_CODE_API_URL = "https://us-zipcode.api.smarty.com/lookup" + self.US_REVERSE_GEO_API_URL = "https://us-reverse-geo.api.smarty.com/lookup" + self.US_ENRICHMENT_API_URL = "https://us-enrichment.api.smarty.com/lookup/" + self.INTERNATIONAL_POSTAL_CODE_API_URL = "https://international-postal-code.api.smarty.com/lookup" def retry_at_most(self, max_retries): """ @@ -47,8 +52,8 @@ def retry_at_most(self, max_retries): def with_max_timeout(self, max_timeout): """ - The maximum time (in milliseconds) to wait for a connection, and also to wait for - the response to be read. (Default is 10000) + The maximum time (in seconds) to wait for a connection, and also to wait for + the response to be read. (Default is 10) Returns self to accommodate method chaining. """ @@ -57,7 +62,7 @@ def with_max_timeout(self, max_timeout): def with_sender(self, sender): """ - Default is a series of nested senders. (See build_sender() + Sets the innermost HTTP transport sender while keeping the full middleware chain intact. Returns self to accommodate method chaining. """ @@ -83,24 +88,69 @@ def with_base_url(self, base_url): self.url_prefix = base_url return self - def with_proxy(self, host, username=None, password=None): + def with_http_proxy(self, host, username=None, password=None): """ - Assigns a proxy through which to send all Lookups. + Assigns a http proxy through which to send all Lookups. :param host: The proxy host including port, but not scheme. (example: localhost:8080) :param username: Username to authenticate with the proxy server :param password: Password to authenticate with the proxy server :return: Returns self to accommodate method chaining. """ - self.proxy = Proxy(host, username, password) # TODO + full_host = 'http://' + host + self.proxy = smarty.Proxy(full_host, username, password) + return self + + def with_https_proxy(self, host, username=None, password=None): + """ + Assigns a https proxy through which to send all Lookups. + :param host: The proxy host including port, but not scheme. (example: localhost:8080) + :param username: Username to authenticate with the proxy server + :param password: Password to authenticate with the proxy server + :return: Returns self to accommodate method chaining. + """ + full_host = 'https://' + host + self.proxy = smarty.Proxy(full_host, username, password) return self def with_custom_header(self, custom_header): """ - Create custom headers when necessary. + Create custom headers when necessary. Headers are merged with any existing custom headers. :param custom_header: Input your custom headers :return: Returns self to accommodate method chaining """ - self.header = custom_header + if self.header is None: + self.header = {} + self.header.update(custom_header) + return self + + def with_appended_header(self, key, value, separator): + """ + Appends the provided value to the existing header value using the specified separator, + rather than adding a separate header value. This is useful for single-value headers like User-Agent. + :param key: The header key + :param value: The header value to append + :param separator: The separator to use when joining values + :return: Returns self to accommodate method chaining + """ + self.append_headers[key] = separator + if self.header is None: + self.header = {} + if key in self.header: + if isinstance(self.header[key], list): + self.header[key].append(value) + else: + self.header[key] = [self.header[key], value] + else: + self.header[key] = [value] + return self + + def with_x_forwarded_for(self, ip): + """ + Add and X-Forwarded-For header when necessary. + :param ip: Input the desired ip for the X-Forwarded-For header + :return: Returns self to accommodate method chaining + """ + self.ip = ip return self def with_debug(self): @@ -120,6 +170,52 @@ def with_licenses(self, licenses): """ self.licenses = licenses return self + + def with_connection_pool_size(self, connections): + """ + Allows the caller to specify the size of the connection pool for multithreading. + :param connections: The desired size of the connection pool + """ + self.pool_size = connections + return self + + def with_custom_query(self, key, value): + """ + Allows the caller to specify key and value pair that is added to the request query. + :param key: The key of the custom query parameter + :param value: The value of the custom query parameter + :return: Returns self to accommodate method chaining + """ + if self.custom_queries is None: + self.custom_queries = {} + self.custom_queries[key] = value + return self + + def with_custom_comma_separated_query(self, key, values): + """ + Allows the caller to specify a key and value pair and appends the value to the current value associated with the key, separated by a comma. + :param key: The key of the custom query parameter + :param values: The value of the custom query parameter + :return: Returns self to accommodate method chaining + """ + if self.custom_queries is None: + self.custom_queries = {} + if key in self.custom_queries: + self.custom_queries[key] = self.custom_queries[key] + ',' + values + else: + self.custom_queries[key] = values + return self + + def with_feature_component_analysis(self): + """ + Adds to the request query to use the component analysis feature. + :return: Returns self to accommodate method chaining + """ + return self.with_custom_comma_separated_query('features', 'component-analysis') + + def with_feature_iana_time_zone(self): + """with_feature_iana_time_zone turns on the IANA timezone feature for the request.""" + return self.with_custom_comma_separated_query('features', 'iana-timezone') def build_international_street_api_client(self): self.ensure_url_prefix_not_null(self.INTERNATIONAL_STREET_API_URL) @@ -129,10 +225,6 @@ def build_international_autocomplete_api_client(self): self.ensure_url_prefix_not_null(self.INTERNATIONAL_AUTOCOMPLETE_API_URL) return InternationalAutocompleteClient(self.build_sender(), self.serializer) - def build_us_autocomplete_api_client(self): - self.ensure_url_prefix_not_null(self.US_AUTOCOMPLETE_API_URL) - return USAutocompleteClient(self.build_sender(), self.serializer) - def build_us_autocomplete_pro_api_client(self): self.ensure_url_prefix_not_null(self.US_AUTOCOMPLETE_PRO_API_URL) return USAutocompleteProClient(self.build_sender(), self.serializer) @@ -153,27 +245,53 @@ def build_us_reverse_geo_api_client(self): self.ensure_url_prefix_not_null(self.US_REVERSE_GEO_API_URL) return USReverseGeoClient(self.build_sender(), self.serializer) - def build_sender(self): - if self.http_sender is not None: - return self.http_sender - - sender = RequestsSender(self.max_timeout, self.proxy) # TODO - sender.debug = self.debug + def build_us_enrichment_api_client(self): + self.ensure_url_prefix_not_null(self.US_ENRICHMENT_API_URL) + return USEnrichmentClient(self.build_sender(), self.serializer) - sender = StatusCodeSender(sender) # TODO + def build_international_postal_code_api_client(self): + self.ensure_url_prefix_not_null(self.INTERNATIONAL_POSTAL_CODE_API_URL) + return InternationalPostalCodeClient(self.build_sender(), self.serializer) - if self.header is not None: - sender = CustomHeaderSender(self.header, sender) # TODO + def build_sender(self): + if self.http_sender is not None: + conflicts = [] + if self.max_timeout != 10: + conflicts.append("with_max_timeout()") + if self.proxy is not None: + conflicts.append("with_http_proxy()/with_https_proxy()") + if self.debug is not None: + conflicts.append("with_debug()") + if self.pool_size is not None: + conflicts.append("with_connection_pool_size()") + if conflicts: + raise ValueError("with_sender() cannot be combined with: {}. These options only apply to the built-in HTTP transport.".format(", ".join(conflicts))) + sender = self.http_sender + else: + sender = smarty.RequestsSender(self.max_timeout, self.proxy, self.pool_size) + sender.debug = self.debug + + sender = smarty.StatusCodeSender(sender) + + effective_header = dict(self.header) if self.header is not None else {} + if self.ip is not None: + effective_header['X-Forwarded-For'] = self.ip + + if effective_header: + sender = smarty.CustomHeaderSender(effective_header, sender, self.append_headers) + + if self.custom_queries is not None: + sender = smarty.CustomQuerySender(self.custom_queries, sender) if self.signer is not None: - sender = SigningSender(self.signer, sender) # TODO + sender = smarty.SigningSender(self.signer, sender) if self.max_retries > 0: - sender = RetrySender(self.max_retries, sender) # TODO + sender = smarty.RetrySender(self.max_retries, sender) - sender = URLPrefixSender(self.url_prefix, sender) # TODO + sender = smarty.URLPrefixSender(self.url_prefix, sender) - sender = LicenseSender(self.licenses, sender) # TODO + sender = smarty.LicenseSender(self.licenses, sender) return sender diff --git a/smarty/smartystreets_python_sdk/custom_header_sender.py b/smarty/smartystreets_python_sdk/custom_header_sender.py index 7d0fad7..9399096 100644 --- a/smarty/smartystreets_python_sdk/custom_header_sender.py +++ b/smarty/smartystreets_python_sdk/custom_header_sender.py @@ -2,9 +2,10 @@ class CustomHeaderSender: - def __init__(self, headers, inner): + def __init__(self, headers, inner, append_headers=None): self.headers = headers self.inner = inner + self.append_headers = append_headers or {} def send(self, smarty_request): request = self.build_request(smarty_request) @@ -12,10 +13,23 @@ def send(self, smarty_request): def build_request(self, smarty_request): request = Request(url=smarty_request.url_prefix, params=smarty_request.parameters) - request.headers = self.headers + request.headers = self.apply_headers() if smarty_request.payload: request.data = smarty_request.payload request.method = 'POST' else: request.method = 'GET' return request + + def apply_headers(self): + result = {} + for key, value in self.headers.items(): + if key in self.append_headers: + separator = self.append_headers[key] + if isinstance(value, list): + result[key] = separator.join(value) + else: + result[key] = value + else: + result[key] = value + return result diff --git a/smarty/smartystreets_python_sdk/custom_query_sender.py b/smarty/smartystreets_python_sdk/custom_query_sender.py new file mode 100644 index 0000000..59b3ea1 --- /dev/null +++ b/smarty/smartystreets_python_sdk/custom_query_sender.py @@ -0,0 +1,10 @@ +class CustomQuerySender: + def __init__(self, custom_queries, inner): + self.custom_queries = custom_queries + self.inner = inner + + def send(self, request): + if self.custom_queries is not None: + for key, value in self.custom_queries.items(): + request.parameters[key] = value + return self.inner.send(request) \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/errors.py b/smarty/smartystreets_python_sdk/errors.py index bd266f3..9bead9f 100644 --- a/smarty/smartystreets_python_sdk/errors.py +++ b/smarty/smartystreets_python_sdk/errors.py @@ -14,8 +14,7 @@ UNPROCESSABLE_ENTITY = "GET request lacked required fields." -TOO_MANY_REQUESTS = "When using public \"website key\" authentication, \ -we restrict the number of requests coming from a given source over too short of a time." +TOO_MANY_REQUESTS = "The rate limit has been exceeded." INTERNAL_SERVER_ERROR = "Internal Server Error." diff --git a/smarty/smartystreets_python_sdk/international_autocomplete/candidate.py b/smarty/smartystreets_python_sdk/international_autocomplete/candidate.py index 2bd5c0a..0619c4c 100644 --- a/smarty/smartystreets_python_sdk/international_autocomplete/candidate.py +++ b/smarty/smartystreets_python_sdk/international_autocomplete/candidate.py @@ -3,5 +3,11 @@ def __init__(self, obj=None): self.street = obj.get('street', None) self.locality = obj.get('locality', None) self.administrative_area = obj.get('administrative_area', None) + self.administrative_area_short = obj.get('administrative_area_short', None) + self.administrative_area_long = obj.get('administrative_area_long', None) self.postal_code = obj.get('postal_code', None) self.country_iso3 = obj.get('country_iso3', None) + # v2 fields + self.entries = obj.get('entries', None) + self.address_text = obj.get('address_text', None) + self.address_id = obj.get('address_id', None) diff --git a/smarty/smartystreets_python_sdk/international_autocomplete/client.py b/smarty/smartystreets_python_sdk/international_autocomplete/client.py index 4642a55..50755f5 100644 --- a/smarty/smartystreets_python_sdk/international_autocomplete/client.py +++ b/smarty/smartystreets_python_sdk/international_autocomplete/client.py @@ -1,12 +1,12 @@ -# from smartystreets_python_sdk import Request -from ..exceptions import SmartyException -# from . import Candidate +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.exceptions import SmartyException +from smartystreets_python_sdk.international_autocomplete import Candidate class Client: def __init__(self, sender, serializer): """ - It is recommended to instantiate this class using ClientBuilder.build_us_autocomplete_api_client() + It is recommended to instantiate this class using ClientBuilder.build_international_autocomplete_api_client() """ self.sender = sender self.serializer = serializer @@ -15,8 +15,8 @@ def send(self, lookup): """ Sends a Lookup object to the International Autocomplete API and stores the result in the Lookup's result field. """ - if not lookup or not lookup.search: - raise SmartyException('Send() must be passed a Lookup with the search field set.') + if not lookup or (not lookup.search and not lookup.address_id): + raise SmartyException('Send() must be passed a Lookup with country set, and search or address_id set.') request = self.build_request(lookup) @@ -34,12 +34,21 @@ def send(self, lookup): def build_request(self, lookup): request = Request() + if lookup.address_id is not None: + request.url_components = "/" + lookup.address_id + self.add_parameter(request, 'country', lookup.country) self.add_parameter(request, 'search', lookup.search) - self.add_parameter(request, 'include_only_administrative_area', lookup.administrative_area) + self.add_parameter(request, 'max_results', lookup.max_results) + self.add_parameter(request, 'max_group_results', lookup.max_group_results) + if lookup.geolocation: + self.add_parameter(request, 'geolocation', 'on') self.add_parameter(request, 'include_only_locality', lookup.locality) self.add_parameter(request, 'include_only_postal_code', lookup.postal_code) + for parameter in lookup.custom_parameter_array: + self.add_parameter(request, parameter, lookup.custom_parameter_array[parameter]) + return request @staticmethod diff --git a/smarty/smartystreets_python_sdk/international_autocomplete/lookup.py b/smarty/smartystreets_python_sdk/international_autocomplete/lookup.py index 53a3365..bf6a656 100644 --- a/smarty/smartystreets_python_sdk/international_autocomplete/lookup.py +++ b/smarty/smartystreets_python_sdk/international_autocomplete/lookup.py @@ -1,7 +1,8 @@ class Lookup: - def __init__(self, search=None, country=None, administrative_area=None, locality=None, postal_code=None): + def __init__(self, search=None, address_id=None, country=None, max_results=5, max_group_results=100, + geolocation=False, locality=None, postal_code=None): """ - In addition to holding all of the input data for this lookup, this class also will contain the result + In addition to holding all the input data for this lookup, this class also will contain the result of the lookup after it comes back from the API. :param country: The country where the desired address is located (required) @@ -12,8 +13,15 @@ def __init__(self, search=None, country=None, administrative_area=None, locality """ self.result = [] + self.custom_parameter_array = {} self.search = search + self.address_id = address_id self.country = country - self.administrative_area = administrative_area + self.max_results = max_results + self.max_group_results = max_group_results + self.geolocation = geolocation self.locality = locality self.postal_code = postal_code + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value diff --git a/smarty/smartystreets_python_sdk/us_autocomplete/__init__.py b/smarty/smartystreets_python_sdk/international_postal_code/__init__.py similarity index 60% rename from smarty/smartystreets_python_sdk/us_autocomplete/__init__.py rename to smarty/smartystreets_python_sdk/international_postal_code/__init__.py index fea7586..c1c21b8 100644 --- a/smarty/smartystreets_python_sdk/us_autocomplete/__init__.py +++ b/smarty/smartystreets_python_sdk/international_postal_code/__init__.py @@ -1,3 +1,3 @@ -from .suggestion import Suggestion +from .candidate import Candidate from .lookup import Lookup from .client import Client diff --git a/smarty/smartystreets_python_sdk/international_postal_code/candidate.py b/smarty/smartystreets_python_sdk/international_postal_code/candidate.py new file mode 100644 index 0000000..652b3c1 --- /dev/null +++ b/smarty/smartystreets_python_sdk/international_postal_code/candidate.py @@ -0,0 +1,14 @@ +class Candidate: + def __init__(self, obj=None): + obj = obj or {} + self.input_id = obj.get('input_id', None) + self.administrative_area = obj.get('administrative_area', None) + self.sub_administrative_area = obj.get('sub_administrative_area', None) + self.super_administrative_area = obj.get('super_administrative_area', None) + self.country_iso_3 = obj.get('country_iso_3', None) + self.locality = obj.get('locality', None) + self.dependent_locality = obj.get('dependent_locality', None) + self.dependent_locality_name = obj.get('dependent_locality_name', None) + self.double_dependent_locality = obj.get('double_dependent_locality', None) + self.postal_code = obj.get('postal_code', None) + self.postal_code_extra = obj.get('postal_code_extra', None) diff --git a/smarty/smartystreets_python_sdk/international_postal_code/client.py b/smarty/smartystreets_python_sdk/international_postal_code/client.py new file mode 100644 index 0000000..ade2196 --- /dev/null +++ b/smarty/smartystreets_python_sdk/international_postal_code/client.py @@ -0,0 +1,39 @@ +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.international_postal_code import Candidate + +class Client: + def __init__(self, sender, serializer): + """ + It is recommended to instantiate this class using ClientBuilder.build_international_postal_code_api_client() + """ + self.sender = sender + self.serializer = serializer + + def send(self, lookup): + if not lookup: + raise ValueError("Send() must be passed a Lookup object with required fields set.") + request = self.build_request(lookup) + response = self.sender.send(request) + if getattr(response, 'error', None): + raise response.error + candidates = self.convert_candidates(self.serializer.deserialize(response.payload)) + lookup.results = candidates + return candidates + + def build_request(self, lookup): + request = Request() + self.add_parameter(request, 'input_id', lookup.input_id) + self.add_parameter(request, 'country', lookup.country) + self.add_parameter(request, 'locality', lookup.locality) + self.add_parameter(request, 'administrative_area', lookup.administrative_area) + self.add_parameter(request, 'postal_code', lookup.postal_code) + return request + + @staticmethod + def convert_candidates(candidate_dicts): + return [Candidate(obj) for obj in (candidate_dicts or [])] + + @staticmethod + def add_parameter(request, key, value): + if value and value != 'none': + request.parameters[key] = value diff --git a/smarty/smartystreets_python_sdk/international_postal_code/lookup.py b/smarty/smartystreets_python_sdk/international_postal_code/lookup.py new file mode 100644 index 0000000..2e77566 --- /dev/null +++ b/smarty/smartystreets_python_sdk/international_postal_code/lookup.py @@ -0,0 +1,27 @@ +class Lookup: + def __init__(self): + """ + In addition to holding all the input data for this lookup, this class also will contain the result + of the lookup after it comes back from the API. + + See "https://smartystreets.com/docs/cloud/international-postal-code-api" + """ + self.results = [] + + self.input_id = None + self.country = None + self.locality = None + self.administrative_area = None + self.postal_code = None + + def populate(self, params): + if self.input_id: + params['input_id'] = self.input_id + if self.country: + params['country'] = self.country + if self.locality: + params['locality'] = self.locality + if self.administrative_area: + params['administrative_area'] = self.administrative_area + if self.postal_code: + params['postal_code'] = self.postal_code diff --git a/smarty/smartystreets_python_sdk/international_street/analysis.py b/smarty/smartystreets_python_sdk/international_street/analysis.py index 4bd3e8c..1d2ae73 100644 --- a/smarty/smartystreets_python_sdk/international_street/analysis.py +++ b/smarty/smartystreets_python_sdk/international_street/analysis.py @@ -1,4 +1,4 @@ -# from . import Changes +from .changes import Changes class Analysis: def __init__(self, obj): diff --git a/smarty/smartystreets_python_sdk/international_street/candidate.py b/smarty/smartystreets_python_sdk/international_street/candidate.py index 99a2d49..1a088e6 100644 --- a/smarty/smartystreets_python_sdk/international_street/candidate.py +++ b/smarty/smartystreets_python_sdk/international_street/candidate.py @@ -1,6 +1,6 @@ -# from . import Components -# from . import Metadata -# from . import Analysis +from .components import Components +from .metadata import Metadata +from .analysis import Analysis from .rootlevel import RootLevel class Candidate(RootLevel): diff --git a/smarty/smartystreets_python_sdk/international_street/changes.py b/smarty/smartystreets_python_sdk/international_street/changes.py index 6e74da0..9a5ce87 100644 --- a/smarty/smartystreets_python_sdk/international_street/changes.py +++ b/smarty/smartystreets_python_sdk/international_street/changes.py @@ -1,5 +1,5 @@ -# from . import Components -# from . import RootLevel +from .components import Components +from .rootlevel import RootLevel class Changes(RootLevel): def __init__(self, obj): diff --git a/smarty/smartystreets_python_sdk/international_street/client.py b/smarty/smartystreets_python_sdk/international_street/client.py index 8253b74..b84c310 100644 --- a/smarty/smartystreets_python_sdk/international_street/client.py +++ b/smarty/smartystreets_python_sdk/international_street/client.py @@ -1,5 +1,5 @@ -# from smartystreets_python_sdk import Request -# from . import Candidate +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.international_street import Candidate class Client: @@ -42,6 +42,10 @@ def build_request(self, lookup): self.add_parameter(request, 'locality', lookup.locality) self.add_parameter(request, 'administrative_area', lookup.administrative_area) self.add_parameter(request, 'postal_code', lookup.postal_code) + self.add_parameter(request, 'features', lookup.features) + + for parameter in lookup.custom_parameter_array: + self.add_parameter(request, parameter, lookup.custom_parameter_array[parameter]) return request diff --git a/smarty/smartystreets_python_sdk/international_street/components.py b/smarty/smartystreets_python_sdk/international_street/components.py index e129f3a..654abc0 100644 --- a/smarty/smartystreets_python_sdk/international_street/components.py +++ b/smarty/smartystreets_python_sdk/international_street/components.py @@ -6,6 +6,9 @@ def __init__(self, obj): self.country_iso_3 = obj.get("country_iso_3", None) self.super_administrative_area = obj.get("super_administrative_area", None) self.administrative_area = obj.get("administrative_area", None) + self.administrative_area_iso2 = obj.get("administrative_area_iso2", None) + self.administrative_area_short = obj.get("administrative_area_short", None) + self.administrative_area_long = obj.get("administrative_area_long", None) self.sub_administrative_area = obj.get("sub_administrative_area", None) self.dependent_locality= obj.get("dependent_locality", None) self.dependent_locality_name = obj.get("dependent_locality_name", None) @@ -39,6 +42,16 @@ def __init__(self, obj): self.sub_building_number = obj.get("sub_building_number", None) self.sub_building_name = obj.get("sub_building_name", None) self.sub_building = obj.get("sub_building", None) + self.level_type = obj.get("level_type", None) + self.level_number = obj.get("level_number", None) self.post_box = obj.get("post_box", None) self.post_box_type = obj.get("post_box_type", None) self.post_box_number = obj.get("post_box_number", None) + self.additional_content = obj.get("additional_content", None) + self.delivery_installation = obj.get("delivery_installation", None) + self.delivery_installation_type = obj.get("delivery_installation_type", None) + self.delivery_installation_qualifier_name = obj.get("delivery_installation_qualifier_name", None) + self.route = obj.get("route", None) + self.route_number = obj.get("route_number", None) + self.route_type = obj.get("route_type", None) + diff --git a/smarty/smartystreets_python_sdk/international_street/lookup.py b/smarty/smartystreets_python_sdk/international_street/lookup.py index 18f35c7..49dbdbc 100644 --- a/smarty/smartystreets_python_sdk/international_street/lookup.py +++ b/smarty/smartystreets_python_sdk/international_street/lookup.py @@ -1,4 +1,4 @@ -from ..exceptions import UnprocessableEntityError +from smartystreets_python_sdk.exceptions import UnprocessableEntityError class Lookup: @@ -19,6 +19,7 @@ def __init__(self, freeform=None, country=None): """ self.result = [] + self.custom_parameter_array = {} self.input_id = None self.country = country self.geocode = None @@ -32,6 +33,7 @@ def __init__(self, freeform=None, country=None): self.locality = None self.administrative_area = None self.postal_code = None + self.features = None @property def missing_country(self): @@ -61,17 +63,11 @@ def field_is_set(self, field): return not self.field_is_missing(field) def ensure_enough_info(self): - if self.missing_country: + if self.field_is_missing(self.country): raise UnprocessableEntityError('Country field is required.') - if self.has_freeform: - return True - - if self.missing_address1: + if self.field_is_missing(self.freeform) and self.field_is_missing(self.address1): raise UnprocessableEntityError('Either freeform or address1 is required.') - - if self.has_postal_code: - return True - - if self.missing_locality_or_administrative_area: - raise UnprocessableEntityError('Insufficient information: One or more required fields were not set on the lookup.') + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value diff --git a/smarty/smartystreets_python_sdk/international_street/metadata.py b/smarty/smartystreets_python_sdk/international_street/metadata.py index d248d3e..278cc95 100644 --- a/smarty/smartystreets_python_sdk/international_street/metadata.py +++ b/smarty/smartystreets_python_sdk/international_street/metadata.py @@ -6,5 +6,7 @@ def __init__(self, obj): self.latitude = obj.get('latitude', None) self.longitude = obj.get('longitude', None) self.geocode_precision = obj.get('geocode_precision', None) + self.geocode_classification = obj.get('geocode_classification', None) self.max_geocode_precision = obj.get('max_geocode_precision', None) self.address_format = obj.get('address_format', None) + self.occupant_use = obj.get("occupant_use", None) diff --git a/smarty/smartystreets_python_sdk/request.py b/smarty/smartystreets_python_sdk/request.py index 2346fa5..c4c9af1 100644 --- a/smarty/smartystreets_python_sdk/request.py +++ b/smarty/smartystreets_python_sdk/request.py @@ -6,5 +6,7 @@ def __init__(self): self.parameters = OrderedDict() self.payload = None self.url_prefix = None + self.url_components = None self.referer = None self.content_type = 'application/json' + self.auth = None diff --git a/smarty/smartystreets_python_sdk/requests_sender.py b/smarty/smartystreets_python_sdk/requests_sender.py index c600c6b..5e53014 100644 --- a/smarty/smartystreets_python_sdk/requests_sender.py +++ b/smarty/smartystreets_python_sdk/requests_sender.py @@ -1,20 +1,23 @@ from requests import Session, Request from .response import Response -from .exceptions import SmartyException -# import smartystreets_python_sdk as smarty -# import smartystreets_python_sdk_version as version -from ..smartystreets_python_sdk_version import __version__ +import requests.adapters +import smartystreets_python_sdk as smarty +import smartystreets_python_sdk_version as version class RequestsSender: - def __init__(self, max_timeout=None, proxy=None): + def __init__(self, max_timeout=None, proxy=None, pool_size=None): self.session = Session() - self.max_timeout = max_timeout or 10000 + self.max_timeout = max_timeout or 10 self.proxy = proxy self.debug = None + self.pool_size = pool_size def send(self, smarty_request): request = build_request(smarty_request) + if (self.pool_size != None): + adapter = requests.adapters.HTTPAdapter(pool_connections=self.pool_size, pool_maxsize=self.pool_size) + self.session.mount('https://', adapter) prepped_request = self.session.prepare_request(request) prepped_proxies = self.build_proxies() if self.debug: @@ -23,40 +26,37 @@ def send(self, smarty_request): settings = self.session.merge_environment_settings( prepped_request.url, prepped_proxies, None, None, None ) - try: - response = self.session.send(prepped_request, timeout=self.max_timeout, **settings) - except Exception as e: - return Response(None, None, e) - - if self.debug: - print_response_data(response) - - return build_smarty_response(response) + with self.session.send(prepped_request, timeout=self.max_timeout, **settings) as response: + if self.debug: + print_response_data(response) + return build_smarty_response(response) def build_proxies(self): if not self.proxy: return {} - if not self.proxy.host: - # raise smarty.exceptions.SmartyException('Proxy must have a valid host (including port)') - raise SmartyException('Proxy must have a valid host (including port)') + if (self.proxy.host == 'http://' or self.proxy.host =='https://'): + raise smarty.exceptions.SmartyException('Proxy must have a valid host (including port)') - proxy_string = 'https://' + proxy_string = self.proxy.host if self.proxy.username: proxy_string += '{}:{}@'.format(self.proxy.username, self.proxy.password) - proxy_string += self.proxy.host - - return {'https': proxy_string} + if ('https://' in self.proxy.host): + return {'https': proxy_string} + else: + return {'http': proxy_string, 'https': proxy_string} def build_request(smarty_request): try: request = Request(url=smarty_request.url_prefix, params=smarty_request.parameters) - request.headers['User-Agent'] = "smartystreets (qgis@{})".format(__version__) + request.headers['User-Agent'] = "smartystreets (sdk:python@{})".format(version.__version__) request.headers['Content-Type'] = smarty_request.content_type if smarty_request.referer: request.headers['Referer'] = smarty_request.referer + if smarty_request.auth: + request.auth = smarty_request.auth if smarty_request.payload: request.data = smarty_request.payload request.method = 'POST' @@ -67,8 +67,8 @@ def build_request(smarty_request): return smarty_request -def build_smarty_response(inner_response): - return Response(inner_response.text, inner_response.status_code) +def build_smarty_response(inner_response, error=None): + return Response(inner_response.text, inner_response.status_code, inner_response.headers, error) def print_request_data(request): diff --git a/smarty/smartystreets_python_sdk/response.py b/smarty/smartystreets_python_sdk/response.py index 5cfaaa5..4e6cc32 100644 --- a/smarty/smartystreets_python_sdk/response.py +++ b/smarty/smartystreets_python_sdk/response.py @@ -1,5 +1,12 @@ class Response: - def __init__(self, payload, status_code, error=None): + def __init__(self, payload, status_code, headers=None, error=None): self.payload = payload self.status_code = status_code + self.headers = headers self.error = error + + def getHeader(self, header): + if self.headers is None: + return None + else: + return self.headers[header] diff --git a/smarty/smartystreets_python_sdk/retry_sender.py b/smarty/smartystreets_python_sdk/retry_sender.py index d19e6b5..bf547a3 100644 --- a/smarty/smartystreets_python_sdk/retry_sender.py +++ b/smarty/smartystreets_python_sdk/retry_sender.py @@ -5,8 +5,9 @@ class RetrySender: MAX_BACKOFF_DURATION = 10 - STATUS_OK = 200 TOO_MANY_REQUESTS = 429 + STATUS_TO_RETRY = [408, 500, 502, 503, 504] + def __init__(self, max_retries, inner): self.inner = inner @@ -16,21 +17,29 @@ def send(self, request): response = self.inner.send(request) for i in range(self.max_retries): - if response.status_code == RetrySender.STATUS_OK: - break - if response.status_code == RetrySender.TOO_MANY_REQUESTS: - backoff(5) - else: + backoff_seconds = 10 + retry_after = response.getHeader("Retry-After") + + if retry_after is not None: + backoff_seconds = int(retry_after) + + backoff(backoff_seconds, True) + elif response.status_code in RetrySender.STATUS_TO_RETRY: backoff(i) + else: + break response = self.inner.send(request) return response -def backoff(attempt): +def backoff(attempt, ignore_max=False): + max_backoff = RetrySender.MAX_BACKOFF_DURATION + if ignore_max: + max_backoff = attempt print("There was an error processing the request. Retrying in {} seconds...".format( - min(attempt, RetrySender.MAX_BACKOFF_DURATION)), sys.stderr) - sleep(min(attempt, RetrySender.MAX_BACKOFF_DURATION)) + min(attempt, max_backoff)), file=sys.stderr) + sleep(min(attempt, max_backoff)) return diff --git a/smarty/smartystreets_python_sdk/status_code_sender.py b/smarty/smartystreets_python_sdk/status_code_sender.py index e22c90b..d922d96 100644 --- a/smarty/smartystreets_python_sdk/status_code_sender.py +++ b/smarty/smartystreets_python_sdk/status_code_sender.py @@ -1,16 +1,34 @@ -# from smartystreets_python_sdk import errors, exceptions -from . import errors, exceptions +import json + +from smartystreets_python_sdk import errors, exceptions class StatusCodeSender: def __init__(self, inner): self.inner = inner + def parse_rate_limit_response(self, response): + error_message = exceptions.TooManyRequestsError(errors.TOO_MANY_REQUESTS) + response_json = json.loads(response.payload) + if response_json is not None: + errors_json = response_json.get('errors') + if errors_json is not None: + message = '' + for current_error in errors_json: + current_message = current_error.get('message') + if current_message is not None: + message = message + current_message + ' ' + error_message = exceptions.TooManyRequestsError(message.rstrip()) + return error_message + def send(self, request): response = self.inner.send(request) if not response.error: - response.error = statuses.get(response.status_code) + if response.status_code != 429: + response.error = statuses.get(response.status_code) + else: + response.error = self.parse_rate_limit_response(response) return response @@ -43,10 +61,6 @@ def unprocessable_entity(): return exceptions.UnprocessableEntityError(errors.UNPROCESSABLE_ENTITY) -def too_many_requests(): - return exceptions.TooManyRequestsError(errors.TOO_MANY_REQUESTS) - - def internal_server_error(): return exceptions.InternalServerError(errors.INTERNAL_SERVER_ERROR) @@ -66,7 +80,6 @@ def gateway_timeout(): 413: request_entity_too_large(), 400: bad_request(), 422: unprocessable_entity(), - 429: too_many_requests(), 500: internal_server_error(), 503: service_unavailable(), 504: gateway_timeout() diff --git a/smarty/smartystreets_python_sdk/url_prefix_sender.py b/smarty/smartystreets_python_sdk/url_prefix_sender.py index 0f3384b..507eef0 100644 --- a/smarty/smartystreets_python_sdk/url_prefix_sender.py +++ b/smarty/smartystreets_python_sdk/url_prefix_sender.py @@ -4,6 +4,8 @@ def __init__(self, url_prefix, inner): self.inner = inner def send(self, request): - request.url_prefix = self.url_prefix - + if request.url_components: + request.url_prefix = self.url_prefix + request.url_components + else: + request.url_prefix = self.url_prefix return self.inner.send(request) diff --git a/smarty/smartystreets_python_sdk/us_autocomplete/client.py b/smarty/smartystreets_python_sdk/us_autocomplete/client.py deleted file mode 100644 index bfd1581..0000000 --- a/smarty/smartystreets_python_sdk/us_autocomplete/client.py +++ /dev/null @@ -1,62 +0,0 @@ -# from smartystreets_python_sdk import Request -from ..exceptions import SmartyException -# from . import Suggestion, geolocation_type - - -class Client: - def __init__(self, sender, serializer): - """ - It is recommended to instantiate this class using ClientBuilder.build_us_autocomplete_api_client() - """ - self.sender = sender - self.serializer = serializer - - def send(self, lookup): - """ - Sends a Lookup object to the US Autocomplete API and stores the result in the Lookup's result field. - """ - if not lookup or not lookup.prefix: - raise SmartyException('Send() must be passed a Lookup with the prefix field set.') - - request = self.build_request(lookup) - - response = self.sender.send(request) - - if response.error: - raise response.error - - result = self.serializer.deserialize(response.payload) - suggestions = self.convert_suggestions(result.get('suggestions') or []) - lookup.result = suggestions - - return suggestions - - def build_request(self, lookup): - request = Request() - - self.add_parameter(request, 'prefix', lookup.prefix) - self.add_parameter(request, 'suggestions', lookup.max_suggestions) - self.add_parameter(request, 'city_filter', self.build_filter_string(lookup.city_filter)) - self.add_parameter(request, 'state_filter', self.build_filter_string(lookup.state_filter)) - self.add_parameter(request, 'prefer', self.build_filter_string(lookup.prefer)) - self.add_parameter(request, 'prefer_ratio', lookup.prefer_ratio) - if lookup.geolocate_type is not geolocation_type.NONE: - request.parameters['geolocate'] = 'true' - request.parameters['geolocate_precision'] = lookup.geolocate_type - else: - request.parameters['geolocate'] = 'false' - - return request - - @staticmethod - def build_filter_string(filter_list): - return ','.join(filter_list or []) or None - - @staticmethod - def convert_suggestions(suggestion_dictionaries): - return [Suggestion(suggestion) for suggestion in suggestion_dictionaries] - - @staticmethod - def add_parameter(request, key, value): - if value and value != 'none': - request.parameters[key] = value diff --git a/smarty/smartystreets_python_sdk/us_autocomplete/geolocation_type.py b/smarty/smartystreets_python_sdk/us_autocomplete/geolocation_type.py deleted file mode 100644 index 5f960f8..0000000 --- a/smarty/smartystreets_python_sdk/us_autocomplete/geolocation_type.py +++ /dev/null @@ -1,5 +0,0 @@ -CITY = 'city' - -STATE = 'state' - -NONE = 'null' diff --git a/smarty/smartystreets_python_sdk/us_autocomplete/lookup.py b/smarty/smartystreets_python_sdk/us_autocomplete/lookup.py deleted file mode 100644 index 535cd23..0000000 --- a/smarty/smartystreets_python_sdk/us_autocomplete/lookup.py +++ /dev/null @@ -1,36 +0,0 @@ -class Lookup: - def __init__(self, prefix=None, suggestions=None, city_filter=None, state_filter=None, prefer=None, - prefer_ratio=None, geolocate_type=None): - """ - In addition to holding all of the input data for this lookup, this class also will contain the result - of the lookup after it comes back from the API. - - See "https://smartystreets.com/docs/cloud/us-autocomplete-api#http-request-input-fields" - - :param prefix: The beginning of an address (required) - :param suggestions: Maximum number of suggestions - :param city_filter: List of cities from which to include suggestions - :param state_filter: List of states from which to include suggestions - :param prefer: List of cities/states. Suggestions from the members of this list will appear first - :param prefer_ratio: Percentage of suggestions that will be from preferred cities/states. - (Decimal value between 0 and 1) - :param geolocate_type: This field corresponds to the geolocate and geolocate_precision fields in the - US Autocomplete API. Use the constants in geolocation_type.py to set this field - """ - self.result = [] - self.prefix = prefix - self.max_suggestions = suggestions - self.city_filter = city_filter or [] - self.state_filter = state_filter or [] - self.prefer = prefer or [] - self.prefer_ratio = prefer_ratio - self.geolocate_type = geolocate_type - - def add_city_filter(self, city): - self.city_filter.append(city) - - def add_state_filter(self, state): - self.state_filter.append(state) - - def add_prefer(self, prefer): - self.prefer.append(prefer) diff --git a/smarty/smartystreets_python_sdk/us_autocomplete/suggestion.py b/smarty/smartystreets_python_sdk/us_autocomplete/suggestion.py deleted file mode 100644 index 115fb6a..0000000 --- a/smarty/smartystreets_python_sdk/us_autocomplete/suggestion.py +++ /dev/null @@ -1,9 +0,0 @@ -class Suggestion: - def __init__(self, obj=None): - """ - See "https://smartystreets.com/docs/cloud/us-autocomplete-api#http-response" - """ - self.text = obj.get('text', None) - self.street_line = obj.get('street_line', None) - self.city = obj.get('city', None) - self.state = obj.get('state', None) diff --git a/smarty/smartystreets_python_sdk/us_autocomplete_pro/client.py b/smarty/smartystreets_python_sdk/us_autocomplete_pro/client.py index cb6f982..ff1b262 100644 --- a/smarty/smartystreets_python_sdk/us_autocomplete_pro/client.py +++ b/smarty/smartystreets_python_sdk/us_autocomplete_pro/client.py @@ -1,6 +1,6 @@ -from .. import Request -from ..exceptions import SmartyException -from . import Suggestion, geolocation_type +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.exceptions import SmartyException +from smartystreets_python_sdk.us_autocomplete_pro import Suggestion, geolocation_type class Client: @@ -48,6 +48,9 @@ def build_request(self, lookup): self.add_parameter(request, 'selected', lookup.selected) self.add_parameter(request, 'source', lookup.source) + for parameter in lookup.custom_parameter_array: + self.add_parameter(request, parameter, lookup.custom_parameter_array[parameter]) + return request @staticmethod diff --git a/smarty/smartystreets_python_sdk/us_autocomplete_pro/lookup.py b/smarty/smartystreets_python_sdk/us_autocomplete_pro/lookup.py index 1d3f785..15b4383 100644 --- a/smarty/smartystreets_python_sdk/us_autocomplete_pro/lookup.py +++ b/smarty/smartystreets_python_sdk/us_autocomplete_pro/lookup.py @@ -1,4 +1,4 @@ -# from . import geolocation_type +from smartystreets_python_sdk.us_autocomplete_pro import geolocation_type class Lookup: @@ -32,8 +32,13 @@ def __init__(self, search=None, max_results=None, city_filter=None, state_filter meaning that if it is not set to none, you may see addresses from the customer's area when you may not desire it :param selected: Used by UI components to request a list of secondaries (up to 100) for the specified address + :param source: Include results from alternate data sources. If no value is passed, the default will be `postal`. + Allowed values are: + all - will include non-postal addresses in the results + postal - will limit the results to postal addresses only """ self.result = [] + self.custom_parameter_array = {} self.search = search self.max_results = max_results self.city_filter = city_filter or [] @@ -70,3 +75,6 @@ def add_state_preference(self, state): def add_zip_preference(self, zipcode): self.prefer_geo = geolocation_type.NONE self.prefer_zips.append(zipcode) + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value diff --git a/smarty/smartystreets_python_sdk/us_enrichment/__init__.py b/smarty/smartystreets_python_sdk/us_enrichment/__init__.py new file mode 100644 index 0000000..0d4b8bc --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/__init__.py @@ -0,0 +1,2 @@ +from .client import Client +from .response import * \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_enrichment/client.py b/smarty/smartystreets_python_sdk/us_enrichment/client.py new file mode 100644 index 0000000..48792e5 --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/client.py @@ -0,0 +1,158 @@ +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.exceptions import SmartyException +from .lookup import PrincipalLookup, GeoReferenceLookup, RiskLookup, SecondaryLookup, SecondaryCountLookup, Lookup +from .response import Response + + +class Client: + def __init__(self, sender, serializer): + """ + It is recommended to instantiate this class using ClientBuilder.build_us_enrichment_api_client() + """ + self.sender = sender + self.serializer = serializer + + def send_property_principal_lookup(self, lookup): + if isinstance(lookup, str): + l = PrincipalLookup(lookup) + send_lookup(self, l) + return l.result + else: + lookup.dataset = 'property' + lookup.dataSubset = 'principal' + send_lookup(self, lookup) + return lookup.result + + def send_geo_reference_lookup(self, lookup): + if isinstance(lookup, str): + l = GeoReferenceLookup(lookup) + send_lookup(self, l) + return l.result + else: + lookup.dataset = 'geo-reference' + lookup.dataSubset = None + send_lookup(self, lookup) + return lookup.result + + def send_risk_lookup(self, lookup): + if isinstance(lookup, str): + l = RiskLookup(lookup) + send_lookup(self, l) + return l.result + else: + lookup.dataset = 'risk' + lookup.dataSubset = None + send_lookup(self, lookup) + return lookup.result + + def send_secondary_lookup(self, lookup): + if isinstance(lookup, str): + l = SecondaryLookup(lookup) + send_lookup(self, l) + return l.result + else: + lookup.dataset = 'secondary' + lookup.dataSubset = None + send_lookup(self, lookup) + return lookup.result + + def send_secondary_count_lookup(self, lookup): + if isinstance(lookup, str): + l = SecondaryCountLookup(lookup) + send_lookup(self, l) + return l.result + else: + lookup.dataset = 'secondary' + lookup.dataSubset = 'count' + send_lookup(self, lookup) + return lookup.result + + def send_generic_lookup(self, lookup, dataset, dataSubset): + if isinstance(lookup, str): + l = Lookup(lookup, dataset, dataSubset) + send_lookup(self, l) + return l.result + else: + lookup.dataset = dataset + lookup.dataSubset = dataSubset + send_lookup(self, lookup) + return lookup.result + + +def send_lookup(client: Client, lookup): + """ + Sends a Lookup object to the US Enrichment API and stores the result in the Lookup's result field. + """ + if lookup is None or (lookup.smartykey is None and lookup.street is None and lookup.freeform is None): + raise SmartyException('Client.send() requires a Lookup with either the "smartykey", "street, or "freeform" field set as a string') + + request = build_request(lookup) + + response = client.sender.send(request) + if response.error: + raise response.error + + response = client.serializer.deserialize(response.payload) + result = [] + for candidate in response: + result.append(Response(candidate)) + lookup.result = result + return result + + +def build_request(lookup): + request = Request() + if lookup.smartykey != None: + if lookup.dataSubset == None: + request.url_components = lookup.smartykey + "/" + lookup.dataset + request.parameters = remap_keys(lookup) + return request + + request.url_components = lookup.smartykey + "/" + lookup.dataset + "/" + lookup.dataSubset + request.parameters = remap_keys(lookup) + + return request + else: + if lookup.dataSubset == None: + request.url_components = 'search/' + lookup.dataset + request.parameters = remap_keys(lookup) + return request + + request.url_components = 'search/' + lookup.dataset + "/" + lookup.dataSubset + + request.parameters = remap_keys(lookup) + return request + +def remap_keys(lookup): + converted_lookup = {} + + if (lookup.freeform != None): + add_field(converted_lookup, 'freeform', lookup.freeform) + if (lookup.street != None): + add_field(converted_lookup, 'street', lookup.street) + if (lookup.city != None): + add_field(converted_lookup, 'city', lookup.city) + if (lookup.state != None): + add_field(converted_lookup, 'state', lookup.state) + if (lookup.zipcode != None): + add_field(converted_lookup, 'zipcode', lookup.zipcode) + if (lookup.include_array != None): + add_field(converted_lookup, 'include', build_filter_string(lookup.include_array)) + if (lookup.exclude_array != None): + add_field(converted_lookup, 'exclude', build_filter_string(lookup.exclude_array)) + if (lookup.features != None): + add_field(converted_lookup, 'features', lookup.features) + + + for parameter in lookup.custom_parameter_array: + add_field(converted_lookup, parameter, lookup.custom_parameter_array[parameter]) + + return converted_lookup + + +def add_field(converted_lookup, key, value): + if value: + converted_lookup[key] = value + +def build_filter_string(filter_list): + return ','.join(filter_list or []) or None diff --git a/smarty/smartystreets_python_sdk/us_enrichment/lookup.py b/smarty/smartystreets_python_sdk/us_enrichment/lookup.py new file mode 100644 index 0000000..ab850b6 --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/lookup.py @@ -0,0 +1,54 @@ +propertyDataset = "property" +principalDataSubset = "principal" +geoReferenceDataset = "geo-reference" +riskDataset = "risk" +secondaryDataset = "secondary" +countDataSubset = "count" +noneDataSubset = None + +class Lookup: + def __init__(self, smartykey = None, dataset = None, dataSubset = None, features = None, freeform = None, street = None, city = None, state = None, zipcode = None): + self.smartykey = smartykey + self.dataset = dataset + self.dataSubset = dataSubset + self.include_array = [] + self.exclude_array = [] + self.features = features + self.freeform = freeform + self.street = street + self.city = city + self.state = state + self.zipcode = zipcode + self.result = [] + self.custom_parameter_array = {} + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value + + def add_include_attribute(self, attribute): + if (attribute not in self.include_array): + self.include_array.append(attribute) + + def add_exclude_attribute(self, attribute): + if (attribute not in self.exclude_array): + self.exclude_array.append(attribute) + +class PrincipalLookup(Lookup): + def __init__(self, smartykey = None): + super().__init__(smartykey, propertyDataset, principalDataSubset) + +class GeoReferenceLookup(Lookup): + def __init__(self, smartykey = None): + super().__init__(smartykey, geoReferenceDataset, noneDataSubset) + +class RiskLookup(Lookup): + def __init__(self, smartykey = None): + super().__init__(smartykey, riskDataset, noneDataSubset) + +class SecondaryLookup(Lookup): + def __init__(self, smartykey = None): + super().__init__(smartykey, secondaryDataset, noneDataSubset) + +class SecondaryCountLookup(Lookup): + def __init__(self, smartykey = None): + super().__init__(smartykey, secondaryDataset, countDataSubset) \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_enrichment/response.py b/smarty/smartystreets_python_sdk/us_enrichment/response.py new file mode 100644 index 0000000..a1cd6bd --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/response.py @@ -0,0 +1,1205 @@ +class Response: + def __init__(self, obj): + self.smarty_key = obj.get('smarty_key', None) + self.matched_address = get_matched_address(obj.get('matched_address', None)) + data_set_name = None + data_subset_name = None + if 'data_set_name' in obj: + self.data_set_name = obj.get('data_set_name') + data_set_name = obj.get('data_set_name') + elif 'secondaries' in obj: + data_set_name = 'secondary' + + if 'data_subset_name' in obj: + self.data_subset_name = obj.get('data_subset_name', None) + data_subset_name = obj.get('data_subset_name', None) + elif 'count' in obj: + data_set_name = 'secondary' + data_subset_name = 'count' + + if data_set_name == 'secondary': + if data_subset_name == 'count': + self.count = obj.get('count', None) + else: + self.root_address = get_secondary_root_address(obj.get('root_address', None)) + if 'aliases' in obj: + self.aliases = get_secondary_aliases(obj.get('aliases', None)) + self.secondaries = get_secondary_secondaries(obj.get('secondaries', None)) + else: + self.attributes = get_attributes(data_set_name, data_subset_name, obj.get('attributes', None)) + + def __str__(self): + lines = [self.__class__.__name__ + ':'] + for key, val in vars(self).items(): + lines += get_lines(key, val) + return '\n '.join(lines) + + def __eq__(self, __value: object) -> bool: + return isinstance(__value, type(self)) and __value.smarty_key == self.smarty_key + +def get_lines(key, val): + lines = [''] + if type(val) is list: + if len(val) > 1: + for item in val: + if val.index(item) == 0: + lines += ['secondaries:'] + lines += get_lines(val.index(item), val[val.index(item)]) + return lines + else: + return get_lines(key, val[0]) + else: + if type(key) == int: + return ' {}: {}'.format(key, val).split('\n') + return '{}: {}'.format(key, val).split('\n') + +class MatchedAddress: + def __init__(self, obj): + self.street = obj.get('street', None) + self.city = obj.get('city', None) + self.state = obj.get('state', None) + self.zipcode = obj.get('zipcode', None) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + +def get_matched_address(matched_address_obj): + if matched_address_obj is None: + return None + output = [] + output.append(MatchedAddress(matched_address_obj)) + + return output + +def get_attributes(dataset, data_subset, attribute_obj): + if dataset == "property": + if data_subset == "principal": + return PrincipalAttributes(attribute_obj) + if dataset == "geo-reference": + return GeoReferenceOutputCategories(attribute_obj) + if dataset == "risk": + return RiskAttributes(attribute_obj) + +class PrincipalAttributes: + def __init__(self, obj): + self.first_floor_sqft = obj.get('1st_floor_sqft', None) + self.second_floor_sqft = obj.get('2nd_floor_sqft', None) + self.acres = obj.get('acres', None) + self.air_conditioner = obj.get('air_conditioner', None) + self.arbor_pergola = obj.get('arbor_pergola', None) + self.assessed_improvement_percent = obj.get('assessed_improvement_percent', None) + self.assessed_improvement_value = obj.get('assessed_improvement_value', None) + self.assessed_land_value = obj.get('assessed_land_value', None) + self.assessed_value = obj.get('assessed_value', None) + self.assessor_last_update = obj.get('assessor_last_update', None) + self.assessor_taxroll_update = obj.get('assessor_taxroll_update', None) + self.attic_area = obj.get('attic_area', None) + self.attic_flag = obj.get('attic_flag', None) + self.balcony = obj.get('balcony', None) + self.balcony_area = obj.get('balcony_area', None) + self.basement_sqft = obj.get('basement_sqft', None) + self.basement_sqft_finished = obj.get('basement_sqft_finished', None) + self.basement_sqft_unfinished = obj.get('basement_sqft_unfinished', None) + self.bath_house = obj.get('bath_house', None) + self.bath_house_sqft = obj.get('bath_house_sqft', None) + self.bathrooms_partial = obj.get('bathrooms_partial', None) + self.bathrooms_total = obj.get('bathrooms_total', None) + self.bedrooms = obj.get('bedrooms', None) + self.block1 = obj.get('block1', None) + self.block2 = obj.get('block2', None) + self.boat_access = obj.get('boat_access', None) + self.boat_house = obj.get('boat_house', None) + self.boat_house_sqft = obj.get('boat_house_sqft', None) + self.boat_lift = obj.get('boat_lift', None) + self.bonus_room = obj.get('bonus_room', None) + self.breakfast_nook = obj.get('breakfast_nook', None) + self.breezeway = obj.get('breezeway', None) + self.building_definition_code = obj.get('building_definition_code', None) + self.building_sqft = obj.get('building_sqft', None) + self.cabin = obj.get('cabin', None) + self.cabin_sqft = obj.get('cabin_sqft', None) + self.canopy = obj.get('canopy', None) + self.canopy_sqft = obj.get('canopy_sqft', None) + self.carport = obj.get('carport', None) + self.carport_sqft = obj.get('carport_sqft', None) + self.cbsa_code = obj.get('cbsa_code', None) + self.cbsa_name = obj.get('cbsa_name', None) + self.cellar = obj.get('cellar', None) + self.census_block = obj.get('census_block', None) + self.census_block_group = obj.get('census_block_group', None) + self.census_fips_place_code = obj.get('census_fips_place_code', None) + self.census_tract = obj.get('census_tract', None) + self.central_vacuum = obj.get('central_vacuum', None) + self.code_title_company = obj.get('code_title_company', None) + self.combined_statistical_area = obj.get('combined_statistical_area', None) + self.community_rec = obj.get('community_rec', None) + self.company_flag = obj.get('company_flag', None) + self.congressional_district = obj.get('congressional_district', None) + self.contact_city = obj.get('contact_city', None) + self.contact_crrt = obj.get('contact_crrt', None) + self.contact_full_address = obj.get('contact_full_address', None) + self.contact_house_number = obj.get('contact_house_number', None) + self.contact_mail_info_format = obj.get('contact_mail_info_format', None) + self.contact_mail_info_privacy = obj.get('contact_mail_info_privacy', None) + self.contact_mailing_county = obj.get('contact_mailing_county', None) + self.contact_mailing_fips = obj.get('contact_mailing_fips', None) + self.contact_post_direction = obj.get('contact_post_direction', None) + self.contact_pre_direction = obj.get('contact_pre_direction', None) + self.contact_state = obj.get('contact_state', None) + self.contact_street_name = obj.get('contact_street_name', None) + self.contact_suffix = obj.get('contact_suffix', None) + self.contact_unit_designator = obj.get('contact_unit_designator', None) + self.contact_value = obj.get('contact_value', None) + self.contact_zip = obj.get('contact_zip', None) + self.contact_zip4 = obj.get('contact_zip4', None) + self.courtyard = obj.get('courtyard', None) + self.courtyard_area = obj.get('courtyard_area', None) + self.deck = obj.get('deck', None) + self.deck_area = obj.get('deck_area', None) + self.deed_document_page = obj.get('deed_document_page', None) + self.deed_document_book = obj.get('deed_document_book', None) + self.deed_document_number = obj.get('deed_document_number', None) + self.deed_owner_first_name = obj.get('deed_owner_first_name', None) + self.deed_owner_first_name2 = obj.get('deed_owner_first_name2', None) + self.deed_owner_first_name3 = obj.get('deed_owner_first_name3', None) + self.deed_owner_first_name4 = obj.get('deed_owner_first_name4', None) + self.deed_owner_full_name = obj.get('deed_owner_full_name', None) + self.deed_owner_full_name2 = obj.get('deed_owner_full_name2', None) + self.deed_owner_full_name3 = obj.get('deed_owner_full_name3', None) + self.deed_owner_full_name4 = obj.get('deed_owner_full_name4', None) + self.deed_owner_last_name = obj.get('deed_owner_last_name', None) + self.deed_owner_last_name2 = obj.get('deed_owner_last_name2', None) + self.deed_owner_last_name3 = obj.get('deed_owner_last_name3', None) + self.deed_owner_last_name4 = obj.get('deed_owner_last_name4', None) + self.deed_owner_middle_name = obj.get('deed_owner_middle_name', None) + self.deed_owner_middle_name = obj.get('deed_owner_middle_name', None) + self.deed_owner_middle_name2 = obj.get('deed_owner_middle_name2', None) + self.deed_owner_middle_name3 = obj.get('deed_owner_middle_name3', None) + self.deed_owner_middle_name4 = obj.get('deed_owner_middle_name4', None) + self.deed_owner_suffix = obj.get('deed_owner_suffix', None) + self.deed_owner_suffix2 = obj.get('deed_owner_suffix2', None) + self.deed_owner_suffix3 = obj.get('deed_owner_suffix3', None) + self.deed_owner_suffix4 = obj.get('deed_owner_suffix4', None) + self.deed_sale_date = obj.get('deed_sale_date', None) + self.deed_sale_price = obj.get('deed_sale_price', None) + self.deed_transaction_id = obj.get('deed_transaction_id', None) + self.depth_linear_footage = obj.get('depth_linear_footage', None) + self.disabled_tax_exemption = obj.get('disabled_tax_exemption', None) + self.document_type_description = obj.get('document_type_description', None) + self.driveway_sqft = obj.get('driveway_sqft', None) + self.driveway_type = obj.get('driveway_type', None) + self.effective_year_built = obj.get('effective_year_built', None) + self.elevation_feet = obj.get('elevation_feet', None) + self.elevator = obj.get('elevator', None) + self.equestrian_arena = obj.get('equestrian_arena', None) + self.escalator = obj.get('escalator', None) + self.exercise_room = obj.get('exercise_room', None) + self.exterior_walls = obj.get('exterior_walls', None) + self.family_room = obj.get('family_room', None) + self.fence = obj.get('fence', None) + self.fence_area = obj.get('fence_area', None) + self.financial_history = get_financial_history(obj.get('financial_history', None)) + self.fips_code = obj.get('fips_code', None) + self.fire_resistance_code = obj.get('fire_resistance_code', None) + self.fire_sprinklers_flag = obj.get('fire_sprinklers_flag', None) + self.fireplace = obj.get('fireplace', None) + self.fireplace_number = obj.get('fireplace_number', None) + self.first_name = obj.get('first_name', None) + self.first_name_2 = obj.get('first_name_2', None) + self.first_name_3 = obj.get('first_name_3', None) + self.first_name_4 = obj.get('first_name_4', None) + self.flooring = obj.get('flooring', None) + self.foundation = obj.get('foundation', None) + self.game_room = obj.get('game_room', None) + self.garage = obj.get('garage', None) + self.garage_sqft = obj.get('garage_sqft', None) + self.gazebo = obj.get('gazebo', None) + self.gazebo_sqft = obj.get('gazebo_sqft', None) + self.golf_course = obj.get('golf_course', None) + self.grainery = obj.get('grainery', None) + self.grainery_sqft = obj.get('grainery_sqft', None) + self.great_room = obj.get('great_room', None) + self.greenhouse = obj.get('greenhouse', None) + self.greenhouse_sqft = obj.get('greenhouse_sqft', None) + self.gross_sqft = obj.get('gross_sqft', None) + self.guesthouse = obj.get('guesthouse', None) + self.guesthouse_sqft = obj.get('guesthouse_sqft', None) + self.handicap_accessibility = obj.get('handicap_accessibility', None) + self.heat = obj.get('heat', None) + self.heat_fuel_type = obj.get('heat_fuel_type', None) + self.hobby_room = obj.get('hobby_room', None) + self.homeowner_tax_exemption = obj.get('homeowner_tax_exemption', None) + self.instrument_date = obj.get('instrument_date', None) + self.intercom_system = obj.get('intercom_system', None) + self.interest_rate_type_2 = obj.get('interest_rate_type_2', None) + self.interior_structure = obj.get('interior_structure', None) + self.kennel = obj.get('kennel', None) + self.kennel_sqft = obj.get('kennel_sqft', None) + self.land_use_code = obj.get('land_use_code', None) + self.land_use_group = obj.get('land_use_group', None) + self.land_use_standard = obj.get('land_use_standard', None) + self.last_name = obj.get('last_name', None) + self.last_name_2 = obj.get('last_name_2', None) + self.last_name_3 = obj.get('last_name_3', None) + self.last_name_4 = obj.get('last_name_4', None) + self.latitude = obj.get('latitude', None) + self.laundry = obj.get('laundry', None) + self.lean_to = obj.get('lean_to', None) + self.lean_to_sqft = obj.get('lean_to_sqft', None) + self.legal_description = obj.get('legal_description', None) + self.legal_unit = obj.get('legal_unit', None) + self.lender_address = obj.get('lender_address', None) + self.lender_address_2 = obj.get('lender_address_2', None) + self.lender_city = obj.get('lender_city', None) + self.lender_city_2 = obj.get('lender_city_2', None) + self.lender_code_2 = obj.get('lender_code_2', None) + self.lender_first_name = obj.get('lender_first_name', None) + self.lender_first_name_2 = obj.get('lender_first_name_2', None) + self.lender_last_name = obj.get('lender_last_name', None) + self.lender_last_name_2 = obj.get('lender_last_name_2', None) + self.lender_name = obj.get('lender_name', None) + self.lender_name_2 = obj.get('lender_name_2', None) + self.lender_seller_carry_back = obj.get('lender_seller_carry_back', None) + self.lender_seller_carry_back_2 = obj.get('lender_seller_carry_back_2', None) + self.lender_state = obj.get('lender_state', None) + self.lender_state_2 = obj.get('lender_state_2', None) + self.lender_zip = obj.get('lender_zip', None) + self.lender_zip_2 = obj.get('lender_zip_2', None) + self.lender_zip_extended = obj.get('lender_zip_extended', None) + self.lender_zip_extended_2 = obj.get('lender_zip_extended_2', None) + self.loading_platform = obj.get('loading_platform', None) + self.loading_platform_sqft = obj.get('loading_platform_sqft', None) + self.longitude = obj.get('longitude', None) + self.lot_1 = obj.get('lot_1', None) + self.lot_2 = obj.get('lot_2', None) + self.lot_3 = obj.get('lot_3', None) + self.lot_sqft = obj.get('lot_sqft', None) + self.market_improvement_percent = obj.get('market_improvement_percent', None) + self.market_improvement_value = obj.get('market_improvement_value', None) + self.market_land_value = obj.get('market_land_value', None) + self.market_value_year = obj.get('market_value_year', None) + self.match_type = obj.get('match_type', None) + self.media_room = obj.get('media_room', None) + self.metro_division = obj.get('metro_division', None) + self.middle_name = obj.get('middle_name', None) + self.middle_name_2 = obj.get('middle_name_2', None) + self.middle_name_3 = obj.get('middle_name_3', None) + self.middle_name_4 = obj.get('middle_name_4', None) + self.milkhouse = obj.get('milkhouse', None) + self.milkhouse_sqft = obj.get('milkhouse_sqft', None) + self.minor_civil_division_code = obj.get('minor_civil_division_code', None) + self.minor_civil_division_name = obj.get('minor_civil_division_name', None) + self.mobile_home_hookup = obj.get('mobile_home_hookup', None) + self.mortgage_amount = obj.get('mortgage_amount', None) + self.mortgage_amount_2 = obj.get('mortgage_amount_2', None) + self.mortgage_due_date = obj.get('mortgage_due_date', None) + self.mortgage_due_date_2 = obj.get('mortgage_due_date_2', None) + self.mortgage_interest_rate = obj.get('mortgage_interest_rate', None) + self.mortgage_interest_rate_type = obj.get('mortgage_interest_rate_type', None) + self.mortgage_lender_code = obj.get('mortgage_lender_code', None) + self.mortgage_rate_2 = obj.get('mortgage_rate_2', None) + self.mortgage_recording_date = obj.get('mortgage_recording_date', None) + self.mortgage_recording_date_2 = obj.get('mortgage_recording_date_2', None) + self.mortgage_term = obj.get('mortgage_term', None) + self.mortgage_term_2 = obj.get('mortgage_term_2', None) + self.mortgage_term_type = obj.get('mortgage_term_type', None) + self.mortgage_term_type_2 = obj.get('mortgage_term_type_2', None) + self.mortgage_type = obj.get('mortgage_type', None) + self.mortgage_type_2 = obj.get('mortgage_type_2', None) + self.msa_code = obj.get('msa_code', None) + self.msa_name = obj.get('msa_name', None) + self.mud_room = obj.get('mud_room', None) + self.multi_parcel_flag = obj.get('multi_parcel_flag', None) + self.name_title_company = obj.get('name_title_company', None) + self.neighborhood_code = obj.get('neighborhood_code', None) + self.number_of_buildings = obj.get('number_of_buildings', None) + self.office = obj.get('office', None) + self.office_sqft = obj.get('office_sqft', None) + self.other_tax_exemption = obj.get('other_tax_exemption', None) + self.outdoor_kitchen_fireplace = obj.get('outdoor_kitchen_fireplace', None) + self.overhead_door = obj.get('overhead_door', None) + self.owner_full_name = obj.get('owner_full_name', None) + self.owner_full_name_2 = obj.get('owner_full_name_2', None) + self.owner_full_name_3 = obj.get('owner_full_name_3', None) + self.owner_full_name_4 = obj.get('owner_full_name_4', None) + self.owner_occupancy_status = obj.get('owner_occupancy_status', None) + self.ownership_transfer_date = obj.get('ownership_transfer_date', None) + self.ownership_transfer_doc_number = obj.get('ownership_transfer_doc_number', None) + self.ownership_transfer_transaction_id = obj.get('ownership_transfer_transaction_id', None) + self.ownership_type = obj.get('ownership_type', None) + self.ownership_type_2 = obj.get('ownership_type_2', None) + self.ownership_vesting_relation_code = obj.get('ownership_vesting_relation_code', None) + self.parcel_account_number = obj.get('parcel_account_number', None) + self.parcel_map_book = obj.get('parcel_map_book', None) + self.parcel_map_page = obj.get('parcel_map_page', None) + self.parcel_number_alternate = obj.get('parcel_number_alternate', None) + self.parcel_number_formatted = obj.get('parcel_number_formatted', None) + self.parcel_number_previous = obj.get('parcel_number_previous', None) + self.parcel_number_year_added = obj.get('parcel_number_year_added', None) + self.parcel_number_year_change = obj.get('parcel_number_year_change', None) + self.parcel_raw_number = obj.get('parcel_raw_number', None) + self.parcel_shell_record = obj.get('parcel_shell_record', None) + self.parking_spaces = obj.get('parking_spaces', None) + self.patio_area = obj.get('patio_area', None) + self.phase_name = obj.get('phase_name', None) + self.plumbing_fixtures_count = obj.get('plumbing_fixtures_count', None) + self.pole_struct = obj.get('pole_struct', None) + self.pole_struct_sqft = obj.get('pole_struct_sqft', None) + self.pond = obj.get('pond', None) + self.pool = obj.get('pool', None) + self.pool_area = obj.get('pool_area', None) + self.poolhouse = obj.get('poolhouse', None) + self.poolhouse_sqft = obj.get('poolhouse_sqft', None) + self.porch = obj.get('porch', None) + self.porch_area = obj.get('porch_area', None) + self.poultry_house = obj.get('poultry_house', None) + self.poultry_house_sqft = obj.get('poultry_house_sqft', None) + self.previous_assessed_value = obj.get('previous_assessed_value', None) + self.prior_sale_amount = obj.get('prior_sale_amount', None) + self.prior_sale_date = obj.get('prior_sale_date', None) + self.property_address_carrier_route_code = obj.get('property_address_carrier_route_code', None) + self.property_address_city = obj.get('property_address_city', None) + self.property_address_full = obj.get('property_address_full', None) + self.property_address_house_number = obj.get('property_address_house_number', None) + self.property_address_post_direction = obj.get('property_address_post_direction', None) + self.property_address_pre_direction = obj.get('property_address_pre_direction', None) + self.property_address_state = obj.get('property_address_state', None) + self.property_address_street_name = obj.get('property_address_street_name', None) + self.property_address_street_suffix = obj.get('property_address_street_suffix', None) + self.property_address_unit_designator = obj.get('property_address_unit_designator', None) + self.property_address_unit_value = obj.get('property_address_unit_value', None) + self.property_address_zip_4 = obj.get('property_address_zip_4', None) + self.property_address_zipcode = obj.get('property_address_zipcode', None) + self.publication_date = obj.get('publication_date', None) + self.quarter = obj.get('quarter', None) + self.quarter_quarter = obj.get('quarter_quarter', None) + self.quonset = obj.get('quonset', None) + self.quonset_sqft = obj.get('quonset_sqft', None) + self.range = obj.get('range', None) + self.recording_date = obj.get('recording_date', None) + self.roof_cover = obj.get('roof_cover', None) + self.roof_frame = obj.get('roof_frame', None) + self.rooms = obj.get('rooms', None) + self.rv_parking = obj.get('rv_parking', None) + self.safe_room = obj.get('safe_room', None) + self.sale_amount = obj.get('sale_amount', None) + self.sale_date = obj.get('sale_date', None) + self.sauna = obj.get('sauna', None) + self.section = obj.get('section', None) + self.security_alarm = obj.get('security_alarm', None) + self.senior_tax_exemption = obj.get('senior_tax_exemption', None) + self.sewer_type = obj.get('sewer_type', None) + self.shed = obj.get('shed', None) + self.shed_sqft = obj.get('shed_sqft', None) + self.silo = obj.get('silo', None) + self.silo_sqft = obj.get('silo_sqft', None) + self.sitting_room = obj.get('sitting_room', None) + self.situs_county = obj.get('situs_county', None) + self.situs_state = obj.get('situs_state', None) + self.sound_system = obj.get('sound_system', None) + self.sports_court = obj.get('sports_court', None) + self.sprinklers = obj.get('sprinklers', None) + self.stable = obj.get('stable', None) + self.stable_sqft = obj.get('stable_sqft', None) + self.storage_building = obj.get('storage_building', None) + self.storage_building_sqft = obj.get('storage_building_sqft', None) + self.stories_number = obj.get('stories_number', None) + self.storm_shelter = obj.get('storm_shelter', None) + self.storm_shutter = obj.get('storm_shutter', None) + self.structure_style = obj.get('structure_style', None) + self.study = obj.get('study', None) + self.subdivision = obj.get('subdivision', None) + self.suffix = obj.get('suffix', None) + self.suffix_2 = obj.get('suffix_2', None) + self.suffix_3 = obj.get('suffix_3', None) + self.suffix_4 = obj.get('suffix_4', None) + self.sunroom = obj.get('sunroom', None) + self.tax_assess_year = obj.get('tax_assess_year', None) + self.tax_billed_amount = obj.get('tax_billed_amount', None) + self.tax_delinquent_year = obj.get('tax_delinquent_year', None) + self.tax_fiscal_year = obj.get('tax_fiscal_year', None) + self.tax_jurisdiction = obj.get('tax_jurisdiction', None) + self.tax_rate_area = obj.get('tax_rate_area', None) + self.tennis_court = obj.get('tennis_court', None) + self.topography_code = obj.get('topography_code', None) + self.total_market_value = obj.get('total_market_value', None) + self.township = obj.get('township', None) + self.tract_number = obj.get('tract_number', None) + self.transfer_amount = obj.get('transfer_amount', None) + self.trust_description = obj.get('trust_description', None) + self.unit_count = obj.get('unit_count', None) + self.upper_floors_sqft = obj.get('upper_floors_sqft', None) + self.utility = obj.get('utility', None) + self.utility_building = obj.get('utility_building', None) + self.utility_building_sqft = obj.get('utility_building_sqft', None) + self.utility_sqft = obj.get('utility_sqft', None) + self.veteran_tax_exemption = obj.get('veteran_tax_exemption', None) + self.view_description = obj.get('view_description', None) + self.water_feature = obj.get('water_feature', None) + self.water_service_type = obj.get('water_service_type', None) + self.wet_bar = obj.get('wet_bar', None) + self.widow_tax_exemption = obj.get('widow_tax_exemption', None) + self.width_linear_footage = obj.get('width_linear_footage', None) + self.wine_cellar = obj.get('wine_cellar', None) + self.year_built = obj.get('year_built', None) + self.zoning = obj.get('zoning', None) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + + +def get_financial_history(financial_history_obj): + if financial_history_obj is None: + return None + output = [] + for obj in financial_history_obj: + output.append(FinancialHistory(obj)) + return output + + +class FinancialHistory: + def __init__(self, obj): + self.code_title_company = obj.get('code_title_company', None) + self.document_type_description = obj.get('document_type_description', None) + self.instrument_date = obj.get('instrument_date', None) + self.interest_rate_type_2 = obj.get('interest_rate_type_2', None) + self.lender_address = obj.get('lender_address', None) + self.lender_address_2 = obj.get('lender_address_2', None) + self.lender_city = obj.get('lender_city', None) + self.lender_city_2 = obj.get('lender_city_2', None) + self.lender_code_2 = obj.get('lender_code_2', None) + self.lender_first_name = obj.get('lender_first_name', None) + self.lender_first_name_2 = obj.get('lender_first_name_2', None) + self.lender_last_name = obj.get('lender_last_name', None) + self.lender_last_name_2 = obj.get('lender_last_name_2', None) + self.lender_name = obj.get('lender_name', None) + self.lender_name_2 = obj.get('lender_name_2', None) + self.lender_seller_carry_back = obj.get('lender_seller_carry_back', None) + self.lender_seller_carry_back_2 = obj.get('lender_seller_carry_back_2', None) + self.lender_state = obj.get('lender_state', None) + self.lender_state_2 = obj.get('lender_state_2', None) + self.lender_zip = obj.get('lender_zip', None) + self.lender_zip_2 = obj.get('lender_zip_2', None) + self.lender_zip_extended = obj.get('lender_zip_extended', None) + self.lender_zip_extended_2 = obj.get('lender_zip_extended_2', None) + self.mortgage_amount = obj.get('mortgage_amount', None) + self.mortgage_amount_2 = obj.get('mortgage_amount_2', None) + self.mortgage_due_date = obj.get('mortgage_due_date', None) + self.mortgage_due_date_2 = obj.get('mortgage_due_date_2', None) + self.mortgage_interest_rate = obj.get('mortgage_interest_rate', None) + self.mortgage_interest_rate_type = obj.get('mortgage_interest_rate_type', None) + self.mortgage_lender_code = obj.get('mortgage_lender_code', None) + self.mortgage_rate_2 = obj.get('mortgage_rate_2', None) + self.mortgage_recording_date = obj.get('mortgage_recording_date', None) + self.mortgage_recording_date_2 = obj.get('mortgage_recording_date_2', None) + self.mortgage_term = obj.get('mortgage_term', None) + self.mortgage_term_2 = obj.get('mortgage_term_2', None) + self.mortgage_term_type = obj.get('mortgage_term_type', None) + self.mortgage_term_type_2 = obj.get('mortgage_term_type_2', None) + self.mortgage_type = obj.get('mortgage_type', None) + self.mortgage_type_2 = obj.get('mortgage_type_2', None) + self.multi_parcel_flag = obj.get('multi_parcel_flag', None) + self.name_title_company = obj.get('name_title_company', None) + self.recording_date = obj.get('recording_date', None) + self.transfer_amount = obj.get('transfer_amount', None) + + def __str__(self): + return self.__dict__.__str__() + +class GeoReferenceOutputCategories: + def __init__(self, obj): + + self.census_block = get_geo_reference_census_block(obj.get('census_block', None)) + self.census_county_division = get_geo_reference_census_county_division(obj.get('census_county_division', None)) + self.census_tract = get_geo_reference_census_tract(obj.get('census_tract', None)) + self.core_based_stat_area = get_geo_reference_core_based_stat_area(obj.get('core_based_stat_area', None)) + self.place = get_geo_reference_place(obj.get('place', None)) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + +class GeoReferenceCensusBlock: + def __init__(self, obj): + self.accuracy = obj.get('accuracy', None) + self.geoid = obj.get('geoid', None) + + def __str__(self): + return self.__dict__.__str__() + +def get_geo_reference_census_block(geo_reference_census_block_obj): + if geo_reference_census_block_obj is None: + return None + output = [] + output.append(GeoReferenceCensusBlock(geo_reference_census_block_obj)) + return output + +class GeoReferenceCensusCountyDivision: + def __init__(self, obj): + self.accuracy = obj.get('accuracy', None) + self.code = obj.get('code', None) + self.name = obj.get('name', None) + + def __str__(self): + return self.__dict__.__str__() + +def get_geo_reference_census_county_division(geo_reference_census_county_division_obj): + if geo_reference_census_county_division_obj is None: + return None + output = [] + output.append(GeoReferenceCensusCountyDivision(geo_reference_census_county_division_obj)) + return output + +class GeoReferenceCensusTract: + def __init__(self, obj): + self.code = obj.get('code', None) + + def __str__(self): + return self.__dict__.__str__() + +def get_geo_reference_census_tract(geo_reference_census_tract_obj): + if geo_reference_census_tract_obj is None: + return None + output = [] + output.append(GeoReferenceCensusTract(geo_reference_census_tract_obj)) + return output + +class GeoReferenceCoreBasedStatArea: + def __init__(self, obj): + self.code = obj.get('code', None) + self.name = obj.get('name', None) + + def __str__(self): + return self.__dict__.__str__() + +def get_geo_reference_core_based_stat_area(geo_reference_core_based_stat_area_obj): + if geo_reference_core_based_stat_area_obj is None: + return None + output = [] + output.append(GeoReferenceCoreBasedStatArea(geo_reference_core_based_stat_area_obj)) + return output + +class GeoReferencePlace: + def __init__(self, obj): + self.accuracy = obj.get('accuracy', None) + self.code = obj.get('code', None) + self.name = obj.get('name', None) + self.type = obj.get('type', None) + + def __str__(self): + return self.__dict__.__str__() + +def get_geo_reference_place(geo_reference_place_obj): + if geo_reference_place_obj is None: + return None + output = [] + output.append(GeoReferencePlace(geo_reference_place_obj)) + return output + +class RiskAttributes: + def __init__(self, obj): + self.AGRIVALUE = obj.get('AGRIVALUE', None) + self.ALR_NPCTL = obj.get('ALR_NPCTL', None) + self.ALR_VALA = obj.get('ALR_VALA', None) + self.ALR_VALB = obj.get('ALR_VALB', None) + self.ALR_VALP = obj.get('ALR_VALP', None) + self.ALR_VRA_NPCTL = obj.get('ALR_VRA_NPCTL', None) + self.AREA = obj.get('AREA', None) + self.AVLN_AFREQ = obj.get('AVLN_AFREQ', None) + self.AVLN_ALRB = obj.get('AVLN_ALRB', None) + self.AVLN_ALRP = obj.get('AVLN_ALRP', None) + self.AVLN_ALR_NPCTL = obj.get('AVLN_ALR_NPCTL', None) + self.AVLN_EALB = obj.get('AVLN_EALB', None) + self.AVLN_EALP = obj.get('AVLN_EALP', None) + self.AVLN_EALPE = obj.get('AVLN_EALPE', None) + self.AVLN_EALR = obj.get('AVLN_EALR', None) + self.AVLN_EALS = obj.get('AVLN_EALS', None) + self.AVLN_EALT = obj.get('AVLN_EALT', None) + self.AVLN_EVNTS = obj.get('AVLN_EVNTS', None) + self.AVLN_EXPB = obj.get('AVLN_EXPB', None) + self.AVLN_EXPP = obj.get('AVLN_EXPP', None) + self.AVLN_EXPPE = obj.get('AVLN_EXPPE', None) + self.AVLN_EXPT = obj.get('AVLN_EXPT', None) + self.AVLN_EXP_AREA = obj.get('AVLN_EXP_AREA', None) + self.AVLN_HLRB = obj.get('AVLN_HLRB', None) + self.AVLN_HLRP = obj.get('AVLN_HLRP', None) + self.AVLN_HLRR = obj.get('AVLN_HLRR', None) + self.AVLN_RISKR = obj.get('AVLN_RISKR', None) + self.AVLN_RISKS = obj.get('AVLN_RISKS', None) + self.AVLN_RISKV = obj.get('AVLN_RISKV', None) + self.BUILDVALUE = obj.get('BUILDVALUE', None) + self.CFLD_AFREQ = obj.get('CFLD_AFREQ', None) + self.CFLD_ALRB = obj.get('CFLD_ALRB', None) + self.CFLD_ALRP = obj.get('CFLD_ALRP', None) + self.CFLD_ALR_NPCTL = obj.get('CFLD_ALR_NPCTL', None) + self.CFLD_EALB = obj.get('CFLD_EALB', None) + self.CFLD_EALP = obj.get('CFLD_EALP', None) + self.CFLD_EALPE = obj.get('CFLD_EALPE', None) + self.CFLD_EALR = obj.get('CFLD_EALR', None) + self.CFLD_EALS = obj.get('CFLD_EALS', None) + self.CFLD_EALT = obj.get('CFLD_EALT', None) + self.CFLD_EVNTS = obj.get('CFLD_EVNTS', None) + self.CFLD_EXPB = obj.get('CFLD_EXPB', None) + self.CFLD_EXPP = obj.get('CFLD_EXPP', None) + self.CFLD_EXPPE = obj.get('CFLD_EXPPE', None) + self.CFLD_EXPT = obj.get('CFLD_EXPT', None) + self.CFLD_EXP_AREA = obj.get('CFLD_EXP_AREA', None) + self.CFLD_HLRB = obj.get('CFLD_HLRB', None) + self.CFLD_HLRP = obj.get('CFLD_HLRP', None) + self.CFLD_HLRR = obj.get('CFLD_HLRR', None) + self.CFLD_RISKR = obj.get('CFLD_RISKR', None) + self.CFLD_RISKS = obj.get('CFLD_RISKS', None) + self.CFLD_RISKV = obj.get('CFLD_RISKV', None) + self.COUNTY = obj.get('COUNTY', None) + self.COUNTYFIPS = obj.get('COUNTYFIPS', None) + self.COUNTYTYPE = obj.get('COUNTYTYPE', None) + self.CRF_VALUE = obj.get('CRF_VALUE', None) + self.CWAV_AFREQ = obj.get('CWAV_AFREQ', None) + self.CWAV_ALRA = obj.get('CWAV_ALRA', None) + self.CWAV_ALRB = obj.get('CWAV_ALRB', None) + self.CWAV_ALRP = obj.get('CWAV_ALRP', None) + self.CWAV_ALR_NPCTL = obj.get('CWAV_ALR_NPCTL', None) + self.CWAV_EALA = obj.get('CWAV_EALA', None) + self.CWAV_EALB = obj.get('CWAV_EALB', None) + self.CWAV_EALP = obj.get('CWAV_EALP', None) + self.CWAV_EALPE = obj.get('CWAV_EALPE', None) + self.CWAV_EALR = obj.get('CWAV_EALR', None) + self.CWAV_EALS = obj.get('CWAV_EALS', None) + self.CWAV_EALT = obj.get('CWAV_EALT', None) + self.CWAV_EVNTS = obj.get('CWAV_EVNTS', None) + self.CWAV_EXPA = obj.get('CWAV_EXPA', None) + self.CWAV_EXPB = obj.get('CWAV_EXPB', None) + self.CWAV_EXPP = obj.get('CWAV_EXPP', None) + self.CWAV_EXPPE = obj.get('CWAV_EXPPE', None) + self.CWAV_EXPT = obj.get('CWAV_EXPT', None) + self.CWAV_EXP_AREA = obj.get('CWAV_EXP_AREA', None) + self.CWAV_HLRA = obj.get('CWAV_HLRA', None) + self.CWAV_HLRB = obj.get('CWAV_HLRB', None) + self.CWAV_HLRP = obj.get('CWAV_HLRP', None) + self.CWAV_HLRR = obj.get('CWAV_HLRR', None) + self.CWAV_RISKR = obj.get('CWAV_RISKR', None) + self.CWAV_RISKS = obj.get('CWAV_RISKS', None) + self.CWAV_RISKV = obj.get('CWAV_RISKV', None) + self.DRGT_AFREQ = obj.get('DRGT_AFREQ', None) + self.DRGT_ALRA = obj.get('DRGT_ALRA', None) + self.DRGT_ALR_NPCTL = obj.get('DRGT_ALR_NPCTL', None) + self.DRGT_EALA = obj.get('DRGT_EALA', None) + self.DRGT_EALR = obj.get('DRGT_EALR', None) + self.DRGT_EALS = obj.get('DRGT_EALS', None) + self.DRGT_EALT = obj.get('DRGT_EALT', None) + self.DRGT_EVNTS = obj.get('DRGT_EVNTS', None) + self.DRGT_EXPA = obj.get('DRGT_EXPA', None) + self.DRGT_EXPT = obj.get('DRGT_EXPT', None) + self.DRGT_EXP_AREA = obj.get('DRGT_EXP_AREA', None) + self.DRGT_HLRA = obj.get('DRGT_HLRA', None) + self.DRGT_HLRR = obj.get('DRGT_HLRR', None) + self.DRGT_RISKR = obj.get('DRGT_RISKR', None) + self.DRGT_RISKS = obj.get('DRGT_RISKS', None) + self.DRGT_RISKV = obj.get('DRGT_RISKV', None) + self.EAL_RATNG = obj.get('EAL_RATNG', None) + self.EAL_SCORE = obj.get('EAL_SCORE', None) + self.EAL_SPCTL = obj.get('EAL_SPCTL', None) + self.EAL_VALA = obj.get('EAL_VALA', None) + self.EAL_VALB = obj.get('EAL_VALB', None) + self.EAL_VALP = obj.get('EAL_VALP', None) + self.EAL_VALPE = obj.get('EAL_VALPE', None) + self.EAL_VALT = obj.get('EAL_VALT', None) + self.ERQK_AFREQ = obj.get('ERQK_AFREQ', None) + self.ERQK_ALRB = obj.get('ERQK_ALRB', None) + self.ERQK_ALRP = obj.get('ERQK_ALRP', None) + self.ERQK_ALR_NPCTL = obj.get('ERQK_ALR_NPCTL', None) + self.ERQK_EALB = obj.get('ERQK_EALB', None) + self.ERQK_EALP = obj.get('ERQK_EALP', None) + self.ERQK_EALPE = obj.get('ERQK_EALPE', None) + self.ERQK_EALR = obj.get('ERQK_EALR', None) + self.ERQK_EALS = obj.get('ERQK_EALS', None) + self.ERQK_EALT = obj.get('ERQK_EALT', None) + self.ERQK_EVNTS = obj.get('ERQK_EVNTS', None) + self.ERQK_EXPB = obj.get('ERQK_EXPB', None) + self.ERQK_EXPP = obj.get('ERQK_EXPP', None) + self.ERQK_EXPPE = obj.get('ERQK_EXPPE', None) + self.ERQK_EXPT = obj.get('ERQK_EXPT', None) + self.ERQK_EXP_AREA = obj.get('ERQK_EXP_AREA', None) + self.ERQK_HLRB = obj.get('ERQK_HLRB', None) + self.ERQK_HLRP = obj.get('ERQK_HLRP', None) + self.ERQK_HLRR = obj.get('ERQK_HLRR', None) + self.ERQK_RISKR = obj.get('ERQK_RISKR', None) + self.ERQK_RISKS = obj.get('ERQK_RISKS', None) + self.ERQK_RISKV = obj.get('ERQK_RISKV', None) + self.HAIL_AFREQ = obj.get('HAIL_AFREQ', None) + self.HAIL_ALRA = obj.get('HAIL_ALRA', None) + self.HAIL_ALRB = obj.get('HAIL_ALRB', None) + self.HAIL_ALRP = obj.get('HAIL_ALRP', None) + self.HAIL_ALR_NPCTL = obj.get('HAIL_ALR_NPCTL', None) + self.HAIL_EALA = obj.get('HAIL_EALA', None) + self.HAIL_EALB = obj.get('HAIL_EALB', None) + self.HAIL_EALP = obj.get('HAIL_EALP', None) + self.HAIL_EALPE = obj.get('HAIL_EALPE', None) + self.HAIL_EALR = obj.get('HAIL_EALR', None) + self.HAIL_EALS = obj.get('HAIL_EALS', None) + self.HAIL_EALT = obj.get('HAIL_EALT', None) + self.HAIL_EVNTS = obj.get('HAIL_EVNTS', None) + self.HAIL_EXPA = obj.get('HAIL_EXPA', None) + self.HAIL_EXPB = obj.get('HAIL_EXPB', None) + self.HAIL_EXPP = obj.get('HAIL_EXPP', None) + self.HAIL_EXPPE = obj.get('HAIL_EXPPE', None) + self.HAIL_EXPT = obj.get('HAIL_EXPT', None) + self.HAIL_EXP_AREA = obj.get('HAIL_EXP_AREA', None) + self.HAIL_HLRA = obj.get('HAIL_HLRA', None) + self.HAIL_HLRB = obj.get('HAIL_HLRB', None) + self.HAIL_HLRP = obj.get('HAIL_HLRP', None) + self.HAIL_HLRR = obj.get('HAIL_HLRR', None) + self.HAIL_RISKR = obj.get('HAIL_RISKR', None) + self.HAIL_RISKS = obj.get('HAIL_RISKS', None) + self.HAIL_RISKV = obj.get('HAIL_RISKV', None) + self.HRCN_AFREQ = obj.get('HRCN_AFREQ', None) + self.HRCN_ALRA = obj.get('HRCN_ALRA', None) + self.HRCN_ALRB = obj.get('HRCN_ALRB', None) + self.HRCN_ALRP = obj.get('HRCN_ALRP', None) + self.HRCN_ALR_NPCTL = obj.get('HRCN_ALR_NPCTL', None) + self.HRCN_EALA = obj.get('HRCN_EALA', None) + self.HRCN_EALB = obj.get('HRCN_EALB', None) + self.HRCN_EALP = obj.get('HRCN_EALP', None) + self.HRCN_EALPE = obj.get('HRCN_EALPE', None) + self.HRCN_EALR = obj.get('HRCN_EALR', None) + self.HRCN_EALS = obj.get('HRCN_EALS', None) + self.HRCN_EALT = obj.get('HRCN_EALT', None) + self.HRCN_EVNTS = obj.get('HRCN_EVNTS', None) + self.HRCN_EXPA = obj.get('HRCN_EXPA', None) + self.HRCN_EXPB = obj.get('HRCN_EXPB', None) + self.HRCN_EXPP = obj.get('HRCN_EXPP', None) + self.HRCN_EXPPE = obj.get('HRCN_EXPPE', None) + self.HRCN_EXPT = obj.get('HRCN_EXPT', None) + self.HRCN_EXP_AREA = obj.get('HRCN_EXP_AREA', None) + self.HRCN_HLRA = obj.get('HRCN_HLRA', None) + self.HRCN_HLRB = obj.get('HRCN_HLRB', None) + self.HRCN_HLRP = obj.get('HRCN_HLRP', None) + self.HRCN_HLRR = obj.get('HRCN_HLRR', None) + self.HRCN_RISKR = obj.get('HRCN_RISKR', None) + self.HRCN_RISKS = obj.get('HRCN_RISKS', None) + self.HRCN_RISKV = obj.get('HRCN_RISKV', None) + self.HWAV_AFREQ = obj.get('HWAV_AFREQ', None) + self.HWAV_ALRA = obj.get('HWAV_ALRA', None) + self.HWAV_ALRB = obj.get('HWAV_ALRB', None) + self.HWAV_ALRP = obj.get('HWAV_ALRP', None) + self.HWAV_ALR_NPCTL = obj.get('HWAV_ALR_NPCTL', None) + self.HWAV_EALA = obj.get('HWAV_EALA', None) + self.HWAV_EALB = obj.get('HWAV_EALB', None) + self.HWAV_EALP = obj.get('HWAV_EALP', None) + self.HWAV_EALPE = obj.get('HWAV_EALPE', None) + self.HWAV_EALR = obj.get('HWAV_EALR', None) + self.HWAV_EALS = obj.get('HWAV_EALS', None) + self.HWAV_EALT = obj.get('HWAV_EALT', None) + self.HWAV_EVNTS = obj.get('HWAV_EVNTS', None) + self.HWAV_EXPA = obj.get('HWAV_EXPA', None) + self.HWAV_EXPB = obj.get('HWAV_EXPB', None) + self.HWAV_EXPP = obj.get('HWAV_EXPP', None) + self.HWAV_EXPPE = obj.get('HWAV_EXPPE', None) + self.HWAV_EXPT = obj.get('HWAV_EXPT', None) + self.HWAV_EXP_AREA = obj.get('HWAV_EXP_AREA', None) + self.HWAV_HLRA = obj.get('HWAV_HLRA', None) + self.HWAV_HLRB = obj.get('HWAV_HLRB', None) + self.HWAV_HLRP = obj.get('HWAV_HLRP', None) + self.HWAV_HLRR = obj.get('HWAV_HLRR', None) + self.HWAV_RISKR = obj.get('HWAV_RISKR', None) + self.HWAV_RISKS = obj.get('HWAV_RISKS', None) + self.HWAV_RISKV = obj.get('HWAV_RISKV', None) + self.ISTM_AFREQ = obj.get('ISTM_AFREQ', None) + self.ISTM_ALRB = obj.get('ISTM_ALRB', None) + self.ISTM_ALRP = obj.get('ISTM_ALRP', None) + self.ISTM_ALR_NPCTL = obj.get('ISTM_ALR_NPCTL', None) + self.ISTM_EALB = obj.get('ISTM_EALB', None) + self.ISTM_EALP = obj.get('ISTM_EALP', None) + self.ISTM_EALPE = obj.get('ISTM_EALPE', None) + self.ISTM_EALR = obj.get('ISTM_EALR', None) + self.ISTM_EALS = obj.get('ISTM_EALS', None) + self.ISTM_EALT = obj.get('ISTM_EALT', None) + self.ISTM_EVNTS = obj.get('ISTM_EVNTS', None) + self.ISTM_EXPB = obj.get('ISTM_EXPB', None) + self.ISTM_EXPP = obj.get('ISTM_EXPP', None) + self.ISTM_EXPPE = obj.get('ISTM_EXPPE', None) + self.ISTM_EXPT = obj.get('ISTM_EXPT', None) + self.ISTM_EXP_AREA = obj.get('ISTM_EXP_AREA', None) + self.ISTM_HLRB = obj.get('ISTM_HLRB', None) + self.ISTM_HLRP = obj.get('ISTM_HLRP', None) + self.ISTM_HLRR = obj.get('ISTM_HLRR', None) + self.ISTM_RISKR = obj.get('ISTM_RISKR', None) + self.ISTM_RISKS = obj.get('ISTM_RISKS', None) + self.ISTM_RISKV = obj.get('ISTM_RISKV', None) + self.LNDS_AFREQ = obj.get('LNDS_AFREQ', None) + self.LNDS_ALRB = obj.get('LNDS_ALRB', None) + self.LNDS_ALRP = obj.get('LNDS_ALRP', None) + self.LNDS_ALR_NPCTL = obj.get('LNDS_ALR_NPCTL', None) + self.LNDS_EALB = obj.get('LNDS_EALB', None) + self.LNDS_EALP = obj.get('LNDS_EALP', None) + self.LNDS_EALPE = obj.get('LNDS_EALPE', None) + self.LNDS_EALR = obj.get('LNDS_EALR', None) + self.LNDS_EALS = obj.get('LNDS_EALS', None) + self.LNDS_EALT = obj.get('LNDS_EALT', None) + self.LNDS_EVNTS = obj.get('LNDS_EVNTS', None) + self.LNDS_EXPB = obj.get('LNDS_EXPB', None) + self.LNDS_EXPP = obj.get('LNDS_EXPP', None) + self.LNDS_EXPPE = obj.get('LNDS_EXPPE', None) + self.LNDS_EXPT = obj.get('LNDS_EXPT', None) + self.LNDS_EXP_AREA = obj.get('LNDS_EXP_AREA', None) + self.LNDS_HLRB = obj.get('LNDS_HLRB', None) + self.LNDS_HLRP = obj.get('LNDS_HLRP', None) + self.LNDS_HLRR = obj.get('LNDS_HLRR', None) + self.LNDS_RISKR = obj.get('LNDS_RISKR', None) + self.LNDS_RISKS = obj.get('LNDS_RISKS', None) + self.LNDS_RISKV = obj.get('LNDS_RISKV', None) + self.LTNG_AFREQ = obj.get('LTNG_AFREQ', None) + self.LTNG_ALRB = obj.get('LTNG_ALRB', None) + self.LTNG_ALRP = obj.get('LTNG_ALRP', None) + self.LTNG_ALR_NPCTL = obj.get('LTNG_ALR_NPCTL', None) + self.LTNG_EALB = obj.get('LTNG_EALB', None) + self.LTNG_EALP = obj.get('LTNG_EALP', None) + self.LTNG_EALPE = obj.get('LTNG_EALPE', None) + self.LTNG_EALR = obj.get('LTNG_EALR', None) + self.LTNG_EALS = obj.get('LTNG_EALS', None) + self.LTNG_EALT = obj.get('LTNG_EALT', None) + self.LTNG_EVNTS = obj.get('LTNG_EVNTS', None) + self.LTNG_EXPB = obj.get('LTNG_EXPB', None) + self.LTNG_EXPP = obj.get('LTNG_EXPP', None) + self.LTNG_EXPPE = obj.get('LTNG_EXPPE', None) + self.LTNG_EXPT = obj.get('LTNG_EXPT', None) + self.LTNG_EXP_AREA = obj.get('LTNG_EXP_AREA', None) + self.LTNG_HLRB = obj.get('LTNG_HLRB', None) + self.LTNG_HLRP = obj.get('LTNG_HLRP', None) + self.LTNG_HLRR = obj.get('LTNG_HLRR', None) + self.LTNG_RISKR = obj.get('LTNG_RISKR', None) + self.LTNG_RISKS = obj.get('LTNG_RISKS', None) + self.LTNG_RISKV = obj.get('LTNG_RISKV', None) + self.NRI_VER = obj.get('NRI_VER', None) + self.POPULATION = obj.get('POPULATION', None) + self.RESL_RATNG = obj.get('RESL_RATNG', None) + self.RESL_SCORE = obj.get('RESL_SCORE', None) + self.RESL_SPCTL = obj.get('RESL_SPCTL', None) + self.RESL_VALUE = obj.get('RESL_VALUE', None) + self.RFLD_AFREQ = obj.get('RFLD_AFREQ', None) + self.RFLD_ALRA = obj.get('RFLD_ALRA', None) + self.RFLD_ALRB = obj.get('RFLD_ALRB', None) + self.RFLD_ALRP = obj.get('RFLD_ALRP', None) + self.RFLD_ALR_NPCTL = obj.get('RFLD_ALR_NPCTL', None) + self.RFLD_EALA = obj.get('RFLD_EALA', None) + self.RFLD_EALB = obj.get('RFLD_EALB', None) + self.RFLD_EALP = obj.get('RFLD_EALP', None) + self.RFLD_EALPE = obj.get('RFLD_EALPE', None) + self.RFLD_EALR = obj.get('RFLD_EALR', None) + self.RFLD_EALS = obj.get('RFLD_EALS', None) + self.RFLD_EALT = obj.get('RFLD_EALT', None) + self.RFLD_EVNTS = obj.get('RFLD_EVNTS', None) + self.RFLD_EXPA = obj.get('RFLD_EXPA', None) + self.RFLD_EXPB = obj.get('RFLD_EXPB', None) + self.RFLD_EXPP = obj.get('RFLD_EXPP', None) + self.RFLD_EXPPE = obj.get('RFLD_EXPPE', None) + self.RFLD_EXPT = obj.get('RFLD_EXPT', None) + self.RFLD_EXP_AREA = obj.get('RFLD_EXP_AREA', None) + self.RFLD_HLRA = obj.get('RFLD_HLRA', None) + self.RFLD_HLRB = obj.get('RFLD_HLRB', None) + self.RFLD_HLRP = obj.get('RFLD_HLRP', None) + self.RFLD_HLRR = obj.get('RFLD_HLRR', None) + self.RFLD_RISKR = obj.get('RFLD_RISKR', None) + self.RFLD_RISKS = obj.get('RFLD_RISKS', None) + self.RFLD_RISKV = obj.get('RFLD_RISKV', None) + self.RISK_RATNG = obj.get('RISK_RATNG', None) + self.RISK_SCORE = obj.get('RISK_SCORE', None) + self.RISK_SPCTL = obj.get('RISK_SPCTL', None) + self.RISK_VALUE = obj.get('RISK_VALUE', None) + self.SOVI_RATNG = obj.get('SOVI_RATNG', None) + self.SOVI_SCORE = obj.get('SOVI_SCORE', None) + self.SOVI_SPCTL = obj.get('SOVI_SPCTL', None) + self.STATE = obj.get('STATE', None) + self.STATEABBRV = obj.get('STATEABBRV', None) + self.STATEFIPS = obj.get('STATEFIPS', None) + self.STCOFIPS = obj.get('STCOFIPS', None) + self.SWND_AFREQ = obj.get('SWND_AFREQ', None) + self.SWND_ALRA = obj.get('SWND_ALRA', None) + self.SWND_ALRB = obj.get('SWND_ALRB', None) + self.SWND_ALRP = obj.get('SWND_ALRP', None) + self.SWND_ALR_NPCTL = obj.get('SWND_ALR_NPCTL', None) + self.SWND_EALA = obj.get('SWND_EALA', None) + self.SWND_EALB = obj.get('SWND_EALB', None) + self.SWND_EALP = obj.get('SWND_EALP', None) + self.SWND_EALPE = obj.get('SWND_EALPE', None) + self.SWND_EALR = obj.get('SWND_EALR', None) + self.SWND_EALS = obj.get('SWND_EALS', None) + self.SWND_EALT = obj.get('SWND_EALT', None) + self.SWND_EVNTS = obj.get('SWND_EVNTS', None) + self.SWND_EXPA = obj.get('SWND_EXPA', None) + self.SWND_EXPB = obj.get('SWND_EXPB', None) + self.SWND_EXPP = obj.get('SWND_EXPP', None) + self.SWND_EXPPE = obj.get('SWND_EXPPE', None) + self.SWND_EXPT = obj.get('SWND_EXPT', None) + self.SWND_EXP_AREA = obj.get('SWND_EXP_AREA', None) + self.SWND_HLRA = obj.get('SWND_HLRA', None) + self.SWND_HLRB = obj.get('SWND_HLRB', None) + self.SWND_HLRP = obj.get('SWND_HLRP', None) + self.SWND_HLRR = obj.get('SWND_HLRR', None) + self.SWND_RISKR = obj.get('SWND_RISKR', None) + self.SWND_RISKS = obj.get('SWND_RISKS', None) + self.SWND_RISKV = obj.get('SWND_RISKV', None) + self.TRACT = obj.get('TRACT', None) + self.TRACTFIPS = obj.get('TRACTFIPS', None) + self.TRND_AFREQ = obj.get('TRND_AFREQ', None) + self.TRND_ALRA = obj.get('TRND_ALRA', None) + self.TRND_ALRB = obj.get('TRND_ALRB', None) + self.TRND_ALRP = obj.get('TRND_ALRP', None) + self.TRND_ALR_NPCTL = obj.get('TRND_ALR_NPCTL', None) + self.TRND_EALA = obj.get('TRND_EALA', None) + self.TRND_EALB = obj.get('TRND_EALB', None) + self.TRND_EALP = obj.get('TRND_EALP', None) + self.TRND_EALPE = obj.get('TRND_EALPE', None) + self.TRND_EALR = obj.get('TRND_EALR', None) + self.TRND_EALS = obj.get('TRND_EALS', None) + self.TRND_EALT = obj.get('TRND_EALT', None) + self.TRND_EVNTS = obj.get('TRND_EVNTS', None) + self.TRND_EXPA = obj.get('TRND_EXPA', None) + self.TRND_EXPB = obj.get('TRND_EXPB', None) + self.TRND_EXPP = obj.get('TRND_EXPP', None) + self.TRND_EXPPE = obj.get('TRND_EXPPE', None) + self.TRND_EXPT = obj.get('TRND_EXPT', None) + self.TRND_EXP_AREA = obj.get('TRND_EXP_AREA', None) + self.TRND_HLRA = obj.get('TRND_HLRA', None) + self.TRND_HLRB = obj.get('TRND_HLRB', None) + self.TRND_HLRP = obj.get('TRND_HLRP', None) + self.TRND_HLRR = obj.get('TRND_HLRR', None) + self.TRND_RISKR = obj.get('TRND_RISKR', None) + self.TRND_RISKS = obj.get('TRND_RISKS', None) + self.TRND_RISKV = obj.get('TRND_RISKV', None) + self.TSUN_AFREQ = obj.get('TSUN_AFREQ', None) + self.TSUN_ALRB = obj.get('TSUN_ALRB', None) + self.TSUN_ALRP = obj.get('TSUN_ALRP', None) + self.TSUN_ALR_NPCTL = obj.get('TSUN_ALR_NPCTL', None) + self.TSUN_EALB = obj.get('TSUN_EALB', None) + self.TSUN_EALP = obj.get('TSUN_EALP', None) + self.TSUN_EALPE = obj.get('TSUN_EALPE', None) + self.TSUN_EALR = obj.get('TSUN_EALR', None) + self.TSUN_EALS = obj.get('TSUN_EALS', None) + self.TSUN_EALT = obj.get('TSUN_EALT', None) + self.TSUN_EVNTS = obj.get('TSUN_EVNTS', None) + self.TSUN_EXPB = obj.get('TSUN_EXPB', None) + self.TSUN_EXPP = obj.get('TSUN_EXPP', None) + self.TSUN_EXPPE = obj.get('TSUN_EXPPE', None) + self.TSUN_EXPT = obj.get('TSUN_EXPT', None) + self.TSUN_EXP_AREA = obj.get('TSUN_EXP_AREA', None) + self.TSUN_HLRB = obj.get('TSUN_HLRB', None) + self.TSUN_HLRP = obj.get('TSUN_HLRP', None) + self.TSUN_HLRR = obj.get('TSUN_HLRR', None) + self.TSUN_RISKR = obj.get('TSUN_RISKR', None) + self.TSUN_RISKS = obj.get('TSUN_RISKS', None) + self.TSUN_RISKV = obj.get('TSUN_RISKV', None) + self.VLCN_AFREQ = obj.get('VLCN_AFREQ', None) + self.VLCN_ALRB = obj.get('VLCN_ALRB', None) + self.VLCN_ALRP = obj.get('VLCN_ALRP', None) + self.VLCN_ALR_NPCTL = obj.get('VLCN_ALR_NPCTL', None) + self.VLCN_EALB = obj.get('VLCN_EALB', None) + self.VLCN_EALP = obj.get('VLCN_EALP', None) + self.VLCN_EALPE = obj.get('VLCN_EALPE', None) + self.VLCN_EALR = obj.get('VLCN_EALR', None) + self.VLCN_EALS = obj.get('VLCN_EALS', None) + self.VLCN_EALT = obj.get('VLCN_EALT', None) + self.VLCN_EVNTS = obj.get('VLCN_EVNTS', None) + self.VLCN_EXPB = obj.get('VLCN_EXPB', None) + self.VLCN_EXPP = obj.get('VLCN_EXPP', None) + self.VLCN_EXPPE = obj.get('VLCN_EXPPE', None) + self.VLCN_EXPT = obj.get('VLCN_EXPT', None) + self.VLCN_EXP_AREA = obj.get('VLCN_EXP_AREA', None) + self.VLCN_HLRB = obj.get('VLCN_HLRB', None) + self.VLCN_HLRP = obj.get('VLCN_HLRP', None) + self.VLCN_HLRR = obj.get('VLCN_HLRR', None) + self.VLCN_RISKR = obj.get('VLCN_RISKR', None) + self.VLCN_RISKS = obj.get('VLCN_RISKS', None) + self.VLCN_RISKV = obj.get('VLCN_RISKV', None) + self.WFIR_AFREQ = obj.get('WFIR_AFREQ', None) + self.WFIR_ALRA = obj.get('WFIR_ALRA', None) + self.WFIR_ALRB = obj.get('WFIR_ALRB', None) + self.WFIR_ALRP = obj.get('WFIR_ALRP', None) + self.WFIR_ALR_NPCTL = obj.get('WFIR_ALR_NPCTL', None) + self.WFIR_EALA = obj.get('WFIR_EALA', None) + self.WFIR_EALB = obj.get('WFIR_EALB', None) + self.WFIR_EALP = obj.get('WFIR_EALP', None) + self.WFIR_EALPE = obj.get('WFIR_EALPE', None) + self.WFIR_EALR = obj.get('WFIR_EALR', None) + self.WFIR_EALS = obj.get('WFIR_EALS', None) + self.WFIR_EALT = obj.get('WFIR_EALT', None) + self.WFIR_EVNTS = obj.get('WFIR_EVNTS', None) + self.WFIR_EXPA = obj.get('WFIR_EXPA', None) + self.WFIR_EXPB = obj.get('WFIR_EXPB', None) + self.WFIR_EXPP = obj.get('WFIR_EXPP', None) + self.WFIR_EXPPE = obj.get('WFIR_EXPPE', None) + self.WFIR_EXPT = obj.get('WFIR_EXPT', None) + self.WFIR_EXP_AREA = obj.get('WFIR_EXP_AREA', None) + self.WFIR_HLRA = obj.get('WFIR_HLRA', None) + self.WFIR_HLRB = obj.get('WFIR_HLRB', None) + self.WFIR_HLRP = obj.get('WFIR_HLRP', None) + self.WFIR_HLRR = obj.get('WFIR_HLRR', None) + self.WFIR_RISKR = obj.get('WFIR_RISKR', None) + self.WFIR_RISKS = obj.get('WFIR_RISKS', None) + self.WFIR_RISKV = obj.get('WFIR_RISKV', None) + self.WNTW_AFREQ = obj.get('WNTW_AFREQ', None) + self.WNTW_ALRA = obj.get('WNTW_ALRA', None) + self.WNTW_ALRB = obj.get('WNTW_ALRB', None) + self.WNTW_ALRP = obj.get('WNTW_ALRP', None) + self.WNTW_ALR_NPCTL = obj.get('WNTW_ALR_NPCTL', None) + self.WNTW_EALA = obj.get('WNTW_EALA', None) + self.WNTW_EALB = obj.get('WNTW_EALB', None) + self.WNTW_EALP = obj.get('WNTW_EALP', None) + self.WNTW_EALPE = obj.get('WNTW_EALPE', None) + self.WNTW_EALR = obj.get('WNTW_EALR', None) + self.WNTW_EALS = obj.get('WNTW_EALS', None) + self.WNTW_EALT = obj.get('WNTW_EALT', None) + self.WNTW_EVNTS = obj.get('WNTW_EVNTS', None) + self.WNTW_EXPA = obj.get('WNTW_EXPA', None) + self.WNTW_EXPB = obj.get('WNTW_EXPB', None) + self.WNTW_EXPP = obj.get('WNTW_EXPP', None) + self.WNTW_EXPPE = obj.get('WNTW_EXPPE', None) + self.WNTW_EXPT = obj.get('WNTW_EXPT', None) + self.WNTW_EXP_AREA = obj.get('WNTW_EXP_AREA', None) + self.WNTW_HLRA = obj.get('WNTW_HLRA', None) + self.WNTW_HLRB = obj.get('WNTW_HLRB', None) + self.WNTW_HLRP = obj.get('WNTW_HLRP', None) + self.WNTW_HLRR = obj.get('WNTW_HLRR', None) + self.WNTW_RISKR = obj.get('WNTW_RISKR', None) + self.WNTW_RISKS = obj.get('WNTW_RISKS', None) + self.WNTW_RISKV = obj.get('WNTW_RISKV', None) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + +class SecondaryRootAddress: + def __init__(self, obj): + self.secondary_count = obj.get('secondary_count', None) + self.smarty_key = obj.get('smarty_key', None) + self.primary_number = obj.get('primary_number', None) + self.street_predirection = obj.get('street_predirection', None) + self.street_name = obj.get('street_name', None) + self.street_suffix = obj.get('street_suffix', None) + self.street_postdirection = obj.get('street_postdirection', None) + self.city_name = obj.get('city_name', None) + self.state_abbreviation = obj.get('state_abbreviation', None) + self.zipcode = obj.get('zipcode', None) + self.plus4_code = obj.get('plus4_code', None) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + +def get_secondary_root_address(secondary_root_address_obj): + if secondary_root_address_obj is None: + return None + output = [] + output.append(SecondaryRootAddress(secondary_root_address_obj)) + + return output + +class SecondaryAliases: + def __init__(self, obj): + self.smarty_key = obj.get('smarty_key', None) + self.primary_number = obj.get('primary_number', None) + self.street_predirection = obj.get('street_predirection', None) + self.street_name = obj.get('street_name', None) + self.street_suffix = obj.get('street_suffix', None) + self.street_postdirection = obj.get('street_postdirection', None) + self.city_name = obj.get('city_name', None) + self.state_abbreviation = obj.get('state_abbreviation', None) + self.zipcode = obj.get('zipcode', None) + self.plus4_code = obj.get('plus4_code', None) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + +def get_secondary_aliases(secondary_aliases_obj): + if secondary_aliases_obj is None: + return None + output = [] + for item in secondary_aliases_obj: + output.append(SecondaryAliases(item)) + return output + +class SecondarySecondaries: + def __init__(self, obj): + self.smarty_key = obj.get('smarty_key', None) + self.secondary_designator = obj.get('secondary_designator', None) + self.secondary_number = obj.get('secondary_number', None) + self.plus4_code = obj.get('plus4_code', None) + + def __str__(self): + lines = [''] + for key, val in vars(self).items(): + if type(val) is list: + lines.append(key + ': ') + for item in val: + for subkey, subval in vars(item).items(): + lines += ' {}: {}'.format(subkey, subval).split('\n') + else: + lines.append(key + ': ' + str(val)) + return '\n '.join(lines) + +def get_secondary_secondaries(secondary_secondaries_obj): + if secondary_secondaries_obj is None: + return None + output = [] + for item in secondary_secondaries_obj: + output.append(SecondarySecondaries(item)) + return output + +class SecondaryCountAttributes: + def __init__(self, obj): + self.smarty_key = obj.get('smarty_key', None) + self.count = obj.get('count', None) + + def __str__(self): + return self.__dict__.__str__() \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_extract/address.py b/smarty/smartystreets_python_sdk/us_extract/address.py index 4ea1a65..d3b0b9c 100644 --- a/smarty/smartystreets_python_sdk/us_extract/address.py +++ b/smarty/smartystreets_python_sdk/us_extract/address.py @@ -1,4 +1,4 @@ -from ..us_street.candidate import Candidate +from smartystreets_python_sdk.us_street.candidate import Candidate class Address: diff --git a/smarty/smartystreets_python_sdk/us_extract/client.py b/smarty/smartystreets_python_sdk/us_extract/client.py index e6f3129..b860563 100644 --- a/smarty/smartystreets_python_sdk/us_extract/client.py +++ b/smarty/smartystreets_python_sdk/us_extract/client.py @@ -1,6 +1,8 @@ -# from smartystreets_python_sdk import Request -from ..exceptions import SmartyException -# from . import Result +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.exceptions import SmartyException +from smartystreets_python_sdk.us_extract import Result +from smartystreets_python_sdk.us_street.match_type import MatchType + class Client: def __init__(self, sender, serializer): @@ -39,6 +41,13 @@ def build_request(lookup): Client.add_parameter(request, 'aggressive', str(lookup.aggressive).lower()) Client.add_parameter(request, 'addr_line_breaks', str(lookup.addresses_have_line_breaks).lower()) Client.add_parameter(request, 'addr_per_line', lookup.addresses_per_line) + if isinstance(lookup.match, MatchType): + Client.add_parameter(request, 'match', lookup.match.value) + else: + Client.add_parameter(request, 'match', lookup.match) + + for parameter in lookup.custom_parameter_array: + Client.add_parameter(request, parameter, lookup.custom_parameter_array[parameter]) return request diff --git a/smarty/smartystreets_python_sdk/us_extract/lookup.py b/smarty/smartystreets_python_sdk/us_extract/lookup.py index 13719a8..577ed21 100644 --- a/smarty/smartystreets_python_sdk/us_extract/lookup.py +++ b/smarty/smartystreets_python_sdk/us_extract/lookup.py @@ -1,15 +1,24 @@ +from smartystreets_python_sdk.us_street.match_type import MatchType + + class Lookup: - def __init__(self, text=None, html=None, aggressive=None, addresses_have_line_breaks=None, addresses_per_line=None): + def __init__(self, text=None, html=None, aggressive=None, addresses_have_line_breaks=None, + addresses_per_line=None, match=MatchType.STRICT): """ - In addition to holding all of the input data for this lookup, this class also will contain the result + In addition to holding all input data for this lookup, this class also will contain the result of the lookup after it comes back from the API. See "https://smartystreets.com/docs/cloud/us-extract-api#http-request-input-fields" """ self.result = None + self.custom_parameter_array = {} self.text = text self.html = html self.aggressive = aggressive self.addresses_have_line_breaks = addresses_have_line_breaks self.addresses_per_line = addresses_per_line + self.match = match + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value diff --git a/smarty/smartystreets_python_sdk/us_extract/result.py b/smarty/smartystreets_python_sdk/us_extract/result.py index 7496eed..0e6f562 100644 --- a/smarty/smartystreets_python_sdk/us_extract/result.py +++ b/smarty/smartystreets_python_sdk/us_extract/result.py @@ -1,5 +1,5 @@ -# from . import Address -# from . import Metadata +from smartystreets_python_sdk.us_extract import Address +from smartystreets_python_sdk.us_extract import Metadata class Result: diff --git a/smarty/smartystreets_python_sdk/us_reverse_geo/address.py b/smarty/smartystreets_python_sdk/us_reverse_geo/address.py index f9dd588..b85d729 100644 --- a/smarty/smartystreets_python_sdk/us_reverse_geo/address.py +++ b/smarty/smartystreets_python_sdk/us_reverse_geo/address.py @@ -7,3 +7,5 @@ def __init__(self, obj): self.city = obj.get('city', None) self.state_abbreviation = obj.get('state_abbreviation', None) self.zipcode = obj.get('zipcode', None) + self.source = obj.get('source', None) + self.smartykey = obj.get('smarty_key', None) diff --git a/smarty/smartystreets_python_sdk/us_reverse_geo/client.py b/smarty/smartystreets_python_sdk/us_reverse_geo/client.py index 198ad3f..f7a3411 100644 --- a/smarty/smartystreets_python_sdk/us_reverse_geo/client.py +++ b/smarty/smartystreets_python_sdk/us_reverse_geo/client.py @@ -1,5 +1,5 @@ -# from smartystreets_python_sdk import Request -# from . import Response +from smartystreets_python_sdk import Request +from smartystreets_python_sdk.us_reverse_geo import Response class Client: @@ -31,6 +31,10 @@ def build_request(self, lookup): self.add_parameter(request, 'latitude', lookup.latitude) self.add_parameter(request, 'longitude', lookup.longitude) + self.add_parameter(request, 'source', lookup.source) + + for parameter in lookup.custom_parameter_array: + self.add_parameter(request, parameter, lookup.custom_parameter_array[parameter]) return request diff --git a/smarty/smartystreets_python_sdk/us_reverse_geo/lookup.py b/smarty/smartystreets_python_sdk/us_reverse_geo/lookup.py index f3b3f56..afd0413 100644 --- a/smarty/smartystreets_python_sdk/us_reverse_geo/lookup.py +++ b/smarty/smartystreets_python_sdk/us_reverse_geo/lookup.py @@ -1,5 +1,5 @@ class Lookup: - def __init__(self, latitude=None, longitude=None): + def __init__(self, latitude=None, longitude=None, source=None): """ In addition to holding the lat/lon data for this lookup, this class also will contain the result of the lookup after it comes back from the API. @@ -7,6 +7,10 @@ def __init__(self, latitude=None, longitude=None): See https://smartystreets.com/docs/cloud/us-reverse-geo-api#http-input-fields """ self.results = [] - + self.custom_parameter_array = {} self.latitude = round(latitude, 8) self.longitude = round(longitude, 8) + self.source = source + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_reverse_geo/response.py b/smarty/smartystreets_python_sdk/us_reverse_geo/response.py index 6fb1b4f..c249b5c 100644 --- a/smarty/smartystreets_python_sdk/us_reverse_geo/response.py +++ b/smarty/smartystreets_python_sdk/us_reverse_geo/response.py @@ -1,4 +1,4 @@ -# from . import Result +from .result import Result class Response: diff --git a/smarty/smartystreets_python_sdk/us_reverse_geo/result.py b/smarty/smartystreets_python_sdk/us_reverse_geo/result.py index f5a8344..ed42ba7 100644 --- a/smarty/smartystreets_python_sdk/us_reverse_geo/result.py +++ b/smarty/smartystreets_python_sdk/us_reverse_geo/result.py @@ -1,5 +1,5 @@ -# from . import Coordinate -# from . import Address +from .coordinate import Coordinate +from .address import Address class Result: diff --git a/smarty/smartystreets_python_sdk/us_street/analysis.py b/smarty/smartystreets_python_sdk/us_street/analysis.py index d42d307..3547551 100644 --- a/smarty/smartystreets_python_sdk/us_street/analysis.py +++ b/smarty/smartystreets_python_sdk/us_street/analysis.py @@ -1,3 +1,5 @@ +from .component_analysis import ComponentAnalysis + class Analysis: def __init__(self, obj): """ @@ -15,3 +17,24 @@ def __init__(self, obj): self.lacs_link_indicator = obj.get('lacslink_indicator', None) self.is_suite_link_match = obj.get('suitelink_match', None) self.enhanced_match = obj.get('enhanced_match', None) + components_obj = obj.get("components", None) + self.components = ComponentAnalysis(components_obj) if components_obj else None + + def to_dict(self): + components_dict = self.components.to_dict() if self.components else None + + result = { + "dpv_match_code": self.dpv_match_code, + "dpv_footnotes": self.dpv_footnotes, + "dpv_cmra": self.cmra, + "dpv_vacant": self.vacant, + "active": self.active, + "dpv_no_stat": self.dpv_no_stat, + "footnotes": self.footnotes, + "lacslink_code": self.lacs_link_code, + "lacslink_indicator": self.lacs_link_indicator, + "suitelink_match": self.is_suite_link_match, + "enhanced_match": self.enhanced_match, + "components": components_dict or None + } + return {k: v for k, v in result.items() if v is not None} diff --git a/smarty/smartystreets_python_sdk/us_street/candidate.py b/smarty/smartystreets_python_sdk/us_street/candidate.py index 653a16d..bb4afe8 100644 --- a/smarty/smartystreets_python_sdk/us_street/candidate.py +++ b/smarty/smartystreets_python_sdk/us_street/candidate.py @@ -1,3 +1,5 @@ +import json + from .components import Components from .metadata import Metadata from .analysis import Analysis @@ -20,6 +22,33 @@ def __init__(self, obj): self.delivery_line_2 = obj.get('delivery_line_2', None) self.last_line = obj.get('last_line', None) self.delivery_point_barcode = obj.get('delivery_point_barcode', None) + self.smarty_key = obj.get('smarty_key', None) + self.smarty_key_ext = obj.get('smarty_key_ext', None) self.components = Components(obj.get('components', {})) self.metadata = Metadata(obj.get('metadata', {})) self.analysis = Analysis(obj.get('analysis', {})) + + def to_dict(self): + components_dict = self.components.to_dict() if self.components else None + metadata_dict = self.metadata.to_dict() if self.metadata else None + analysis_dict = self.analysis.to_dict() if self.analysis else None + + result = { + "input_id": self.input_id, + "input_index": self.input_index, + "candidate_index": self.candidate_index, + "addressee": self.addressee, + "delivery_line_1": self.delivery_line_1, + "delivery_line_2": self.delivery_line_2, + "last_line": self.last_line, + "delivery_point_barcode": self.delivery_point_barcode, + "smarty_key": self.smarty_key, + "smarty_key_ext": self.smarty_key_ext, + "components": components_dict or None, + "metadata": metadata_dict or None, + "analysis": analysis_dict or None + } + return {k: v for k, v in result.items() if v is not None} + + def to_json(self): + return json.dumps(self.to_dict()) \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_street/client.py b/smarty/smartystreets_python_sdk/us_street/client.py index f768fc4..3b4c8f2 100644 --- a/smarty/smartystreets_python_sdk/us_street/client.py +++ b/smarty/smartystreets_python_sdk/us_street/client.py @@ -1,5 +1,8 @@ -from .candidate import Candidate -from .. import Request, Batch +from smartystreets_python_sdk.us_street.match_type import MatchType +from smartystreets_python_sdk.us_street.output_format import OutputFormat + +from smartystreets_python_sdk.us_street import Candidate +from smartystreets_python_sdk import Request, Batch class Client: @@ -55,10 +58,16 @@ def remap_keys(obj): for lookup in obj: converted_lookup = {} - if lookup.match == 'enhanced' and lookup.candidates == 1: - add_field(converted_lookup, 'candidates', 5) - else: + # Determine effective match strategy (default to ENHANCED if not specified) + match_strategy = lookup.match + if match_strategy is None: + match_strategy = MatchType.ENHANCED + + # Handle candidates + if lookup.candidates > 0: add_field(converted_lookup, 'candidates', lookup.candidates) + elif match_strategy == MatchType.ENHANCED or match_strategy == "enhanced": + add_field(converted_lookup, 'candidates', 5) add_field(converted_lookup, 'input_id', lookup.input_id) add_field(converted_lookup, 'street', lookup.street) @@ -70,7 +79,20 @@ def remap_keys(obj): add_field(converted_lookup, 'lastline', lookup.lastline) add_field(converted_lookup, 'addressee', lookup.addressee) add_field(converted_lookup, 'urbanization', lookup.urbanization) - add_field(converted_lookup, 'match', lookup.match) + add_field(converted_lookup, 'county_source', lookup.county_source) + + if isinstance(match_strategy, MatchType): + add_field(converted_lookup, 'match', match_strategy.value) + else: + add_field(converted_lookup, 'match', match_strategy) + + if isinstance(lookup.outputformat, OutputFormat): + add_field(converted_lookup, 'format', lookup.outputformat.value) + else: + add_field(converted_lookup, 'format', lookup.outputformat) + + for parameter in lookup.custom_parameter_array: + add_field(converted_lookup, parameter, lookup.custom_parameter_array[parameter]) converted_obj.append(converted_lookup) diff --git a/smarty/smartystreets_python_sdk/us_street/component_analysis.py b/smarty/smartystreets_python_sdk/us_street/component_analysis.py new file mode 100644 index 0000000..e58bb0a --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_street/component_analysis.py @@ -0,0 +1,40 @@ +from .match_info import MatchInfo + +class ComponentAnalysis: + def __init__(self, obj): + """ + This class contains detailed match information for each component of an address. + """ + self.primary_number = MatchInfo(obj['primary_number']) if 'primary_number' in obj else None + self.street_predirection = MatchInfo(obj['street_predirection']) if 'street_predirection' in obj else None + self.street_name = MatchInfo(obj['street_name']) if 'street_name' in obj else None + self.street_postdirection = MatchInfo(obj['street_postdirection']) if 'street_postdirection' in obj else None + self.street_suffix = MatchInfo(obj['street_suffix']) if 'street_suffix' in obj else None + self.secondary_number = MatchInfo(obj['secondary_number']) if 'secondary_number' in obj else None + self.secondary_designator = MatchInfo(obj['secondary_designator']) if 'secondary_designator' in obj else None + self.extra_secondary_number = MatchInfo(obj['extra_secondary_number']) if 'extra_secondary_number' in obj else None + self.extra_secondary_designator = MatchInfo(obj['extra_secondary_designator']) if 'extra_secondary_designator' in obj else None + self.city_name = MatchInfo(obj['city_name']) if 'city_name' in obj else None + self.state_abbreviation = MatchInfo(obj['state_abbreviation']) if 'state_abbreviation' in obj else None + self.zipcode = MatchInfo(obj['zipcode']) if 'zipcode' in obj else None + self.plus4_code = MatchInfo(obj['plus4_code']) if 'plus4_code' in obj else None + self.urbanization = MatchInfo(obj['urbanization']) if 'urbanization' in obj else None + + def to_dict(self): + result = { + 'primary_number': self.primary_number.to_dict() if self.primary_number else None, + 'street_predirection': self.street_predirection.to_dict() if self.street_predirection else None, + 'street_name': self.street_name.to_dict() if self.street_name else None, + 'street_postdirection': self.street_postdirection.to_dict() if self.street_postdirection else None, + 'street_suffix': self.street_suffix.to_dict() if self.street_suffix else None, + 'secondary_number': self.secondary_number.to_dict() if self.secondary_number else None, + 'secondary_designator': self.secondary_designator.to_dict() if self.secondary_designator else None, + 'extra_secondary_number': self.extra_secondary_number.to_dict() if self.extra_secondary_number else None, + 'extra_secondary_designator': self.extra_secondary_designator.to_dict() if self.extra_secondary_designator else None, + 'city_name': self.city_name.to_dict() if self.city_name else None, + 'state_abbreviation': self.state_abbreviation.to_dict() if self.state_abbreviation else None, + 'zipcode': self.zipcode.to_dict() if self.zipcode else None, + 'plus4_code': self.plus4_code.to_dict() if self.plus4_code else None, + 'urbanization': self.urbanization.to_dict() if self.urbanization else None, + } + return {k: v for k, v in result.items() if v is not None} \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_street/components.py b/smarty/smartystreets_python_sdk/us_street/components.py index ebf26a2..26c4ed9 100644 --- a/smarty/smartystreets_python_sdk/us_street/components.py +++ b/smarty/smartystreets_python_sdk/us_street/components.py @@ -24,3 +24,27 @@ def __init__(self, obj): self.plus4_code = obj.get('plus4_code', None) self.delivery_point = obj.get('delivery_point', None) self.delivery_point_check_digit = obj.get('delivery_point_check_digit', None) + + def to_dict(self): + result = { + "urbanization": self.urbanization, + "primary_number": self.primary_number, + "street_name": self.street_name, + "street_predirection": self.street_predirection, + "street_postdirection": self.street_postdirection, + "street_suffix": self.street_suffix, + "secondary_number": self.secondary_number, + "secondary_designator": self.secondary_designator, + "extra_secondary_number": self.extra_secondary_number, + "extra_secondary_designator": self.extra_secondary_designator, + "pmb_designator": self.pmb_designator, + "pmb_number": self.pmb_number, + "city_name": self.city_name, + "default_city_name": self.default_city_name, + "state_abbreviation": self.state_abbreviation, + "zipcode": self.zipcode, + "plus4_code": self.plus4_code, + "delivery_point": self.delivery_point, + "delivery_point_check_digit": self.delivery_point_check_digit + } + return {k: v for k, v in result.items() if v is not None} diff --git a/smarty/smartystreets_python_sdk/us_street/lookup.py b/smarty/smartystreets_python_sdk/us_street/lookup.py index db75358..275d5c8 100644 --- a/smarty/smartystreets_python_sdk/us_street/lookup.py +++ b/smarty/smartystreets_python_sdk/us_street/lookup.py @@ -1,15 +1,20 @@ +from smartystreets_python_sdk.us_street.match_type import MatchType +from smartystreets_python_sdk.us_street.output_format import OutputFormat +import json + + class Lookup: def __init__(self, street=None, street2=None, secondary=None, city=None, state=None, zipcode=None, lastline=None, - addressee=None, urbanization=None, match=None, candidates=1, input_id=None): + addressee=None, urbanization=None, match=None, candidates=0, input_id=None, + outputformat=OutputFormat.DEFAULT, county_source=None): """ - In addition to holding all of the input data for this lookup, this class also will contain - the result of the lookup after it comes back from the API. + In addition to holding all input data for this lookup, this class also will contain the result + of the lookup after it comes back from the API. See "https://smartystreets.com/docs/cloud/us-street-api#input-fields" - - :param match: Must be set to 'strict', 'enhanced', or 'invalid'. Constants for these are in match_type.py """ self.result = [] + self.custom_parameter_array = {} self.input_id = input_id self.street = street self.street2 = street2 @@ -22,3 +27,32 @@ def __init__(self, street=None, street2=None, secondary=None, city=None, state=N self.urbanization = urbanization self.match = match self.candidates = candidates + self.outputformat = outputformat + self.county_source = county_source + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value + + def to_dict(self): + result = { + "input_id": self.input_id, + "street": self.street, + "street2": self.street2, + "secondary": self.secondary, + "city": self.city, + "state": self.state, + "zipcode": self.zipcode, + "lastline": self.lastline, + "addressee": self.addressee, + "urbanization": self.urbanization, + "match": self.match, + "candidates": self.candidates, + "outputformat": self.outputformat, + "county_source": self.county_source, + "result": [candidate.to_dict() for candidate in self.result], + "custom_parameter_array": self.custom_parameter_array + } + return {k: v for k, v in result.items() if v is not None} + + def to_json(self): + return json.dumps(self.to_dict()) \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_street/match_info.py b/smarty/smartystreets_python_sdk/us_street/match_info.py new file mode 100644 index 0000000..910770c --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_street/match_info.py @@ -0,0 +1,14 @@ +class MatchInfo: + def __init__(self, obj): + """ + Holds matching status and change information for an address component. + """ + self.status = obj.get('status', None) + self.change = obj.get('change', None) + + def to_dict(self): + result = { + "status": self.status, + "change": self.change + } + return {k: v for k, v in result.items() if v is not None} \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_street/match_type.py b/smarty/smartystreets_python_sdk/us_street/match_type.py index 299f4c4..740a93e 100644 --- a/smarty/smartystreets_python_sdk/us_street/match_type.py +++ b/smarty/smartystreets_python_sdk/us_street/match_type.py @@ -1,7 +1,7 @@ -STRICT = 'strict' +from enum import Enum -RANGE = 'range' # Deprecated -INVALID = 'invalid' - -ENHANCED = 'enhanced' +class MatchType(str, Enum): + STRICT = "strict" + INVALID = "invalid" + ENHANCED = "enhanced" diff --git a/smarty/smartystreets_python_sdk/us_street/metadata.py b/smarty/smartystreets_python_sdk/us_street/metadata.py index 4958a3d..ebf04fd 100644 --- a/smarty/smartystreets_python_sdk/us_street/metadata.py +++ b/smarty/smartystreets_python_sdk/us_street/metadata.py @@ -15,8 +15,35 @@ def __init__(self, obj): self.elot_sort = obj.get('elot_sort', None) self.latitude = obj.get('latitude', None) self.longitude = obj.get('longitude', None) + self.coordinate_license = obj.get('coordinate_license', None) self.precision = obj.get('precision', None) self.time_zone = obj.get('time_zone', None) self.utc_offset = obj.get('utc_offset', None) self.obeys_dst = obj.get('dst', None) + self.iana_time_zone = obj.get('iana_time_zone', None) + self.iana_utc_offset = obj.get('iana_utc_offset', None) + self.iana_obeys_dst = obj.get('iana_dst', None) self.is_ews_match = obj.get('ews_match', None) + + def to_dict(self): + result = { + "record_type": self.record_type, + "zip_type": self.zip_type, + "county_fips": self.county_fips, + "county_name": self.county_name, + "carrier_route": self.carrier_route, + "congressional_district": self.congressional_district, + "building_default_indicator": self.building_default_indicator, + "rdi": self.rdi, + "elot_sequence": self.elot_sequence, + "elot_sort": self.elot_sort, + "latitude": self.latitude, + "longitude": self.longitude, + "coordinate_license": self.coordinate_license, + "precision": self.precision, + "time_zone": self.time_zone, + "utc_offset": self.utc_offset, + "dst": self.obeys_dst, + "ews_match": self.is_ews_match + } + return {k: v for k, v in result.items() if v is not None} \ No newline at end of file diff --git a/smarty/smartystreets_python_sdk/us_street/output_format.py b/smarty/smartystreets_python_sdk/us_street/output_format.py new file mode 100644 index 0000000..0c9d985 --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_street/output_format.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class OutputFormat(str, Enum): + DEFAULT = "default" + PROJECT_USA = "project-usa" diff --git a/smarty/smartystreets_python_sdk/us_zipcode/client.py b/smarty/smartystreets_python_sdk/us_zipcode/client.py index d211348..dd76667 100644 --- a/smarty/smartystreets_python_sdk/us_zipcode/client.py +++ b/smarty/smartystreets_python_sdk/us_zipcode/client.py @@ -1,5 +1,5 @@ -# from . import Result -from .. import Request, Batch +from smartystreets_python_sdk.us_zipcode import Result +from smartystreets_python_sdk import Request, Batch class Client: @@ -61,6 +61,9 @@ def remap_keys(obj): add_field(converted_lookup, 'state', lookup.state) add_field(converted_lookup, 'zipcode', lookup.zipcode) + for parameter in lookup.custom_parameter_array: + add_field(converted_lookup, parameter, lookup.custom_parameter_array[parameter]) + converted_obj.append(converted_lookup) return converted_obj diff --git a/smarty/smartystreets_python_sdk/us_zipcode/lookup.py b/smarty/smartystreets_python_sdk/us_zipcode/lookup.py index eebf35d..3be94da 100644 --- a/smarty/smartystreets_python_sdk/us_zipcode/lookup.py +++ b/smarty/smartystreets_python_sdk/us_zipcode/lookup.py @@ -7,7 +7,11 @@ def __init__(self, city=None, state=None, zipcode=None, input_id=None): See "https://smartystreets.com/docs/cloud/us-zipcode-api#http-request-input-fields" """ self.result = None + self.custom_parameter_array = {} self.input_id = input_id self.city = city self.state = state self.zipcode = zipcode + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value diff --git a/smarty/smartystreets_python_sdk/us_zipcode/result.py b/smarty/smartystreets_python_sdk/us_zipcode/result.py index 262fdec..97562d2 100644 --- a/smarty/smartystreets_python_sdk/us_zipcode/result.py +++ b/smarty/smartystreets_python_sdk/us_zipcode/result.py @@ -1,4 +1,4 @@ -# from . import City, ZipCode +from smartystreets_python_sdk.us_zipcode import City, ZipCode class Result: diff --git a/smarty/smartystreets_python_sdk/us_zipcode/zipcode.py b/smarty/smartystreets_python_sdk/us_zipcode/zipcode.py index 1d46727..c08f239 100644 --- a/smarty/smartystreets_python_sdk/us_zipcode/zipcode.py +++ b/smarty/smartystreets_python_sdk/us_zipcode/zipcode.py @@ -1,4 +1,4 @@ -# from .alternate_county import AlternateCounty +from .alternate_county import AlternateCounty class ZipCode: diff --git a/smarty/smartystreets_python_sdk_version/__init__.py b/smarty/smartystreets_python_sdk_version/__init__.py index 2a0a377..2e081a2 100644 --- a/smarty/smartystreets_python_sdk_version/__init__.py +++ b/smarty/smartystreets_python_sdk_version/__init__.py @@ -1,2 +1,2 @@ __version__ = '0.0.0' # DO NOT EDIT (this is updated by a build job when a new release is published) -__version__="4.10.10" +__version__="5.7.0" diff --git a/vendor.sh b/vendor.sh new file mode 100755 index 0000000..634ba2a --- /dev/null +++ b/vendor.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Updates the vendored Smarty SDK inside the plugin directory. +# Usage: ./vendor.sh +# After running, commit the updated smartystreets_python_sdk* directories. +set -euo pipefail + +PLUGIN_DIR="smarty" + +# Remove old vendored SDK artifacts +rm -rf "$PLUGIN_DIR/smartystreets_python_sdk" +rm -rf "$PLUGIN_DIR/smartystreets_python_sdk_version" +rm -rf "$PLUGIN_DIR"/smartystreets_python_sdk-*.dist-info + +# Install SDK without transitive deps — requests is bundled with QGIS's Python +pip install -r requirements.txt --target "$PLUGIN_DIR" --no-deps --upgrade + +# Remove bytecode cache that pip may have left behind +find "$PLUGIN_DIR" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true +find "$PLUGIN_DIR" -name "*.pyc" -delete 2>/dev/null || true + +echo "Done. Commit the updated smartystreets_python_sdk* directories." From a8d55f352673f5d6b4e617848b26cd847713abab Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 23 Apr 2026 11:55:07 -0600 Subject: [PATCH 02/11] Updated sdk imports and removed licenses requirements. --- smarty/Makefile | 6 +++++- smarty/smarty.py | 15 +++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/smarty/Makefile b/smarty/Makefile index 75f9f34..2cc9d47 100644 --- a/smarty/Makefile +++ b/smarty/Makefile @@ -77,7 +77,7 @@ PLUGIN_UPLOAD = $(c)/plugin_upload.py RESOURCE_SRC=$(shell grep '^ *@@g;s/.*>//g' | tr '\n' ' ') -.PHONY: default vendor +.PHONY: default vendor check default: @echo While you can use make to build and deploy your plugin, pb_tool @echo is a much better solution. @@ -89,6 +89,10 @@ default: vendor: cd .. && ./vendor.sh +check: + python3 -m py_compile __init__.py smarty.py smarty_dialog.py utils.py + python3 -c "import sys; sys.path.insert(0, '.'); import smartystreets_python_sdk; from smartystreets_python_sdk import StaticCredentials, exceptions, ClientBuilder, SharedCredentials, Batch, Request; from smartystreets_python_sdk.us_street import Lookup; from smartystreets_python_sdk.us_autocomplete_pro import Lookup; print('OK')" + compile: $(COMPILED_RESOURCE_FILES) %.py : %.qrc $(RESOURCES_SRC) diff --git a/smarty/smarty.py b/smarty/smarty.py index 644c3bd..752e4d4 100644 --- a/smarty/smarty.py +++ b/smarty/smarty.py @@ -35,10 +35,9 @@ ######### import pip -# import smartystreets_python_sdk -from .smartystreets_python_sdk import StaticCredentials, exceptions, ClientBuilder, SharedCredentials, StaticCredentials, Batch, Request -from .smartystreets_python_sdk.us_street import Lookup as StreetLookup -from .smartystreets_python_sdk.us_autocomplete_pro import Lookup as AutocompleteProLookup, geolocation_type +from smartystreets_python_sdk import StaticCredentials, exceptions, ClientBuilder, SharedCredentials, Batch, Request +from smartystreets_python_sdk.us_street import Lookup as StreetLookup +from smartystreets_python_sdk.us_autocomplete_pro import Lookup as AutocompleteProLookup ######### # Initialize Qt resources from file resources.py @@ -269,7 +268,7 @@ def smarty_single(self): request = Request() credentials.sign(request) # 20250829 - change license from us-rooftop-geo to a license supported by the demo plan - client = ClientBuilder(credentials).with_licenses(["us-rooftop-geocoding-cloud"]).build_us_street_api_client() + client = ClientBuilder(credentials).build_us_street_api_client() lookup = StreetLookup() lookup.match = "enhanced" @@ -490,7 +489,7 @@ def smarty_batch(self): auth_id = self.dlg.auth_id.text() auth_token = self.dlg.auth_token.text() credentials = StaticCredentials(auth_id, auth_token) - client = ClientBuilder(credentials).with_licenses(["us-rooftop-geocoding-custom-enterprise-cloud,us-rooftop-geocoding-cloud,us-rooftop-geocoding-enterprise-cloud"]).build_us_street_api_client() + client = ClientBuilder(credentials).build_us_street_api_client() batch = Batch() counter = 0 @@ -694,7 +693,7 @@ def add_tokens(self): return # Set up credentials for an initial lookup credentials = StaticCredentials(self.dlg.auth_id.text() , self.dlg.auth_token.text()) - client = ClientBuilder(credentials).with_licenses(["us-rooftop-geocoding-custom-enterprise-cloud,us-rooftop-geocoding-cloud,us-rooftop-geocoding-enterprise-cloud"]).build_us_street_api_client() + client = ClientBuilder(credentials).build_us_street_api_client() lookup = StreetLookup() lookup.street = "484 W Bulldog Blvd, Provo, UT 84604" # Send one lookup to make sure they are authorized to use send batches to Smarty API @@ -852,7 +851,7 @@ def autocomplete(self): hostname = 'qgis_smarty' # secret key token --> secret_key_token credentials = SharedCredentials(key, hostname) - client = ClientBuilder(credentials).with_licenses(["us-autocomplete-pro-cloud"]).build_us_autocomplete_pro_api_client() + client = ClientBuilder(credentials).build_us_autocomplete_pro_api_client() text = self.dlg.single_address_lookup.text() # Send an API autocomplete call if user adds text From 99bdfa6afc4737a58e93eb08a3291697cc3642a6 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 23 Apr 2026 14:38:28 -0600 Subject: [PATCH 03/11] Added Smarty Key and Smarty Key EXT. --- smarty/smarty.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/smarty/smarty.py b/smarty/smarty.py index 752e4d4..15b46a3 100644 --- a/smarty/smarty.py +++ b/smarty/smarty.py @@ -267,8 +267,7 @@ def smarty_single(self): credentials = SharedCredentials(key, hostname) request = Request() credentials.sign(request) - # 20250829 - change license from us-rooftop-geo to a license supported by the demo plan - client = ClientBuilder(credentials).build_us_street_api_client() + client = ClientBuilder(credentials).with_custom_header({'User-Agent': 'qgis-demo'}).build_us_street_api_client() lookup = StreetLookup() lookup.match = "enhanced" @@ -478,18 +477,18 @@ def smarty_batch(self): project = QgsProject.instance() # Create new VectorLayer to output results on if self.dlg.layer_name_batch.text() == '': - layer_out = QgsVectorLayer("Point?crs=EPSG:4326&field=id:string&field=address:string&field=longitude:string&field=latitude:string&field=city:string&field=state:string&field=zip_code:string&field=zip_4:string&field=precision:string&field=county:string&field=county_fips:string&field=rdi:string&field=cong_dist:string&field=time_zone:string&field=dst:string&field=label:string&field=summary:string&field=i_address:string&field=i_city:string&field=i_state:string&field=i_zip:string", + layer_out = QgsVectorLayer("Point?crs=EPSG:4326&field=id:string&field=address:string&field=longitude:string&field=latitude:string&field=city:string&field=state:string&field=zip_code:string&field=zip_4:string&field=precision:string&field=county:string&field=county_fips:string&field=rdi:string&field=cong_dist:string&field=time_zone:string&field=dst:string&field=label:string&field=summary:string&field=i_address:string&field=i_city:string&field=i_state:string&field=i_zip:string&field=smarty_key:string&field=smarty_key_ext:string", 'Smarty', "memory") else: - layer_out = QgsVectorLayer("Point?crs=EPSG:4326&field=id:string&field=address:string&field=longitude:string&field=latitude:string&field=city:string&field=state:string&field=zip_code:string&field=zip_4:string&field=precision:string&field=county:string&field=county_fips:string&field=rdi:string&field=cong_dist:string&field=time_zone:string&field=dst:string&field=label:string&field=summary:string&field=i_address:string&field=i_city:string&field=i_state:string&field=i_zip:string", + layer_out = QgsVectorLayer("Point?crs=EPSG:4326&field=id:string&field=address:string&field=longitude:string&field=latitude:string&field=city:string&field=state:string&field=zip_code:string&field=zip_4:string&field=precision:string&field=county:string&field=county_fips:string&field=rdi:string&field=cong_dist:string&field=time_zone:string&field=dst:string&field=label:string&field=summary:string&field=i_address:string&field=i_city:string&field=i_state:string&field=i_zip:string&field=smarty_key:string&field=smarty_key_ext:string", self.dlg.layer_name_batch.text(), "memory") # Set up credentials and Batch auth_id = self.dlg.auth_id.text() auth_token = self.dlg.auth_token.text() credentials = StaticCredentials(auth_id, auth_token) - client = ClientBuilder(credentials).build_us_street_api_client() + client = ClientBuilder(credentials).with_custom_header({'User-Agent': 'qgis'}).build_us_street_api_client() batch = Batch() counter = 0 @@ -599,7 +598,7 @@ def process_batch(self, batch_meta, id_column_name, address, city, state, zip, l if len(candidates) == 0: self.iface.messageBar().pushMessage('No Match for given address: ' + i_address + ' ' + i_city + ' ' + i_state, duration=6, level=Qgis.Critical) feature.setAttributes([lookup_id, i_address, '', '', i_city, i_state, i_zip, '', '', '', - '', '', '', '', '', label, 'No Match', i_address, i_city, i_state, i_zip]) + '', '', '', '', '', label, 'No Match', i_address, i_city, i_state, i_zip, '', '']) invalid_lookup_occured = True else: # Get all the information from this lookup's top candidate @@ -618,6 +617,8 @@ def process_batch(self, batch_meta, id_column_name, address, city, state, zip, l cong_dist = candidate.metadata.congressional_district time_zone = candidate.metadata.time_zone dst = candidate.metadata.obeys_dst + smarty_key = candidate.smarty_key + smarty_key_ext = candidate.smarty_key_ext if longitude is None or latitude is None: longitude = 0 @@ -632,7 +633,7 @@ def process_batch(self, batch_meta, id_column_name, address, city, state, zip, l # Set attributes for associated layer feature.setAttributes([lookup_id, address_result, longitude, latitude, city_result, state_result, zip_result, zip_4, precision, county, - county_fips, rdi, cong_dist, time_zone, dst, label, success, i_address, i_city, i_state, i_zip]) + county_fips, rdi, cong_dist, time_zone, dst, label, success, i_address, i_city, i_state, i_zip, smarty_key, smarty_key_ext]) # Set symbol features symbol = self.set_symbol(self.dlg.symbol_color.color(), self.dlg.symbol_drop_down.currentText(), self.dlg.symbol_size_batch.value()) From e5ae25993eb810bb1cc41694447ab54b18fad40f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 5 May 2026 11:47:26 -0600 Subject: [PATCH 04/11] Updated summary field. --- smarty/Makefile | 8 +++ smarty/smarty.py | 25 ++++---- smarty/summary-0.1.1.dist-info/INSTALLER | 1 + smarty/summary-0.1.1.dist-info/METADATA | 4 ++ smarty/summary-0.1.1.dist-info/RECORD | 8 +++ smarty/summary-0.1.1.dist-info/REQUESTED | 0 smarty/summary-0.1.1.dist-info/WHEEL | 4 ++ .../summary-0.1.1.dist-info/direct_url.json | 1 + smarty/summary/__init__.py | 63 +++++++++++++++++++ 9 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 smarty/summary-0.1.1.dist-info/INSTALLER create mode 100644 smarty/summary-0.1.1.dist-info/METADATA create mode 100644 smarty/summary-0.1.1.dist-info/RECORD create mode 100644 smarty/summary-0.1.1.dist-info/REQUESTED create mode 100644 smarty/summary-0.1.1.dist-info/WHEEL create mode 100644 smarty/summary-0.1.1.dist-info/direct_url.json create mode 100644 smarty/summary/__init__.py diff --git a/smarty/Makefile b/smarty/Makefile index 2cc9d47..d022c3c 100644 --- a/smarty/Makefile +++ b/smarty/Makefile @@ -77,6 +77,9 @@ PLUGIN_UPLOAD = $(c)/plugin_upload.py RESOURCE_SRC=$(shell grep '^ *@@g;s/.*>//g' | tr '\n' ' ') +PLUGIN_DIR = $(HOME)/Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins/$(notdir $(CURDIR)) + + .PHONY: default vendor check default: @echo While you can use make to build and deploy your plugin, pb_tool @@ -86,12 +89,17 @@ default: @echo You can install pb_tool using: pip install pb_tool @echo See https://g-sherman.github.io/plugin_build_tool/ for info. +install: + mkdir -p "$(PLUGIN_DIR)" + cp -r . "$(PLUGIN_DIR)" + vendor: cd .. && ./vendor.sh check: python3 -m py_compile __init__.py smarty.py smarty_dialog.py utils.py python3 -c "import sys; sys.path.insert(0, '.'); import smartystreets_python_sdk; from smartystreets_python_sdk import StaticCredentials, exceptions, ClientBuilder, SharedCredentials, Batch, Request; from smartystreets_python_sdk.us_street import Lookup; from smartystreets_python_sdk.us_autocomplete_pro import Lookup; print('OK')" + python3 -c "import sys; sys.path.insert(0, '.'); import summary; print('OK')" compile: $(COMPILED_RESOURCE_FILES) diff --git a/smarty/smarty.py b/smarty/smarty.py index 15b46a3..f75427f 100644 --- a/smarty/smarty.py +++ b/smarty/smarty.py @@ -35,6 +35,7 @@ ######### import pip +from summary import summary from smartystreets_python_sdk import StaticCredentials, exceptions, ClientBuilder, SharedCredentials, Batch, Request from smartystreets_python_sdk.us_street import Lookup as StreetLookup from smartystreets_python_sdk.us_autocomplete_pro import Lookup as AutocompleteProLookup @@ -351,8 +352,8 @@ def smarty_single(self): self.dlg.dst_result.setText(str(dst)) # Check if the candidate returned is good to plot. - success = Utils.handle_success(result) - if success == "No Match - The address is invalid.": + success = self.handle_success(result) + if success == "No Match": self.dlg.resize(586, 532) self.dlg.results.setVisible(True) self.dlg.summary_result.setText(success) @@ -629,7 +630,7 @@ def process_batch(self, batch_meta, id_column_name, address, city, state, zip, l feature.setGeometry(QgsGeometry.fromPointXY(point_out)) # Handle success of address lookup - success = Utils.handle_success(candidates) + success = self.handle_success(candidates) # Set attributes for associated layer feature.setAttributes([lookup_id, address_result, longitude, latitude, city_result, state_result, zip_result, zip_4, precision, county, @@ -1023,15 +1024,15 @@ def autocomplete_state(self): self.dlg.single_address_lookup.setCompleter(None) def handle_success(self, result): # Handle and determine the success of the API request - if Utils.is_valid(result): - return "valid_address" - if Utils.is_invalid(result): - return "invalid_address" - if Utils.is_missing_secondary(result): - return "missing_secondary" - if Utils.is_ambiguous(result): - return "ambiguous_address" - return "MAJOR ERROR" + enhanced_match = "" + dpv_match_code = "" + dpv_footnotes = "" + if len(result) > 0: + candidate = result[0] + enhanced_match = candidate.analysis.enhanced_match + dpv_match_code = candidate.analysis.dpv_match_code + dpv_footnotes = candidate.analysis.dpv_footnotes + return summary(enhanced_match, dpv_match_code, dpv_footnotes) def output_csv(self, layer_out): # Throw error if the file path has not been chosen diff --git a/smarty/summary-0.1.1.dist-info/INSTALLER b/smarty/summary-0.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/smarty/summary-0.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/smarty/summary-0.1.1.dist-info/METADATA b/smarty/summary-0.1.1.dist-info/METADATA new file mode 100644 index 0000000..6e5a157 --- /dev/null +++ b/smarty/summary-0.1.1.dist-info/METADATA @@ -0,0 +1,4 @@ +Metadata-Version: 2.4 +Name: summary +Version: 0.1.1 +Requires-Python: >=3.11 diff --git a/smarty/summary-0.1.1.dist-info/RECORD b/smarty/summary-0.1.1.dist-info/RECORD new file mode 100644 index 0000000..36de590 --- /dev/null +++ b/smarty/summary-0.1.1.dist-info/RECORD @@ -0,0 +1,8 @@ +summary-0.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +summary-0.1.1.dist-info/METADATA,sha256=9Mg5Wfqx8ZZKN1ocbOMHLVFHjkI57VEikL72_CLCcoQ,75 +summary-0.1.1.dist-info/RECORD,, +summary-0.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +summary-0.1.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87 +summary-0.1.1.dist-info/direct_url.json,sha256=-_e93onMQmX3iyacTS6794Bza66tlpi-I43yiuo28ng,135 +summary/__init__.py,sha256=tjJJeQWDZxdkveUm75SzDW2MJKglFZw9GutEbBqwE5Y,2079 +summary/__pycache__/__init__.cpython-311.pyc,, diff --git a/smarty/summary-0.1.1.dist-info/REQUESTED b/smarty/summary-0.1.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/smarty/summary-0.1.1.dist-info/WHEEL b/smarty/summary-0.1.1.dist-info/WHEEL new file mode 100644 index 0000000..b1b94fd --- /dev/null +++ b/smarty/summary-0.1.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.29.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/smarty/summary-0.1.1.dist-info/direct_url.json b/smarty/summary-0.1.1.dist-info/direct_url.json new file mode 100644 index 0000000..16c4f22 --- /dev/null +++ b/smarty/summary-0.1.1.dist-info/direct_url.json @@ -0,0 +1 @@ +{"url": "ssh://git@github.com/smarty/summary.git", "vcs_info": {"commit_id": "44aa0e7384920dcf2610c70162c287acc2754044", "vcs": "git"}} \ No newline at end of file diff --git a/smarty/summary/__init__.py b/smarty/summary/__init__.py new file mode 100644 index 0000000..433fb78 --- /dev/null +++ b/smarty/summary/__init__.py @@ -0,0 +1,63 @@ +MESSAGE_MATCH = 'Match' +MESSAGE_MATCH_WITH_EXCEPTION = 'Match With Exceptions' +MESSAGE_NO_MATCH = 'No Match' + +ENHANCED_NO_MATCH = 'none' +ENHANCED_POSTAL_MATCH = 'postal-match' +ENHANCED_NON_POSTAL_MATCH = 'non-postal-match' +ENHANCED_MISSING_SECONDARY = 'missing-secondary' +ENHANCED_UNKNOWN_SECONDARY = 'unknown-secondary' +ENHANCED_IGNORED_INPUT = 'ignored-input' + +DPV_MILITARY_MATCH = 'F1' +DPV_BOX_NUMBER_MISSING = 'P1' +DPV_CONFIRMED_PMB = 'RR' +DPV_CONFIRMED_WITHOUT_PMB = 'R1' +DPV_PHANTOM_CARRIER_ROUTE = 'R7' +DPV_UNIQUE_ZIP_CODE = 'U1' +DPV_TRAILING_ALPHA = 'TA' + +_dpv_exception_set = { + DPV_MILITARY_MATCH, + DPV_BOX_NUMBER_MISSING, + DPV_CONFIRMED_PMB, + DPV_CONFIRMED_WITHOUT_PMB, + DPV_PHANTOM_CARRIER_ROUTE, + DPV_UNIQUE_ZIP_CODE, + DPV_TRAILING_ALPHA, +} + + +def _has_dpv_footnote_exceptions(dpv_footnotes: str) -> bool: + if dpv_footnotes is None: + return False + return any(dpv_footnotes[i:i+2] in _dpv_exception_set for i in range(0, len(dpv_footnotes) - 1, 2)) + + +def _enhanced_match_summary(enhanced_match: str, dpv_footnotes: str) -> str: + is_postal_match = False + has_enhanced_exception = False + for val in enhanced_match.split(','): + if val in (ENHANCED_POSTAL_MATCH, ENHANCED_NON_POSTAL_MATCH): + is_postal_match = True + elif val in (ENHANCED_MISSING_SECONDARY, ENHANCED_UNKNOWN_SECONDARY, ENHANCED_IGNORED_INPUT): + has_enhanced_exception = True + if not is_postal_match: + return MESSAGE_NO_MATCH + if has_enhanced_exception or _has_dpv_footnote_exceptions(dpv_footnotes): + return MESSAGE_MATCH_WITH_EXCEPTION + return MESSAGE_MATCH + + +def _dpv_match_code_summary(dpv_match_code: str, dpv_footnotes: str) -> str: + if dpv_match_code == 'Y': + return MESSAGE_MATCH_WITH_EXCEPTION if _has_dpv_footnote_exceptions(dpv_footnotes) else MESSAGE_MATCH + if dpv_match_code in ('S', 'D'): + return MESSAGE_MATCH_WITH_EXCEPTION + return MESSAGE_NO_MATCH + + +def summary(enhanced_match: str, dpv_match_code: str, dpv_footnotes: str) -> str: + if enhanced_match: + return _enhanced_match_summary(enhanced_match, dpv_footnotes) + return _dpv_match_code_summary(dpv_match_code, dpv_footnotes) From 352c6f699ab035b38a27aaef4515389e76efeb78 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 5 May 2026 11:48:18 -0600 Subject: [PATCH 05/11] Updated vendor script and requirements. --- requirements.txt | 1 + vendor.sh | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index e4eb672..8b485c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ smartystreets-python-sdk==5.7.0 +git+ssh://git@github.com/smarty/summary.git diff --git a/vendor.sh b/vendor.sh index 634ba2a..a97e456 100755 --- a/vendor.sh +++ b/vendor.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -# Updates the vendored Smarty SDK inside the plugin directory. +# Updates the vendored Smarty SDK and summary library inside the plugin directory. # Usage: ./vendor.sh -# After running, commit the updated smartystreets_python_sdk* directories. +# After running, commit the updated vendored directories. set -euo pipefail PLUGIN_DIR="smarty" @@ -11,11 +11,15 @@ rm -rf "$PLUGIN_DIR/smartystreets_python_sdk" rm -rf "$PLUGIN_DIR/smartystreets_python_sdk_version" rm -rf "$PLUGIN_DIR"/smartystreets_python_sdk-*.dist-info -# Install SDK without transitive deps — requests is bundled with QGIS's Python +# Remove old vendored summary artifacts +rm -rf "$PLUGIN_DIR/summary" +rm -rf "$PLUGIN_DIR"/summary-*.dist-info + +# Install libraries without transitive deps — requests is bundled with QGIS's Python pip install -r requirements.txt --target "$PLUGIN_DIR" --no-deps --upgrade # Remove bytecode cache that pip may have left behind find "$PLUGIN_DIR" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true find "$PLUGIN_DIR" -name "*.pyc" -delete 2>/dev/null || true -echo "Done. Commit the updated smartystreets_python_sdk* directories." +echo "Done. Commit the updated vendored directories." From df93ace591528aa06cd4d4708884556ac2e1c93f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 5 May 2026 16:16:56 -0600 Subject: [PATCH 06/11] Updated the version of the python sdk and summary library. --- .../INSTALLER | 0 .../METADATA | 4 +- .../RECORD | 42 ++-- .../REQUESTED | 0 .../WHEEL | 0 .../licenses/LICENSE.md | 0 .../top_level.txt | 0 .../custom_header_sender.py | 18 +- smarty/smartystreets_python_sdk/errors.py | 2 + smarty/smartystreets_python_sdk/exceptions.py | 6 + smarty/smartystreets_python_sdk/request.py | 1 + .../requests_sender.py | 3 + smarty/smartystreets_python_sdk/response.py | 9 + .../status_code_sender.py | 8 +- .../us_enrichment/__init__.py | 14 +- .../us_enrichment/business/__init__.py | 2 + .../us_enrichment/business/detail.py | 206 ++++++++++++++++++ .../us_enrichment/business/summary.py | 15 ++ .../us_enrichment/client.py | 188 ++++++++++------ .../us_enrichment/lookup.py | 68 ++++-- .../__init__.py | 2 +- smarty/summary-0.1.1.dist-info/RECORD | 2 +- .../summary-0.1.1.dist-info/direct_url.json | 2 +- 23 files changed, 459 insertions(+), 133 deletions(-) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/INSTALLER (100%) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/METADATA (96%) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/RECORD (85%) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/REQUESTED (100%) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/WHEEL (100%) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/licenses/LICENSE.md (100%) rename smarty/{smartystreets_python_sdk-5.7.0.dist-info => smartystreets_python_sdk-6.1.0.dist-info}/top_level.txt (100%) create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/business/__init__.py create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/business/detail.py create mode 100644 smarty/smartystreets_python_sdk/us_enrichment/business/summary.py diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/INSTALLER b/smarty/smartystreets_python_sdk-6.1.0.dist-info/INSTALLER similarity index 100% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/INSTALLER rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/INSTALLER diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/METADATA b/smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA similarity index 96% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/METADATA rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA index 2644bfe..71411a2 100644 --- a/smarty/smartystreets_python_sdk-5.7.0.dist-info/METADATA +++ b/smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA @@ -1,9 +1,9 @@ Metadata-Version: 2.4 Name: smartystreets_python_sdk -Version: 5.7.0 +Version: 6.1.0 Summary: An official library to help Python developers easily access the SmartyStreets APIs Home-page: https://github.com/smartystreets/smartystreets-python-sdk -Download-URL: https://github.com/smartystreets/smartystreets-python-sdk/tarball/5.7.0 +Download-URL: https://github.com/smartystreets/smartystreets-python-sdk/tarball/6.1.0 Author: SmartyStreets SDK Team Author-email: support@smartystreets.com License: Apache 2 diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD b/smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD similarity index 85% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD index 882ad3f..b436510 100644 --- a/smarty/smartystreets_python_sdk-5.7.0.dist-info/RECORD +++ b/smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD @@ -1,10 +1,10 @@ -smartystreets_python_sdk-5.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -smartystreets_python_sdk-5.7.0.dist-info/METADATA,sha256=9o091ZFO6l87lmmH0z4OO7EgWlOdDtJI8i2mya2Ctg0,1054 -smartystreets_python_sdk-5.7.0.dist-info/RECORD,, -smartystreets_python_sdk-5.7.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -smartystreets_python_sdk-5.7.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91 -smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md,sha256=Cu67SvL5YQlDIEaH0UOH2rlm4LIPiCfdO4hlAACCWl4,11332 -smartystreets_python_sdk-5.7.0.dist-info/top_level.txt,sha256=uPitCujTcHdnUQwzTZKMfb1GoYxgM5Evyq_CJrhfVnU,58 +smartystreets_python_sdk-6.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +smartystreets_python_sdk-6.1.0.dist-info/METADATA,sha256=uD3h0K_qRovZB3QfTfCstRPIoa8hC6HbkqCHxp2uHHc,1054 +smartystreets_python_sdk-6.1.0.dist-info/RECORD,, +smartystreets_python_sdk-6.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +smartystreets_python_sdk-6.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91 +smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md,sha256=Cu67SvL5YQlDIEaH0UOH2rlm4LIPiCfdO4hlAACCWl4,11332 +smartystreets_python_sdk-6.1.0.dist-info/top_level.txt,sha256=uPitCujTcHdnUQwzTZKMfb1GoYxgM5Evyq_CJrhfVnU,58 smartystreets_python_sdk/__init__.py,sha256=cJpR9L-R1gDD7b4-L3QJltQOacFe8Sdom586X3feFJo,805 smartystreets_python_sdk/__pycache__/__init__.cpython-311.pyc,, smartystreets_python_sdk/__pycache__/basic_auth_credentials.cpython-311.pyc,, @@ -29,10 +29,10 @@ smartystreets_python_sdk/__pycache__/url_prefix_sender.cpython-311.pyc,, smartystreets_python_sdk/basic_auth_credentials.py,sha256=-9vCG8z0Mr8GR-7Zl8UuXWbfzposXc9aIRa1Ynjz2Ek,401 smartystreets_python_sdk/batch.py,sha256=FafhYEGpTbHIb6oGkBozblsf00PNfMQsCVT_EY0c-aw,1371 smartystreets_python_sdk/client_builder.py,sha256=g-hhGVT9xSzFEZnkApabmITcpJe8K0I8ZXLQnZ5047A,12787 -smartystreets_python_sdk/custom_header_sender.py,sha256=fH0b1_fvxa1q5dePM3Wa8QQBwpeJhnjPvBz4ydVv9yU,1166 +smartystreets_python_sdk/custom_header_sender.py,sha256=qmTUM7afM5mBGGocuzr1THbB5f7F5NMNr5dgycuHMco,795 smartystreets_python_sdk/custom_query_sender.py,sha256=q238mqAOh3nK26HS5mHUmeucT3_ki6ue5PFJtOAcTMw,364 -smartystreets_python_sdk/errors.py,sha256=aJz6de55P4IJQkaVmz4EApywhEjsVV0lP1yKzoRRqos,1091 -smartystreets_python_sdk/exceptions.py,sha256=8hel1fr7kYHOL3DSUCL06RwKNJf-DQgxqc8NFTyYZKg,652 +smartystreets_python_sdk/errors.py,sha256=DTnAmoxVG1uSCFsmzkknzVqzXyOHqYx28eXkdbUw28k,1214 +smartystreets_python_sdk/exceptions.py,sha256=TFnXjje1TPwfZ4S0L1l0gQqejEzy5FQVTfBCwGNYkvs,830 smartystreets_python_sdk/international_autocomplete/__init__.py,sha256=zmHkBQ4bBdQRXgA98Luey4xGgAOYUD0j8_nMcz-1kDw,87 smartystreets_python_sdk/international_autocomplete/__pycache__/__init__.cpython-311.pyc,, smartystreets_python_sdk/international_autocomplete/__pycache__/candidate.cpython-311.pyc,, @@ -72,14 +72,14 @@ smartystreets_python_sdk/international_street/rootlevel.py,sha256=ZeErBuBhNkgD7- smartystreets_python_sdk/license_sender.py,sha256=hAPSejluaFcAjhG2B5nt910Q474hnbtMnbb2FPUXi3c,313 smartystreets_python_sdk/native_serializer.py,sha256=QpN2-woD1Muu3bzr-LVzF4n3l-0Ae2OtynVCW4YxoIc,225 smartystreets_python_sdk/proxy.py,sha256=2asS-F-v_rikgPQvVJh10oI5Wp8ezprS1E10tZUFKXc,506 -smartystreets_python_sdk/request.py,sha256=YbgBBmJuAKpcDAfeskk8BkSe_5EUuO8W3pPvI-LJ0cg,311 -smartystreets_python_sdk/requests_sender.py,sha256=x3Ltx2ykmZVHOwdvO39SFqKI61dMiS0zwhqWbuJ0LuQ,3253 -smartystreets_python_sdk/response.py,sha256=0lh6bn471YekUSVKOPKvK3sQy-6dFc3Qw9F2729nOlM,361 +smartystreets_python_sdk/request.py,sha256=mEXPJKPJQqAWs4iNZ1HqVL8UhAB37HollVniYPPpvuw,337 +smartystreets_python_sdk/requests_sender.py,sha256=veejQiYR2vwyhbVz8n21gzXFmaKx7wFdSAInwJF4YP4,3395 +smartystreets_python_sdk/response.py,sha256=_uzx5N4MhqKZSBBnOaeaRda1XS41RHNcHowy5Kjz3hY,617 smartystreets_python_sdk/retry_sender.py,sha256=8V2_a1PKKvILKhUMrvQINXc5CIa7JhWOnOrb5HBnHG4,1257 smartystreets_python_sdk/shared_credentials.py,sha256=YJTE3_089mTqB2OlLSfxUfp9s33MoiHG3DB65zTxoNs,248 smartystreets_python_sdk/signing_sender.py,sha256=g5USdC86_HnL5t2oH2oyCqEevakcqdVhedML-ws4OEI,220 smartystreets_python_sdk/static_credentials.py,sha256=BHx34sjh-QKqjGziAaYASFSblG0WpvEnAqNwz1BQe58,280 -smartystreets_python_sdk/status_code_sender.py,sha256=7n1OWEoXBvQJMh4bcdkizy66uuBLasG10NFsWYvm1e0,2444 +smartystreets_python_sdk/status_code_sender.py,sha256=m3QhbF7u_bsA8j2ETQ1YUOJsD6SFy3zwYdOuLBOGv_U,2602 smartystreets_python_sdk/url_prefix_sender.py,sha256=_NGjV9fNbaQI9zRfsVHpmIraXE0L6nC6AygNNbbsHS4,372 smartystreets_python_sdk/us_autocomplete_pro/__init__.py,sha256=l4m1GmSshTs5jtUVwrGIwFZ0FaPUwjhPzOpgVg6udDs,89 smartystreets_python_sdk/us_autocomplete_pro/__pycache__/__init__.cpython-311.pyc,, @@ -91,13 +91,19 @@ smartystreets_python_sdk/us_autocomplete_pro/client.py,sha256=6emfu5NqeIgIEnAsLK smartystreets_python_sdk/us_autocomplete_pro/geolocation_type.py,sha256=Y3Dl2fYDyCnEZY6e39CV8v5iLFfdoo7y3BxkdXZBHCI,29 smartystreets_python_sdk/us_autocomplete_pro/lookup.py,sha256=aDJ5Fhu8m2O6C_vmj8EzOVTDzPr3Hc576PEuRDsLzMo,4314 smartystreets_python_sdk/us_autocomplete_pro/suggestion.py,sha256=eMr4BDL0XK5wwCIt1Ijt1RJVtDrKKCdnmZe-HAOb3xU,451 -smartystreets_python_sdk/us_enrichment/__init__.py,sha256=ZllT-z0eZvAYEnscXzsEAEFBlVHXE1GytW2Z95Xy9UA,50 +smartystreets_python_sdk/us_enrichment/__init__.py,sha256=eWKzMA_YOl9rlbMi5Zmnnk_GVKTbQXH78MBBWfxCOKk,368 smartystreets_python_sdk/us_enrichment/__pycache__/__init__.cpython-311.pyc,, smartystreets_python_sdk/us_enrichment/__pycache__/client.cpython-311.pyc,, smartystreets_python_sdk/us_enrichment/__pycache__/lookup.cpython-311.pyc,, smartystreets_python_sdk/us_enrichment/__pycache__/response.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/client.py,sha256=wFBEWoH8a0MWdNUjZYzbWXhb-sYEvOd3EfyO_zzfdmg,5445 -smartystreets_python_sdk/us_enrichment/lookup.py,sha256=pjPNkHj0YPowYlF_nxWDiKPBYQYtALRait_CfXFz2bI,1935 +smartystreets_python_sdk/us_enrichment/business/__init__.py,sha256=uAJgJDshudrPwGdGkU7E5KBYwLlSrzvkFiv0Kd0ReTQ,129 +smartystreets_python_sdk/us_enrichment/business/__pycache__/__init__.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/business/__pycache__/detail.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/business/__pycache__/summary.cpython-311.pyc,, +smartystreets_python_sdk/us_enrichment/business/detail.py,sha256=rLYUmEVOz1LegIoFYNDRhTehb7_5aKTJ7xJntXDz9Ws,14605 +smartystreets_python_sdk/us_enrichment/business/summary.py,sha256=4epCKRql0_HZ8SGIH06GmIj81sPu6eSo9aIV93tRptg,536 +smartystreets_python_sdk/us_enrichment/client.py,sha256=t3mBN3dfdpRtpM3hMnj_vK5nEm0UlgDgG2exrxMe_mU,6581 +smartystreets_python_sdk/us_enrichment/lookup.py,sha256=341lcUXgJs2Omk7QnztAeTArZ42CqKfGaAYbFKD-Lvg,2399 smartystreets_python_sdk/us_enrichment/response.py,sha256=zqQBPMTFkYDJ-wI6iDt2bfz4aeHnTSGs7utnuLD_Hq0,62925 smartystreets_python_sdk/us_extract/__init__.py,sha256=Fc_OZTtDwP5lE1HXFnbrcGXmEa6pNU4MJxvXlgAUuSU,141 smartystreets_python_sdk/us_extract/__pycache__/__init__.cpython-311.pyc,, @@ -161,5 +167,5 @@ smartystreets_python_sdk/us_zipcode/client.py,sha256=9UJzNvk7BM3DC00wltIdmDyLA-0 smartystreets_python_sdk/us_zipcode/lookup.py,sha256=SYlMExfKS9clDrDOdE7RX69XAUK3yjPeIIQ_gfBvXDQ,687 smartystreets_python_sdk/us_zipcode/result.py,sha256=HZiLJ6xmJ6jdFwNCmBJDPA4uH5kNHIjpZ2Rj2cCw4Io,938 smartystreets_python_sdk/us_zipcode/zipcode.py,sha256=gHJAv6nObkKi8hdcRgOgEfTOazEmXB6uAFr2rWhbqao,852 -smartystreets_python_sdk_version/__init__.py,sha256=pkujCwAzmEFZh_I47UMkNRFvSaqfWtBlzTM7TgqvB5E,122 +smartystreets_python_sdk_version/__init__.py,sha256=eg7m4JO8kxAXocPAUQeVPe5xu-pqJTMYPbp39lRhkL4,122 smartystreets_python_sdk_version/__pycache__/__init__.cpython-311.pyc,, diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/REQUESTED b/smarty/smartystreets_python_sdk-6.1.0.dist-info/REQUESTED similarity index 100% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/REQUESTED rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/REQUESTED diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/WHEEL b/smarty/smartystreets_python_sdk-6.1.0.dist-info/WHEEL similarity index 100% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/WHEEL rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/WHEEL diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md b/smarty/smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md similarity index 100% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/licenses/LICENSE.md rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md diff --git a/smarty/smartystreets_python_sdk-5.7.0.dist-info/top_level.txt b/smarty/smartystreets_python_sdk-6.1.0.dist-info/top_level.txt similarity index 100% rename from smarty/smartystreets_python_sdk-5.7.0.dist-info/top_level.txt rename to smarty/smartystreets_python_sdk-6.1.0.dist-info/top_level.txt diff --git a/smarty/smartystreets_python_sdk/custom_header_sender.py b/smarty/smartystreets_python_sdk/custom_header_sender.py index 9399096..a85bc0b 100644 --- a/smarty/smartystreets_python_sdk/custom_header_sender.py +++ b/smarty/smartystreets_python_sdk/custom_header_sender.py @@ -1,26 +1,14 @@ -from requests import Request - - class CustomHeaderSender: def __init__(self, headers, inner, append_headers=None): self.headers = headers self.inner = inner self.append_headers = append_headers or {} - def send(self, smarty_request): - request = self.build_request(smarty_request) + def send(self, request): + for key, value in self.apply_headers().items(): + request.headers[key] = value return self.inner.send(request) - def build_request(self, smarty_request): - request = Request(url=smarty_request.url_prefix, params=smarty_request.parameters) - request.headers = self.apply_headers() - if smarty_request.payload: - request.data = smarty_request.payload - request.method = 'POST' - else: - request.method = 'GET' - return request - def apply_headers(self): result = {} for key, value in self.headers.items(): diff --git a/smarty/smartystreets_python_sdk/errors.py b/smarty/smartystreets_python_sdk/errors.py index 9bead9f..15ac5c8 100644 --- a/smarty/smartystreets_python_sdk/errors.py +++ b/smarty/smartystreets_python_sdk/errors.py @@ -22,3 +22,5 @@ GATEWAY_TIMEOUT = "The upstream data provider did not respond in a timely fashion and the request failed. " \ "A serious, yet rare occurrence indeed." + +NOT_MODIFIED = "Not Modified: The requested record has not been modified since the previous request with the Etag value." diff --git a/smarty/smartystreets_python_sdk/exceptions.py b/smarty/smartystreets_python_sdk/exceptions.py index 4856d14..434c52a 100644 --- a/smarty/smartystreets_python_sdk/exceptions.py +++ b/smarty/smartystreets_python_sdk/exceptions.py @@ -44,3 +44,9 @@ class GatewayTimeoutError(SmartyException): class BatchFullError(SmartyException): pass + + +class NotModifiedError(SmartyException): + def __init__(self, message=None, response_etag=None): + super().__init__(message) + self.response_etag = response_etag diff --git a/smarty/smartystreets_python_sdk/request.py b/smarty/smartystreets_python_sdk/request.py index c4c9af1..ad39de8 100644 --- a/smarty/smartystreets_python_sdk/request.py +++ b/smarty/smartystreets_python_sdk/request.py @@ -10,3 +10,4 @@ def __init__(self): self.referer = None self.content_type = 'application/json' self.auth = None + self.headers = {} diff --git a/smarty/smartystreets_python_sdk/requests_sender.py b/smarty/smartystreets_python_sdk/requests_sender.py index 5e53014..6825f97 100644 --- a/smarty/smartystreets_python_sdk/requests_sender.py +++ b/smarty/smartystreets_python_sdk/requests_sender.py @@ -55,6 +55,9 @@ def build_request(smarty_request): request.headers['Content-Type'] = smarty_request.content_type if smarty_request.referer: request.headers['Referer'] = smarty_request.referer + if smarty_request.headers: + for key, value in smarty_request.headers.items(): + request.headers[key] = value if smarty_request.auth: request.auth = smarty_request.auth if smarty_request.payload: diff --git a/smarty/smartystreets_python_sdk/response.py b/smarty/smartystreets_python_sdk/response.py index 4e6cc32..f5c089c 100644 --- a/smarty/smartystreets_python_sdk/response.py +++ b/smarty/smartystreets_python_sdk/response.py @@ -10,3 +10,12 @@ def getHeader(self, header): return None else: return self.headers[header] + + def find_header(self, name): + if self.headers is None: + return None + target = name.lower() + for key, value in self.headers.items(): + if key.lower() == target: + return value + return None diff --git a/smarty/smartystreets_python_sdk/status_code_sender.py b/smarty/smartystreets_python_sdk/status_code_sender.py index d922d96..6b5361c 100644 --- a/smarty/smartystreets_python_sdk/status_code_sender.py +++ b/smarty/smartystreets_python_sdk/status_code_sender.py @@ -25,10 +25,12 @@ def send(self, request): response = self.inner.send(request) if not response.error: - if response.status_code != 429: - response.error = statuses.get(response.status_code) - else: + if response.status_code == 304: + response.error = exceptions.NotModifiedError(errors.NOT_MODIFIED, response.find_header('etag')) + elif response.status_code == 429: response.error = self.parse_rate_limit_response(response) + else: + response.error = statuses.get(response.status_code) return response diff --git a/smarty/smartystreets_python_sdk/us_enrichment/__init__.py b/smarty/smartystreets_python_sdk/us_enrichment/__init__.py index 0d4b8bc..904f520 100644 --- a/smarty/smartystreets_python_sdk/us_enrichment/__init__.py +++ b/smarty/smartystreets_python_sdk/us_enrichment/__init__.py @@ -1,2 +1,14 @@ +from .business import BusinessDetailAttributes, BusinessDetailResponse, BusinessEntry, BusinessSummaryResponse from .client import Client -from .response import * \ No newline at end of file +from .lookup import ( + BusinessDetailLookup, + BusinessLookup, + GeoReferenceLookup, + Lookup, + LookupBase, + PrincipalLookup, + RiskLookup, + SecondaryCountLookup, + SecondaryLookup, +) +from .response import * diff --git a/smarty/smartystreets_python_sdk/us_enrichment/business/__init__.py b/smarty/smartystreets_python_sdk/us_enrichment/business/__init__.py new file mode 100644 index 0000000..31c7b18 --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/business/__init__.py @@ -0,0 +1,2 @@ +from .summary import BusinessSummaryResponse, BusinessEntry +from .detail import BusinessDetailResponse, BusinessDetailAttributes diff --git a/smarty/smartystreets_python_sdk/us_enrichment/business/detail.py b/smarty/smartystreets_python_sdk/us_enrichment/business/detail.py new file mode 100644 index 0000000..db634d3 --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/business/detail.py @@ -0,0 +1,206 @@ +class BusinessDetailAttributes: + def __init__(self, obj): + if obj is None: + obj = {} + self.accounting_expense_range = obj.get('accounting_expense_range', None) + self.accounting_expense_total = obj.get('accounting_expense_total', None) + self.advertising_expense_range = obj.get('advertising_expense_range', None) + self.advertising_expense_total = obj.get('advertising_expense_total', None) + self.business_insurance_expense_range = obj.get('business_insurance_expense_range', None) + self.business_insurance_expense_total = obj.get('business_insurance_expense_total', None) + self.business_status = obj.get('business_status', None) + self.business_type = obj.get('business_type', None) + self.carrier_route = obj.get('carrier_route', None) + self.census_block = obj.get('census_block', None) + self.census_tract = obj.get('census_tract', None) + self.city_name = obj.get('city_name', None) + self.company_name = obj.get('company_name', None) + self.company_name_secondary = obj.get('company_name_secondary', None) + self.contact_first_name = obj.get('contact_first_name', None) + self.contact_full_name = obj.get('contact_full_name', None) + self.contact_gender = obj.get('contact_gender', None) + self.contact_last_name = obj.get('contact_last_name', None) + self.contact_middle_name = obj.get('contact_middle_name', None) + self.contact_prefix = obj.get('contact_prefix', None) + self.contact_professional_title = obj.get('contact_professional_title', None) + self.contact_suffix = obj.get('contact_suffix', None) + self.core_based_stat_area_code = obj.get('core_based_stat_area_code', None) + self.core_based_stat_area_name = obj.get('core_based_stat_area_name', None) + self.corporate_employee_count_range = obj.get('corporate_employee_count_range', None) + self.corporate_employee_count_total = obj.get('corporate_employee_count_total', None) + self.county_fips = obj.get('county_fips', None) + self.county_name = obj.get('county_name', None) + self.credit_capacity = obj.get('credit_capacity', None) + self.credit_capacity_range = obj.get('credit_capacity_range', None) + self.credit_score = obj.get('credit_score', None) + self.credit_score_description = obj.get('credit_score_description', None) + self.date_of_last_update = obj.get('date_of_last_update', None) + self.delivery_line_1 = obj.get('delivery_line_1', None) + self.delivery_point = obj.get('delivery_point', None) + self.delivery_point_check_digit = obj.get('delivery_point_check_digit', None) + self.domestic_foreign_owner_indicator = obj.get('domestic_foreign_owner_indicator', None) + self.ein = obj.get('ein', None) + self.email = obj.get('email', None) + self.email_available_indicator = obj.get('email_available_indicator', None) + self.executive_department = obj.get('executive_department', None) + self.executive_level = obj.get('executive_level', None) + self.executive_verification_type = obj.get('executive_verification_type', None) + self.fax = obj.get('fax', None) + self.female_owned_indicator = obj.get('female_owned_indicator', None) + self.foreign_parent_city_name = obj.get('foreign_parent_city_name', None) + self.foreign_parent_company_name = obj.get('foreign_parent_company_name', None) + self.foreign_parent_country = obj.get('foreign_parent_country', None) + self.fortune_1000_branches = obj.get('fortune_1000_branches', None) + self.fortune_1000_indicator = obj.get('fortune_1000_indicator', None) + self.fortune_1000_rank = obj.get('fortune_1000_rank', None) + self.holding_city_name = obj.get('holding_city_name', None) + self.holding_company_name = obj.get('holding_company_name', None) + self.holding_id = obj.get('holding_id', None) + self.holding_state_abbreviation = obj.get('holding_state_abbreviation', None) + self.home_based_business_indicator = obj.get('home_based_business_indicator', None) + self.hq_city_name = obj.get('hq_city_name', None) + self.hq_company_name = obj.get('hq_company_name', None) + self.hq_id = obj.get('hq_id', None) + self.hq_number_of_companies = obj.get('hq_number_of_companies', None) + self.hq_state_abbreviation = obj.get('hq_state_abbreviation', None) + self.latitude = obj.get('latitude', None) + self.legal_expense_range = obj.get('legal_expense_range', None) + self.legal_expense_total = obj.get('legal_expense_total', None) + self.linkage_company_name = obj.get('linkage_company_name', None) + self.linkage_indicator = obj.get('linkage_indicator', None) + self.linkage_level = obj.get('linkage_level', None) + self.linkage_type = obj.get('linkage_type', None) + self.location_employee_count = obj.get('location_employee_count', None) + self.location_employee_count_range = obj.get('location_employee_count_range', None) + self.location_sales_range = obj.get('location_sales_range', None) + self.location_sales_total = obj.get('location_sales_total', None) + self.longitude = obj.get('longitude', None) + self.mail_score_code = obj.get('mail_score_code', None) + self.mail_score_description = obj.get('mail_score_description', None) + self.mailing_carrier_route = obj.get('mailing_carrier_route', None) + self.mailing_city_name = obj.get('mailing_city_name', None) + self.mailing_delivery_line_1 = obj.get('mailing_delivery_line_1', None) + self.mailing_delivery_point = obj.get('mailing_delivery_point', None) + self.mailing_delivery_point_check_digit = obj.get('mailing_delivery_point_check_digit', None) + self.mailing_plus4_code = obj.get('mailing_plus4_code', None) + self.mailing_state_abbreviation = obj.get('mailing_state_abbreviation', None) + self.mailing_zipcode = obj.get('mailing_zipcode', None) + self.manufacturing_indicator = obj.get('manufacturing_indicator', None) + self.minority_owned_indicator = obj.get('minority_owned_indicator', None) + self.minority_type = obj.get('minority_type', None) + self.naics_01_code = obj.get('naics_01_code', None) + self.naics_01_description = obj.get('naics_01_description', None) + self.naics_02_code = obj.get('naics_02_code', None) + self.naics_02_description = obj.get('naics_02_description', None) + self.naics_03_code = obj.get('naics_03_code', None) + self.naics_03_description = obj.get('naics_03_description', None) + self.naics_04_code = obj.get('naics_04_code', None) + self.naics_04_description = obj.get('naics_04_description', None) + self.naics_05_code = obj.get('naics_05_code', None) + self.naics_05_description = obj.get('naics_05_description', None) + self.naics_06_code = obj.get('naics_06_code', None) + self.naics_06_description = obj.get('naics_06_description', None) + self.new_business_indicator = obj.get('new_business_indicator', None) + self.non_profit_indicator = obj.get('non_profit_indicator', None) + self.num_of_pcs_range = obj.get('num_of_pcs_range', None) + self.num_of_pcs_total = obj.get('num_of_pcs_total', None) + self.number_of_years_in_business = obj.get('number_of_years_in_business', None) + self.number_of_years_in_business_range = obj.get('number_of_years_in_business_range', None) + self.office_equipment_expense_range = obj.get('office_equipment_expense_range', None) + self.office_equipment_expense_total = obj.get('office_equipment_expense_total', None) + self.operating_hours_friday = obj.get('operating_hours_friday', None) + self.operating_hours_monday = obj.get('operating_hours_monday', None) + self.operating_hours_saturday = obj.get('operating_hours_saturday', None) + self.operating_hours_sunday = obj.get('operating_hours_sunday', None) + self.operating_hours_thursday = obj.get('operating_hours_thursday', None) + self.operating_hours_tuesday = obj.get('operating_hours_tuesday', None) + self.operating_hours_wednesday = obj.get('operating_hours_wednesday', None) + self.phone = obj.get('phone', None) + self.phone_area_code = obj.get('phone_area_code', None) + self.phone_secondary = obj.get('phone_secondary', None) + self.phone_toll_free = obj.get('phone_toll_free', None) + self.plus4_code = obj.get('plus4_code', None) + self.population_range = obj.get('population_range', None) + self.precision = obj.get('precision', None) + self.primary_executive_indicator = obj.get('primary_executive_indicator', None) + self.primary_number = obj.get('primary_number', None) + self.primary_sic_2digit_code = obj.get('primary_sic_2digit_code', None) + self.primary_sic_2digit_description = obj.get('primary_sic_2digit_description', None) + self.primary_sic_4digit_code = obj.get('primary_sic_4digit_code', None) + self.primary_sic_4digit_description = obj.get('primary_sic_4digit_description', None) + self.primary_sic_code = obj.get('primary_sic_code', None) + self.primary_sic_description = obj.get('primary_sic_description', None) + self.public_indicator = obj.get('public_indicator', None) + self.rdi = obj.get('rdi', None) + self.rent_expense_range = obj.get('rent_expense_range', None) + self.rent_expense_total = obj.get('rent_expense_total', None) + self.secondary_01_sic_7digit_code = obj.get('secondary_01_sic_7digit_code', None) + self.secondary_01_sic_7digit_description = obj.get('secondary_01_sic_7digit_description', None) + self.secondary_02_sic_7digit_code = obj.get('secondary_02_sic_7digit_code', None) + self.secondary_02_sic_7digit_description = obj.get('secondary_02_sic_7digit_description', None) + self.secondary_03_sic_7digit_code = obj.get('secondary_03_sic_7digit_code', None) + self.secondary_03_sic_7digit_description = obj.get('secondary_03_sic_7digit_description', None) + self.secondary_04_sic_7digit_code = obj.get('secondary_04_sic_7digit_code', None) + self.secondary_04_sic_7digit_description = obj.get('secondary_04_sic_7digit_description', None) + self.secondary_05_sic_7digit_code = obj.get('secondary_05_sic_7digit_code', None) + self.secondary_05_sic_7digit_description = obj.get('secondary_05_sic_7digit_description', None) + self.secondary_designator = obj.get('secondary_designator', None) + self.secondary_number = obj.get('secondary_number', None) + self.sectional_center_facility = obj.get('sectional_center_facility', None) + self.small_business_indicator = obj.get('small_business_indicator', None) + self.source_title = obj.get('source_title', None) + self.square_footage = obj.get('square_footage', None) + self.square_footage_range = obj.get('square_footage_range', None) + self.standardized_title = obj.get('standardized_title', None) + self.standardized_title_rank = obj.get('standardized_title_rank', None) + self.state_abbreviation = obj.get('state_abbreviation', None) + self.stock_exchange = obj.get('stock_exchange', None) + self.street_name = obj.get('street_name', None) + self.street_postdirection = obj.get('street_postdirection', None) + self.street_predirection = obj.get('street_predirection', None) + self.street_suffix = obj.get('street_suffix', None) + self.sub_hq_city_name = obj.get('sub_hq_city_name', None) + self.sub_hq_company_name = obj.get('sub_hq_company_name', None) + self.sub_hq_id = obj.get('sub_hq_id', None) + self.sub_hq_number_of_companies = obj.get('sub_hq_number_of_companies', None) + self.sub_hq_state_abbreviation = obj.get('sub_hq_state_abbreviation', None) + self.technology_expense_range = obj.get('technology_expense_range', None) + self.technology_expense_total = obj.get('technology_expense_total', None) + self.telecom_expense_range = obj.get('telecom_expense_range', None) + self.telecom_expense_total = obj.get('telecom_expense_total', None) + self.ticker_symbol = obj.get('ticker_symbol', None) + self.time_zone = obj.get('time_zone', None) + self.url = obj.get('url', None) + self.url_facebook = obj.get('url_facebook', None) + self.url_instagram = obj.get('url_instagram', None) + self.url_linkedin = obj.get('url_linkedin', None) + self.url_twitter = obj.get('url_twitter', None) + self.url_yelp = obj.get('url_yelp', None) + self.url_youtube = obj.get('url_youtube', None) + self.utilities_expense_range = obj.get('utilities_expense_range', None) + self.utilities_expense_total = obj.get('utilities_expense_total', None) + self.webmail_indicator = obj.get('webmail_indicator', None) + self.year_current = obj.get('year_current', None) + self.year_current_employee_count = obj.get('year_current_employee_count', None) + self.year_established = obj.get('year_established', None) + self.year_four_prior = obj.get('year_four_prior', None) + self.year_four_prior_employee_count = obj.get('year_four_prior_employee_count', None) + self.year_four_prior_employee_growth = obj.get('year_four_prior_employee_growth', None) + self.year_one_prior = obj.get('year_one_prior', None) + self.year_one_prior_employee_count = obj.get('year_one_prior_employee_count', None) + self.year_one_prior_employee_growth = obj.get('year_one_prior_employee_growth', None) + self.year_three_prior = obj.get('year_three_prior', None) + self.year_three_prior_employee_count = obj.get('year_three_prior_employee_count', None) + self.year_three_prior_employee_growth = obj.get('year_three_prior_employee_growth', None) + self.year_two_prior = obj.get('year_two_prior', None) + self.year_two_prior_employee_count = obj.get('year_two_prior_employee_count', None) + self.year_two_prior_employee_growth = obj.get('year_two_prior_employee_growth', None) + self.zipcode = obj.get('zipcode', None) + + +class BusinessDetailResponse: + def __init__(self, obj): + self.smarty_key = obj.get('smarty_key', None) + self.data_set_name = obj.get('data_set_name', None) + self.business_id = obj.get('business_id', None) + self.attributes = BusinessDetailAttributes(obj.get('attributes', None)) diff --git a/smarty/smartystreets_python_sdk/us_enrichment/business/summary.py b/smarty/smartystreets_python_sdk/us_enrichment/business/summary.py new file mode 100644 index 0000000..cb68e18 --- /dev/null +++ b/smarty/smartystreets_python_sdk/us_enrichment/business/summary.py @@ -0,0 +1,15 @@ +class BusinessEntry: + def __init__(self, obj): + self.company_name = obj.get('company_name', None) + self.business_id = obj.get('business_id', None) + + +class BusinessSummaryResponse: + def __init__(self, obj): + self.smarty_key = obj.get('smarty_key', None) + self.data_set_name = obj.get('data_set_name', None) + businesses = obj.get('businesses', None) + if businesses is None: + self.businesses = [] + else: + self.businesses = [BusinessEntry(b) for b in businesses] diff --git a/smarty/smartystreets_python_sdk/us_enrichment/client.py b/smarty/smartystreets_python_sdk/us_enrichment/client.py index 48792e5..3321345 100644 --- a/smarty/smartystreets_python_sdk/us_enrichment/client.py +++ b/smarty/smartystreets_python_sdk/us_enrichment/client.py @@ -1,6 +1,18 @@ +from urllib.parse import quote + from smartystreets_python_sdk import Request from smartystreets_python_sdk.exceptions import SmartyException -from .lookup import PrincipalLookup, GeoReferenceLookup, RiskLookup, SecondaryLookup, SecondaryCountLookup, Lookup +from .business import BusinessSummaryResponse, BusinessDetailResponse +from .lookup import ( + BusinessDetailLookup, + BusinessLookup, + GeoReferenceLookup, + Lookup, + PrincipalLookup, + RiskLookup, + SecondaryCountLookup, + SecondaryLookup, +) from .response import Response @@ -22,7 +34,7 @@ def send_property_principal_lookup(self, lookup): lookup.dataSubset = 'principal' send_lookup(self, lookup) return lookup.result - + def send_geo_reference_lookup(self, lookup): if isinstance(lookup, str): l = GeoReferenceLookup(lookup) @@ -33,7 +45,7 @@ def send_geo_reference_lookup(self, lookup): lookup.dataSubset = None send_lookup(self, lookup) return lookup.result - + def send_risk_lookup(self, lookup): if isinstance(lookup, str): l = RiskLookup(lookup) @@ -55,7 +67,7 @@ def send_secondary_lookup(self, lookup): lookup.dataSubset = None send_lookup(self, lookup) return lookup.result - + def send_secondary_count_lookup(self, lookup): if isinstance(lookup, str): l = SecondaryCountLookup(lookup) @@ -66,7 +78,7 @@ def send_secondary_count_lookup(self, lookup): lookup.dataSubset = 'count' send_lookup(self, lookup) return lookup.result - + def send_generic_lookup(self, lookup, dataset, dataSubset): if isinstance(lookup, str): l = Lookup(lookup, dataset, dataSubset) @@ -78,81 +90,117 @@ def send_generic_lookup(self, lookup, dataset, dataSubset): send_lookup(self, lookup) return lookup.result + def send_business_lookup(self, lookup): + if isinstance(lookup, str): + l = BusinessLookup(lookup) + send_lookup(self, l, BusinessSummaryResponse) + return l.result + else: + lookup.dataset = 'business' + lookup.dataSubset = None + send_lookup(self, lookup, BusinessSummaryResponse) + return lookup.result -def send_lookup(client: Client, lookup): + def send_business_detail_lookup(self, lookup): + if isinstance(lookup, str): + l = BusinessDetailLookup(lookup) + send_business_detail_lookup(self, l) + return l.result + else: + send_business_detail_lookup(self, lookup) + return lookup.result + + +def send_lookup(client: Client, lookup, response_class=Response): """ Sends a Lookup object to the US Enrichment API and stores the result in the Lookup's result field. """ - if lookup is None or (lookup.smartykey is None and lookup.street is None and lookup.freeform is None): - raise SmartyException('Client.send() requires a Lookup with either the "smartykey", "street, or "freeform" field set as a string') + if lookup is None or ( + _is_blank(getattr(lookup, 'smartykey', None)) + and _is_blank(getattr(lookup, 'street', None)) + and _is_blank(getattr(lookup, 'freeform', None)) + ): + raise SmartyException("Lookup requires one of 'smartykey', 'street', or 'freeform' to be set") request = build_request(lookup) + raw = _dispatch(client, request, lookup) + lookup.result = [response_class(candidate) for candidate in raw] + return lookup.result - response = client.sender.send(request) - if response.error: - raise response.error - response = client.serializer.deserialize(response.payload) - result = [] - for candidate in response: - result.append(Response(candidate)) - lookup.result = result - return result +def send_business_detail_lookup(client: Client, lookup): + if lookup is None or _is_blank(getattr(lookup, 'business_id', None)): + raise SmartyException("BusinessDetailLookup requires a non-empty 'business_id'") + + request = Request() + request.url_components = 'business/' + quote(lookup.business_id, safe='') + request.parameters = _common_parameters(lookup) + _apply_etag_header(request, lookup) + + raw = _dispatch(client, request, lookup) + if not raw: + lookup.result = None + elif len(raw) > 1: + raise SmartyException( + "business detail response contained {} results; expected at most 1".format(len(raw)) + ) + else: + lookup.result = BusinessDetailResponse(raw[0]) + return lookup.result def build_request(lookup): request = Request() - if lookup.smartykey != None: - if lookup.dataSubset == None: - request.url_components = lookup.smartykey + "/" + lookup.dataset - request.parameters = remap_keys(lookup) - return request - - request.url_components = lookup.smartykey + "/" + lookup.dataset + "/" + lookup.dataSubset - request.parameters = remap_keys(lookup) - - return request + request.url_components = _url_components(lookup) + request.parameters = _address_parameters(lookup) + request.parameters.update(_common_parameters(lookup)) + _apply_etag_header(request, lookup) + return request + + +def _url_components(lookup): + if lookup.smartykey is not None: + base = lookup.smartykey + "/" + lookup.dataset else: - if lookup.dataSubset == None: - request.url_components = 'search/' + lookup.dataset - request.parameters = remap_keys(lookup) - return request - - request.url_components = 'search/' + lookup.dataset + "/" + lookup.dataSubset - - request.parameters = remap_keys(lookup) - return request - -def remap_keys(lookup): - converted_lookup = {} - - if (lookup.freeform != None): - add_field(converted_lookup, 'freeform', lookup.freeform) - if (lookup.street != None): - add_field(converted_lookup, 'street', lookup.street) - if (lookup.city != None): - add_field(converted_lookup, 'city', lookup.city) - if (lookup.state != None): - add_field(converted_lookup, 'state', lookup.state) - if (lookup.zipcode != None): - add_field(converted_lookup, 'zipcode', lookup.zipcode) - if (lookup.include_array != None): - add_field(converted_lookup, 'include', build_filter_string(lookup.include_array)) - if (lookup.exclude_array != None): - add_field(converted_lookup, 'exclude', build_filter_string(lookup.exclude_array)) - if (lookup.features != None): - add_field(converted_lookup, 'features', lookup.features) - - - for parameter in lookup.custom_parameter_array: - add_field(converted_lookup, parameter, lookup.custom_parameter_array[parameter]) - - return converted_lookup - - -def add_field(converted_lookup, key, value): - if value: - converted_lookup[key] = value - -def build_filter_string(filter_list): - return ','.join(filter_list or []) or None + base = 'search/' + lookup.dataset + if lookup.dataSubset is None: + return base + return base + "/" + lookup.dataSubset + + +def _address_parameters(lookup): + params = {} + for key in ('freeform', 'street', 'city', 'state', 'zipcode', 'features'): + value = getattr(lookup, key, None) + if value: + params[key] = value + return params + + +def _common_parameters(lookup): + params = {} + if lookup.include_array: + params['include'] = ','.join(lookup.include_array) + if lookup.exclude_array: + params['exclude'] = ','.join(lookup.exclude_array) + for key, value in lookup.custom_parameter_array.items(): + params[key] = value + return params + + +def _apply_etag_header(request, lookup): + if lookup.request_etag is not None: + request.headers['Etag'] = lookup.request_etag + + +def _dispatch(client, request, lookup): + response = client.sender.send(request) + lookup.response_etag = response.find_header('etag') + if response.error: + raise response.error + raw = client.serializer.deserialize(response.payload) + return raw or [] + + +def _is_blank(value): + return value is None or (isinstance(value, str) and value.strip() == '') diff --git a/smarty/smartystreets_python_sdk/us_enrichment/lookup.py b/smarty/smartystreets_python_sdk/us_enrichment/lookup.py index ab850b6..6fad933 100644 --- a/smarty/smartystreets_python_sdk/us_enrichment/lookup.py +++ b/smarty/smartystreets_python_sdk/us_enrichment/lookup.py @@ -4,15 +4,36 @@ riskDataset = "risk" secondaryDataset = "secondary" countDataSubset = "count" +businessDataset = "business" noneDataSubset = None -class Lookup: - def __init__(self, smartykey = None, dataset = None, dataSubset = None, features = None, freeform = None, street = None, city = None, state = None, zipcode = None): + +class LookupBase: + def __init__(self): + self.include_array = [] + self.exclude_array = [] + self.request_etag = None + self.response_etag = None + self.custom_parameter_array = {} + + def add_custom_parameter(self, parameter, value): + self.custom_parameter_array[parameter] = value + + def add_include_attribute(self, attribute): + if attribute not in self.include_array: + self.include_array.append(attribute) + + def add_exclude_attribute(self, attribute): + if attribute not in self.exclude_array: + self.exclude_array.append(attribute) + + +class Lookup(LookupBase): + def __init__(self, smartykey=None, dataset=None, dataSubset=None, features=None, freeform=None, street=None, city=None, state=None, zipcode=None): + super().__init__() self.smartykey = smartykey self.dataset = dataset self.dataSubset = dataSubset - self.include_array = [] - self.exclude_array = [] self.features = features self.freeform = freeform self.street = street @@ -20,35 +41,40 @@ def __init__(self, smartykey = None, dataset = None, dataSubset = None, features self.state = state self.zipcode = zipcode self.result = [] - self.custom_parameter_array = {} - - def add_custom_parameter(self, parameter, value): - self.custom_parameter_array[parameter] = value - def add_include_attribute(self, attribute): - if (attribute not in self.include_array): - self.include_array.append(attribute) - - def add_exclude_attribute(self, attribute): - if (attribute not in self.exclude_array): - self.exclude_array.append(attribute) class PrincipalLookup(Lookup): - def __init__(self, smartykey = None): + def __init__(self, smartykey=None): super().__init__(smartykey, propertyDataset, principalDataSubset) + class GeoReferenceLookup(Lookup): - def __init__(self, smartykey = None): + def __init__(self, smartykey=None): super().__init__(smartykey, geoReferenceDataset, noneDataSubset) + class RiskLookup(Lookup): - def __init__(self, smartykey = None): + def __init__(self, smartykey=None): super().__init__(smartykey, riskDataset, noneDataSubset) + class SecondaryLookup(Lookup): - def __init__(self, smartykey = None): + def __init__(self, smartykey=None): super().__init__(smartykey, secondaryDataset, noneDataSubset) + class SecondaryCountLookup(Lookup): - def __init__(self, smartykey = None): - super().__init__(smartykey, secondaryDataset, countDataSubset) \ No newline at end of file + def __init__(self, smartykey=None): + super().__init__(smartykey, secondaryDataset, countDataSubset) + + +class BusinessLookup(Lookup): + def __init__(self, smartykey=None): + super().__init__(smartykey, businessDataset, noneDataSubset) + + +class BusinessDetailLookup(LookupBase): + def __init__(self, business_id=None): + super().__init__() + self.business_id = business_id + self.result = None diff --git a/smarty/smartystreets_python_sdk_version/__init__.py b/smarty/smartystreets_python_sdk_version/__init__.py index 2e081a2..12405a6 100644 --- a/smarty/smartystreets_python_sdk_version/__init__.py +++ b/smarty/smartystreets_python_sdk_version/__init__.py @@ -1,2 +1,2 @@ __version__ = '0.0.0' # DO NOT EDIT (this is updated by a build job when a new release is published) -__version__="5.7.0" +__version__="6.1.0" diff --git a/smarty/summary-0.1.1.dist-info/RECORD b/smarty/summary-0.1.1.dist-info/RECORD index 36de590..8d225a2 100644 --- a/smarty/summary-0.1.1.dist-info/RECORD +++ b/smarty/summary-0.1.1.dist-info/RECORD @@ -3,6 +3,6 @@ summary-0.1.1.dist-info/METADATA,sha256=9Mg5Wfqx8ZZKN1ocbOMHLVFHjkI57VEikL72_CLC summary-0.1.1.dist-info/RECORD,, summary-0.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 summary-0.1.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87 -summary-0.1.1.dist-info/direct_url.json,sha256=-_e93onMQmX3iyacTS6794Bza66tlpi-I43yiuo28ng,135 +summary-0.1.1.dist-info/direct_url.json,sha256=UJlmbmCY4U1o9Bziyx6pHpgHgEmbw4IYy26U87M4WOc,167 summary/__init__.py,sha256=tjJJeQWDZxdkveUm75SzDW2MJKglFZw9GutEbBqwE5Y,2079 summary/__pycache__/__init__.cpython-311.pyc,, diff --git a/smarty/summary-0.1.1.dist-info/direct_url.json b/smarty/summary-0.1.1.dist-info/direct_url.json index 16c4f22..25527dd 100644 --- a/smarty/summary-0.1.1.dist-info/direct_url.json +++ b/smarty/summary-0.1.1.dist-info/direct_url.json @@ -1 +1 @@ -{"url": "ssh://git@github.com/smarty/summary.git", "vcs_info": {"commit_id": "44aa0e7384920dcf2610c70162c287acc2754044", "vcs": "git"}} \ No newline at end of file +{"url": "ssh://git@github.com/smarty/summary.git", "vcs_info": {"commit_id": "44aa0e7384920dcf2610c70162c287acc2754044", "requested_revision": "v0.1.1", "vcs": "git"}} \ No newline at end of file From 71597763ecf4477e101acfa694a194c7990dc7f5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 5 May 2026 16:17:34 -0600 Subject: [PATCH 07/11] Updated versions in requirements.txt. --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 8b485c7..96313fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -smartystreets-python-sdk==5.7.0 -git+ssh://git@github.com/smarty/summary.git +smartystreets-python-sdk==6.1.0 +git+ssh://git@github.com/smarty/summary.git@v0.1.1 From 9322a848d0fdc57b831421983650bc8dde235886 Mon Sep 17 00:00:00 2001 From: Andy Johnson Date: Tue, 12 May 2026 13:49:13 -0600 Subject: [PATCH 08/11] Updated summary import and fixed make command. --- Makefile | 2 +- smarty/smarty.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 93cc7a8..d2df6ed 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ deploy: cp -rf smarty "$(QGIS_PLUGINS_DIR)/smarty" redeploy: deploy - osascript -e 'quit app "QGIS"' + killall QGIS > /dev/null 2>&1 open -a QGIS vendor: diff --git a/smarty/smarty.py b/smarty/smarty.py index e2f2f8c..355fc20 100644 --- a/smarty/smarty.py +++ b/smarty/smarty.py @@ -34,6 +34,7 @@ from smartystreets_python_sdk import StaticCredentials, exceptions, ClientBuilder, SharedCredentials, Batch, Request from smartystreets_python_sdk.us_street import Lookup as StreetLookup from smartystreets_python_sdk.us_autocomplete_pro import Lookup as AutocompleteProLookup +from summary import summary ######### # Initialize Qt resources from file resources.py From c93aaa639f83dc3c37c71937de728dfc4b9ee6f5 Mon Sep 17 00:00:00 2001 From: Andy Johnson Date: Tue, 12 May 2026 14:06:38 -0600 Subject: [PATCH 09/11] Updated version. --- smarty/metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smarty/metadata.txt b/smarty/metadata.txt index 49c54c3..b0153d6 100644 --- a/smarty/metadata.txt +++ b/smarty/metadata.txt @@ -6,7 +6,7 @@ name=Smarty qgisMinimumVersion=3.0 description=Smarty Geocoding QGIS Plugin -version=1.0.14 +version=1.0.15 author=Smarty email=osgeo-it@smarty.com From 1e81b8900ee89bdc3bf80fe74bce6666d428e0db Mon Sep 17 00:00:00 2001 From: Andy Johnson Date: Tue, 12 May 2026 14:12:56 -0600 Subject: [PATCH 10/11] Removed unneeded .dist-info --- .gitignore | 1 + .../INSTALLER | 1 - .../METADATA | 30 --- .../RECORD | 171 --------------- .../REQUESTED | 0 .../WHEEL | 5 - .../licenses/LICENSE.md | 202 ------------------ .../top_level.txt | 2 - smarty/summary-0.1.1.dist-info/INSTALLER | 1 - smarty/summary-0.1.1.dist-info/METADATA | 4 - smarty/summary-0.1.1.dist-info/RECORD | 8 - smarty/summary-0.1.1.dist-info/REQUESTED | 0 smarty/summary-0.1.1.dist-info/WHEEL | 4 - .../summary-0.1.1.dist-info/direct_url.json | 1 - 14 files changed, 1 insertion(+), 429 deletions(-) delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/INSTALLER delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/REQUESTED delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/WHEEL delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md delete mode 100644 smarty/smartystreets_python_sdk-6.1.0.dist-info/top_level.txt delete mode 100644 smarty/summary-0.1.1.dist-info/INSTALLER delete mode 100644 smarty/summary-0.1.1.dist-info/METADATA delete mode 100644 smarty/summary-0.1.1.dist-info/RECORD delete mode 100644 smarty/summary-0.1.1.dist-info/REQUESTED delete mode 100644 smarty/summary-0.1.1.dist-info/WHEEL delete mode 100644 smarty/summary-0.1.1.dist-info/direct_url.json diff --git a/.gitignore b/.gitignore index d646835..93c25a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.pyc __pycache__/ +*.dist-info/ diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/INSTALLER b/smarty/smartystreets_python_sdk-6.1.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/smarty/smartystreets_python_sdk-6.1.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA b/smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA deleted file mode 100644 index 71411a2..0000000 --- a/smarty/smartystreets_python_sdk-6.1.0.dist-info/METADATA +++ /dev/null @@ -1,30 +0,0 @@ -Metadata-Version: 2.4 -Name: smartystreets_python_sdk -Version: 6.1.0 -Summary: An official library to help Python developers easily access the SmartyStreets APIs -Home-page: https://github.com/smartystreets/smartystreets-python-sdk -Download-URL: https://github.com/smartystreets/smartystreets-python-sdk/tarball/6.1.0 -Author: SmartyStreets SDK Team -Author-email: support@smartystreets.com -License: Apache 2 -Keywords: smartystreets,smarty,address,validation,verification,street,sdk,library,geocode -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Natural Language :: English -Classifier: Programming Language :: Python :: 3 -License-File: LICENSE.md -Requires-Dist: requests -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: download-url -Dynamic: home-page -Dynamic: keywords -Dynamic: license -Dynamic: license-file -Dynamic: requires-dist -Dynamic: summary - -Official Python library for SmartyStreets diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD b/smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD deleted file mode 100644 index b436510..0000000 --- a/smarty/smartystreets_python_sdk-6.1.0.dist-info/RECORD +++ /dev/null @@ -1,171 +0,0 @@ -smartystreets_python_sdk-6.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -smartystreets_python_sdk-6.1.0.dist-info/METADATA,sha256=uD3h0K_qRovZB3QfTfCstRPIoa8hC6HbkqCHxp2uHHc,1054 -smartystreets_python_sdk-6.1.0.dist-info/RECORD,, -smartystreets_python_sdk-6.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -smartystreets_python_sdk-6.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91 -smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md,sha256=Cu67SvL5YQlDIEaH0UOH2rlm4LIPiCfdO4hlAACCWl4,11332 -smartystreets_python_sdk-6.1.0.dist-info/top_level.txt,sha256=uPitCujTcHdnUQwzTZKMfb1GoYxgM5Evyq_CJrhfVnU,58 -smartystreets_python_sdk/__init__.py,sha256=cJpR9L-R1gDD7b4-L3QJltQOacFe8Sdom586X3feFJo,805 -smartystreets_python_sdk/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/basic_auth_credentials.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/batch.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/client_builder.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/custom_header_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/custom_query_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/errors.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/exceptions.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/license_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/native_serializer.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/proxy.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/request.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/requests_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/response.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/retry_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/shared_credentials.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/signing_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/static_credentials.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/status_code_sender.cpython-311.pyc,, -smartystreets_python_sdk/__pycache__/url_prefix_sender.cpython-311.pyc,, -smartystreets_python_sdk/basic_auth_credentials.py,sha256=-9vCG8z0Mr8GR-7Zl8UuXWbfzposXc9aIRa1Ynjz2Ek,401 -smartystreets_python_sdk/batch.py,sha256=FafhYEGpTbHIb6oGkBozblsf00PNfMQsCVT_EY0c-aw,1371 -smartystreets_python_sdk/client_builder.py,sha256=g-hhGVT9xSzFEZnkApabmITcpJe8K0I8ZXLQnZ5047A,12787 -smartystreets_python_sdk/custom_header_sender.py,sha256=qmTUM7afM5mBGGocuzr1THbB5f7F5NMNr5dgycuHMco,795 -smartystreets_python_sdk/custom_query_sender.py,sha256=q238mqAOh3nK26HS5mHUmeucT3_ki6ue5PFJtOAcTMw,364 -smartystreets_python_sdk/errors.py,sha256=DTnAmoxVG1uSCFsmzkknzVqzXyOHqYx28eXkdbUw28k,1214 -smartystreets_python_sdk/exceptions.py,sha256=TFnXjje1TPwfZ4S0L1l0gQqejEzy5FQVTfBCwGNYkvs,830 -smartystreets_python_sdk/international_autocomplete/__init__.py,sha256=zmHkBQ4bBdQRXgA98Luey4xGgAOYUD0j8_nMcz-1kDw,87 -smartystreets_python_sdk/international_autocomplete/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/international_autocomplete/__pycache__/candidate.cpython-311.pyc,, -smartystreets_python_sdk/international_autocomplete/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/international_autocomplete/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/international_autocomplete/candidate.py,sha256=SMy274DXAIwA7Gp4jQ_-oFbAzPU7vuYQaDrpvHVNrKQ,679 -smartystreets_python_sdk/international_autocomplete/client.py,sha256=ejuGxnrt6C2-jHlvq5QOanzOlssdOOoPqaAzhEQaGNs,2339 -smartystreets_python_sdk/international_autocomplete/lookup.py,sha256=HZdbDW3DpfUuuSa8yU9zuIBxYHm6rApV6YU_qNFjcCM,1268 -smartystreets_python_sdk/international_postal_code/__init__.py,sha256=zmHkBQ4bBdQRXgA98Luey4xGgAOYUD0j8_nMcz-1kDw,87 -smartystreets_python_sdk/international_postal_code/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/international_postal_code/__pycache__/candidate.cpython-311.pyc,, -smartystreets_python_sdk/international_postal_code/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/international_postal_code/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/international_postal_code/candidate.py,sha256=cOEHsemaWzOfPoUE21BdqLMvqE4LgR_zkKuWBtdt8fM,829 -smartystreets_python_sdk/international_postal_code/client.py,sha256=MoWTqqwN0xuiQdoOduYL2UiwW8YeUY27cAxIddjLR_8,1570 -smartystreets_python_sdk/international_postal_code/lookup.py,sha256=J55Hi62-nvRTpjNHrNOnOdNeh-mb-Ed3De1v1jmLyVs,945 -smartystreets_python_sdk/international_street/__init__.py,sha256=lCUAdOYSQ4vKvcSRvmGIjElHWPE188CXrGtHEMUnbWg,184 -smartystreets_python_sdk/international_street/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/analysis.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/candidate.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/changes.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/components.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/language_mode.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/metadata.cpython-311.pyc,, -smartystreets_python_sdk/international_street/__pycache__/rootlevel.cpython-311.pyc,, -smartystreets_python_sdk/international_street/analysis.py,sha256=va5FCw0oCR_d7eME-8fvQ2ErwFvHnwB6ZLxt_jUuOgM,437 -smartystreets_python_sdk/international_street/candidate.py,sha256=vV3jAYYRQZTHi9LKzbs4_02gtdsuVoGYecK6y2dmKwc,672 -smartystreets_python_sdk/international_street/changes.py,sha256=qBUYwl90FKppDLLg1j4VG4yi6GzYAeVracwEO5I9Yu0,226 -smartystreets_python_sdk/international_street/client.py,sha256=gtJcIjrRcvfhUuxnNjE8n19SO3M2ZGdDce87U60DA48,2370 -smartystreets_python_sdk/international_street/components.py,sha256=Q8VbHv5jTaOJ_gYAoTxFpKZHibNYz3fQLBqKPnD7Az0,3812 -smartystreets_python_sdk/international_street/language_mode.py,sha256=zf45F-2Y-RCYdE88JcRnN8R2HPs_EbP6A2chYTKvhbk,35 -smartystreets_python_sdk/international_street/lookup.py,sha256=qmYEEAwXI85mcG5CoPPBKmOt51SVaAdf7l1L4IkYPY4,2679 -smartystreets_python_sdk/international_street/metadata.py,sha256=DM9VJAxrUV5czeOwxt3ea6171-xBupUSVZRFWGsKEWw,598 -smartystreets_python_sdk/international_street/rootlevel.py,sha256=ZeErBuBhNkgD7-nEOXa4EDYN-EOYvlKqPiaycz_J_08,759 -smartystreets_python_sdk/license_sender.py,sha256=hAPSejluaFcAjhG2B5nt910Q474hnbtMnbb2FPUXi3c,313 -smartystreets_python_sdk/native_serializer.py,sha256=QpN2-woD1Muu3bzr-LVzF4n3l-0Ae2OtynVCW4YxoIc,225 -smartystreets_python_sdk/proxy.py,sha256=2asS-F-v_rikgPQvVJh10oI5Wp8ezprS1E10tZUFKXc,506 -smartystreets_python_sdk/request.py,sha256=mEXPJKPJQqAWs4iNZ1HqVL8UhAB37HollVniYPPpvuw,337 -smartystreets_python_sdk/requests_sender.py,sha256=veejQiYR2vwyhbVz8n21gzXFmaKx7wFdSAInwJF4YP4,3395 -smartystreets_python_sdk/response.py,sha256=_uzx5N4MhqKZSBBnOaeaRda1XS41RHNcHowy5Kjz3hY,617 -smartystreets_python_sdk/retry_sender.py,sha256=8V2_a1PKKvILKhUMrvQINXc5CIa7JhWOnOrb5HBnHG4,1257 -smartystreets_python_sdk/shared_credentials.py,sha256=YJTE3_089mTqB2OlLSfxUfp9s33MoiHG3DB65zTxoNs,248 -smartystreets_python_sdk/signing_sender.py,sha256=g5USdC86_HnL5t2oH2oyCqEevakcqdVhedML-ws4OEI,220 -smartystreets_python_sdk/static_credentials.py,sha256=BHx34sjh-QKqjGziAaYASFSblG0WpvEnAqNwz1BQe58,280 -smartystreets_python_sdk/status_code_sender.py,sha256=m3QhbF7u_bsA8j2ETQ1YUOJsD6SFy3zwYdOuLBOGv_U,2602 -smartystreets_python_sdk/url_prefix_sender.py,sha256=_NGjV9fNbaQI9zRfsVHpmIraXE0L6nC6AygNNbbsHS4,372 -smartystreets_python_sdk/us_autocomplete_pro/__init__.py,sha256=l4m1GmSshTs5jtUVwrGIwFZ0FaPUwjhPzOpgVg6udDs,89 -smartystreets_python_sdk/us_autocomplete_pro/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/__pycache__/geolocation_type.cpython-311.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/__pycache__/suggestion.cpython-311.pyc,, -smartystreets_python_sdk/us_autocomplete_pro/client.py,sha256=6emfu5NqeIgIEnAsLKDYuuCdgqWBCkdqgnVXqpP1cEM,2901 -smartystreets_python_sdk/us_autocomplete_pro/geolocation_type.py,sha256=Y3Dl2fYDyCnEZY6e39CV8v5iLFfdoo7y3BxkdXZBHCI,29 -smartystreets_python_sdk/us_autocomplete_pro/lookup.py,sha256=aDJ5Fhu8m2O6C_vmj8EzOVTDzPr3Hc576PEuRDsLzMo,4314 -smartystreets_python_sdk/us_autocomplete_pro/suggestion.py,sha256=eMr4BDL0XK5wwCIt1Ijt1RJVtDrKKCdnmZe-HAOb3xU,451 -smartystreets_python_sdk/us_enrichment/__init__.py,sha256=eWKzMA_YOl9rlbMi5Zmnnk_GVKTbQXH78MBBWfxCOKk,368 -smartystreets_python_sdk/us_enrichment/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/__pycache__/response.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/business/__init__.py,sha256=uAJgJDshudrPwGdGkU7E5KBYwLlSrzvkFiv0Kd0ReTQ,129 -smartystreets_python_sdk/us_enrichment/business/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/business/__pycache__/detail.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/business/__pycache__/summary.cpython-311.pyc,, -smartystreets_python_sdk/us_enrichment/business/detail.py,sha256=rLYUmEVOz1LegIoFYNDRhTehb7_5aKTJ7xJntXDz9Ws,14605 -smartystreets_python_sdk/us_enrichment/business/summary.py,sha256=4epCKRql0_HZ8SGIH06GmIj81sPu6eSo9aIV93tRptg,536 -smartystreets_python_sdk/us_enrichment/client.py,sha256=t3mBN3dfdpRtpM3hMnj_vK5nEm0UlgDgG2exrxMe_mU,6581 -smartystreets_python_sdk/us_enrichment/lookup.py,sha256=341lcUXgJs2Omk7QnztAeTArZ42CqKfGaAYbFKD-Lvg,2399 -smartystreets_python_sdk/us_enrichment/response.py,sha256=zqQBPMTFkYDJ-wI6iDt2bfz4aeHnTSGs7utnuLD_Hq0,62925 -smartystreets_python_sdk/us_extract/__init__.py,sha256=Fc_OZTtDwP5lE1HXFnbrcGXmEa6pNU4MJxvXlgAUuSU,141 -smartystreets_python_sdk/us_extract/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_extract/__pycache__/address.cpython-311.pyc,, -smartystreets_python_sdk/us_extract/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/us_extract/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/us_extract/__pycache__/metadata.cpython-311.pyc,, -smartystreets_python_sdk/us_extract/__pycache__/result.cpython-311.pyc,, -smartystreets_python_sdk/us_extract/address.py,sha256=vtMzxoocQGISehKm78Bzqm-hqif-o-_-P0OB-Q2AZO4,613 -smartystreets_python_sdk/us_extract/client.py,sha256=k4KMcFohAnMZ_hO-ciyC5rzoFmNMOgOZ-DuCb7uMoHg,2207 -smartystreets_python_sdk/us_extract/lookup.py,sha256=6xnVgkT_nbz5eGtZWYhorOH-_RbSAY1o7tX89bmuzbI,945 -smartystreets_python_sdk/us_extract/metadata.py,sha256=4j898o9Wp_QxCgGqVxGUkHn7Hm2Lb35lHQv98bZhfHo,478 -smartystreets_python_sdk/us_extract/result.py,sha256=yPnmrotiq5-DHU1x6FxRkpjo6KiACWpOrjG-U2eIrMw,619 -smartystreets_python_sdk/us_reverse_geo/__init__.py,sha256=ePdvUgk-y-6jTZzGmDPiyPgpi6u_dSmF5mWHJLXezD4,176 -smartystreets_python_sdk/us_reverse_geo/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/__pycache__/address.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/__pycache__/coordinate.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/__pycache__/response.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/__pycache__/result.cpython-311.pyc,, -smartystreets_python_sdk/us_reverse_geo/address.py,sha256=9ImBpoVsI-CSkntZsELiDwY3_FHhK0VLdmxLghe4RVs,451 -smartystreets_python_sdk/us_reverse_geo/client.py,sha256=gsGAaXsbkDPE9ma6gEilbhjO6FeSKfnVKmXEG-WXoQc,1406 -smartystreets_python_sdk/us_reverse_geo/coordinate.py,sha256=qlnkLnV3nsCP_5s91UoovBgdsmQHLxGmvrmHLFk1BqQ,507 -smartystreets_python_sdk/us_reverse_geo/lookup.py,sha256=4EwaqCpsBRAuUpVkN8gevTK7FVzGiJU34YJ8rvxgZhw,647 -smartystreets_python_sdk/us_reverse_geo/response.py,sha256=lyI8XRkzvnMFgvK7ndGj0GSzwOERChrw5FY3wBZl0ps,194 -smartystreets_python_sdk/us_reverse_geo/result.py,sha256=5sRFUwoJsBqMRmZ5JhqD_VBCv3kcLarXSYNV1A07aCc,379 -smartystreets_python_sdk/us_street/__init__.py,sha256=f_baQcNCWCTLwH9uGO_xsFPdfgK10gT7aA1sItGLCuA,185 -smartystreets_python_sdk/us_street/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/analysis.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/candidate.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/component_analysis.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/components.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/match_info.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/match_type.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/metadata.cpython-311.pyc,, -smartystreets_python_sdk/us_street/__pycache__/output_format.cpython-311.pyc,, -smartystreets_python_sdk/us_street/analysis.py,sha256=y4tnZ-K9acqWtfAKkkS7EaMDpJdNjY8Z-yTcmEgb3g4,1802 -smartystreets_python_sdk/us_street/candidate.py,sha256=O7YCz-rz3wu20pblQ0AnwaYeBLWhRIFkuQvMBGwAqFY,2284 -smartystreets_python_sdk/us_street/client.py,sha256=qSZo3Wv1wOGPqwpMVwwUbPAZdj8cfNFbPBKngsubnJ4,3780 -smartystreets_python_sdk/us_street/component_analysis.py,sha256=SCNHra9OGVR-DZmSDuRuE1t4Ff8ZLSbj1QSt-9JrMIQ,3162 -smartystreets_python_sdk/us_street/components.py,sha256=uG5UCNxcxeGvHtca9aixt2tk5LF7sXDne6yVB_t3nww,2630 -smartystreets_python_sdk/us_street/lookup.py,sha256=_PZhl9T-UBrsMQq-XFXefHzMn37mLDu7augUMYb9BeY,2245 -smartystreets_python_sdk/us_street/match_info.py,sha256=IlrotWKFgbU2Ea3_F4j2ttuv2-L4cQCtb323JGbQauE,428 -smartystreets_python_sdk/us_street/match_type.py,sha256=Y_MlddxylUgBmW_f20HmfEqoyJfp4TiVzaXxXEsTWG4,124 -smartystreets_python_sdk/us_street/metadata.py,sha256=VWlTYqfaeMlJeDvyjIGwS2ZV_dS0GZyBnlOhJ6mdu1o,2294 -smartystreets_python_sdk/us_street/output_format.py,sha256=YuFLP81dRw43gwae2CO28FE4z8zoH2GlzCEkJhJu4qQ,111 -smartystreets_python_sdk/us_zipcode/__init__.py,sha256=Yw0343wwUaSD0FTS5GfTEgsK3lsqr-1OqOX7KGLrCsc,179 -smartystreets_python_sdk/us_zipcode/__pycache__/__init__.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/__pycache__/alternate_county.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/__pycache__/city.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/__pycache__/client.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/__pycache__/lookup.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/__pycache__/result.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/__pycache__/zipcode.cpython-311.pyc,, -smartystreets_python_sdk/us_zipcode/alternate_county.py,sha256=j1ya-Dosx_ZbxBE9reTHK23meavitEsH2FpzIa5o-qE,353 -smartystreets_python_sdk/us_zipcode/city.py,sha256=0SAnjWOli2t38wsQSSb28JkdSTMWctWToMljeiIXYzw,411 -smartystreets_python_sdk/us_zipcode/client.py,sha256=9UJzNvk7BM3DC00wltIdmDyLA-0fHsSiguceES_jcDo,2205 -smartystreets_python_sdk/us_zipcode/lookup.py,sha256=SYlMExfKS9clDrDOdE7RX69XAUK3yjPeIIQ_gfBvXDQ,687 -smartystreets_python_sdk/us_zipcode/result.py,sha256=HZiLJ6xmJ6jdFwNCmBJDPA4uH5kNHIjpZ2Rj2cCw4Io,938 -smartystreets_python_sdk/us_zipcode/zipcode.py,sha256=gHJAv6nObkKi8hdcRgOgEfTOazEmXB6uAFr2rWhbqao,852 -smartystreets_python_sdk_version/__init__.py,sha256=eg7m4JO8kxAXocPAUQeVPe5xu-pqJTMYPbp39lRhkL4,122 -smartystreets_python_sdk_version/__pycache__/__init__.cpython-311.pyc,, diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/REQUESTED b/smarty/smartystreets_python_sdk-6.1.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/WHEEL b/smarty/smartystreets_python_sdk-6.1.0.dist-info/WHEEL deleted file mode 100644 index 14a883f..0000000 --- a/smarty/smartystreets_python_sdk-6.1.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.1) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md b/smarty/smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md deleted file mode 100644 index 6611688..0000000 --- a/smarty/smartystreets_python_sdk-6.1.0.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright Smarty - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/smarty/smartystreets_python_sdk-6.1.0.dist-info/top_level.txt b/smarty/smartystreets_python_sdk-6.1.0.dist-info/top_level.txt deleted file mode 100644 index 6368c2c..0000000 --- a/smarty/smartystreets_python_sdk-6.1.0.dist-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -smartystreets_python_sdk -smartystreets_python_sdk_version diff --git a/smarty/summary-0.1.1.dist-info/INSTALLER b/smarty/summary-0.1.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/smarty/summary-0.1.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/smarty/summary-0.1.1.dist-info/METADATA b/smarty/summary-0.1.1.dist-info/METADATA deleted file mode 100644 index 6e5a157..0000000 --- a/smarty/summary-0.1.1.dist-info/METADATA +++ /dev/null @@ -1,4 +0,0 @@ -Metadata-Version: 2.4 -Name: summary -Version: 0.1.1 -Requires-Python: >=3.11 diff --git a/smarty/summary-0.1.1.dist-info/RECORD b/smarty/summary-0.1.1.dist-info/RECORD deleted file mode 100644 index 8d225a2..0000000 --- a/smarty/summary-0.1.1.dist-info/RECORD +++ /dev/null @@ -1,8 +0,0 @@ -summary-0.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -summary-0.1.1.dist-info/METADATA,sha256=9Mg5Wfqx8ZZKN1ocbOMHLVFHjkI57VEikL72_CLCcoQ,75 -summary-0.1.1.dist-info/RECORD,, -summary-0.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -summary-0.1.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87 -summary-0.1.1.dist-info/direct_url.json,sha256=UJlmbmCY4U1o9Bziyx6pHpgHgEmbw4IYy26U87M4WOc,167 -summary/__init__.py,sha256=tjJJeQWDZxdkveUm75SzDW2MJKglFZw9GutEbBqwE5Y,2079 -summary/__pycache__/__init__.cpython-311.pyc,, diff --git a/smarty/summary-0.1.1.dist-info/REQUESTED b/smarty/summary-0.1.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/smarty/summary-0.1.1.dist-info/WHEEL b/smarty/summary-0.1.1.dist-info/WHEEL deleted file mode 100644 index b1b94fd..0000000 --- a/smarty/summary-0.1.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.29.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/smarty/summary-0.1.1.dist-info/direct_url.json b/smarty/summary-0.1.1.dist-info/direct_url.json deleted file mode 100644 index 25527dd..0000000 --- a/smarty/summary-0.1.1.dist-info/direct_url.json +++ /dev/null @@ -1 +0,0 @@ -{"url": "ssh://git@github.com/smarty/summary.git", "vcs_info": {"commit_id": "44aa0e7384920dcf2610c70162c287acc2754044", "requested_revision": "v0.1.1", "vcs": "git"}} \ No newline at end of file From 845116be0f74edb5b3f59cfacc90668ebe930fc2 Mon Sep 17 00:00:00 2001 From: Andy Johnson Date: Tue, 12 May 2026 14:14:17 -0600 Subject: [PATCH 11/11] Fixed make redeploy command. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d2df6ed..df3e576 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ deploy: cp -rf smarty "$(QGIS_PLUGINS_DIR)/smarty" redeploy: deploy - killall QGIS > /dev/null 2>&1 + killall QGIS > /dev/null 2>&1 || true open -a QGIS vendor: