├── MANIFEST.in ├── tests ├── fixtures │ ├── us-il-chicago │ │ ├── count-only.json │ │ └── metadata.json │ ├── us-fl-polk │ │ ├── us-fl-polk-count-only.json │ │ ├── us-fl-polk-ids-only.json │ │ ├── us-fl-polk-statistics.json │ │ └── us-fl-polk-0.json │ ├── us-mi-kent │ │ ├── us-mi-kent-count-only.json │ │ ├── us-mi-kent-ids-only.json │ │ ├── us-mi-kent-statistics.json │ │ ├── us-mi-kent-metadata.json │ │ └── us-mi-kent-0.json │ ├── us-ca-tuolumne │ │ ├── us-ca-tuolumne-count-only.json │ │ ├── us-ca-tuolumne-ids-only.json │ │ ├── us-ca-tuolumne-statistics.json │ │ ├── us-ca-tuolumne-metadata.json │ │ └── us-ca-tuolumne-0.json │ ├── us-esri-test │ │ ├── us-esri-test-count-only.json │ │ └── us-esri-test-ids-only.json │ ├── us-mo-columbia │ │ ├── us-mo-columbia-count-only.json │ │ ├── us-mo-columbia-ids-only.json │ │ ├── us-mo-columbia-metadata.json │ │ └── us-mo-columbia-0.json │ ├── us-ca-carson │ │ ├── us-ca-carson-count-only.json │ │ ├── us-ca-carson-ids-only.json │ │ ├── us-ca-carson-metadata.json │ │ └── us-ca-carson-0.json │ ├── us-ms-madison │ │ ├── us-ms-madison-count-only.json │ │ ├── us-ms-madison-ids-only.json │ │ ├── us-ms-madison-outStatistics.json │ │ ├── us-ms-madison-0.json │ │ └── us-ms-madison-metadata.json │ └── us-il-cook │ │ ├── page-partial.json │ │ └── metadata.json ├── test_cli.py ├── test_download.py └── test_esrijson.py ├── esridump ├── errors.py ├── __init__.py ├── esri2geojson.py ├── cli.py └── dumper.py ├── .bumpversion.cfg ├── Pipfile ├── .gitignore ├── RELEASING.md ├── setup.py ├── .github └── workflows │ ├── release.yml │ └── test.yml ├── LICENSE ├── README.md └── Pipfile.lock /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE 3 | -------------------------------------------------------------------------------- /tests/fixtures/us-il-chicago/count-only.json: -------------------------------------------------------------------------------- 1 | {"count":0} 2 | -------------------------------------------------------------------------------- /esridump/errors.py: -------------------------------------------------------------------------------- 1 | class EsriDownloadError(Exception): 2 | pass 3 | -------------------------------------------------------------------------------- /tests/fixtures/us-fl-polk/us-fl-polk-count-only.json: -------------------------------------------------------------------------------- 1 | {"count": 338142} -------------------------------------------------------------------------------- /tests/fixtures/us-mi-kent/us-mi-kent-count-only.json: -------------------------------------------------------------------------------- 1 | {"count":222460} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-ca-tuolumne/us-ca-tuolumne-count-only.json: -------------------------------------------------------------------------------- 1 | {"count":469} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-esri-test/us-esri-test-count-only.json: -------------------------------------------------------------------------------- 1 | {"count":312} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-mo-columbia/us-mo-columbia-count-only.json: -------------------------------------------------------------------------------- 1 | {"count":84296} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-ca-carson/us-ca-carson-count-only.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 30551 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/us-ms-madison/us-ms-madison-count-only.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 124 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/us-ms-madison/us-ms-madison-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIdFieldName":"OBJECTID","objectIds":[1]} -------------------------------------------------------------------------------- /esridump/__init__.py: -------------------------------------------------------------------------------- 1 | from esridump.esri2geojson import esri2geojson 2 | from esridump.dumper import EsriDumper 3 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 1.13.0 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | -------------------------------------------------------------------------------- /tests/fixtures/us-mi-kent/us-mi-kent-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIdFieldName":"OBJECTID","objectIds":[1,2,3,4,5,6,7,8,10,11,12,13,14,15,17]} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-mi-kent/us-mi-kent-statistics.json: -------------------------------------------------------------------------------- 1 | {"error":{"code":400,"message":"Unable to complete operation.","details":[]}} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-fl-polk/us-fl-polk-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIds": [3345100, 3345101, 3345102, 3345103, 3345104, 3345105, 3345106, 3345107, 3345108, 3345109]} -------------------------------------------------------------------------------- /tests/fixtures/us-ca-tuolumne/us-ca-tuolumne-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIds": [410106100009, 410106100019, 410106200003, 410105100002, 410104200011, 410104200031, 410104200024, 410103100027, 410102100014, 410102100024, 410106100035, 410106100017, 410105200061, 410105200045, 410106100030]} -------------------------------------------------------------------------------- /tests/fixtures/us-ms-madison/us-ms-madison-outStatistics.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"","fieldAliases":{"THE_MIN":"THE_MIN","THE_MAX":"THE_MAX"},"fields":[{"name":"THE_MIN","type":"esriFieldTypeDouble","alias":"THE_MIN"},{"name":"THE_MAX","type":"esriFieldTypeDouble","alias":"THE_MAX"}],"features":[{"attributes":{"THE_MIN":0,"THE_MAX":43}}]} 2 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.python.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | requests = "*" 8 | esridump = {editable = true, path = "."} 9 | 10 | [dev-packages] 11 | mock = "*" 12 | responses = "*" 13 | cookies = "*" 14 | bumpversion = "*" 15 | nose = "*" 16 | "autopep8" = "*" 17 | pytest = "*" 18 | -------------------------------------------------------------------------------- /tests/fixtures/us-fl-polk/us-fl-polk-statistics.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName": "", "fieldAliases": {"THE_MIN": "THE_MIN", "THE_MAX": "THE_MAX"}, "fields": [{"name": "THE_MIN", "type": "esriFieldTypeInteger", "alias": "THE_MIN"}, {"name": "THE_MAX", "type": "esriFieldTypeInteger", "alias": "THE_MAX"}], "features": [{"attributes": {"THE_MIN": 2335900, "THE_MAX": 2670953}}]} -------------------------------------------------------------------------------- /tests/fixtures/us-ca-tuolumne/us-ca-tuolumne-statistics.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"","fieldAliases":{"MIN(SHAPE.fid) AS THE_MIN":"MIN(SHAPE.fid) AS THE_MIN","MAX(SHAPE.fid) AS THE_MAX":"MAX(SHAPE.fid) AS THE_MAX"},"fields":[{"name":"MIN(SHAPE.fid) AS THE_MIN","type":"esriFieldTypeInteger","alias":"MIN(SHAPE.fid) AS THE_MIN"},{"name":"MAX(SHAPE.fid) AS THE_MAX","type":"esriFieldTypeInteger","alias":"MAX(SHAPE.fid) AS THE_MAX"}],"features":[{"attributes":{"MIN(SHAPE.fid) AS THE_MIN":1,"MAX(SHAPE.fid) AS THE_MAX":167}}]} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | .noseids 29 | nosetests.xml 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | .vscode 39 | -------------------------------------------------------------------------------- /tests/fixtures/us-mo-columbia/us-mo-columbia-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIdFieldName":"OBJECTID","objectIds":[6.4579816E7,6.4579817E7,6.4579818E7,6.4579819E7,6.457982E7,6.4579821E7,6.4579822E7,6.4579823E7,6.4579824E7,6.4579825E7,6.4579826E7,6.4579827E7,6.4579828E7,6.4579829E7,6.457983E7,6.4579831E7,6.4579832E7,6.4579833E7,6.4579834E7,6.4579835E7,6.4579836E7,6.4579837E7,6.4579838E7,6.4579839E7,6.457984E7,6.4579841E7,6.4579842E7,6.4579843E7,6.4579844E7,6.4579845E7,6.4579846E7,6.4579847E7,6.4579848E7,6.4579849E7,6.457985E7,6.4579851E7,6.4579852E7,6.4579853E7,6.4579854E7,6.4579855E7,6.4579856E7,6.4579857E7,6.4579858E7]} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-ca-carson/us-ca-carson-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIdFieldName":"OBJECTID","objectIds":[70193,70194,70195,70196,70197,70198,70199,70200,70201,70202,70203,70204,70205,70206,70207,70208,70209,70210,70211,70212,70213,70214,70215,70216,70217,70218,70219,70220,70223,70224,70225,70226,70227,70228,70229,70230,70231,70232,70233,70234,70237,70238,70239,70241,70242,70243,70244,70245,70246,70247,70252,70254,70255,70256,70258,70259,70260,70261,70262,70263,70264,70265,70266,70267,70270,70271,70272,70273,70274,70275,70276,70277,70278,70279,70280,70281,70282,70283,70284,70285,70286,70287,70288,70289,70290,70291,70292,70293,70294,70295,70296,70297,70298,70300,70301,70302,70303,70304,70305,70307]} 2 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | Deploying 2 | ========= 3 | 4 | 0. Make sure you've merged all the pull requests you care to include in this release and ensure you're on the `master` branch. 5 | 6 | ``` 7 | git checkout master 8 | ``` 9 | 10 | 1. Use `bumpversion` to increment the version number. This will generate a tag and a commit. 11 | 12 | ``` 13 | bumpversion minor 14 | ``` 15 | 16 | 2. Push the tag and commit to GitHub so everyone can see it. 17 | 18 | ``` 19 | git push origin master 20 | ``` 21 | 22 | 3. Pushing the tag will trigger a GitHub Action process that will send the tag to pypi. 23 | 24 | ``` 25 | git push --tags 26 | ``` 27 | 28 | 4. Done! 29 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup, find_packages 4 | 5 | 6 | with open('README.md') as f: 7 | readme = f.read() 8 | 9 | setup( 10 | name='esridump', 11 | version='1.13.0', 12 | description='Dump geodata from ESRI endpoints to GeoJSON', 13 | long_description=readme, 14 | long_description_content_type='text/markdown', 15 | author='Ian Dees', 16 | author_email='ian.dees@gmail.com', 17 | url='https://github.com/openaddresses/pyesridump', 18 | license='MIT', 19 | packages=find_packages(exclude=('tests', 'docs')), 20 | install_requires=[ 21 | 'requests', 22 | 'six', 23 | ], 24 | entry_points={ 25 | 'console_scripts': ['esri2geojson=esridump.cli:main'], 26 | } 27 | ) 28 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Set up Python 18 | uses: actions/setup-python@v3 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install build 25 | - name: Build package 26 | run: python -m build 27 | - name: Publish package 28 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 29 | with: 30 | user: __token__ 31 | password: ${{ secrets.PYPI_API_TOKEN }} 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 OSM Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Set up Python 13 | uses: actions/setup-python@v3 14 | with: 15 | python-version: "3.x" 16 | 17 | - name: Install pipenv 18 | run: | 19 | python -m pip install --upgrade pipenv wheel flake8 20 | 21 | - id: cache-pipenv 22 | uses: actions/cache@v1 23 | with: 24 | path: ~/.local/share/virtualenvs 25 | key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} 26 | 27 | - name: Install dependencies 28 | if: steps.cache-pipenv.outputs.cache-hit != 'true' 29 | run: | 30 | pipenv install --deploy --dev 31 | 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | 39 | - name: Test with pytest 40 | run: | 41 | pipenv run pytest 42 | -------------------------------------------------------------------------------- /tests/fixtures/us-il-cook/page-partial.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"NAME","fieldAliases":{"NAME":"Name","OBJECTID":"OBJECTID","ID":"ID","ADDRESS":"Address","LOW_CROSS":"LOW_CROSS","HIGH_CROSS":"HIGH_CROSS","RESPONSE":"RESPONSE","MESSAGE":"MESSAGE","SECURITY":"SECURITY","CITY_ID":"City","POLICE_ID":"POLICE_ID","FIRE_ID":"FIRE_ID","EMS_ID":"EMS_ID","MAP_PAGE_I":"MAP_PAGE_I","REPORT_DIS":"REPORT_DIS","LAST_EDIT":"LAST_EDIT","EDITOR":"EDITOR","TOW_ID":"TOW_ID","TYPE":"TYPE","MAP":"MAP","ALIAS_NAME":"ALIAS_NAME","ID2":"ID2","ADDRESS_ER":"ADDRESS_ER","FOREST_PRE":"FOREST_PRE","STYLE_ID":"STYLE_ID","COOK_LAW_I":"COOK_LAW_I","ATMLABEL":"ATMLABEL","LABEL_ANGL":"LABEL_ANGL","LABEL_X":"LABEL_X","LABEL_Y":"LABEL_Y","FONT_ID":"FONT_ID"},"geometryType":"esriGeometryPoint","spatialReference":{"wkid":4326},"features":[{"attributes":{"NAME":"SYLVAN WOODS","OBJECTID":2196,"ID":1000524,"ADDRESS":"CEDAR RD/135TH ST","LOW_CROSS":" ","HIGH_CROSS":" ","RESPONSE":" ","MESSAGE":0,"SECURITY":" ","CITY_ID":"LEMONT TWP","POLICE_ID":"DCM6","FIRE_ID":"88","EMS_ID":" ","MAP_PAGE_I":" ","REPORT_DIS":"2234","LAST_EDIT":"4/21/2006 12:00:00 AM","EDITOR":"LJK","TOW_ID":" ","TYPE":" ","MAP":" ","ALIAS_NAME":" ","ID2":0,"ADDRESS_ER":" ","FOREST_PRE":"99","STYLE_ID":" ","COOK_LAW_I":"44","ATMLABEL":" ","LABEL_ANGL":0,"LABEL_X":0,"LABEL_Y":0,"FONT_ID":" "},"geometry":{"x":-87.969739519,"y":41.6429841820001}},{"attributes":{"NAME":"SIDE TRACKED","OBJECTID":3442,"ID":6000819,"ADDRESS":"11100 ARCHER AVE","LOW_CROSS":" ","HIGH_CROSS":" ","RESPONSE":" ","MESSAGE":0,"SECURITY":" ","CITY_ID":"LEMONT TWP","POLICE_ID":"DCM6","FIRE_ID":"54","EMS_ID":" ","MAP_PAGE_I":" ","REPORT_DIS":"2232","LAST_EDIT":"3/2/1999 12:00:00 AM","EDITOR":"GGM","TOW_ID":" ","TYPE":"Liquor","MAP":" ","ALIAS_NAME":" ","ID2":0,"ADDRESS_ER":" ","FOREST_PRE":"99","STYLE_ID":" ","COOK_LAW_I":"44","ATMLABEL":" ","LABEL_ANGL":0,"LABEL_X":0,"LABEL_Y":0,"FONT_ID":" "},"geometry":{"x":-87.9982473539999,"y":41.645235567}}]} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-il-cook/metadata.json: -------------------------------------------------------------------------------- 1 | {"id":11,"name":"Point of Interest","type":"Feature Layer","geometryType":"esriGeometryPoint","description":"","definitionExpression":"","copyrightText":"","minScale":35000,"maxScale":0,"extent":{"xmin":1003477.096,"ymin":1749983.277,"xmax":1324820.8775,"ymax":2004197.31125,"spatialReference":{"wkid":3435}},"displayField":"NAME","fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID"},{"name":"ID","type":"esriFieldTypeDouble","alias":"ID"},{"name":"NAME","type":"esriFieldTypeString","alias":"Name"},{"name":"ADDRESS","type":"esriFieldTypeString","alias":"Address"},{"name":"LOW_CROSS","type":"esriFieldTypeString","alias":"LOW_CROSS"},{"name":"HIGH_CROSS","type":"esriFieldTypeString","alias":"HIGH_CROSS"},{"name":"RESPONSE","type":"esriFieldTypeString","alias":"RESPONSE"},{"name":"MESSAGE","type":"esriFieldTypeDouble","alias":"MESSAGE"},{"name":"SECURITY","type":"esriFieldTypeString","alias":"SECURITY"},{"name":"CITY_ID","type":"esriFieldTypeString","alias":"City"},{"name":"POLICE_ID","type":"esriFieldTypeString","alias":"POLICE_ID"},{"name":"FIRE_ID","type":"esriFieldTypeString","alias":"FIRE_ID"},{"name":"EMS_ID","type":"esriFieldTypeString","alias":"EMS_ID"},{"name":"MAP_PAGE_I","type":"esriFieldTypeString","alias":"MAP_PAGE_I"},{"name":"REPORT_DIS","type":"esriFieldTypeString","alias":"REPORT_DIS"},{"name":"LAST_EDIT","type":"esriFieldTypeDate","alias":"LAST_EDIT"},{"name":"EDITOR","type":"esriFieldTypeString","alias":"EDITOR"},{"name":"TOW_ID","type":"esriFieldTypeString","alias":"TOW_ID"},{"name":"TYPE","type":"esriFieldTypeString","alias":"TYPE"},{"name":"MAP","type":"esriFieldTypeString","alias":"MAP"},{"name":"ALIAS_NAME","type":"esriFieldTypeString","alias":"ALIAS_NAME"},{"name":"ID2","type":"esriFieldTypeDouble","alias":"ID2"},{"name":"ADDRESS_ER","type":"esriFieldTypeString","alias":"ADDRESS_ER"},{"name":"FOREST_PRE","type":"esriFieldTypeString","alias":"FOREST_PRE"},{"name":"STYLE_ID","type":"esriFieldTypeString","alias":"STYLE_ID"},{"name":"COOK_LAW_I","type":"esriFieldTypeString","alias":"COOK_LAW_I"},{"name":"ATMLABEL","type":"esriFieldTypeString","alias":"ATMLABEL"},{"name":"LABEL_ANGL","type":"esriFieldTypeDouble","alias":"LABEL_ANGL"},{"name":"LABEL_X","type":"esriFieldTypeDouble","alias":"LABEL_X"},{"name":"LABEL_Y","type":"esriFieldTypeDouble","alias":"LABEL_Y"},{"name":"FONT_ID","type":"esriFieldTypeString","alias":"FONT_ID"},{"name":"SHAPE","type":"esriFieldTypeGeometry","alias":"Shape"}],"parentLayer":null,"subLayers":[]} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-ca-carson/us-ca-carson-metadata.json: -------------------------------------------------------------------------------- 1 | {"currentVersion":10.0,"id":1,"name":"Address Points","type":"Feature Layer","description":"","definitionExpression":"","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":null,"subLayers":[],"minScale":4000,"maxScale":0,"defaultVisibility":false,"extent":{"xmin":6474022.25324975,"ymin":1748978.69257216,"xmax":6499010.09933418,"ymax":1780987.81360582,"spatialReference":{"wkid":2229}},"hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeNone","drawingInfo":{"renderer":{"type":"simple","symbol":{"type":"esriPMS","url":"DDB48031","imageData":"iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAC1JREFUCJljYSjxTWdgZOJkQALsjP9OsjD8Z2hlYPgnjCzB8O9fKwsDDkBFCQDVowgyJIfu/AAAAABJRU5ErkJggg==","contentType":"image/png","color" : null,"width":4,"height":4,"angle":0,"xoffset":0,"yoffset":0},"label":"","description":""},"transparency":0,"labelingInfo":[{"labelPlacement":"esriServerPointLabelPlacementCenterCenter","labelExpression":"[SITENUMBER]","useCodedValues":true,"symbol":{"type":"esriTS","color":[0,115,76,255],"backgroundColor" : null,"borderLineColor" : null,"verticalAlignment":"bottom","horizontalAlignment":"center","rightToLeft":false,"angle":0,"xoffset":0,"yoffset":0,"font":{"family":"Arial","size":8,"style":"normal","weight":"bold","decoration":"none"}},"minScale":2000,"maxScale":0}]},"displayField":"STREETNAME","fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID"},{"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape"},{"name":"SITENUMBER","type":"esriFieldTypeString","alias":"SITENUMBER","length":13},{"name":"SITEFRAC","type":"esriFieldTypeString","alias":"SITEFRAC","length":10},{"name":"SITEPREF","type":"esriFieldTypeString","alias":"SITEPREF","length":4},{"name":"SITESTREET","type":"esriFieldTypeString","alias":"SITESTREET","length":25},{"name":"SITEUNIT","type":"esriFieldTypeString","alias":"SITEUNIT","length":8},{"name":"SITECITY","type":"esriFieldTypeString","alias":"SITECITY","length":14},{"name":"SITEZIP","type":"esriFieldTypeString","alias":"SITEZIP","length":10},{"name":"STREETNAME","type":"esriFieldTypeString","alias":"STREETNAME","length":70},{"name":"STREETTYPE","type":"esriFieldTypeString","alias":"STREETTYPE","length":70},{"name":"TYPE","type":"esriFieldTypeString","alias":"TYPE","length":5},{"name":"ADDRESS","type":"esriFieldTypeString","alias":"ADDRESS","length":50},{"name":"VACANT","type":"esriFieldTypeString","alias":"VACANT","length":5},{"name":"RES_BUS","type":"esriFieldTypeString","alias":"RES_BUS","length":10},{"name":"Field_Chec","type":"esriFieldTypeString","alias":"Field_Chec","length":25},{"name":"Need_Check","type":"esriFieldTypeString","alias":"Need_Check","length":10},{"name":"Comments","type":"esriFieldTypeString","alias":"Comments","length":50},{"name":"Edit_Date","type":"esriFieldTypeDate","alias":"Edit_Date","length":8}],"typeIdField" : null,"types" : null,"relationships":[],"capabilities":"Map,Query,Data"} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-mo-columbia/us-mo-columbia-metadata.json: -------------------------------------------------------------------------------- 1 | {"currentVersion":10.01,"id":2,"name":"city.COLUMBIA.addresses","type":"Feature Layer","description":"","definitionExpression":"","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":null,"subLayers":[],"minScale":0,"maxScale":0,"drawingInfo":{"renderer":{"type":"simple","symbol":{"type":"esriSMS","style":"esriSMSCircle","color":[171,54,0,255],"size":4,"angle":0,"xoffset":0,"yoffset":0,"outline":{"color":[0,0,0,255],"width":1}},"label":"","description":""},"transparency":0,"labelingInfo":null},"defaultVisibility":true,"extent":{"xmin":1620818.7939999998,"ymin":1027740.6027999967,"xmax":1752279.9814000018,"ymax":1242953.810999997,"spatialReference":{"wkid":102697}},"hasAttachments":false,"htmlPopupType":null,"displayField":"PRE_DIR","typeIdField":null,"fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null},{"name":"HOUSENO","type":"esriFieldTypeInteger","alias":"HOUSENO","domain":null},{"name":"PRE_DIR","type":"esriFieldTypeString","alias":"PRE_DIR","length":1,"domain":null},{"name":"SUFFIX","type":"esriFieldTypeString","alias":"SUFFIX","length":11,"domain":null},{"name":"POST_DIR","type":"esriFieldTypeString","alias":"POST_DIR","length":1,"domain":null},{"name":"POST_QUAL","type":"esriFieldTypeString","alias":"POST_QUAL","length":10,"domain":null},{"name":"APT","type":"esriFieldTypeString","alias":"APT","length":17,"domain":null},{"name":"CITY_LIMIT","type":"esriFieldTypeString","alias":"CITY_LIMIT","length":2,"domain":null},{"name":"ACCURACY","type":"esriFieldTypeString","alias":"ACCURACY","length":10,"domain":null},{"name":"ASSESSOR","type":"esriFieldTypeString","alias":"ASSESSOR","length":16,"domain":null},{"name":"PRE_QUAL","type":"esriFieldTypeString","alias":"PRE_QUAL","length":10,"domain":null},{"name":"XCOORD","type":"esriFieldTypeDouble","alias":"XCOORD","domain":null},{"name":"YCOORD","type":"esriFieldTypeDouble","alias":"YCOORD","domain":null},{"name":"STREET","type":"esriFieldTypeString","alias":"STREET","length":35,"domain":null},{"name":"HISTORY","type":"esriFieldTypeString","alias":"HISTORY","length":35,"domain":null},{"name":"ZIP","type":"esriFieldTypeString","alias":"ZIP","length":8,"domain":null},{"name":"NOTES","type":"esriFieldTypeString","alias":"NOTES","length":35,"domain":null},{"name":"CITY","type":"esriFieldTypeString","alias":"CITY","length":35,"domain":null},{"name":"DRIVEWAY_NUM","type":"esriFieldTypeInteger","alias":"DRIVEWAY_NUM","domain":null},{"name":"ADDRESS_NUM","type":"esriFieldTypeInteger","alias":"ADDRESS_NUM","domain":null},{"name":"X","type":"esriFieldTypeDouble","alias":"X","domain":null},{"name":"Y","type":"esriFieldTypeDouble","alias":"Y","domain":null},{"name":"Z","type":"esriFieldTypeString","alias":"Z","length":8,"domain":null},{"name":"EDIT_CODE","type":"esriFieldTypeString","alias":"EDIT_CODE","length":15,"domain":null},{"name":"ALIAS","type":"esriFieldTypeString","alias":"ALIAS","length":45,"domain":null},{"name":"GlobalID","type":"esriFieldTypeGUID","alias":"GlobalID","length":38,"domain":null},{"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape","domain":null}],"types":null,"relationships":[],"capabilities":"Map,Query,Data"} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-ca-tuolumne/us-ca-tuolumne-metadata.json: -------------------------------------------------------------------------------- 1 | {"currentVersion":10.11,"id":0,"name":"Parcel Addresses","type":"Feature Layer","description":"","definitionExpression":"","geometryType":"esriGeometryPolygon","copyrightText":"","parentLayer":null,"subLayers":[],"minScale":6001,"maxScale":0,"drawingInfo":{"renderer":{"type":"simple","symbol":{"type":"esriSFS","style":"esriSFSSolid","color":[0,0,0,0],"outline":{"type":"esriSLS","style":"esriSLSSolid","color":[0,0,0,0],"width":0.4}},"label":"","description":""},"transparency":0,"labelingInfo":[{"labelPlacement":"esriServerPolygonPlacementAlwaysHorizontal","where":null,"labelExpression":"[address]","useCodedValues":true,"symbol":{"type":"esriTS","color":[0,0,0,255],"backgroundColor":null,"borderLineColor":null,"borderLineSize":null,"verticalAlignment":"bottom","horizontalAlignment":"left","rightToLeft":false,"angle":0,"xoffset":0,"yoffset":0,"kerning":true,"haloColor":[255,255,255,255],"haloSize":1,"font":{"family":"Arial","size":7,"style":"normal","weight":"normal","decoration":"none"}},"minScale":6001,"maxScale":0}]},"defaultVisibility":true,"extent":{"xmin":6517178.499594241,"ymin":2053819.5679192394,"xmax":6941848.0014297515,"ymax":2347684.7501449287,"spatialReference":{"wkid":102643,"latestWkid":2227}},"hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText","displayField":"STREET_NAME","typeIdField":null,"fields":[{"name":"O_ID","type":"esriFieldTypeInteger","alias":"O_ID","domain":null},{"name":"SHAPE","type":"esriFieldTypeGeometry","alias":"SHAPE","domain":null},{"name":"PREFIX","type":"esriFieldTypeString","alias":"PREFIX","length":8,"domain":null},{"name":"SUFFIX","type":"esriFieldTypeString","alias":"SUFFIX","length":2,"domain":null},{"name":"ZONING","type":"esriFieldTypeString","alias":"ZONING","length":50,"domain":null},{"name":"REF2","type":"esriFieldTypeString","alias":"REF2","length":100,"domain":null},{"name":"ORDINANCE","type":"esriFieldTypeString","alias":"ORDINANCE","length":50,"domain":null},{"name":"ORD","type":"esriFieldTypeString","alias":"ORD","length":70,"domain":null},{"name":"usecode","type":"esriFieldTypeString","alias":"usecode","length":2,"domain":null},{"name":"parcel_type","type":"esriFieldTypeString","alias":"parcel_type","length":2,"domain":null},{"name":"TRA","type":"esriFieldTypeString","alias":"TRA","length":6,"domain":null},{"name":"owner1","type":"esriFieldTypeString","alias":"owner1","length":30,"domain":null},{"name":"owner2","type":"esriFieldTypeString","alias":"owner2","length":30,"domain":null},{"name":"MAIL_ADDR","type":"esriFieldTypeString","alias":"MAIL_ADDR","length":30,"domain":null},{"name":"mail_cityst","type":"esriFieldTypeString","alias":"mail_cityst","length":30,"domain":null},{"name":"mail_zip","type":"esriFieldTypeString","alias":"mail_zip","length":10,"domain":null},{"name":"legal_desc","type":"esriFieldTypeString","alias":"legal_desc","length":65,"domain":null},{"name":"acreage","type":"esriFieldTypeDouble","alias":"acreage","domain":null},{"name":"num_units","type":"esriFieldTypeInteger","alias":"num_units","domain":null},{"name":"O_ID2","type":"esriFieldTypeInteger","alias":"O_ID2","domain":null},{"name":"address","type":"esriFieldTypeString","alias":"address","length":60,"domain":null},{"name":"HOUSE_NUM","type":"esriFieldTypeInteger","alias":"HOUSE_NUM","domain":null},{"name":"STREET_NAME","type":"esriFieldTypeString","alias":"STREET_NAME","length":100,"domain":null},{"name":"zip_city","type":"esriFieldTypeString","alias":"zip_city","length":50,"domain":null},{"name":"zip_code","type":"esriFieldTypeString","alias":"zip_code","length":5,"domain":null},{"name":"SHAPE.area","type":"esriFieldTypeDouble","alias":"SHAPE.area","domain":null},{"name":"SHAPE.len","type":"esriFieldTypeDouble","alias":"SHAPE.len","domain":null},{"name":"SHAPE.fid","type":"esriFieldTypeOID","alias":"SHAPE.fid","domain":null}],"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":true,"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF","ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true}} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-mi-kent/us-mi-kent-metadata.json: -------------------------------------------------------------------------------- 1 | {"currentVersion":10.22,"id":5,"name":"Parcels","type":"Feature Layer","description":"","geometryType":"esriGeometryPolygon","copyrightText":"","parentLayer":null,"subLayers":[],"minScale":20000,"maxScale":0,"drawingInfo":{"renderer":{"type":"simple","symbol":{"type":"esriSFS","style":"esriSFSSolid","color":[0,0,0,0],"outline":{"type":"esriSLS","style":"esriSLSSolid","color":[230,230,0,255],"width":1}},"label":"","description":""},"transparency":0,"labelingInfo":[{"labelPlacement":"esriServerPolygonPlacementAlwaysHorizontal","where":"INROW_FLAG = 'No'","labelExpression":"[PROPADDRESSNUMBER]","useCodedValues":true,"symbol":{"type":"esriTS","color":[0,0,0,255],"backgroundColor":null,"borderLineColor":null,"borderLineSize":null,"verticalAlignment":"bottom","horizontalAlignment":"center","rightToLeft":false,"angle":0,"xoffset":0,"yoffset":0,"kerning":true,"haloColor":[230,230,0,255],"haloSize":1.5,"font":{"family":"Arial","size":7,"style":"normal","weight":"normal","decoration":"none"}},"minScale":1641,"maxScale":821},{"labelPlacement":"esriServerPolygonPlacementAlwaysHorizontal","where":"INROW_FLAG = 'No'","labelExpression":"[PROPADDRESSNUMBER] CONCAT \" \" CONCAT [PROPADDSTREET]","useCodedValues":true,"symbol":{"type":"esriTS","color":[0,0,0,255],"backgroundColor":null,"borderLineColor":null,"borderLineSize":null,"verticalAlignment":"bottom","horizontalAlignment":"center","rightToLeft":false,"angle":0,"xoffset":0,"yoffset":0,"kerning":true,"haloColor":[230,230,0,255],"haloSize":1.5,"font":{"family":"Arial","size":7,"style":"normal","weight":"normal","decoration":"none"}},"minScale":821,"maxScale":0}]},"defaultVisibility":true,"extent":{"xmin":1.2743225073103264E7,"ymin":464184.2463259846,"xmax":1.287163029313019E7,"ymax":656630.4869274348,"spatialReference":{"wkt":"PROJCS[\"NAD_1983_StatePlane_Michigan_South_FIPS_2113_IntlFeet\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Lambert_Conformal_Conic\"],PARAMETER[\"False_Easting\",13123359.58005249],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-84.36666666666666],PARAMETER[\"Standard_Parallel_1\",42.1],PARAMETER[\"Standard_Parallel_2\",43.66666666666666],PARAMETER[\"Latitude_Of_Origin\",41.5],UNIT[\"Foot\",0.3048]]"}},"hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeNone","displayField":"PPN","typeIdField":null,"fields":[{"name":"PPN","type":"esriFieldTypeDouble","alias":"PPN","domain":null},{"name":"PNUM","type":"esriFieldTypeString","alias":"PNUM","length":16,"domain":null},{"name":"OWNERNAME1","type":"esriFieldTypeString","alias":"Owner Name","length":35,"domain":null},{"name":"OWNERNAME2","type":"esriFieldTypeString","alias":"Owner Name 2","length":35,"domain":null},{"name":"PROPERTYADDRESS","type":"esriFieldTypeString","alias":"Property Address","length":33,"domain":null},{"name":"PROPADDRESSCITY","type":"esriFieldTypeString","alias":"Property City","length":25,"domain":null},{"name":"PROPADDRESSSTATE_ZIPCODE","type":"esriFieldTypeString","alias":"Property State Zip Code","length":25,"domain":null},{"name":"SEVTRIBUNAL1","type":"esriFieldTypeDouble","alias":"SEV","domain":null},{"name":"TAXABLETRIBUNAL1","type":"esriFieldTypeDouble","alias":"Taxable Value","domain":null},{"name":"PROPADDRESSNUMBER","type":"esriFieldTypeString","alias":"House Number","length":5,"domain":null},{"name":"PROPADDSTREET","type":"esriFieldTypeString","alias":"Street","length":27,"domain":null},{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null},{"name":"SHAPE","type":"esriFieldTypeGeometry","alias":"SHAPE","domain":null},{"name":"SHAPE.STArea()","type":"esriFieldTypeDouble","alias":"SHAPE.STArea()","domain":null},{"name":"SHAPE.STLength()","type":"esriFieldTypeDouble","alias":"SHAPE.STLength()","domain":null}],"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":true,"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF","ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true} 2 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import mock 3 | import os 4 | import re 5 | import responses 6 | import unittest 7 | 8 | import esridump.cli 9 | 10 | class TestEsriDumpCommandlineHelpers(unittest.TestCase): 11 | def test_collect_headers(self): 12 | self.assertDictEqual( 13 | esridump.cli._collect_headers(['Content-Type: application/json']), 14 | { 15 | "Content-Type": "application/json" 16 | } 17 | ) 18 | 19 | def test_collect_params(self): 20 | self.assertDictEqual( 21 | esridump.cli._collect_params(['outFields=PIN14']), 22 | { 23 | "outFields": "PIN14" 24 | } 25 | ) 26 | 27 | 28 | class TestEsriDumpCommandlineMain(unittest.TestCase): 29 | def setUp(self): 30 | self.responses = responses.RequestsMock() 31 | self.responses.start() 32 | 33 | self.add_fixture_response( 34 | '.*f=json.*', 35 | 'us-ca-carson/us-ca-carson-metadata.json', 36 | method='GET', 37 | ) 38 | self.add_fixture_response( 39 | '.*returnCountOnly=true.*', 40 | 'us-ca-carson/us-ca-carson-count-only.json', 41 | method='GET', 42 | ) 43 | self.add_fixture_response( 44 | '.*returnIdsOnly=true.*', 45 | 'us-ca-carson/us-ca-carson-ids-only.json', 46 | method='GET', 47 | ) 48 | self.add_fixture_response( 49 | '.*query.*', 50 | 'us-ca-carson/us-ca-carson-0.json', 51 | method='POST', 52 | ) 53 | 54 | self.patcher = mock.patch('esridump.cli._parse_args') 55 | self.mock_parseargs = self.patcher.start() 56 | self.mock_outfile = mock.MagicMock() 57 | self.parse_return = mock.MagicMock() 58 | self.parse_return.url = 'http://example.com' 59 | self.parse_return.outfile = self.mock_outfile 60 | self.parse_return.max_page_size = 1000 61 | self.parse_return.loglevel = logging.ERROR 62 | self.parse_return.jsonlines = False 63 | self.parse_return.fields = None 64 | self.parse_return.request_geometry = True 65 | self.parse_return.headers = [] 66 | self.parse_return.params = [] 67 | self.parse_return.proxy = None 68 | self.parse_return.output_format = 'geojson' 69 | self.mock_parseargs.return_value = self.parse_return 70 | 71 | self.fake_url = 'http://example.com' 72 | 73 | def tearDown(self): 74 | self.patcher.stop() 75 | self.responses.stop(allow_assert=False) 76 | self.responses.reset() 77 | 78 | def add_fixture_response(self, url_re, file, method='POST', **kwargs): 79 | with open(os.path.join('tests/fixtures', file), 'r') as f: 80 | self.responses.add( 81 | method=method, 82 | url=re.compile(url_re), 83 | body=f.read(), 84 | match_querystring=True, 85 | **kwargs 86 | ) 87 | 88 | def test_cli_simple(self): 89 | esridump.cli.main() 90 | 91 | # Make sure it has the FeatureCollection "header" and footer 92 | self.mock_outfile.write.assert_any_call('{"type":"FeatureCollection","features":[\n') 93 | self.mock_outfile.write.assert_any_call(']}') 94 | self.assertEqual(self.mock_outfile.write.call_count, 14) 95 | 96 | def test_cli_jsonlines(self): 97 | self.parse_return.jsonlines = True 98 | 99 | esridump.cli.main() 100 | 101 | # jsonlines won't have FeatureCollection wrapper 102 | self.assertEqual(self.mock_outfile.write.call_count, 12) 103 | 104 | def test_cli_override_where(self): 105 | self.parse_return.params = ['where=foo=bar'] 106 | 107 | esridump.cli.main() 108 | 109 | self.assertIn('where=foo%3Dbar', self.responses.calls[2].request.url) 110 | self.assertIn('where=%28OBJECTID+%3E%3D+70193+AND+OBJECTID+%3C%3D+70307%29+AND+%28foo%3Dbar%29', self.responses.calls[3].request.body) 111 | self.assertEqual(self.mock_outfile.write.call_count, 14) 112 | -------------------------------------------------------------------------------- /tests/fixtures/us-il-chicago/metadata.json: -------------------------------------------------------------------------------- 1 | {"currentVersion":10.81,"id":28,"name":"Census Designated Places","type":"Feature Layer","description":"Census Designated Places; ACS 2017 - January 1, 2017 vintage","geometryType":"esriGeometryPolygon","sourceSpatialReference":{"wkid":102100,"latestWkid":3857},"copyrightText":"Source: U.S. Census Bureau","parentLayer":null,"subLayers":[],"minScale":1400000,"maxScale":100.00000000673367,"drawingInfo":{"renderer":{"type":"simple","symbol":{"type":"esriSFS","style":"esriSFSSolid","color":[0,0,0,0],"outline":{"type":"esriSLS","style":"esriSLSSolid","color":[230,161,138,255],"width":0.75}},"label":"","description":""},"transparency":15,"labelingInfo":null},"defaultVisibility":false,"extent":{"xmin":-19707613.1476,"ymin":-1633572.792,"xmax":19352664.3864,"ymax":11569901.304,"spatialReference":{"wkid":102100,"latestWkid":3857}},"hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeNone","displayField":"BASENAME","typeIdField":null,"subtypeFieldName":null,"subtypeField":null,"defaultSubtypeCode":null,"fields":[{"name":"MTFCC","type":"esriFieldTypeString","alias":"MTFCC","length":5,"domain":null},{"name":"OID","type":"esriFieldTypeString","alias":"OID","length":22,"domain":null},{"name":"GEOID","type":"esriFieldTypeString","alias":"GEOID","length":7,"domain":null},{"name":"STATE","type":"esriFieldTypeString","alias":"STATE","length":2,"domain":null},{"name":"PLACE","type":"esriFieldTypeString","alias":"PLACE","length":5,"domain":null},{"name":"BASENAME","type":"esriFieldTypeString","alias":"BASENAME","length":100,"domain":null},{"name":"NAME","type":"esriFieldTypeString","alias":"NAME","length":100,"domain":null},{"name":"LSADC","type":"esriFieldTypeString","alias":"LSADC","length":2,"domain":null},{"name":"FUNCSTAT","type":"esriFieldTypeString","alias":"FUNCSTAT","length":1,"domain":null},{"name":"PLACECC","type":"esriFieldTypeString","alias":"PLACECC","length":2,"domain":null},{"name":"AREALAND","type":"esriFieldTypeDouble","alias":"AREALAND","domain":null},{"name":"AREAWATER","type":"esriFieldTypeDouble","alias":"AREAWATER","domain":null},{"name":"CBSAPCI","type":"esriFieldTypeString","alias":"CBSAPCI","length":1,"domain":null},{"name":"NECTAPCI","type":"esriFieldTypeString","alias":"NECTAPCI","length":1,"domain":null},{"name":"STGEOMETRY","type":"esriFieldTypeGeometry","alias":"STGEOMETRY","domain":null},{"name":"CENTLAT","type":"esriFieldTypeString","alias":"CENTLAT","length":11,"domain":null},{"name":"CENTLON","type":"esriFieldTypeString","alias":"CENTLON","length":12,"domain":null},{"name":"INTPTLAT","type":"esriFieldTypeString","alias":"INTPTLAT","length":11,"domain":null},{"name":"INTPTLON","type":"esriFieldTypeString","alias":"INTPTLON","length":12,"domain":null},{"name":"PLACENS","type":"esriFieldTypeString","alias":"PLACENS","length":8,"domain":null},{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null}],"geometryField":{"name":"STGEOMETRY","type":"esriFieldTypeGeometry","alias":"STGEOMETRY"},"indexes":[{"name":"PLACE_57_BASENAME","fields":"BASENAME","isAscending":true,"isUnique":false,"description":""},{"name":"PLACE_57_GEOID","fields":"GEOID","isAscending":true,"isUnique":false,"description":""},{"name":"PLACE_57_LSADC","fields":"LSADC","isAscending":true,"isUnique":false,"description":""},{"name":"PLACE_57_MTFCC","fields":"MTFCC","isAscending":true,"isUnique":false,"description":""},{"name":"PLACE_57_OID","fields":"OID","isAscending":true,"isUnique":false,"description":""},{"name":"PLACE_57_PK","fields":"STATE,PLACE","isAscending":true,"isUnique":false,"description":""},{"name":"R1728765_SDE_ROWID_UK","fields":"OBJECTID","isAscending":true,"isUnique":true,"description":""},{"name":"A124382_IX1","fields":"STGEOMETRY","isAscending":true,"isUnique":true,"description":""}],"subtypes":[],"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,"capabilities":"Map,Data,Query","maxRecordCount":100000,"supportsStatistics":true,"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, geoJSON","isDataVersioned":false,"ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true,"advancedQueryCapabilities":{"useStandardizedQueries":true,"supportsStatistics":true,"supportsHavingClause":true,"supportsCountDistinct":true,"supportsOrderBy":true,"supportsDistinct":true,"supportsPagination":true,"supportsTrueCurve":true,"supportsReturningQueryExtent":true,"supportsQueryWithDistance":true,"supportsSqlExpression":true},"supportsDatumTransformation":true,"supportsCoordinatesQuantization":true} 2 | -------------------------------------------------------------------------------- /esridump/esri2geojson.py: -------------------------------------------------------------------------------- 1 | from itertools import tee 2 | 3 | def esri2geojson(esrijson_feature): 4 | response = dict(type="Feature", geometry=None, properties=None) 5 | 6 | geojson_geometry = convert_esri_geometry(esrijson_feature.get('geometry')) 7 | if geojson_geometry: 8 | response['geometry'] = geojson_geometry 9 | 10 | esri_attributes = esrijson_feature.get('attributes') 11 | if esri_attributes: 12 | response['properties'] = esri_attributes 13 | 14 | return response 15 | 16 | def convert_esri_geometry(esri_geometry): 17 | if esri_geometry is None: 18 | return esri_geometry 19 | elif 'x' in esri_geometry or 'y' in esri_geometry: 20 | return convert_esri_point(esri_geometry) 21 | elif 'points' in esri_geometry: 22 | return convert_esri_multipoint(esri_geometry) 23 | elif 'paths' in esri_geometry: 24 | return convert_esri_polyline(esri_geometry) 25 | elif 'rings' in esri_geometry: 26 | return convert_esri_polygon(esri_geometry) 27 | 28 | def convert_esri_point(esri_geometry): 29 | x_coord = esri_geometry.get('x') 30 | y_coord = esri_geometry.get('y') 31 | 32 | if x_coord and y_coord: 33 | return { 34 | "type": "Point", 35 | "coordinates": [x_coord, y_coord] 36 | } 37 | else: 38 | return None 39 | 40 | def convert_esri_multipoint(esri_geometry): 41 | points = esri_geometry.get('points') 42 | 43 | if len(points) == 1: 44 | return { 45 | "type": "Point", 46 | "coordinates": points[0] 47 | } 48 | else: 49 | return { 50 | "type": "MultiPoint", 51 | "coordinates": points 52 | } 53 | 54 | def convert_esri_polyline(esri_geometry): 55 | paths = esri_geometry.get('paths') 56 | 57 | if len(paths) == 1: 58 | return { 59 | "type": "LineString", 60 | "coordinates": paths[0] 61 | } 62 | else: 63 | return { 64 | "type": "MultiLineString", 65 | "coordinates": paths 66 | } 67 | 68 | def convert_esri_polygon(esri_geometry): 69 | rings = esri_geometry.get('rings') 70 | 71 | def ensure_closed_ring(ring): 72 | first = ring[0] 73 | last = ring[-1] 74 | 75 | if first != last: 76 | # Trickery here to not modify the passed-in list 77 | ring = list(ring) 78 | ring.append(ring[0]) 79 | 80 | return ring 81 | 82 | def is_valid_ring(ring): 83 | return len(ring) >= 3 and not (len(ring) == 3 and ring[0] == ring[2]) 84 | 85 | clean_rings = [ 86 | ensure_closed_ring(ring) 87 | for ring in filter(is_valid_ring, rings) 88 | ] 89 | 90 | if len(clean_rings) == 1: 91 | return { 92 | "type": "Polygon", 93 | "coordinates": clean_rings 94 | } 95 | elif len(clean_rings) == 0: 96 | return None 97 | else: 98 | return decode_polygon(clean_rings) 99 | 100 | def decode_polygon(esri_rings): 101 | coords = [] 102 | outer_ring_index = -1 103 | 104 | for ring in esri_rings: 105 | try: 106 | if ring_is_clockwise(ring): 107 | coords.append([ring]) 108 | outer_ring_index += 1 109 | else: 110 | coords[outer_ring_index].append(ring) 111 | except IndexError: 112 | # Skip over rings that are in an unexpected order 113 | continue 114 | 115 | if len(coords) == 1: 116 | return { 117 | "type": "Polygon", 118 | "coordinates": coords[0] 119 | } 120 | else: 121 | return { 122 | "type": "MultiPolygon", 123 | "coordinates": coords 124 | } 125 | 126 | def ring_is_clockwise(ring): 127 | """ 128 | Determine if polygon ring coordinates are clockwise. Clockwise signifies 129 | outer ring, counter-clockwise an inner ring or hole. this logic was found 130 | at http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order 131 | this code taken from http://esri.github.com/geojson-utils/src/jsonConverters.js by James Cardona (MIT lisense) 132 | """ 133 | total = 0 134 | for (pt1, pt2) in pairwise(ring): 135 | total += (pt2[0] - pt1[0]) * (pt2[1] + pt1[1]) 136 | return total >= 0 137 | 138 | def pairwise(iterable): 139 | "s -> (s0,s1), (s1,s2), (s2, s3), ..." 140 | a, b = tee(iterable) 141 | next(b, None) 142 | return zip(a, b) 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esri-dump 2 | 3 | Scrapes an Esri REST endpoint and writes a GeoJSON file. 4 | 5 | ## Installation 6 | 7 | If you just want to use the command line tool `esri2geojson`, the recommended way to install this package is to create a [virtual environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/) and install it there. This method does not require that you `git clone` this repository and can get you up and running quickly: 8 | 9 | ``` 10 | virtualenv esridump 11 | source esridump/bin/activate 12 | pip install esridump 13 | ``` 14 | 15 | ## Usage 16 | 17 | ### Command line 18 | 19 | This module will install a command line utility called `esri2geojson` that accepts an Esri REST layer endpoint URL and a filename to write the output GeoJSON to: 20 | 21 | ```bash 22 | esri2geojson https://maps.six.nsw.gov.au/arcgis/rest/services/sixmaps/MaritimePublic/MapServer/13 martime_maps.geojson 23 | ``` 24 | 25 | You can write to `stdout` by using the special output filename of `-` (a single dash character). 26 | 27 | You can also pass in the `--jsonlines` option to write newline-separated (`\n`) lines of GeoJSON features, which you can then pipe into other applications. 28 | 29 | ### Python module 30 | 31 | You can use this module in your code to get GeoJSON Feature-shaped Python `dicts` into your code: 32 | 33 | ```python 34 | import json 35 | from esridump.dumper import EsriDumper 36 | 37 | d = EsriDumper('http://example.com/arcgis/rest/services/Layer/MapServer/1') 38 | 39 | # Iterate over each feature 40 | for feature in d: 41 | print(json.dumps(feature)) 42 | 43 | d = EsriDumper('http://example.com/arcgis/rest/services/Layer/MapServer/2') 44 | 45 | # Or get all features in one list 46 | all_features = list(d) 47 | ``` 48 | 49 | ## Methodology 50 | 51 | The module will do its best to find the most efficient method of retrieving data from the Esri server, given [the capabilities of the server](http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Query_Feature_Service_Layer/02r3000000r1000000/). There are several strategies we use to get the data, described here in most to least efficient order: 52 | 53 | ### `resultOffset` Pagination 54 | 55 | In ArcGIS REST API version 10.3, Esri added support for pagination directly with the `resultOffset` and `resultRecordCount` parameters. Unfortunately, most servers don't support this feature because the backend SQL engine must also be configured to support it. So far, it seems that only the Esri-hosted layers support this feature reliably. 56 | 57 | ### `objectId` Field Chunking 58 | 59 | In ArcGIS REST API version 10.0, Esri added support for the server to return an exhaustive list of object IDs for all features in a layer. Once this list of object IDs is retrieved, we break it into chunks of `maxRecordCount` queries using the `objectIds` parameter. 60 | 61 | ### `objectId` Statistics `where`-clauses 62 | 63 | In ArcGIS REST API version 10.1, Esri added support for performing various statistical queries on the server without requiring the client to download the whole dataset. On servers that support this and don't respond to the `objectIds` queries, we will use a minimum and maximum statistics query to find the minimum and maximum values for the `objectId` column, then build chunks of `where`-clauses that narrow the range down to `objectId`s between two fenceposts. 64 | 65 | ### Geometry Quadtree Queries 66 | 67 | When a server does not support any of these methods, we'll make recursive quad-tree queries using bounding envelopes. We start with a query for the layer's entire `extent`. If the server returns exactly the `maxRecordCount` number of features, we split that `extent` into 4 equal rectangles and query those. If those smaller queries return `maxRecordCount` features, we split the rectangle again and continue until the server returns something less than the `maxRecordCount`. 68 | 69 | ## Development 70 | 71 | To suggest changes or improvements to this code, create a fork on Github and clone your repository locally: 72 | 73 | ``` 74 | git clone git@github.com:openaddresses/pyesridump.git # replace with your fork 75 | cd pyesridump 76 | ``` 77 | 78 | We use Pipenv to manage dependencies for development. Make sure you have [Pipenv installed](https://docs.pipenv.org/en/latest/install/) and then install the dependencies for development: 79 | 80 | ``` 81 | pipenv install --dev 82 | pipenv shell 83 | ``` 84 | 85 | Your changes to the code will be reflected when you run the `esri2geojson` command from within the virtual environment. You can also run (and add) tests to check that your changes didn't break anything: 86 | 87 | ``` 88 | nosetests 89 | ``` 90 | 91 | ## See Also 92 | This Python module was extracted from OpenAddresses [`machine`](http://github.com/openaddresses/machine), which was inspired by code from [`koop`](https://github.com/koopjs/koop). A similar node/JavaScript module is available in [`esri-dump`](https://github.com/openaddresses/esri-dump). 93 | -------------------------------------------------------------------------------- /esridump/cli.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import email.parser 3 | from six.moves import urllib 4 | import logging 5 | import json 6 | import sys 7 | 8 | from esridump import EsriDumper 9 | 10 | def _collect_headers(strings): 11 | headers = {} 12 | parser = email.parser.Parser() 13 | 14 | for string in strings: 15 | headers.update(dict(parser.parsestr(string))) 16 | 17 | return headers 18 | 19 | def _collect_params(strings): 20 | params = {} 21 | 22 | for string in strings: 23 | params.update(dict(urllib.parse.parse_qsl(string))) 24 | 25 | return params 26 | 27 | def _parse_args(args): 28 | parser = argparse.ArgumentParser( 29 | description="Convert a single Esri feature service URL to GeoJSON") 30 | parser.add_argument("url", 31 | help="Esri layer URL") 32 | parser.add_argument("outfile", 33 | type=argparse.FileType('w'), 34 | help="Output file name (use - for stdout)") 35 | parser.add_argument("--proxy", 36 | help="Proxy string to send requests through ie: https://example.com/proxy.ashx?") 37 | parser.add_argument("--jsonlines", 38 | action='store_true', 39 | default=False, 40 | help="Output newline-delimited GeoJSON Features instead of a FeatureCollection") 41 | parser.add_argument("-v", "--verbose", 42 | action='store_const', 43 | dest='loglevel', 44 | const=logging.DEBUG, 45 | default=logging.INFO, 46 | help="Turn on verbose logging") 47 | parser.add_argument("-q", "--quiet", 48 | action='store_const', 49 | dest='loglevel', 50 | const=logging.WARNING, 51 | default=logging.INFO, 52 | help="Turn off most logging") 53 | parser.add_argument("-f", "--fields", 54 | help="Specify a comma-separated list of fields to request from the server") 55 | parser.add_argument("--no-geometry", 56 | dest='request_geometry', 57 | action='store_false', 58 | default=True, 59 | help="Don't request geometry for the feature so the server returns attributes only") 60 | parser.add_argument("-H", "--header", 61 | action='append', 62 | dest='headers', 63 | default=[], 64 | help="Add an HTTP header to send when requesting from Esri server") 65 | parser.add_argument("-p", "--param", 66 | action='append', 67 | dest='params', 68 | default=[], 69 | help="Add a URL parameter to send when requesting from Esri server") 70 | parser.add_argument("-t", "--timeout", 71 | type=int, 72 | default=30, 73 | help="HTTP timeout in seconds, default 30") 74 | parser.add_argument("-m", "--max-page-size", 75 | type=int, 76 | default=1000, 77 | help="Maximum number of features to pull per batch, default 1000") 78 | parser.add_argument("--paginate-oid", 79 | dest='paginate_oid', 80 | action='store_true', 81 | default=False, 82 | help="Turn on paginate by OID regardless of normal pagination support") 83 | parser.add_argument("--output-format", 84 | dest='output_format', 85 | action='store', 86 | default='geojson', 87 | help="The JSON output format of the feature data") 88 | 89 | return parser.parse_args(args) 90 | 91 | def main(): 92 | args = _parse_args(sys.argv[1:]) 93 | headers = _collect_headers(args.headers) 94 | params = _collect_params(args.params) 95 | 96 | logger = logging.getLogger('cli') 97 | logger.setLevel(args.loglevel) 98 | handler = logging.StreamHandler() 99 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 100 | handler.setFormatter(formatter) 101 | logger.addHandler(handler) 102 | 103 | requested_fields = args.fields.split(',') if args.fields else None 104 | 105 | dumper = EsriDumper(args.url, 106 | extra_query_args=params, 107 | extra_headers=headers, 108 | fields=requested_fields, 109 | request_geometry=args.request_geometry, 110 | proxy=args.proxy, 111 | timeout=args.timeout, 112 | max_page_size=args.max_page_size, 113 | parent_logger=logger, 114 | paginate_oid=args.paginate_oid, 115 | output_format=args.output_format) 116 | 117 | if args.jsonlines: 118 | for feature in dumper: 119 | args.outfile.write(json.dumps(feature)) 120 | args.outfile.write('\n') 121 | else: 122 | args.outfile.write('{"type":"FeatureCollection","features":[\n') 123 | feature_iter = iter(dumper) 124 | try: 125 | feature = next(feature_iter) 126 | while True: 127 | args.outfile.write(json.dumps(feature)) 128 | feature = next(feature_iter) 129 | args.outfile.write(',\n') 130 | except StopIteration: 131 | args.outfile.write('\n') 132 | args.outfile.write(']}') 133 | 134 | if __name__ == '__main__': 135 | main() 136 | -------------------------------------------------------------------------------- /tests/fixtures/us-ms-madison/us-ms-madison-0.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"PARCEL_ID_EED","fieldAliases":{"Landhook":"Landhook","REGION":"REGION","EDITDATE":"EDITDATE","POST_AC":"POST_AC","NEW_AC":"NEW_AC","PARCEL":"PARCEL","SHAPE_Length":"Shape_Length","SHAPE_Area":"Shape_Area","OBJECTID":"OBJECTID","PARCEL_ID_EED":"PARCEL_ID_EED","Parcel_Type":"Parcel_Type","OBJECTID_1":"OBJECTID_1","OWNER":"OWNER","DIST":"DIST","SVDIST":"SVDIST","MUNI":"MUNI","SCL":"SCL","SPASS":"SPASS","PHY_ST":"PHY_ST","PHY_STNO":"PHY_STNO","MAILADDRS":"MAILADDRS","CITY":"CITY","ST":"ST","ZIP":"ZIP","LAND_VTR":"LAND_VTR","IMPR_VTR":"IMPR_VTR","TOTAL_TR":"TOTAL_TR","LAND_VAS":"LAND_VAS","IMPR_VAS":"IMPR_VAS","TOTAL_AS":"TOTAL_AS","ACRES":"ACRES","LEGAL_DESC":"LEGAL_DESC","LEGAL_DES2":"LEGAL_DES2","LEGAL_DES3":"LEGAL_DES3","TSHIP":"TSHIP","RNG":"RNG","TSHIP_D":"TSHIP_D","RNG_D":"RNG_D","SECTION":"SECTION","BOOK":"BOOK","PAGE":"PAGE","DEED_DATE":"DEED_DATE","HSTEAD":"HSTEAD","SUBD_CODE":"SUBD_CODE","PMAPLINK":"PMAPLINK","TAX_EXEMPT":"TAX_EXEMPT","PPIN":"PPIN"},"geometryType":"esriGeometryPolygon","spatialReference":{"wkid":4326,"latestWkid":4326},"fields":[{"name":"Landhook","type":"esriFieldTypeString","alias":"Landhook","length":10},{"name":"REGION","type":"esriFieldTypeString","alias":"REGION","length":10},{"name":"EDITDATE","type":"esriFieldTypeDate","alias":"EDITDATE","length":8},{"name":"POST_AC","type":"esriFieldTypeString","alias":"POST_AC","length":10},{"name":"NEW_AC","type":"esriFieldTypeDouble","alias":"NEW_AC"},{"name":"PARCEL","type":"esriFieldTypeString","alias":"PARCEL","length":255},{"name":"SHAPE_Length","type":"esriFieldTypeDouble","alias":"Shape_Length"},{"name":"SHAPE_Area","type":"esriFieldTypeDouble","alias":"Shape_Area"},{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID"},{"name":"PARCEL_ID_EED","type":"esriFieldTypeString","alias":"PARCEL_ID_EED","length":35},{"name":"Parcel_Type","type":"esriFieldTypeSmallInteger","alias":"Parcel_Type"},{"name":"OBJECTID_1","type":"esriFieldTypeInteger","alias":"OBJECTID_1"},{"name":"OWNER","type":"esriFieldTypeString","alias":"OWNER","length":255},{"name":"DIST","type":"esriFieldTypeString","alias":"DIST","length":255},{"name":"SVDIST","type":"esriFieldTypeInteger","alias":"SVDIST"},{"name":"MUNI","type":"esriFieldTypeString","alias":"MUNI","length":255},{"name":"SCL","type":"esriFieldTypeString","alias":"SCL","length":255},{"name":"SPASS","type":"esriFieldTypeString","alias":"SPASS","length":255},{"name":"PHY_ST","type":"esriFieldTypeString","alias":"PHY_ST","length":255},{"name":"PHY_STNO","type":"esriFieldTypeInteger","alias":"PHY_STNO"},{"name":"MAILADDRS","type":"esriFieldTypeString","alias":"MAILADDRS","length":255},{"name":"CITY","type":"esriFieldTypeString","alias":"CITY","length":255},{"name":"ST","type":"esriFieldTypeString","alias":"ST","length":255},{"name":"ZIP","type":"esriFieldTypeInteger","alias":"ZIP"},{"name":"LAND_VTR","type":"esriFieldTypeInteger","alias":"LAND_VTR"},{"name":"IMPR_VTR","type":"esriFieldTypeInteger","alias":"IMPR_VTR"},{"name":"TOTAL_TR","type":"esriFieldTypeInteger","alias":"TOTAL_TR"},{"name":"LAND_VAS","type":"esriFieldTypeInteger","alias":"LAND_VAS"},{"name":"IMPR_VAS","type":"esriFieldTypeInteger","alias":"IMPR_VAS"},{"name":"TOTAL_AS","type":"esriFieldTypeInteger","alias":"TOTAL_AS"},{"name":"ACRES","type":"esriFieldTypeDouble","alias":"ACRES"},{"name":"LEGAL_DESC","type":"esriFieldTypeString","alias":"LEGAL_DESC","length":255},{"name":"LEGAL_DES2","type":"esriFieldTypeString","alias":"LEGAL_DES2","length":255},{"name":"LEGAL_DES3","type":"esriFieldTypeString","alias":"LEGAL_DES3","length":255},{"name":"TSHIP","type":"esriFieldTypeString","alias":"TSHIP","length":255},{"name":"RNG","type":"esriFieldTypeString","alias":"RNG","length":255},{"name":"TSHIP_D","type":"esriFieldTypeDouble","alias":"TSHIP_D"},{"name":"RNG_D","type":"esriFieldTypeDouble","alias":"RNG_D"},{"name":"SECTION","type":"esriFieldTypeInteger","alias":"SECTION"},{"name":"BOOK","type":"esriFieldTypeInteger","alias":"BOOK"},{"name":"PAGE","type":"esriFieldTypeInteger","alias":"PAGE"},{"name":"DEED_DATE","type":"esriFieldTypeDate","alias":"DEED_DATE","length":8},{"name":"HSTEAD","type":"esriFieldTypeString","alias":"HSTEAD","length":255},{"name":"SUBD_CODE","type":"esriFieldTypeInteger","alias":"SUBD_CODE"},{"name":"PMAPLINK","type":"esriFieldTypeString","alias":"PMAPLINK","length":255},{"name":"TAX_EXEMPT","type":"esriFieldTypeString","alias":"TAX_EXEMPT","length":255},{"name":"PPIN","type":"esriFieldTypeInteger","alias":"PPIN"}],"features":[{"attributes":{"Landhook":null,"REGION":"UBL","EDITDATE":null,"POST_AC":null,"NEW_AC":null,"PARCEL":null,"SHAPE_Length":3.5374392102460845,"SHAPE_Area":0.024888754327773235,"OBJECTID":26353,"PARCEL_ID_EED":null,"Parcel_Type":2,"OBJECTID_1":null,"OWNER":null,"DIST":null,"SVDIST":null,"MUNI":null,"SCL":null,"SPASS":null,"PHY_ST":null,"PHY_STNO":null,"MAILADDRS":null,"CITY":null,"ST":null,"ZIP":null,"LAND_VTR":null,"IMPR_VTR":null,"TOTAL_TR":null,"LAND_VAS":null,"IMPR_VAS":null,"TOTAL_AS":null,"ACRES":null,"LEGAL_DESC":null,"LEGAL_DES2":null,"LEGAL_DES3":null,"TSHIP":null,"RNG":null,"TSHIP_D":null,"RNG_D":null,"SECTION":null,"BOOK":null,"PAGE":null,"DEED_DATE":null,"HSTEAD":null,"SUBD_CODE":null,"PMAPLINK":null,"TAX_EXEMPT":null,"PPIN":null},"geometry":{"rings":[[[-90.1765528,32.5190731],[-90.1765476,32.5190751],[-90.1765528,32.5190731]]]}}]} -------------------------------------------------------------------------------- /tests/fixtures/us-ms-madison/us-ms-madison-metadata.json: -------------------------------------------------------------------------------- 1 | {"currentVersion":10.2,"id":13,"name":"Parcels","type":"Feature Layer","description":"","geometryType":"esriGeometryPolygon","copyrightText":"","parentLayer":null,"subLayers":[],"minScale":500000,"maxScale":0,"drawingInfo":{"renderer":{"type":"simple","symbol":{"type":"esriSFS","style":"esriSFSSolid","color":[0,0,0,0],"outline":{"type":"esriSLS","style":"esriSLSSolid","color":[130,130,130,255],"width":0.1}},"label":"","description":""},"transparency":0,"labelingInfo":[{"labelPlacement":"esriServerPolygonPlacementAlwaysHorizontal","where":null,"labelExpression":"[PARCEL_ID_EED]","useCodedValues":true,"symbol":{"type":"esriTS","color":[0,0,0,255],"backgroundColor":null,"borderLineColor":null,"borderLineSize":null,"verticalAlignment":"bottom","horizontalAlignment":"center","rightToLeft":false,"angle":0,"xoffset":0,"yoffset":0,"kerning":true,"haloColor":[255,255,255,255],"haloSize":1,"font":{"family":"Arial","size":7,"style":"normal","weight":"bold","decoration":"none"}},"minScale":5000,"maxScale":0}]},"defaultVisibility":false,"extent":{"xmin":2260647.21398557,"ymin":1054664.4693302438,"xmax":2482295.8933821693,"ymax":1231806.6722895503,"spatialReference":{"wkid":102695,"latestWkid":2255}},"hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText","displayField":"PARCEL_ID_EED","typeIdField":null,"fields":[{"name":"SHAPE","type":"esriFieldTypeGeometry","alias":"Shape","domain":null},{"name":"Landhook","type":"esriFieldTypeString","alias":"Landhook","length":10,"domain":null},{"name":"REGION","type":"esriFieldTypeString","alias":"REGION","length":10,"domain":null},{"name":"EDITDATE","type":"esriFieldTypeDate","alias":"EDITDATE","length":8,"domain":null},{"name":"POST_AC","type":"esriFieldTypeString","alias":"POST_AC","length":10,"domain":null},{"name":"NEW_AC","type":"esriFieldTypeDouble","alias":"NEW_AC","domain":null},{"name":"PARCEL","type":"esriFieldTypeString","alias":"PARCEL","length":255,"domain":null},{"name":"SHAPE_Length","type":"esriFieldTypeDouble","alias":"Shape_Length","domain":null},{"name":"SHAPE_Area","type":"esriFieldTypeDouble","alias":"Shape_Area","domain":null},{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null},{"name":"PARCEL_ID_EED","type":"esriFieldTypeString","alias":"PARCEL_ID_EED","length":35,"domain":null},{"name":"Parcel_Type","type":"esriFieldTypeSmallInteger","alias":"Parcel_Type","domain":null},{"name":"OBJECTID_1","type":"esriFieldTypeInteger","alias":"OBJECTID_1","domain":null},{"name":"OWNER","type":"esriFieldTypeString","alias":"OWNER","length":255,"domain":null},{"name":"DIST","type":"esriFieldTypeString","alias":"DIST","length":255,"domain":null},{"name":"SVDIST","type":"esriFieldTypeInteger","alias":"SVDIST","domain":null},{"name":"MUNI","type":"esriFieldTypeString","alias":"MUNI","length":255,"domain":null},{"name":"SCL","type":"esriFieldTypeString","alias":"SCL","length":255,"domain":null},{"name":"SPASS","type":"esriFieldTypeString","alias":"SPASS","length":255,"domain":null},{"name":"PHY_ST","type":"esriFieldTypeString","alias":"PHY_ST","length":255,"domain":null},{"name":"PHY_STNO","type":"esriFieldTypeInteger","alias":"PHY_STNO","domain":null},{"name":"MAILADDRS","type":"esriFieldTypeString","alias":"MAILADDRS","length":255,"domain":null},{"name":"CITY","type":"esriFieldTypeString","alias":"CITY","length":255,"domain":null},{"name":"ST","type":"esriFieldTypeString","alias":"ST","length":255,"domain":null},{"name":"ZIP","type":"esriFieldTypeInteger","alias":"ZIP","domain":null},{"name":"LAND_VTR","type":"esriFieldTypeInteger","alias":"LAND_VTR","domain":null},{"name":"IMPR_VTR","type":"esriFieldTypeInteger","alias":"IMPR_VTR","domain":null},{"name":"TOTAL_TR","type":"esriFieldTypeInteger","alias":"TOTAL_TR","domain":null},{"name":"LAND_VAS","type":"esriFieldTypeInteger","alias":"LAND_VAS","domain":null},{"name":"IMPR_VAS","type":"esriFieldTypeInteger","alias":"IMPR_VAS","domain":null},{"name":"TOTAL_AS","type":"esriFieldTypeInteger","alias":"TOTAL_AS","domain":null},{"name":"ACRES","type":"esriFieldTypeDouble","alias":"ACRES","domain":null},{"name":"LEGAL_DESC","type":"esriFieldTypeString","alias":"LEGAL_DESC","length":255,"domain":null},{"name":"LEGAL_DES2","type":"esriFieldTypeString","alias":"LEGAL_DES2","length":255,"domain":null},{"name":"LEGAL_DES3","type":"esriFieldTypeString","alias":"LEGAL_DES3","length":255,"domain":null},{"name":"TSHIP","type":"esriFieldTypeString","alias":"TSHIP","length":255,"domain":null},{"name":"RNG","type":"esriFieldTypeString","alias":"RNG","length":255,"domain":null},{"name":"TSHIP_D","type":"esriFieldTypeDouble","alias":"TSHIP_D","domain":null},{"name":"RNG_D","type":"esriFieldTypeDouble","alias":"RNG_D","domain":null},{"name":"SECTION","type":"esriFieldTypeInteger","alias":"SECTION","domain":null},{"name":"BOOK","type":"esriFieldTypeInteger","alias":"BOOK","domain":null},{"name":"PAGE","type":"esriFieldTypeInteger","alias":"PAGE","domain":null},{"name":"DEED_DATE","type":"esriFieldTypeDate","alias":"DEED_DATE","length":8,"domain":null},{"name":"HSTEAD","type":"esriFieldTypeString","alias":"HSTEAD","length":255,"domain":null},{"name":"SUBD_CODE","type":"esriFieldTypeInteger","alias":"SUBD_CODE","domain":null},{"name":"PMAPLINK","type":"esriFieldTypeString","alias":"PMAPLINK","length":255,"domain":null},{"name":"TAX_EXEMPT","type":"esriFieldTypeString","alias":"TAX_EXEMPT","length":255,"domain":null},{"name":"PPIN","type":"esriFieldTypeInteger","alias":"PPIN","domain":null}],"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":true,"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF","ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true} -------------------------------------------------------------------------------- /tests/fixtures/us-esri-test/us-esri-test-ids-only.json: -------------------------------------------------------------------------------- 1 | {"objectIds": [306120, 306121, 306122, 306124, 306127, 306128, 306129, 306131, 306133, 306135, 306137, 306139, 306521, 306522, 306523, 306525, 306527, 306529, 306531, 306533, 306535, 306537, 306539, 306541, 306543, 306545, 306547, 306549, 306918, 307319, 307320, 307719, 308518, 308918, 310120, 310121, 310122, 310124, 310126, 310128, 310130, 310132, 310134, 310136, 310138, 310140, 310142, 310144, 310146, 310148, 310150, 310152, 310154, 310156, 310158, 310160, 310520, 310521, 310522, 310524, 310526, 310528, 310530, 310533, 310920, 310921, 310922, 310924, 310926, 310928, 310930, 310932, 310934, 310936, 310938, 310940, 310942, 310944, 310946, 310948, 310950, 310952, 310954, 310956, 310958, 310960, 311320, 311321, 311322, 311323, 311324, 311327, 311328, 311329, 311330, 311331, 311332, 311334, 312118, 312121, 312122, 312123, 312125, 312127, 312129, 312131, 312133, 312135, 312137, 312139, 312141, 312143, 312145, 312147, 312149, 312151, 312153, 312155, 312157, 312159, 312161, 312518, 312519, 313718, 314118, 314119, 314518, 314521, 314918, 314919, 315318, 315718, 315719, 316518, 316519, 316920, 316921, 316922, 316924, 316926, 316928, 316930, 317320, 317321, 317322, 317324, 317326, 317328, 317330, 318118, 318119, 318518, 318920, 318921, 318922, 318924, 318926, 318928, 318930, 318932, 318934, 318936, 318938, 318940, 318942, 318944, 318946, 318948, 318950, 318952, 318954, 318956, 318958, 318960, 319320, 319321, 319322, 319324, 319326, 319328, 319330, 319332, 319334, 319336, 319338, 319340, 319342, 319344, 319346, 319348, 319350, 319352, 319354, 319356, 319358, 319360, 319718, 320120, 320121, 320122, 320124, 320126, 320128, 320130, 320132, 320134, 320136, 320138, 320140, 320142, 320144, 320146, 320148, 320150, 320152, 320154, 320156, 320158, 320160, 320165, 320166, 320167, 320169, 320171, 320173, 320175, 320177, 320179, 320181, 320183, 320185, 320187, 320189, 320191, 320193, 320195, 320197, 320199, 320201, 320203, 320205, 320518, 320519, 320520, 320521, 320522, 320523, 320524, 320525, 320526, 320527, 320528, 320529, 320530, 320531, 320532, 320533, 320534, 320535, 320536, 320537, 320538, 320539, 320540, 320541, 320542, 320543, 320544, 320545, 320546, 320547, 320548, 320549, 320550, 320551, 320552, 320553, 320554, 320555, 320556, 320557, 320558, 320559, 320560, 320561, 320562, 320563, 320564, 320565, 320566, 320567, 320568, 320569, 320570, 320571, 320572, 320573, 320574, 320575, 320576, 320577, 320578, 320579, 320580, 320581, 320582, 320583, 320584, 320585, 320586, 320587, 320588, 320589, 320590, 320591, 320592, 320593, 320594, 320595, 320596, 320597, 320598, 320599, 320600, 320601, 320602, 320603, 320604, 320605, 320606, 320607, 320608, 320609, 320610, 320611, 320612, 320613, 320614, 320615, 320616, 320617, 320618, 320619, 320620, 320621, 320622, 320623, 320624, 320625, 320626, 320627, 320628, 320629, 320630, 320631, 320632, 320633, 320634, 320635, 320636, 320637, 320638, 320639, 320640, 320641, 320642, 320643, 320644, 320645, 320646, 320647, 320648, 320649, 320650, 320651, 320652, 320653, 320654, 320655, 320656, 320657, 320658, 320659, 320660, 320661, 320662, 320663, 320664, 320665, 320666, 320667, 320668, 320669, 320670, 320671, 320672, 320673, 320674, 320675, 320676, 320677, 320678, 320679, 320680, 320681, 320682, 320683, 320684, 320685, 320686, 320687, 320688, 320689, 320690, 320691, 320692, 320693, 320694, 320695, 320696, 320697, 320698, 320699, 320700, 320701, 320702, 320703, 320704, 320705, 320706, 320707, 320708, 320709, 320710, 320711, 320712, 320713, 320714, 320715, 320716, 320717, 320718, 320719, 320720, 320721, 320722, 320723, 320724, 320725, 320726, 320727, 320728, 320729, 320730, 320731, 320732, 320733, 320734, 320735, 320736, 320737, 320738, 320739, 320740, 320741, 320742, 320743, 320744, 320745, 320746, 320747, 320748, 320749, 320750, 320751, 320752, 320753, 320754, 320755, 320756, 320757, 320758, 320759, 320760, 320761, 320762, 320763, 320764, 320765, 320766, 320767, 320768, 320769, 320770, 320771, 320772, 320773, 320774, 320775, 320776, 320777, 320778, 320779, 320780, 320781, 320782, 320783, 320784, 320785, 320786, 320787, 320788, 320789, 320790, 320791, 320792, 320793, 320794, 320795, 320796, 320797, 320798, 320799, 320800, 320801, 320802, 320803, 320804, 320805, 320806, 320807, 320808, 320809, 320810, 320811, 320812, 320813, 320814, 320815, 320816, 320817, 320818, 320819, 320820, 320821, 320822, 320823, 320824, 320825, 320826, 320827, 320828, 320829, 320830, 320831, 320832, 320833, 320834, 320835, 320836, 320837, 320838, 320839, 320840, 320841, 320842, 320843, 320844, 320845, 320846, 320847, 320848, 320849, 320850, 320851, 320852, 320853, 320854, 320855, 320856, 320857, 320858, 320859, 320860, 320861, 320862, 320863, 320864, 320865, 320866, 320867, 320868, 320869, 320870, 320871, 320872, 320873, 320874, 320875, 320876, 320877, 320878, 320879, 320880, 320881, 320882, 320883, 320884, 320885, 320886, 320887, 320888, 320889, 320890, 320891, 320892, 320893, 320894, 320895, 320896, 320897, 320898, 320899, 320900, 320901, 320902, 320903, 320904, 320905, 320906, 320907, 320908, 320909, 320910, 320911, 320912, 320913, 320914, 320915, 320916, 320917, 320918, 320919, 320920, 320921, 320922, 320923, 320924, 320925, 320926, 320927, 320928, 320929, 320930, 320931, 320932, 320933, 320934, 320935, 320936, 320937, 320938, 320939, 320940, 320941, 320942, 320943, 320944, 320945, 320946, 320947, 320948, 320949, 320950, 320951, 320952, 320953, 320954, 320955, 320956, 320957, 320958, 320959, 320960, 320961, 320962, 320963, 320964, 320965, 320966, 320967, 320968, 320969, 320970, 320971, 320972, 320973, 320974, 320975, 320976, 320977, 320978, 320979, 320980, 320981, 320982, 320983, 320984, 320985, 320986, 320987, 320988, 320989, 320990, 320991, 320992, 320993, 320994, 320995, 320996, 320997, 320998, 320999, 321000, 321001, 321002, 321003, 321004, 321005, 321006, 321007, 321008, 321009, 321010, 321011, 321012, 321013, 321014, 321015, 321016, 321017, 321018, 321019, 321020, 321021, 321022, 321023, 321024, 321025, 321026, 321027, 321028, 321029, 321030, 321031, 321032, 321033, 321034, 321035, 321036, 321037, 321038, 321039, 321040, 321041, 321042, 321043, 321044, 321045, 321046, 321047, 321048, 321049, 321050, 321051, 321052, 321053, 321054, 321055, 321056, 321057, 321058, 321059, 321060, 321061, 321062, 321063, 321064, 321065, 321066, 321067, 321068, 321069, 321070, 321071, 321072, 321073, 321074, 321075, 321076, 321077, 321078, 321079, 321080, 321081, 321082, 321083, 321084, 321085, 321086, 321087, 321088, 321089, 321090, 321091, 321092, 321093, 321094, 321095, 321096, 321097, 321098, 321099, 321100, 321101, 321102, 321103, 321104, 321105, 321106, 321107, 321108, 321109, 321110, 321111, 321112, 321113, 321114, 321115, 321116, 321117, 321118, 321119, 321120, 321121, 321122, 321123, 321124, 321125, 321126, 321127, 321128, 321129, 321130, 321131, 321132, 321133, 321134, 321135, 321136, 321137, 321138, 321139, 321140, 321141, 321142, 321143, 321144, 321145, 321146, 321147, 321148, 321149, 321150, 321151, 321152, 321153, 321154, 321155, 321156, 321157, 321158, 321159, 321160, 321161, 321162, 321163, 321164, 321165, 321166, 321167, 321168, 321169, 321170, 321171, 321172, 321173, 321174, 321175, 321176, 321177, 321178, 321179, 321180, 321181, 321182, 321183, 321184, 321185, 321186, 321187, 321188, 321189, 321190, 321191, 321192, 321193, 321194, 321195, 321196, 321197, 321198, 321199, 321200, 321201, 321202, 321203, 321204, 321205, 321206, 321207, 321208, 321209, 321210, 321211, 321212, 321213, 321214, 321215, 321216, 321217, 321218, 321219, 321220, 321221, 321222, 321223, 321224, 321225, 321226, 321227, 321228, 321229, 321230, 321231, 321232, 321233, 321234, 321235, 321236, 321237, 321238, 321239, 321240, 321241, 321242, 321243, 321244, 321245, 321246, 321247, 321248, 321249, 321250, 321251, 321252, 321253, 321254, 321255, 321256, 321257, 321258, 321259, 321260, 321261, 321262, 321263, 321264, 321265, 321266, 321267, 321268, 321269, 321270, 321271, 321272, 321273, 321274, 321275, 321276]} -------------------------------------------------------------------------------- /tests/fixtures/us-ca-carson/us-ca-carson-0.json: -------------------------------------------------------------------------------- 1 | { 2 | "displayFieldName": "STREETNAME", 3 | "fieldAliases": { 4 | "OBJECTID": "OBJECTID", 5 | "SITENUMBER": "SITENUMBER", 6 | "SITEFRAC": "SITEFRAC", 7 | "SITEPREF": "SITEPREF", 8 | "SITESTREET": "SITESTREET", 9 | "SITEUNIT": "SITEUNIT", 10 | "SITECITY": "SITECITY", 11 | "SITEZIP": "SITEZIP", 12 | "STREETNAME": "STREETNAME", 13 | "STREETTYPE": "STREETTYPE", 14 | "TYPE": "TYPE", 15 | "ADDRESS": "ADDRESS", 16 | "VACANT": "VACANT", 17 | "RES_BUS": "RES_BUS", 18 | "Field_Chec": "Field_Chec", 19 | "Need_Check": "Need_Check", 20 | "Comments": "Comments", 21 | "Edit_Date": "Edit_Date" 22 | }, 23 | "geometryType": "esriGeometryPoint", 24 | "spatialReference": { 25 | "wkid": 4326 26 | }, 27 | "fields": [ 28 | { 29 | "name": "OBJECTID", 30 | "type": "esriFieldTypeOID", 31 | "alias": "OBJECTID" 32 | }, 33 | { 34 | "name": "SITENUMBER", 35 | "type": "esriFieldTypeString", 36 | "alias": "SITENUMBER", 37 | "length": 13 38 | }, 39 | { 40 | "name": "SITEFRAC", 41 | "type": "esriFieldTypeString", 42 | "alias": "SITEFRAC", 43 | "length": 10 44 | }, 45 | { 46 | "name": "SITEPREF", 47 | "type": "esriFieldTypeString", 48 | "alias": "SITEPREF", 49 | "length": 4 50 | }, 51 | { 52 | "name": "SITESTREET", 53 | "type": "esriFieldTypeString", 54 | "alias": "SITESTREET", 55 | "length": 25 56 | }, 57 | { 58 | "name": "SITEUNIT", 59 | "type": "esriFieldTypeString", 60 | "alias": "SITEUNIT", 61 | "length": 8 62 | }, 63 | { 64 | "name": "SITECITY", 65 | "type": "esriFieldTypeString", 66 | "alias": "SITECITY", 67 | "length": 14 68 | }, 69 | { 70 | "name": "SITEZIP", 71 | "type": "esriFieldTypeString", 72 | "alias": "SITEZIP", 73 | "length": 10 74 | }, 75 | { 76 | "name": "STREETNAME", 77 | "type": "esriFieldTypeString", 78 | "alias": "STREETNAME", 79 | "length": 70 80 | }, 81 | { 82 | "name": "STREETTYPE", 83 | "type": "esriFieldTypeString", 84 | "alias": "STREETTYPE", 85 | "length": 70 86 | }, 87 | { 88 | "name": "TYPE", 89 | "type": "esriFieldTypeString", 90 | "alias": "TYPE", 91 | "length": 5 92 | }, 93 | { 94 | "name": "ADDRESS", 95 | "type": "esriFieldTypeString", 96 | "alias": "ADDRESS", 97 | "length": 50 98 | }, 99 | { 100 | "name": "VACANT", 101 | "type": "esriFieldTypeString", 102 | "alias": "VACANT", 103 | "length": 5 104 | }, 105 | { 106 | "name": "RES_BUS", 107 | "type": "esriFieldTypeString", 108 | "alias": "RES_BUS", 109 | "length": 10 110 | }, 111 | { 112 | "name": "Field_Chec", 113 | "type": "esriFieldTypeString", 114 | "alias": "Field_Chec", 115 | "length": 25 116 | }, 117 | { 118 | "name": "Need_Check", 119 | "type": "esriFieldTypeString", 120 | "alias": "Need_Check", 121 | "length": 10 122 | }, 123 | { 124 | "name": "Comments", 125 | "type": "esriFieldTypeString", 126 | "alias": "Comments", 127 | "length": 50 128 | }, 129 | { 130 | "name": "Edit_Date", 131 | "type": "esriFieldTypeDate", 132 | "alias": "Edit_Date", 133 | "length": 8 134 | } 135 | ], 136 | "features": [ 137 | { 138 | "attributes": { 139 | "OBJECTID": 1, 140 | "SITENUMBER": "555", 141 | "SITEFRAC": " ", 142 | "SITEPREF": "E", 143 | "SITESTREET": "CARSON ST", 144 | "SITEUNIT": "122", 145 | "SITECITY": "CARSON, CA", 146 | "SITEZIP": "90745", 147 | "STREETNAME": "CARSON", 148 | "STREETTYPE": "ST", 149 | "TYPE": "R", 150 | "ADDRESS": "555 E CARSON ST 122", 151 | "VACANT": " ", 152 | "RES_BUS": "RES", 153 | "Field_Chec": " ", 154 | "Need_Check": "NO", 155 | "Comments": " ", 156 | "Edit_Date": null 157 | }, 158 | "geometry": { 159 | "x": -118.26612584395593, 160 | "y": 33.83225576098862 161 | } 162 | }, 163 | { 164 | "attributes": { 165 | "OBJECTID": 2, 166 | "SITENUMBER": "555", 167 | "SITEFRAC": " ", 168 | "SITEPREF": "E", 169 | "SITESTREET": "CARSON ST", 170 | "SITEUNIT": "123", 171 | "SITECITY": "CARSON, CA", 172 | "SITEZIP": "90745", 173 | "STREETNAME": "CARSON", 174 | "STREETTYPE": "ST", 175 | "TYPE": "R", 176 | "ADDRESS": "555 E CARSON ST 123", 177 | "VACANT": " ", 178 | "RES_BUS": "RES", 179 | "Field_Chec": " ", 180 | "Need_Check": "NO", 181 | "Comments": " ", 182 | "Edit_Date": null 183 | }, 184 | "geometry": { 185 | "x": -118.26616993499418, 186 | "y": 33.832297351408734 187 | } 188 | }, 189 | { 190 | "attributes": { 191 | "OBJECTID": 3, 192 | "SITENUMBER": "555", 193 | "SITEFRAC": " ", 194 | "SITEPREF": "E", 195 | "SITESTREET": "CARSON ST", 196 | "SITEUNIT": "124", 197 | "SITECITY": "CARSON, CA", 198 | "SITEZIP": "90745", 199 | "STREETNAME": "CARSON", 200 | "STREETTYPE": "ST", 201 | "TYPE": "R", 202 | "ADDRESS": "555 E CARSON ST 124", 203 | "VACANT": " ", 204 | "RES_BUS": "RES", 205 | "Field_Chec": " ", 206 | "Need_Check": "NO", 207 | "Comments": " ", 208 | "Edit_Date": null 209 | }, 210 | "geometry": { 211 | "x": -118.26609000493768, 212 | "y": 33.83229586021424 213 | } 214 | }, 215 | { 216 | "attributes": { 217 | "OBJECTID": 1, 218 | "SITENUMBER": "555", 219 | "SITEFRAC": " ", 220 | "SITEPREF": "E", 221 | "SITESTREET": "CARSON ST", 222 | "SITEUNIT": "120", 223 | "SITECITY": "CARSON, CA", 224 | "SITEZIP": "90745", 225 | "STREETNAME": "CARSON", 226 | "STREETTYPE": "ST", 227 | "TYPE": "R", 228 | "ADDRESS": "555 E CARSON ST 120", 229 | "VACANT": " ", 230 | "RES_BUS": "RES", 231 | "Field_Chec": " ", 232 | "Need_Check": "NO", 233 | "Comments": " ", 234 | "Edit_Date": null 235 | } 236 | }, 237 | { 238 | "attributes": { 239 | "OBJECTID": 4, 240 | "SITENUMBER": "555", 241 | "SITEFRAC": " ", 242 | "SITEPREF": "E", 243 | "SITESTREET": "CARSON ST", 244 | "SITEUNIT": "80", 245 | "SITECITY": "CARSON, CA", 246 | "SITEZIP": "90745", 247 | "STREETNAME": "CARSON", 248 | "STREETTYPE": "ST", 249 | "TYPE": "R", 250 | "ADDRESS": "555 E CARSON ST 80", 251 | "VACANT": " ", 252 | "RES_BUS": "RES", 253 | "Field_Chec": " ", 254 | "Need_Check": "NO", 255 | "Comments": " ", 256 | "Edit_Date": null 257 | }, 258 | "geometry": { 259 | "x": -118.26712656670806, 260 | "y": 33.8322835165975 261 | } 262 | }, 263 | { 264 | "attributes": { 265 | "OBJECTID": 5, 266 | "SITENUMBER": "555", 267 | "SITEFRAC": " ", 268 | "SITEPREF": "E", 269 | "SITESTREET": "CARSON ST", 270 | "SITEUNIT": "81", 271 | "SITECITY": "CARSON, CA", 272 | "SITEZIP": "90745", 273 | "STREETNAME": "CARSON", 274 | "STREETTYPE": "ST", 275 | "TYPE": "R", 276 | "ADDRESS": "555 E CARSON ST 81", 277 | "VACANT": " ", 278 | "RES_BUS": "RES", 279 | "Field_Chec": " ", 280 | "Need_Check": "NO", 281 | "Comments": " ", 282 | "Edit_Date": null 283 | }, 284 | "geometry": { 285 | "x": -118.26711788300821, 286 | "y": 33.832217189774546 287 | } 288 | } 289 | ] 290 | } 291 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "5eaca7d9284739c3acfd74120b9391bef39f76705dfea371ea673e5bf016e236" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": {}, 8 | "sources": [ 9 | { 10 | "name": "pypi", 11 | "url": "https://pypi.python.org/simple", 12 | "verify_ssl": true 13 | } 14 | ] 15 | }, 16 | "default": { 17 | "certifi": { 18 | "hashes": [ 19 | "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", 20 | "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" 21 | ], 22 | "version": "==2021.10.8" 23 | }, 24 | "charset-normalizer": { 25 | "hashes": [ 26 | "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", 27 | "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" 28 | ], 29 | "markers": "python_version >= '3'", 30 | "version": "==2.0.12" 31 | }, 32 | "esridump": { 33 | "editable": true, 34 | "path": "." 35 | }, 36 | "idna": { 37 | "hashes": [ 38 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", 39 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" 40 | ], 41 | "markers": "python_version >= '3'", 42 | "version": "==3.3" 43 | }, 44 | "requests": { 45 | "hashes": [ 46 | "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", 47 | "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" 48 | ], 49 | "index": "pypi", 50 | "version": "==2.27.1" 51 | }, 52 | "six": { 53 | "hashes": [ 54 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 55 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 56 | ], 57 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 58 | "version": "==1.16.0" 59 | }, 60 | "urllib3": { 61 | "hashes": [ 62 | "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", 63 | "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" 64 | ], 65 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 66 | "version": "==1.26.9" 67 | } 68 | }, 69 | "develop": { 70 | "attrs": { 71 | "hashes": [ 72 | "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", 73 | "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" 74 | ], 75 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 76 | "version": "==21.4.0" 77 | }, 78 | "autopep8": { 79 | "hashes": [ 80 | "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979", 81 | "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f" 82 | ], 83 | "index": "pypi", 84 | "version": "==1.6.0" 85 | }, 86 | "bump2version": { 87 | "hashes": [ 88 | "sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410", 89 | "sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6" 90 | ], 91 | "markers": "python_version >= '3.5'", 92 | "version": "==1.0.1" 93 | }, 94 | "bumpversion": { 95 | "hashes": [ 96 | "sha256:4ba55e4080d373f80177b4dabef146c07ce73c7d1377aabf9d3c3ae1f94584a6", 97 | "sha256:4eb3267a38194d09f048a2179980bb4803701969bff2c85fa8f6d1ce050be15e" 98 | ], 99 | "index": "pypi", 100 | "version": "==0.6.0" 101 | }, 102 | "certifi": { 103 | "hashes": [ 104 | "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", 105 | "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" 106 | ], 107 | "version": "==2021.10.8" 108 | }, 109 | "charset-normalizer": { 110 | "hashes": [ 111 | "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", 112 | "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" 113 | ], 114 | "markers": "python_version >= '3'", 115 | "version": "==2.0.12" 116 | }, 117 | "cookies": { 118 | "hashes": [ 119 | "sha256:15bee753002dff684987b8df8c235288eb8d45f8191ae056254812dfd42c81d3", 120 | "sha256:d6b698788cae4cfa4e62ef8643a9ca332b79bd96cb314294b864ae8d7eb3ee8e" 121 | ], 122 | "index": "pypi", 123 | "version": "==2.2.1" 124 | }, 125 | "idna": { 126 | "hashes": [ 127 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", 128 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" 129 | ], 130 | "markers": "python_version >= '3'", 131 | "version": "==3.3" 132 | }, 133 | "iniconfig": { 134 | "hashes": [ 135 | "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", 136 | "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" 137 | ], 138 | "version": "==1.1.1" 139 | }, 140 | "mock": { 141 | "hashes": [ 142 | "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", 143 | "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc" 144 | ], 145 | "index": "pypi", 146 | "version": "==4.0.3" 147 | }, 148 | "nose": { 149 | "hashes": [ 150 | "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", 151 | "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", 152 | "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" 153 | ], 154 | "index": "pypi", 155 | "version": "==1.3.7" 156 | }, 157 | "packaging": { 158 | "hashes": [ 159 | "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", 160 | "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" 161 | ], 162 | "markers": "python_version >= '3.6'", 163 | "version": "==21.3" 164 | }, 165 | "pluggy": { 166 | "hashes": [ 167 | "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", 168 | "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" 169 | ], 170 | "markers": "python_version >= '3.6'", 171 | "version": "==1.0.0" 172 | }, 173 | "py": { 174 | "hashes": [ 175 | "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", 176 | "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" 177 | ], 178 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 179 | "version": "==1.11.0" 180 | }, 181 | "pycodestyle": { 182 | "hashes": [ 183 | "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", 184 | "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" 185 | ], 186 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 187 | "version": "==2.8.0" 188 | }, 189 | "pyparsing": { 190 | "hashes": [ 191 | "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954", 192 | "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06" 193 | ], 194 | "markers": "python_full_version >= '3.6.8'", 195 | "version": "==3.0.8" 196 | }, 197 | "pytest": { 198 | "hashes": [ 199 | "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c", 200 | "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45" 201 | ], 202 | "index": "pypi", 203 | "version": "==7.1.2" 204 | }, 205 | "requests": { 206 | "hashes": [ 207 | "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", 208 | "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" 209 | ], 210 | "index": "pypi", 211 | "version": "==2.27.1" 212 | }, 213 | "responses": { 214 | "hashes": [ 215 | "sha256:18831bc2d72443b67664d98038374a6fa1f27eaaff4dd9a7d7613723416fea3c", 216 | "sha256:644905bc4fb8a18fa37e3882b2ac05e610fe8c2f967d327eed669e314d94a541" 217 | ], 218 | "index": "pypi", 219 | "version": "==0.20.0" 220 | }, 221 | "toml": { 222 | "hashes": [ 223 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 224 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 225 | ], 226 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 227 | "version": "==0.10.2" 228 | }, 229 | "tomli": { 230 | "hashes": [ 231 | "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", 232 | "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" 233 | ], 234 | "markers": "python_version >= '3.7'", 235 | "version": "==2.0.1" 236 | }, 237 | "urllib3": { 238 | "hashes": [ 239 | "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", 240 | "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" 241 | ], 242 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 243 | "version": "==1.26.9" 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /tests/fixtures/us-ca-tuolumne/us-ca-tuolumne-0.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"O_ID","fieldAliases":{"O_ID":"O_ID","PREFIX":"PREFIX","owner1":"Owner Name","owner2":"Owner Name 2","address":"Property Address","zip_city":"Property City","zip_code":"Property State Zip Code","usecode":"SEV","REF2":"Taxable Value","HOUSE_NUM":"House Number","STREET_NAME":"Street","usecode":"usecode","SHAPE.area":"SHAPE.area","SHAPE.len":"SHAPE.len"},"geometryType":"esriGeometryPolygon","spatialReference":{"wkt":"PROJCS[\"NAD_1983_StatePlane_Michigan_South_FIPS_2113_IntlFeet\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Lambert_Conformal_Conic\"],PARAMETER[\"False_Easting\",13123359.58005249],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-84.36666666666666],PARAMETER[\"Standard_Parallel_1\",42.1],PARAMETER[\"Standard_Parallel_2\",43.66666666666666],PARAMETER[\"Latitude_Of_Origin\",41.5],UNIT[\"Foot\",0.3048]]"},"fields":[{"name":"O_ID","type":"esriFieldTypeDouble","alias":"O_ID"},{"name":"PREFIX","type":"esriFieldTypeString","alias":"PREFIX","length":16},{"name":"owner1","type":"esriFieldTypeString","alias":"Owner Name","length":35},{"name":"owner2","type":"esriFieldTypeString","alias":"Owner Name 2","length":35},{"name":"address","type":"esriFieldTypeString","alias":"Property Address","length":33},{"name":"zip_city","type":"esriFieldTypeString","alias":"Property City","length":25},{"name":"zip_code","type":"esriFieldTypeString","alias":"Property State Zip Code","length":25},{"name":"usecode","type":"esriFieldTypeDouble","alias":"SEV"},{"name":"REF2","type":"esriFieldTypeDouble","alias":"Taxable Value"},{"name":"HOUSE_NUM","type":"esriFieldTypeString","alias":"House Number","length":5},{"name":"STREET_NAME","type":"esriFieldTypeString","alias":"Street","length":27},{"name":"usecode","type":"esriFieldTypeOID","alias":"usecode"},{"name":"SHAPE.area","type":"esriFieldTypeDouble","alias":"SHAPE.area"},{"name":"SHAPE.len","type":"esriFieldTypeDouble","alias":"SHAPE.len"}],"features":[{"attributes":{"O_ID":410106100009,"PREFIX":"41-01-06-100-009","owner1":"NIECE JERMEY J & SARAH R ","owner2":" ","address":"4660 22 MILE RD NW ","zip_city":"GRANT ","zip_code":"MI49327 ","usecode":56100,"REF2":55270,"HOUSE_NUM":" 4660","STREET_NAME":"22 MILE RD NW ","usecode":1,"SHAPE.area":160469.21826171875,"SHAPE.len":1603.7360378288413},"geometry":{"rings":[[[12745374.032152027,656587.58437995613],[12745374.032152027,656587.51898862422],[12745369.312105104,656203.35898822546],[12745145.082176879,656205.36900486052],[12744951.83220613,656207.06898151338],[12744956.552154109,656591.41912129521],[12744956.552154109,656591.5266558975],[12745374.032152027,656587.58437995613]]]}},{"attributes":{"O_ID":410106100019,"PREFIX":"41-01-06-100-019","owner1":"DEHAAS KATHRYN ","owner2":" ","address":"4500 22 MILE RD NW ","zip_city":"GRANT ","zip_code":"MI49327 ","usecode":34100,"REF2":34100,"HOUSE_NUM":" 4500","STREET_NAME":"22 MILE RD NW ","usecode":2,"SHAPE.area":642763.94384765625,"SHAPE.len":3376.4308414717143},"geometry":{"rings":[[[12746521.942377746,656576.79896591604],[12746521.922097534,656575.48896294832],[12746508.332078144,655468.61906634271],[12745928.352158591,655474.189002648],[12745935.352097377,656044.14901208878],[12745938.542125732,656304.2989603281],[12745941.942177966,656581.28900551796],[12745941.952169687,656582.14898554981],[12745941.953356817,656582.25157377124],[12746521.942377746,656576.79896591604]]]}},{"attributes":{"O_ID":410106200003,"PREFIX":"41-01-06-200-003","owner1":"SHAW JAMES P ","owner2":" ","address":"4114 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":97200,"REF2":54187,"HOUSE_NUM":" 4114","STREET_NAME":"22 MILE RD NW ","usecode":3,"SHAPE.area":864599.64404296875,"SHAPE.len":4210.8168278107269},"geometry":{"rings":[[[12749336.219204664,656555.66925723851],[12749335.635233402,656479.7211381793],[12749329.691943273,655008.33901022375],[12748764.132047981,655015.01901626587],[12748773.582034603,655785.41897569597],[12748783.072087005,656558.36899903417],[12748783.087321907,656559.62963697314],[12749335.942107677,656555.67262078822],[12749336.219204664,656555.66925723851]]]}},{"attributes":{"O_ID":410105100002,"PREFIX":"41-01-05-100-002","owner1":"SHAW JAMES P ","owner2":" ","address":"3940 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":28300,"REF2":4093,"HOUSE_NUM":" 3940","STREET_NAME":"22 MILE RD NW ","usecode":4,"SHAPE.area":441112.45263671875,"SHAPE.len":3665.7195516204642},"geometry":{"rings":[[[12749620.942046359,656553.1789457649],[12749620.943925992,656553.66923233867],[12749905.935159028,656551.96203394234],[12749905.931993335,656551.06901198626],[12749900.132049695,655003.90901984274],[12749883.572116494,655004.09906029701],[12749759.832038507,655005.12899844348],[12749615.132012084,655006.02904427052],[12749620.942046359,656553.1789457649]]]}},{"attributes":{"O_ID":410104200011,"PREFIX":"41-01-04-200-011","owner1":"LOOMIS JEFFREY W & LORRAINE A ","owner2":" ","address":"2790 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":59700,"REF2":59131,"HOUSE_NUM":" 2790","STREET_NAME":"22 MILE RD NW ","usecode":5,"SHAPE.area":36354.10400390625,"SHAPE.len":765.90566680343068},"geometry":{"rings":[[[12757139.588785633,656486.92101021111],[12757348.161794335,656484.80791074038],[12757348.161794335,656484.73895800114],[12757347.991737306,656309.80904527009],[12757243.861736864,656311.77899610996],[12757139.281812429,656313.33898980916],[12757139.432083875,656469.90610769391],[12757139.450385526,656472.03879489005],[12757139.588785633,656486.92101021111]]]}},{"attributes":{"O_ID":410104200031,"PREFIX":"41-01-04-200-031","owner1":"HORNACK CHARLES & MANDY ","owner2":" ","address":"2620 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":60300,"REF2":59740,"HOUSE_NUM":" 2620","STREET_NAME":"22 MILE RD NW ","usecode":6,"SHAPE.area":117740.94091796875,"SHAPE.len":1374.1287329589663},"geometry":{"rings":[[[12758518.901903242,656467.93694828451],[12758516.401698977,656200.91903105378],[12758516.3918062,656200.42904126644],[12758515.841767192,656140.92896798253],[12758155.88170217,656146.25900419056],[12758158.941739291,656473.24897961318],[12758158.942629635,656473.35156783462],[12758518.901903242,656467.93694828451]]]}},{"attributes":{"O_ID":410104200024,"PREFIX":"41-01-04-200-024","owner1":"NORKUS KEVIN M & ANNA ","owner2":" ","address":"2580 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":54900,"REF2":54900,"HOUSE_NUM":" 2580","STREET_NAME":"22 MILE RD NW ","usecode":7,"SHAPE.area":111348.86181640625,"SHAPE.len":1368.0532953577172},"geometry":{"rings":[[[12758935.851944506,656461.69746808708],[12758933.351740256,656194.6789572835],[12758724.871723756,656197.79904362559],[12758516.401698977,656200.91903105378],[12758518.901903242,656467.93694828451],[12758935.851944506,656461.69746808708]]]}},{"attributes":{"O_ID":410103100027,"PREFIX":"41-01-03-100-027","owner1":"THOMPSON TRUST ","owner2":" ","address":"2250 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":61300,"REF2":60147,"HOUSE_NUM":" 2250","STREET_NAME":"22 MILE RD NW ","usecode":8,"SHAPE.area":247652.2021484375,"SHAPE.len":2021.3609722238307},"geometry":{"rings":[[[12761080.524250448,656429.79599742591],[12761135.337219805,656428.98548132181],[12761135.331679851,656428.58897837996],[12761127.011746377,655835.3990214169],[12760709.57171534,655842.49897629023],[12760717.884229213,656435.15778948367],[12761080.524250448,656429.79599742591]]]}},{"attributes":{"O_ID":410102100014,"PREFIX":"41-01-02-100-014","owner1":"MCCARTY ROBERT E & JUDITH K ","owner2":" ","address":"1320 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":92600,"REF2":90525,"HOUSE_NUM":" 1320","STREET_NAME":"22 MILE RD NW ","usecode":10,"SHAPE.area":478939.36083984375,"SHAPE.len":4794.0457866653851},"geometry":{"rings":[[[12766812.46149388,656388.76902358234],[12766812.475442722,656390.07704797387],[12767032.528438091,656393.98469915986],[12767032.50143078,656391.43898807466],[12767009.491498858,654214.81911107898],[12766789.481438175,654215.53910817206],[12766812.46149388,656388.76902358234]]]}},{"attributes":{"O_ID":410102100024,"PREFIX":"41-01-02-100-024","owner1":"O'HARE LE E & MELODY A J ","owner2":" ","address":"1548 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":12100,"REF2":12100,"HOUSE_NUM":" 1548","STREET_NAME":"22 MILE RD NW ","usecode":11,"SHAPE.area":93245.32861328125,"SHAPE.len":1315.4518438411608},"geometry":{"rings":[[[12765488.831515238,655917.02896422148],[12765280.23149924,655915.89901000261],[12765287.002815709,656366.50807461143],[12765393.66151163,656364.8868445605],[12765493.513079211,656366.65518036485],[12765488.831515238,655917.02896422148]]]}},{"attributes":{"O_ID":410106100035,"PREFIX":"41-01-06-100-035","owner1":"UPTON JOSEPH W ","owner2":" ","address":"17900 KENOWA AVE NW ","zip_city":"GRANT ","zip_code":"MI49327 ","usecode":98900,"REF2":89584,"HOUSE_NUM":"17900","STREET_NAME":"KENOWA AVE NW ","usecode":12,"SHAPE.area":484905.07568359375,"SHAPE.len":3319.5788808813686},"geometry":{"rings":[[[12744951.83220613,656207.06898151338],[12745145.082176879,656205.36900486052],[12745369.312105104,656203.35898822546],[12745366.152150825,655945.87900449336],[12745364.4022156,655803.63901761174],[12745361.512136564,655567.659029603],[12745044.432162389,655570.60905893147],[12745044.802152649,655806.60903036594],[12744338.131037578,655813.1762586236],[12744345.062913984,656212.85833986104],[12744951.83220613,656207.06898151338]]]}},{"attributes":{"O_ID":410106100017,"PREFIX":"41-01-06-100-017","owner1":"SHAFER WILLIAM N & BRENDA L ","owner2":" ","address":"4522 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":16400,"REF2":4915,"HOUSE_NUM":" 4522","STREET_NAME":"22 MILE RD NW ","usecode":13,"SHAPE.area":447466.40771484375,"SHAPE.len":3075.9077714025047},"geometry":{"rings":[[[12745728.362132594,655476.10899490118],[12745928.352158591,655474.189002648],[12746508.332078144,655468.61906634271],[12746503.542089224,655078.6490316689],[12746473.542111292,655078.89902241528],[12746325.402164698,655080.14907507598],[12746138.222111762,655082.50899960101],[12745969.192158744,655083.99905130267],[12745808.382123113,655085.38898798823],[12745632.032100677,655087.72902801633],[12745355.642151996,655089.66900371015],[12745357.872184217,655270.91902285814],[12745358.302124783,655305.6490394026],[12745360.432140917,655479.63903838396],[12745728.362132594,655476.10899490118]]]}},{"attributes":{"O_ID":410105200061,"PREFIX":"41-01-05-200-061","owner1":"SLOAN CHRISTOPHER ","owner2":" ","address":"17837 PEACH RIDGE AVE NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":43900,"REF2":43078,"HOUSE_NUM":"17837","STREET_NAME":"PEACH RIDGE AVE NW ","usecode":14,"SHAPE.area":76038.873046875,"SHAPE.len":1405.2241006524075},"geometry":{"rings":[[[12754465.371871948,655425.59899254143],[12754464.611809075,655326.47909554839],[12754481.681814417,655326.28905509412],[12754481.681814417,655248.42905585468],[12754481.471889451,655216.17906227708],[12754481.681814417,655161.89901739359],[12754481.121956825,655128.47220250964],[12754464.121819288,655128.8690764308],[12754296.161870196,655132.76901122928],[12754295.651896983,655102.01906105876],[12754295.451864809,655063.55906780064],[12754295.631814629,655010.47901807725],[12754197.271881595,655012.77899232507],[12754197.091832846,655063.64899323881],[12754197.291865021,655103.09905670583],[12754198.311910376,655163.7289852798],[12754198.111878201,655216.55904425681],[12754198.321902081,655249.34888726473],[12754198.321902081,655346.80907125771],[12754414.721886635,655341.74900922179],[12754415.381834507,655426.75902083516],[12754465.371871948,655425.59899254143]]]}},{"attributes":{"O_ID":410105200045,"PREFIX":"41-01-05-200-045","owner1":"HOWELL ROBERT J ","owner2":" ","address":"17825 PEACH RIDGE AVE NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":5700,"REF2":5700,"HOUSE_NUM":"17825","STREET_NAME":"PEACH RIDGE AVE NW ","usecode":15,"SHAPE.area":34020.1689453125,"SHAPE.len":740.34824875619006},"geometry":{"rings":[[[12754464.181967437,654931.52781961858],[12754464.183401898,654926.79352709651],[12754463.701870441,654926.8056704998],[12754295.702597529,654931.04104499519],[12754295.70185557,654935.45904037356],[12754295.691962779,654994.28907513618],[12754295.631814629,655010.47901807725],[12754295.451864809,655063.55906780064],[12754295.651896983,655102.01906105876],[12754296.161870196,655132.76901122928],[12754464.121819288,655128.8690764308],[12754464.181967437,654931.52781961858]]]}},{"attributes":{"O_ID":410106100030,"PREFIX":"41-01-06-100-030","owner1":"DEATRICK CLAUDE ","owner2":" ","address":"4408 22 MILE RD NW ","zip_city":"KENT CITY ","zip_code":"MI49330 ","usecode":8600,"REF2":4617,"HOUSE_NUM":" 4408","STREET_NAME":"22 MILE RD NW ","usecode":17,"SHAPE.area":108899.4462890625,"SHAPE.len":1488.9983989745019},"geometry":{"rings":[[[12746666.102060094,654301.91917195916],[12746664.102134123,654301.93905647099],[12746466.112133026,654304.27909648418],[12746472.752073273,654848.73906038702],[12746670.73208265,654846.39902035892],[12746672.732008621,654846.37903693318],[12746666.102060094,654301.91917195916]]]}}]} 2 | -------------------------------------------------------------------------------- /tests/fixtures/us-mi-kent/us-mi-kent-0.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"PPN","fieldAliases":{"PPN":"PPN","PNUM":"PNUM","OWNERNAME1":"Owner Name","OWNERNAME2":"Owner Name 2","PROPERTYADDRESS":"Property Address","PROPADDRESSCITY":"Property City","PROPADDRESSSTATE_ZIPCODE":"Property State Zip Code","SEVTRIBUNAL1":"SEV","TAXABLETRIBUNAL1":"Taxable Value","PROPADDRESSNUMBER":"House Number","PROPADDSTREET":"Street","OBJECTID":"OBJECTID","SHAPE.STArea()":"SHAPE.STArea()","SHAPE.STLength()":"SHAPE.STLength()"},"geometryType":"esriGeometryPolygon","spatialReference":{"wkt":"PROJCS[\"NAD_1983_StatePlane_Michigan_South_FIPS_2113_IntlFeet\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Lambert_Conformal_Conic\"],PARAMETER[\"False_Easting\",13123359.58005249],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-84.36666666666666],PARAMETER[\"Standard_Parallel_1\",42.1],PARAMETER[\"Standard_Parallel_2\",43.66666666666666],PARAMETER[\"Latitude_Of_Origin\",41.5],UNIT[\"Foot\",0.3048]]"},"fields":[{"name":"PPN","type":"esriFieldTypeDouble","alias":"PPN"},{"name":"PNUM","type":"esriFieldTypeString","alias":"PNUM","length":16},{"name":"OWNERNAME1","type":"esriFieldTypeString","alias":"Owner Name","length":35},{"name":"OWNERNAME2","type":"esriFieldTypeString","alias":"Owner Name 2","length":35},{"name":"PROPERTYADDRESS","type":"esriFieldTypeString","alias":"Property Address","length":33},{"name":"PROPADDRESSCITY","type":"esriFieldTypeString","alias":"Property City","length":25},{"name":"PROPADDRESSSTATE_ZIPCODE","type":"esriFieldTypeString","alias":"Property State Zip Code","length":25},{"name":"SEVTRIBUNAL1","type":"esriFieldTypeDouble","alias":"SEV"},{"name":"TAXABLETRIBUNAL1","type":"esriFieldTypeDouble","alias":"Taxable Value"},{"name":"PROPADDRESSNUMBER","type":"esriFieldTypeString","alias":"House Number","length":5},{"name":"PROPADDSTREET","type":"esriFieldTypeString","alias":"Street","length":27},{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID"},{"name":"SHAPE.STArea()","type":"esriFieldTypeDouble","alias":"SHAPE.STArea()"},{"name":"SHAPE.STLength()","type":"esriFieldTypeDouble","alias":"SHAPE.STLength()"}],"features":[{"attributes":{"PPN":410106100009,"PNUM":"41-01-06-100-009","OWNERNAME1":"NIECE JERMEY J & SARAH R ","OWNERNAME2":" ","PROPERTYADDRESS":"4660 22 MILE RD NW ","PROPADDRESSCITY":"GRANT ","PROPADDRESSSTATE_ZIPCODE":"MI49327 ","SEVTRIBUNAL1":56100,"TAXABLETRIBUNAL1":55270,"PROPADDRESSNUMBER":" 4660","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":1,"SHAPE.STArea()":160469.21826171875,"SHAPE.STLength()":1603.7360378288413},"geometry":{"rings":[[[12745374.032152027,656587.58437995613],[12745374.032152027,656587.51898862422],[12745369.312105104,656203.35898822546],[12745145.082176879,656205.36900486052],[12744951.83220613,656207.06898151338],[12744956.552154109,656591.41912129521],[12744956.552154109,656591.5266558975],[12745374.032152027,656587.58437995613]]]}},{"attributes":{"PPN":410106100019,"PNUM":"41-01-06-100-019","OWNERNAME1":"DEHAAS KATHRYN ","OWNERNAME2":" ","PROPERTYADDRESS":"4500 22 MILE RD NW ","PROPADDRESSCITY":"GRANT ","PROPADDRESSSTATE_ZIPCODE":"MI49327 ","SEVTRIBUNAL1":34100,"TAXABLETRIBUNAL1":34100,"PROPADDRESSNUMBER":" 4500","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":2,"SHAPE.STArea()":642763.94384765625,"SHAPE.STLength()":3376.4308414717143},"geometry":{"rings":[[[12746521.942377746,656576.79896591604],[12746521.922097534,656575.48896294832],[12746508.332078144,655468.61906634271],[12745928.352158591,655474.189002648],[12745935.352097377,656044.14901208878],[12745938.542125732,656304.2989603281],[12745941.942177966,656581.28900551796],[12745941.952169687,656582.14898554981],[12745941.953356817,656582.25157377124],[12746521.942377746,656576.79896591604]]]}},{"attributes":{"PPN":410106200003,"PNUM":"41-01-06-200-003","OWNERNAME1":"SHAW JAMES P ","OWNERNAME2":" ","PROPERTYADDRESS":"4114 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":97200,"TAXABLETRIBUNAL1":54187,"PROPADDRESSNUMBER":" 4114","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":3,"SHAPE.STArea()":864599.64404296875,"SHAPE.STLength()":4210.8168278107269},"geometry":{"rings":[[[12749336.219204664,656555.66925723851],[12749335.635233402,656479.7211381793],[12749329.691943273,655008.33901022375],[12748764.132047981,655015.01901626587],[12748773.582034603,655785.41897569597],[12748783.072087005,656558.36899903417],[12748783.087321907,656559.62963697314],[12749335.942107677,656555.67262078822],[12749336.219204664,656555.66925723851]]]}},{"attributes":{"PPN":410105100002,"PNUM":"41-01-05-100-002","OWNERNAME1":"SHAW JAMES P ","OWNERNAME2":" ","PROPERTYADDRESS":"3940 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":28300,"TAXABLETRIBUNAL1":4093,"PROPADDRESSNUMBER":" 3940","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":4,"SHAPE.STArea()":441112.45263671875,"SHAPE.STLength()":3665.7195516204642},"geometry":{"rings":[[[12749620.942046359,656553.1789457649],[12749620.943925992,656553.66923233867],[12749905.935159028,656551.96203394234],[12749905.931993335,656551.06901198626],[12749900.132049695,655003.90901984274],[12749883.572116494,655004.09906029701],[12749759.832038507,655005.12899844348],[12749615.132012084,655006.02904427052],[12749620.942046359,656553.1789457649]]]}},{"attributes":{"PPN":410104200011,"PNUM":"41-01-04-200-011","OWNERNAME1":"LOOMIS JEFFREY W & LORRAINE A ","OWNERNAME2":" ","PROPERTYADDRESS":"2790 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":59700,"TAXABLETRIBUNAL1":59131,"PROPADDRESSNUMBER":" 2790","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":5,"SHAPE.STArea()":36354.10400390625,"SHAPE.STLength()":765.90566680343068},"geometry":{"rings":[[[12757139.588785633,656486.92101021111],[12757348.161794335,656484.80791074038],[12757348.161794335,656484.73895800114],[12757347.991737306,656309.80904527009],[12757243.861736864,656311.77899610996],[12757139.281812429,656313.33898980916],[12757139.432083875,656469.90610769391],[12757139.450385526,656472.03879489005],[12757139.588785633,656486.92101021111]]]}},{"attributes":{"PPN":410104200031,"PNUM":"41-01-04-200-031","OWNERNAME1":"HORNACK CHARLES & MANDY ","OWNERNAME2":" ","PROPERTYADDRESS":"2620 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":60300,"TAXABLETRIBUNAL1":59740,"PROPADDRESSNUMBER":" 2620","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":6,"SHAPE.STArea()":117740.94091796875,"SHAPE.STLength()":1374.1287329589663},"geometry":{"rings":[[[12758518.901903242,656467.93694828451],[12758516.401698977,656200.91903105378],[12758516.3918062,656200.42904126644],[12758515.841767192,656140.92896798253],[12758155.88170217,656146.25900419056],[12758158.941739291,656473.24897961318],[12758158.942629635,656473.35156783462],[12758518.901903242,656467.93694828451]]]}},{"attributes":{"PPN":410104200024,"PNUM":"41-01-04-200-024","OWNERNAME1":"NORKUS KEVIN M & ANNA ","OWNERNAME2":" ","PROPERTYADDRESS":"2580 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":54900,"TAXABLETRIBUNAL1":54900,"PROPADDRESSNUMBER":" 2580","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":7,"SHAPE.STArea()":111348.86181640625,"SHAPE.STLength()":1368.0532953577172},"geometry":{"rings":[[[12758935.851944506,656461.69746808708],[12758933.351740256,656194.6789572835],[12758724.871723756,656197.79904362559],[12758516.401698977,656200.91903105378],[12758518.901903242,656467.93694828451],[12758935.851944506,656461.69746808708]]]}},{"attributes":{"PPN":410103100027,"PNUM":"41-01-03-100-027","OWNERNAME1":"THOMPSON TRUST ","OWNERNAME2":" ","PROPERTYADDRESS":"2250 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":61300,"TAXABLETRIBUNAL1":60147,"PROPADDRESSNUMBER":" 2250","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":8,"SHAPE.STArea()":247652.2021484375,"SHAPE.STLength()":2021.3609722238307},"geometry":{"rings":[[[12761080.524250448,656429.79599742591],[12761135.337219805,656428.98548132181],[12761135.331679851,656428.58897837996],[12761127.011746377,655835.3990214169],[12760709.57171534,655842.49897629023],[12760717.884229213,656435.15778948367],[12761080.524250448,656429.79599742591]]]}},{"attributes":{"PPN":410102100014,"PNUM":"41-01-02-100-014","OWNERNAME1":"MCCARTY ROBERT E & JUDITH K ","OWNERNAME2":" ","PROPERTYADDRESS":"1320 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":92600,"TAXABLETRIBUNAL1":90525,"PROPADDRESSNUMBER":" 1320","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":10,"SHAPE.STArea()":478939.36083984375,"SHAPE.STLength()":4794.0457866653851},"geometry":{"rings":[[[12766812.46149388,656388.76902358234],[12766812.475442722,656390.07704797387],[12767032.528438091,656393.98469915986],[12767032.50143078,656391.43898807466],[12767009.491498858,654214.81911107898],[12766789.481438175,654215.53910817206],[12766812.46149388,656388.76902358234]]]}},{"attributes":{"PPN":410102100024,"PNUM":"41-01-02-100-024","OWNERNAME1":"O'HARE LE E & MELODY A J ","OWNERNAME2":" ","PROPERTYADDRESS":"1548 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":12100,"TAXABLETRIBUNAL1":12100,"PROPADDRESSNUMBER":" 1548","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":11,"SHAPE.STArea()":93245.32861328125,"SHAPE.STLength()":1315.4518438411608},"geometry":{"rings":[[[12765488.831515238,655917.02896422148],[12765280.23149924,655915.89901000261],[12765287.002815709,656366.50807461143],[12765393.66151163,656364.8868445605],[12765493.513079211,656366.65518036485],[12765488.831515238,655917.02896422148]]]}},{"attributes":{"PPN":410106100035,"PNUM":"41-01-06-100-035","OWNERNAME1":"UPTON JOSEPH W ","OWNERNAME2":" ","PROPERTYADDRESS":"17900 KENOWA AVE NW ","PROPADDRESSCITY":"GRANT ","PROPADDRESSSTATE_ZIPCODE":"MI49327 ","SEVTRIBUNAL1":98900,"TAXABLETRIBUNAL1":89584,"PROPADDRESSNUMBER":"17900","PROPADDSTREET":"KENOWA AVE NW ","OBJECTID":12,"SHAPE.STArea()":484905.07568359375,"SHAPE.STLength()":3319.5788808813686},"geometry":{"rings":[[[12744951.83220613,656207.06898151338],[12745145.082176879,656205.36900486052],[12745369.312105104,656203.35898822546],[12745366.152150825,655945.87900449336],[12745364.4022156,655803.63901761174],[12745361.512136564,655567.659029603],[12745044.432162389,655570.60905893147],[12745044.802152649,655806.60903036594],[12744338.131037578,655813.1762586236],[12744345.062913984,656212.85833986104],[12744951.83220613,656207.06898151338]]]}},{"attributes":{"PPN":410106100017,"PNUM":"41-01-06-100-017","OWNERNAME1":"SHAFER WILLIAM N & BRENDA L ","OWNERNAME2":" ","PROPERTYADDRESS":"4522 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":16400,"TAXABLETRIBUNAL1":4915,"PROPADDRESSNUMBER":" 4522","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":13,"SHAPE.STArea()":447466.40771484375,"SHAPE.STLength()":3075.9077714025047},"geometry":{"rings":[[[12745728.362132594,655476.10899490118],[12745928.352158591,655474.189002648],[12746508.332078144,655468.61906634271],[12746503.542089224,655078.6490316689],[12746473.542111292,655078.89902241528],[12746325.402164698,655080.14907507598],[12746138.222111762,655082.50899960101],[12745969.192158744,655083.99905130267],[12745808.382123113,655085.38898798823],[12745632.032100677,655087.72902801633],[12745355.642151996,655089.66900371015],[12745357.872184217,655270.91902285814],[12745358.302124783,655305.6490394026],[12745360.432140917,655479.63903838396],[12745728.362132594,655476.10899490118]]]}},{"attributes":{"PPN":410105200061,"PNUM":"41-01-05-200-061","OWNERNAME1":"SLOAN CHRISTOPHER ","OWNERNAME2":" ","PROPERTYADDRESS":"17837 PEACH RIDGE AVE NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":43900,"TAXABLETRIBUNAL1":43078,"PROPADDRESSNUMBER":"17837","PROPADDSTREET":"PEACH RIDGE AVE NW ","OBJECTID":14,"SHAPE.STArea()":76038.873046875,"SHAPE.STLength()":1405.2241006524075},"geometry":{"rings":[[[12754465.371871948,655425.59899254143],[12754464.611809075,655326.47909554839],[12754481.681814417,655326.28905509412],[12754481.681814417,655248.42905585468],[12754481.471889451,655216.17906227708],[12754481.681814417,655161.89901739359],[12754481.121956825,655128.47220250964],[12754464.121819288,655128.8690764308],[12754296.161870196,655132.76901122928],[12754295.651896983,655102.01906105876],[12754295.451864809,655063.55906780064],[12754295.631814629,655010.47901807725],[12754197.271881595,655012.77899232507],[12754197.091832846,655063.64899323881],[12754197.291865021,655103.09905670583],[12754198.311910376,655163.7289852798],[12754198.111878201,655216.55904425681],[12754198.321902081,655249.34888726473],[12754198.321902081,655346.80907125771],[12754414.721886635,655341.74900922179],[12754415.381834507,655426.75902083516],[12754465.371871948,655425.59899254143]]]}},{"attributes":{"PPN":410105200045,"PNUM":"41-01-05-200-045","OWNERNAME1":"HOWELL ROBERT J ","OWNERNAME2":" ","PROPERTYADDRESS":"17825 PEACH RIDGE AVE NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":5700,"TAXABLETRIBUNAL1":5700,"PROPADDRESSNUMBER":"17825","PROPADDSTREET":"PEACH RIDGE AVE NW ","OBJECTID":15,"SHAPE.STArea()":34020.1689453125,"SHAPE.STLength()":740.34824875619006},"geometry":{"rings":[[[12754464.181967437,654931.52781961858],[12754464.183401898,654926.79352709651],[12754463.701870441,654926.8056704998],[12754295.702597529,654931.04104499519],[12754295.70185557,654935.45904037356],[12754295.691962779,654994.28907513618],[12754295.631814629,655010.47901807725],[12754295.451864809,655063.55906780064],[12754295.651896983,655102.01906105876],[12754296.161870196,655132.76901122928],[12754464.121819288,655128.8690764308],[12754464.181967437,654931.52781961858]]]}},{"attributes":{"PPN":410106100030,"PNUM":"41-01-06-100-030","OWNERNAME1":"DEATRICK CLAUDE ","OWNERNAME2":" ","PROPERTYADDRESS":"4408 22 MILE RD NW ","PROPADDRESSCITY":"KENT CITY ","PROPADDRESSSTATE_ZIPCODE":"MI49330 ","SEVTRIBUNAL1":8600,"TAXABLETRIBUNAL1":4617,"PROPADDRESSNUMBER":" 4408","PROPADDSTREET":"22 MILE RD NW ","OBJECTID":17,"SHAPE.STArea()":108899.4462890625,"SHAPE.STLength()":1488.9983989745019},"geometry":{"rings":[[[12746666.102060094,654301.91917195916],[12746664.102134123,654301.93905647099],[12746466.112133026,654304.27909648418],[12746472.752073273,654848.73906038702],[12746670.73208265,654846.39902035892],[12746672.732008621,654846.37903693318],[12746666.102060094,654301.91917195916]]]}}]} 2 | -------------------------------------------------------------------------------- /tests/test_download.py: -------------------------------------------------------------------------------- 1 | import os 2 | import responses 3 | import unittest 4 | import re 5 | 6 | from esridump.dumper import EsriDumper 7 | from esridump.errors import EsriDownloadError 8 | 9 | 10 | class TestEsriDownload(unittest.TestCase): 11 | def setUp(self): 12 | self.responses = responses.RequestsMock() 13 | self.responses.start() 14 | 15 | self.fake_url = 'http://example.com' 16 | 17 | def tearDown(self): 18 | self.responses.stop() 19 | self.responses.reset() 20 | 21 | def add_fixture_response(self, url_re, file, method='POST', **kwargs): 22 | with open(os.path.join('tests/fixtures', file), 'rb') as f: 23 | self.responses.add( 24 | method=method, 25 | url=re.compile(url_re), 26 | body=f.read(), 27 | match_querystring=True, 28 | **kwargs 29 | ) 30 | 31 | def test_object_id_enumeration(self): 32 | self.add_fixture_response( 33 | r'.*/\?f=json.*', 34 | 'us-ca-carson/us-ca-carson-metadata.json', 35 | method='GET', 36 | ) 37 | self.add_fixture_response( 38 | '.*returnCountOnly=true.*', 39 | 'us-ca-carson/us-ca-carson-count-only.json', 40 | method='GET', 41 | ) 42 | self.add_fixture_response( 43 | '.*returnIdsOnly=true.*', 44 | 'us-ca-carson/us-ca-carson-ids-only.json', 45 | method='GET', 46 | ) 47 | self.add_fixture_response( 48 | '.*query.*', 49 | 'us-ca-carson/us-ca-carson-0.json', 50 | method='POST', 51 | ) 52 | 53 | dump = EsriDumper(self.fake_url) 54 | data = list(dump) 55 | 56 | self.assertEqual(6, len(data)) 57 | 58 | def test_statistics_pagination(self): 59 | self.add_fixture_response( 60 | r'.*/\?f=json.*', 61 | 'us-ms-madison/us-ms-madison-metadata.json', 62 | method='GET', 63 | ) 64 | self.add_fixture_response( 65 | '.*returnCountOnly=true.*', 66 | 'us-ms-madison/us-ms-madison-count-only.json', 67 | method='GET', 68 | ) 69 | self.add_fixture_response( 70 | '.*outStatistics=.*', 71 | 'us-ms-madison/us-ms-madison-outStatistics.json', 72 | method='GET', 73 | ) 74 | self.add_fixture_response( 75 | '.*returnIdsOnly=true.*', 76 | 'us-ms-madison/us-ms-madison-ids-only.json', 77 | method='GET', 78 | ) 79 | self.add_fixture_response( 80 | '.*returnIdsOnly=true.*', 81 | 'us-ms-madison/us-ms-madison-ids-only.json', 82 | method='GET', 83 | ) 84 | self.add_fixture_response( 85 | '.*query.*', 86 | 'us-ms-madison/us-ms-madison-0.json', 87 | method='POST', 88 | ) 89 | 90 | dump = EsriDumper(self.fake_url) 91 | data = list(dump) 92 | 93 | self.assertEqual(1, len(data)) 94 | 95 | def test_advanced_query_pagination(self): 96 | self.add_fixture_response( 97 | r'.*/\?f=json.*', 98 | 'us-esri-test/us-esri-test-metadata.json', 99 | method='GET', 100 | ) 101 | self.add_fixture_response( 102 | '.*returnCountOnly=true.*', 103 | 'us-esri-test/us-esri-test-count-only.json', 104 | method='GET', 105 | ) 106 | self.add_fixture_response( 107 | '.*query.*', 108 | 'us-esri-test/us-esri-test-0.json', 109 | method='POST', 110 | ) 111 | 112 | dump = EsriDumper(self.fake_url) 113 | data = list(dump) 114 | 115 | self.assertEqual(1000, len(data)) 116 | 117 | def test_advanced_query_pagination_incorrect_outfield_name(self): 118 | self.add_fixture_response( 119 | r'.*/\?f=json.*', 120 | 'us-ca-tuolumne/us-ca-tuolumne-metadata.json', 121 | method='GET', 122 | ) 123 | self.add_fixture_response( 124 | '.*returnCountOnly=true.*', 125 | 'us-ca-tuolumne/us-ca-tuolumne-count-only.json', 126 | method='GET', 127 | ) 128 | self.add_fixture_response( 129 | '.*outStatistics=.*', 130 | 'us-ca-tuolumne/us-ca-tuolumne-statistics.json', 131 | method='GET', 132 | ) 133 | self.add_fixture_response( 134 | '.*returnIdsOnly=true.*', 135 | 'us-ca-tuolumne/us-ca-tuolumne-ids-only.json', 136 | method='GET', 137 | ) 138 | self.add_fixture_response( 139 | '.*returnIdsOnly=true.*', 140 | 'us-ca-tuolumne/us-ca-tuolumne-ids-only.json', 141 | method='GET', 142 | ) 143 | self.add_fixture_response( 144 | '.*query.*', 145 | 'us-ca-tuolumne/us-ca-tuolumne-0.json', 146 | method='POST', 147 | ) 148 | 149 | dump = EsriDumper(self.fake_url) 150 | data = list(dump) 151 | 152 | self.assertEqual(15, len(data)) 153 | 154 | def test_oid_enumeration_when_wrong_min_max_is_given(self): 155 | self.add_fixture_response( 156 | r'.*/\?f=json.*', 157 | 'us-fl-polk/us-fl-polk-metadata.json', 158 | method='GET', 159 | ) 160 | self.add_fixture_response( 161 | '.*returnCountOnly=true.*', 162 | 'us-fl-polk/us-fl-polk-count-only.json', 163 | method='GET', 164 | ) 165 | self.add_fixture_response( 166 | '.*outStatistics=.*', 167 | 'us-fl-polk/us-fl-polk-statistics.json', 168 | method='GET', 169 | ) 170 | self.add_fixture_response( 171 | '.*returnIdsOnly=true.*', 172 | 'us-fl-polk/us-fl-polk-ids-only.json', 173 | method='GET', 174 | ) 175 | self.add_fixture_response( 176 | '.*returnIdsOnly=true.*', 177 | 'us-fl-polk/us-fl-polk-ids-only.json', 178 | method='GET', 179 | ) 180 | self.add_fixture_response( 181 | '.*query.*', 182 | 'us-fl-polk/us-fl-polk-0.json', 183 | method='POST', 184 | ) 185 | 186 | dump = EsriDumper(self.fake_url) 187 | data = list(dump) 188 | 189 | self.assertEqual(10, len(data)) 190 | 191 | def test_oid_enumeration_when_statistics_doesnt_work(self): 192 | self.add_fixture_response( 193 | r'.*/\?f=json.*', 194 | 'us-mi-kent/us-mi-kent-metadata.json', 195 | method='GET', 196 | ) 197 | self.add_fixture_response( 198 | '.*returnCountOnly=true.*', 199 | 'us-mi-kent/us-mi-kent-count-only.json', 200 | method='GET', 201 | ) 202 | self.add_fixture_response( 203 | '.*outStatistics=.*', 204 | 'us-mi-kent/us-mi-kent-statistics.json', 205 | method='GET', 206 | ) 207 | self.add_fixture_response( 208 | '.*returnIdsOnly=true.*', 209 | 'us-mi-kent/us-mi-kent-ids-only.json', 210 | method='GET', 211 | ) 212 | self.add_fixture_response( 213 | '.*query.*', 214 | 'us-mi-kent/us-mi-kent-0.json', 215 | method='POST', 216 | ) 217 | 218 | dump = EsriDumper(self.fake_url) 219 | data = list(dump) 220 | 221 | self.assertEqual(15, len(data)) 222 | 223 | def test_coerces_floats_to_integer(self): 224 | self.add_fixture_response( 225 | r'.*/\?f=json.*', 226 | 'us-mo-columbia/us-mo-columbia-metadata.json', 227 | method='GET', 228 | ) 229 | self.add_fixture_response( 230 | '.*returnCountOnly=true.*', 231 | 'us-mo-columbia/us-mo-columbia-count-only.json', 232 | method='GET', 233 | ) 234 | self.add_fixture_response( 235 | '.*returnIdsOnly=true.*', 236 | 'us-mo-columbia/us-mo-columbia-ids-only.json', 237 | method='GET', 238 | ) 239 | self.add_fixture_response( 240 | '.*query.*', 241 | 'us-mo-columbia/us-mo-columbia-0.json', 242 | method='POST', 243 | ) 244 | 245 | dump = EsriDumper(self.fake_url) 246 | data = list(dump) 247 | 248 | self.assertEqual(43, len(data)) 249 | 250 | def test_proxy_requests(self): 251 | self.add_fixture_response( 252 | r'http://proxy/\?http://example\.com\?f=json', 253 | 'us-mo-columbia/us-mo-columbia-metadata.json', 254 | method='GET', 255 | ) 256 | self.add_fixture_response( 257 | r'http://proxy/\?http://example\.com/.*returnCountOnly=true.*', 258 | 'us-mo-columbia/us-mo-columbia-count-only.json', 259 | method='GET', 260 | ) 261 | self.add_fixture_response( 262 | r'http://proxy/\?http://example\.com/.*returnIdsOnly=true.*', 263 | 'us-mo-columbia/us-mo-columbia-ids-only.json', 264 | method='GET', 265 | ) 266 | self.add_fixture_response( 267 | r'http://proxy/\?http://example\.com/.*query.*', 268 | 'us-mo-columbia/us-mo-columbia-0.json', 269 | method='POST', 270 | ) 271 | 272 | dump = EsriDumper(self.fake_url, proxy='http://proxy?') 273 | data = list(dump) 274 | 275 | self.assertEqual(43, len(data)) 276 | 277 | def test_handles_timeout_error(self): 278 | self.add_fixture_response( 279 | r'.*/\?f=json.*', 280 | 'us-mo-columbia/us-mo-columbia-metadata.json', 281 | method='GET', 282 | ) 283 | self.add_fixture_response( 284 | '.*returnCountOnly=true.*', 285 | 'us-mo-columbia/us-mo-columbia-count-only.json', 286 | method='GET', 287 | ) 288 | self.add_fixture_response( 289 | '.*returnIdsOnly=true.*', 290 | 'us-mo-columbia/us-mo-columbia-ids-only.json', 291 | method='GET', 292 | ) 293 | import socket 294 | self.responses.add( 295 | method='POST', 296 | url=re.compile('.*query.*'), 297 | body=socket.timeout(), 298 | ) 299 | 300 | dump = EsriDumper(self.fake_url) 301 | with self.assertRaisesRegex(EsriDownloadError, "Timeout when connecting to URL"): 302 | list(dump) 303 | 304 | def test_handles_value_error(self): 305 | self.add_fixture_response( 306 | r'.*/\?f=json.*', 307 | 'us-mo-columbia/us-mo-columbia-metadata.json', 308 | method='GET', 309 | ) 310 | self.add_fixture_response( 311 | '.*returnCountOnly=true.*', 312 | 'us-mo-columbia/us-mo-columbia-count-only.json', 313 | method='GET', 314 | ) 315 | self.add_fixture_response( 316 | '.*returnIdsOnly=true.*', 317 | 'us-mo-columbia/us-mo-columbia-ids-only.json', 318 | method='GET', 319 | ) 320 | self.responses.add( 321 | method='POST', 322 | url=re.compile('.*query.*'), 323 | body=ValueError(), 324 | ) 325 | 326 | dump = EsriDumper(self.fake_url) 327 | with self.assertRaisesRegex(EsriDownloadError, "Could not parse JSON"): 328 | list(dump) 329 | 330 | def test_handles_exception(self): 331 | self.add_fixture_response( 332 | r'.*/\?f=json.*', 333 | 'us-mo-columbia/us-mo-columbia-metadata.json', 334 | method='GET', 335 | ) 336 | self.add_fixture_response( 337 | '.*returnCountOnly=true.*', 338 | 'us-mo-columbia/us-mo-columbia-count-only.json', 339 | method='GET', 340 | ) 341 | self.add_fixture_response( 342 | '.*returnIdsOnly=true.*', 343 | 'us-mo-columbia/us-mo-columbia-ids-only.json', 344 | method='GET', 345 | ) 346 | self.responses.add( 347 | method='POST', 348 | url=re.compile('.*query.*'), 349 | body=Exception(), 350 | ) 351 | 352 | dump = EsriDumper(self.fake_url, pause_seconds=0.01) 353 | with self.assertRaisesRegex(EsriDownloadError, "Could not connect to URL"): 354 | list(dump) 355 | 356 | def test_geo_queries_when_oid_enumeration_doesnt_work(self): 357 | self.add_fixture_response( 358 | r'.*/\?f=json.*', 359 | 'us-il-cook/metadata.json', 360 | method='GET', 361 | ) 362 | self.add_fixture_response( 363 | '.*returnCountOnly=true.*', 364 | 'us-il-cook/count-only.json', 365 | method='GET', 366 | ) 367 | self.add_fixture_response( 368 | '.*returnIdsOnly=true.*', 369 | 'us-il-cook/ids-only.json', 370 | method='GET', 371 | ) 372 | self.add_fixture_response( 373 | '.*geometry=.*', 374 | 'us-il-cook/page-full.json', 375 | method='GET', 376 | ) 377 | self.add_fixture_response( 378 | '.*geometry=.*', 379 | 'us-il-cook/page-partial.json', 380 | method='GET', 381 | ) 382 | self.add_fixture_response( 383 | '.*geometry=.*', 384 | 'us-il-cook/page-partial.json', 385 | method='GET', 386 | ) 387 | self.add_fixture_response( 388 | '.*geometry=.*', 389 | 'us-il-cook/page-partial.json', 390 | method='GET', 391 | ) 392 | self.add_fixture_response( 393 | '.*geometry=.*', 394 | 'us-il-cook/page-partial.json', 395 | method='GET', 396 | ) 397 | 398 | dump = EsriDumper(self.fake_url) 399 | data = list(dump) 400 | 401 | # Note that this count is entirely fake because of the deduping happening 402 | # This test is only designed to make sure we're splitting into smaller 403 | # bounding boxes. 404 | 405 | self.assertEqual(2, len(data)) 406 | 407 | def test_empty_result_set_short_circuits(self): 408 | self.add_fixture_response( 409 | r'.*/\?f=json.*', 410 | 'us-il-chicago/metadata.json', 411 | method='GET', 412 | ) 413 | 414 | self.add_fixture_response( 415 | '.*returnCountOnly=true.*', 416 | 'us-il-chicago/count-only.json', 417 | method='GET', 418 | ) 419 | 420 | dump = EsriDumper(self.fake_url) 421 | data = list(dump) 422 | 423 | self.assertEqual(0, len(data)) 424 | 425 | def test_esri_json_output(self): 426 | self.add_fixture_response( 427 | r'.*/\?f=json.*', 428 | 'us-ca-carson/us-ca-carson-metadata.json', 429 | method='GET', 430 | ) 431 | self.add_fixture_response( 432 | '.*returnCountOnly=true.*', 433 | 'us-ca-carson/us-ca-carson-count-only.json', 434 | method='GET', 435 | ) 436 | self.add_fixture_response( 437 | '.*returnIdsOnly=true.*', 438 | 'us-ca-carson/us-ca-carson-ids-only.json', 439 | method='GET', 440 | ) 441 | self.add_fixture_response( 442 | '.*query.*', 443 | 'us-ca-carson/us-ca-carson-0.json', 444 | method='POST', 445 | ) 446 | 447 | dump = EsriDumper(self.fake_url, output_format='esrijson') 448 | data = list(dump) 449 | self.assertIn('attributes', data[0], message='Data does not have "attributes" key with output format == esrijson') 450 | -------------------------------------------------------------------------------- /tests/fixtures/us-fl-polk/us-fl-polk-0.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName": "PrimaryName", "fieldAliases": {"OBJECTID": "OBJECTID", "MCode": "MCode", "ESN": "ESN", "GPSFLG": "GPSFLG", "LR": "LR", "Comments": "Comments", "Flag": "Flag", "Flg": "Flg", "DelRec": "DelRec", "ESiteID": "ESiteID", "SiteType": "SITETYPE", "Zip": "Zip", "GPSX": "GPSX", "GPSY": "GPSY", "StreetID": "StreetID", "JBoundID": "JBoundID", "ParcelNum": "ParcelNum", "PD": "PD", "PT": "PT", "SN": "SN", "ST": "ST", "SD": "SD", "GeoNameID": "GeoNameID", "ZN": "ZN", "HouseNumber": "HouseNumber", "HouseInt": "HouseInt", "PrimaryAddress": "PrimaryAddress", "ALIAddress": "ALIAddress", "AddrLocation": "AddrLocation", "PrimaryName": "PrimaryName", "ALIName": "ALIName", "Alias1": "Alias1", "Alias2": "Alias2", "Alias3": "Alias3", "Alias4": "Alias4", "Alias5": "Alias5", "CREATION_DATE": "CREATION_DATE", "C1_EXCEPTION": "C1_EXCEPTION", "MODIFY_USER": "MODIFY_USER", "MODIFY_DATE": "MODIFY_DATE", "CREATION_USER": "CREATION_USER", "SiteTypeCode": "SiteTypeCode", "Unit": "Unit", "County": "County", "City_Ovr": "City_Ovr", "Blg": "Blg", "Apt": "Apt", "Sign": "Sign", "PMOD": "PMOD", "FEMOD": "FEMOD", "P_Override": "P_Override", "MailingCity": "MailingCity", "ESN_City_Name": "ESN_City_Name", "City_Code": "City_Code", "T_MailingCityNm": "T_MailingCityNm", "FE_OVERRIDE": "FE_OVERRIDE", "GlobalID": "GlobalID"}, "geometryType": "esriGeometryPoint", "spatialReference": {"wkid": 4326, "latestWkid": 4326}, "fields": [{"name": "OBJECTID", "type": "esriFieldTypeOID", "alias": "OBJECTID"}, {"name": "MCode", "type": "esriFieldTypeInteger", "alias": "MCode"}, {"name": "ESN", "type": "esriFieldTypeInteger", "alias": "ESN"}, {"name": "GPSFLG", "type": "esriFieldTypeString", "alias": "GPSFLG", "length": 1}, {"name": "LR", "type": "esriFieldTypeString", "alias": "LR", "length": 1}, {"name": "Comments", "type": "esriFieldTypeString", "alias": "Comments", "length": 255}, {"name": "Flag", "type": "esriFieldTypeString", "alias": "Flag", "length": 10}, {"name": "Flg", "type": "esriFieldTypeSmallInteger", "alias": "Flg"}, {"name": "DelRec", "type": "esriFieldTypeInteger", "alias": "DelRec"}, {"name": "ESiteID", "type": "esriFieldTypeInteger", "alias": "ESiteID"}, {"name": "SiteType", "type": "esriFieldTypeString", "alias": "SITETYPE", "length": 2}, {"name": "Zip", "type": "esriFieldTypeString", "alias": "Zip", "length": 5}, {"name": "GPSX", "type": "esriFieldTypeDouble", "alias": "GPSX"}, {"name": "GPSY", "type": "esriFieldTypeDouble", "alias": "GPSY"}, {"name": "StreetID", "type": "esriFieldTypeInteger", "alias": "StreetID"}, {"name": "JBoundID", "type": "esriFieldTypeInteger", "alias": "JBoundID"}, {"name": "ParcelNum", "type": "esriFieldTypeString", "alias": "ParcelNum", "length": 20}, {"name": "PD", "type": "esriFieldTypeString", "alias": "PD", "length": 5}, {"name": "PT", "type": "esriFieldTypeString", "alias": "PT", "length": 5}, {"name": "SN", "type": "esriFieldTypeString", "alias": "SN", "length": 50}, {"name": "ST", "type": "esriFieldTypeString", "alias": "ST", "length": 5}, {"name": "SD", "type": "esriFieldTypeString", "alias": "SD", "length": 5}, {"name": "GeoNameID", "type": "esriFieldTypeInteger", "alias": "GeoNameID"}, {"name": "ZN", "type": "esriFieldTypeString", "alias": "ZN", "length": 50}, {"name": "HouseNumber", "type": "esriFieldTypeString", "alias": "HouseNumber", "length": 15}, {"name": "HouseInt", "type": "esriFieldTypeInteger", "alias": "HouseInt"}, {"name": "PrimaryAddress", "type": "esriFieldTypeString", "alias": "PrimaryAddress", "length": 100}, {"name": "ALIAddress", "type": "esriFieldTypeString", "alias": "ALIAddress", "length": 100}, {"name": "AddrLocation", "type": "esriFieldTypeString", "alias": "AddrLocation", "length": 2}, {"name": "PrimaryName", "type": "esriFieldTypeString", "alias": "PrimaryName", "length": 100}, {"name": "ALIName", "type": "esriFieldTypeString", "alias": "ALIName", "length": 100}, {"name": "Alias1", "type": "esriFieldTypeString", "alias": "Alias1", "length": 60}, {"name": "Alias2", "type": "esriFieldTypeString", "alias": "Alias2", "length": 60}, {"name": "Alias3", "type": "esriFieldTypeString", "alias": "Alias3", "length": 60}, {"name": "Alias4", "type": "esriFieldTypeString", "alias": "Alias4", "length": 60}, {"name": "Alias5", "type": "esriFieldTypeString", "alias": "Alias5", "length": 60}, {"name": "CREATION_DATE", "type": "esriFieldTypeDouble", "alias": "CREATION_DATE"}, {"name": "C1_EXCEPTION", "type": "esriFieldTypeInteger", "alias": "C1_EXCEPTION"}, {"name": "MODIFY_USER", "type": "esriFieldTypeString", "alias": "MODIFY_USER", "length": 50}, {"name": "MODIFY_DATE", "type": "esriFieldTypeDouble", "alias": "MODIFY_DATE"}, {"name": "CREATION_USER", "type": "esriFieldTypeString", "alias": "CREATION_USER", "length": 50}, {"name": "SiteTypeCode", "type": "esriFieldTypeString", "alias": "SiteTypeCode", "length": 2}, {"name": "Unit", "type": "esriFieldTypeString", "alias": "Unit", "length": 40}, {"name": "County", "type": "esriFieldTypeString", "alias": "County", "length": 154}, {"name": "City_Ovr", "type": "esriFieldTypeString", "alias": "City_Ovr", "length": 3}, {"name": "Blg", "type": "esriFieldTypeString", "alias": "Blg", "length": 3}, {"name": "Apt", "type": "esriFieldTypeString", "alias": "Apt", "length": 3}, {"name": "Sign", "type": "esriFieldTypeString", "alias": "Sign", "length": 1}, {"name": "PMOD", "type": "esriFieldTypeString", "alias": "PMOD", "length": 10}, {"name": "FEMOD", "type": "esriFieldTypeString", "alias": "FEMOD", "length": 10}, {"name": "P_Override", "type": "esriFieldTypeString", "alias": "P_Override", "length": 8}, {"name": "MailingCity", "type": "esriFieldTypeString", "alias": "MailingCity", "length": 254}, {"name": "ESN_City_Name", "type": "esriFieldTypeString", "alias": "ESN_City_Name", "length": 254}, {"name": "City_Code", "type": "esriFieldTypeString", "alias": "City_Code", "length": 5}, {"name": "T_MailingCityNm", "type": "esriFieldTypeString", "alias": "T_MailingCityNm", "length": 254}, {"name": "FE_OVERRIDE", "type": "esriFieldTypeString", "alias": "FE_OVERRIDE", "length": 10}, {"name": "GlobalID", "type": "esriFieldTypeGlobalID", "alias": "GlobalID", "length": 38}], "features": [{"attributes": {"OBJECTID": 3345100, "MCode": 116, "ESN": 605, "GPSFLG": "N", "LR": "L", "Comments": " ", "Flag": "0", "Flg": 1, "DelRec": 0, "ESiteID": 148249, "SiteType": "R1", "Zip": "33884", "GPSX": -81.69135534, "GPSY": 27.9749712, "StreetID": 22812, "JBoundID": 10, "ParcelNum": "262911687421000210", "PD": "", "PT": "", "SN": "BRIDGEWATER", "ST": "DR", "SD": "", "GeoNameID": 4852, "ZN": "POLK COUNTY", "HouseNumber": "7", "HouseInt": 7, "PrimaryAddress": "7 BRIDGEWATER DR", "ALIAddress": "7 BRIDGEWATER DR", "AddrLocation": "B", "PrimaryName": "BRIDGEWATER DR", "ALIName": "BRIDGEWATER DR", "Alias1": "BRIDGEWATER DR SE", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.142044, "CREATION_USER": null, "SiteTypeCode": "R1", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "WINTER HAVEN", "ESN_City_Name": "WINTER HAVEN UNINCORP EAST", "City_Code": "WHE", "T_MailingCityNm": "WINTER HAVEN", "FE_OVERRIDE": null, "GlobalID": "{BF7BC90E-0FBF-4634-9391-DBEBA357911B}"}, "geometry": {"x": -81.6913585, "y": 27.9749764}}, {"attributes": {"OBJECTID": 3345101, "MCode": 116, "ESN": 630, "GPSFLG": "N", "LR": "L", "Comments": " ", "Flag": "7", "Flg": 1, "DelRec": 0, "ESiteID": 318656, "SiteType": "R3", "Zip": "33897", "GPSX": -81.66822167, "GPSY": 28.29659671, "StreetID": 47824, "JBoundID": 10, "ParcelNum": "262524000000032010", "PD": "", "PT": "", "SN": "CIRCLE", "ST": "DR", "SD": "", "GeoNameID": 16209, "ZN": "POLK COUNTY", "HouseNumber": "1017", "HouseInt": 1017, "PrimaryAddress": "1017 CIRCLE DR", "ALIAddress": "1017 CIRCLE DR", "AddrLocation": "B", "PrimaryName": "CIRCLE DR", "ALIName": "CIRCLE DR", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.142046, "CREATION_USER": null, "SiteTypeCode": "R3", "Unit": "", "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "DAVENPORT / NORTHRIDGE", "ESN_City_Name": "NORTHRIDGE", "City_Code": "NRG", "T_MailingCityNm": "DAVENPORT", "FE_OVERRIDE": null, "GlobalID": "{76EE2C6D-6259-4A84-9744-8F82F58AC339}"}, "geometry": {"x": -81.6682249, "y": 28.296602}}, {"attributes": {"OBJECTID": 3345102, "MCode": 113, "ESN": 672, "GPSFLG": "N", "LR": "L", "Comments": " ", "Flag": "0-N-------", "Flg": 2, "DelRec": 0, "ESiteID": 45106, "SiteType": "R3", "Zip": "33810", "GPSX": -81.98172636, "GPSY": 28.10486254, "StreetID": 20599, "JBoundID": 10, "ParcelNum": "232726000000023010", "PD": "", "PT": "", "SN": "CUTTER", "ST": "LN", "SD": "", "GeoNameID": 12010, "ZN": "LAKELAND", "HouseNumber": "1652", "HouseInt": 1652, "PrimaryAddress": "1652 CUTTER LN", "ALIAddress": "1652 CUTTER LN", "AddrLocation": "B", "PrimaryName": "CUTTER LN", "ALIName": "CUTTER LN", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.142045, "CREATION_USER": null, "SiteTypeCode": "R3", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "LAKELAND", "ESN_City_Name": "LAKELAND", "City_Code": "LKD", "T_MailingCityNm": "LAKELAND", "FE_OVERRIDE": null, "GlobalID": "{303CCD50-D70B-4124-8BA5-757470A68C63}"}, "geometry": {"x": -81.9817296, "y": 28.1048678}}, {"attributes": {"OBJECTID": 3345103, "MCode": 106, "ESN": 667, "GPSFLG": "N", "LR": "L", "Comments": "Lot 216, Clubhouse Dr", "Flag": "", "Flg": 0, "DelRec": 0, "ESiteID": 349706, "SiteType": "R3", "Zip": "33841", "GPSX": -81.78590783, "GPSY": 27.74427022, "StreetID": 29805, "JBoundID": 10, "ParcelNum": "253135485500004000", "PD": "", "PT": "", "SN": "WASHINGTON", "ST": "AVE", "SD": "S", "GeoNameID": 1125, "ZN": "FORT MEADE", "HouseNumber": "300", "HouseInt": 300, "PrimaryAddress": "300 WASHINGTON AVE S #216", "ALIAddress": "300 WASHINGTON AVE S #216", "AddrLocation": "B", "PrimaryName": "WASHINGTON AVE S", "ALIName": "WASHINGTON AVE S", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emmelibl", "MODIFY_DATE": 20170807.114952, "CREATION_USER": null, "SiteTypeCode": "R3", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "FORT MEADE", "ESN_City_Name": "FORT MEADE", "City_Code": "FTM", "T_MailingCityNm": "FORT MEADE", "FE_OVERRIDE": null, "GlobalID": "{5630DD38-06A5-4D51-ACF0-64ECA283EB78}"}, "geometry": {"x": -81.785911, "y": 27.7442754}}, {"attributes": {"OBJECTID": 3345104, "MCode": 150, "ESN": 625, "GPSFLG": "N", "LR": "R", "Comments": " ", "Flag": "0", "Flg": 1, "DelRec": 0, "ESiteID": 139580, "SiteType": "R1", "Zip": "33880", "GPSX": -81.72953774, "GPSY": 27.95911626, "StreetID": 7710, "JBoundID": 10, "ParcelNum": "262917689500017804", "PD": "", "PT": "", "SN": "2ND", "ST": "TER", "SD": "W", "GeoNameID": 54631, "ZN": "WAHNETA", "HouseNumber": "131", "HouseInt": 131, "PrimaryAddress": "131 2ND TER W", "ALIAddress": "131 2ND TER W", "AddrLocation": "B", "PrimaryName": "2ND TER W", "ALIName": "2ND TER W", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.145431, "CREATION_USER": null, "SiteTypeCode": "R1", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "WINTER HAVEN / WAHNETA", "ESN_City_Name": "WAHNETA", "City_Code": "WAH", "T_MailingCityNm": "WINTER HAVEN", "FE_OVERRIDE": null, "GlobalID": "{017F59C6-B3EC-4319-9A08-DD1F7FE458A3}"}, "geometry": {"x": -81.7295409, "y": 27.9591215}}, {"attributes": {"OBJECTID": 3345105, "MCode": 116, "ESN": 631, "GPSFLG": "N", "LR": "R", "Comments": " ", "Flag": "0", "Flg": 1, "DelRec": 0, "ESiteID": 131960, "SiteType": "R1", "Zip": "33860", "GPSX": -82.00064454, "GPSY": 27.9205938, "StreetID": 3141, "JBoundID": 10, "ParcelNum": "232934142460001920", "PD": "", "PT": "", "SN": "TIGEREYE", "ST": "CT", "SD": "", "GeoNameID": 10467, "ZN": "POLK COUNTY", "HouseNumber": "3557", "HouseInt": 3557, "PrimaryAddress": "3557 TIGEREYE CT", "ALIAddress": "3557 TIGEREYE CT", "AddrLocation": "B", "PrimaryName": "TIGEREYE CT", "ALIName": "TIGEREYE CT", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.142124, "CREATION_USER": null, "SiteTypeCode": "R1", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "MULBERRY", "ESN_City_Name": "MULBERRY UNINCORP WEST IMPERIAL LAKES NICHOLS WILLOW OAK", "City_Code": "MUW", "T_MailingCityNm": "MULBERRY", "FE_OVERRIDE": null, "GlobalID": "{6247639F-89A3-4C19-8509-37DCB7A06233}"}, "geometry": {"x": -82.0006478, "y": 27.920599}}, {"attributes": {"OBJECTID": 3345106, "MCode": 112, "ESN": 671, "GPSFLG": "N", "LR": "L", "Comments": " ", "Flag": "0-N-------", "Flg": 2, "DelRec": 0, "ESiteID": 33115, "SiteType": "R1", "Zip": "33853", "GPSX": -81.59519966, "GPSY": 27.91251937, "StreetID": 2901, "JBoundID": 10, "ParcelNum": "272934872000002040", "PD": "", "PT": "", "SN": "JACKSON", "ST": "AVE", "SD": "", "GeoNameID": 1965, "ZN": "LAKE WALES", "HouseNumber": "512", "HouseInt": 512, "PrimaryAddress": "512 JACKSON AVE", "ALIAddress": "512 JACKSON AVE", "AddrLocation": "B", "PrimaryName": "JACKSON AVE", "ALIName": "JACKSON AVE", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.142111, "CREATION_USER": null, "SiteTypeCode": "R1", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "LAKE WALES", "ESN_City_Name": "LAKE WALES", "City_Code": "LWL", "T_MailingCityNm": "LAKE WALES", "FE_OVERRIDE": null, "GlobalID": "{1693B344-0C93-4C0E-892E-51C6DE35BD3C}"}, "geometry": {"x": -81.5952028, "y": 27.9125246}}, {"attributes": {"OBJECTID": 3345107, "MCode": 116, "ESN": 686, "GPSFLG": "N", "LR": "L", "Comments": " ", "Flag": "0-N-------", "Flg": 2, "DelRec": 0, "ESiteID": 225107, "SiteType": "R3", "Zip": "33843", "GPSX": -81.59520057, "GPSY": 27.70388616, "StreetID": 22346, "JBoundID": 10, "ParcelNum": "273211932553001090", "PD": "", "PT": "", "SN": "ACIE", "ST": "LN", "SD": "", "GeoNameID": 4145, "ZN": "POLK COUNTY", "HouseNumber": "75", "HouseInt": 75, "PrimaryAddress": "75 ACIE LN", "ALIAddress": "75 ACIE LN", "AddrLocation": "B", "PrimaryName": "ACIE LN", "ALIName": "ACIE LN", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emmelibl", "MODIFY_DATE": 20170421.09184, "CREATION_USER": null, "SiteTypeCode": "R3", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "FROSTPROOF", "ESN_City_Name": "FROSTPROOF UNINCORP", "City_Code": "FRU", "T_MailingCityNm": "FROSTPROOF", "FE_OVERRIDE": null, "GlobalID": "{818FE101-78A1-47C0-860A-601073CC285A}"}, "geometry": {"x": -81.5952787, "y": 27.7039345}}, {"attributes": {"OBJECTID": 3345108, "MCode": 113, "ESN": 672, "GPSFLG": "N", "LR": "R", "Comments": "Lot 192 Kings Manor MHP ", "Flag": "--Y", "Flg": 2, "DelRec": 0, "ESiteID": 53357, "SiteType": "R3", "Zip": "33815", "GPSX": -81.98308456, "GPSY": 28.03198166, "StreetID": 335320, "JBoundID": 10, "ParcelNum": "232823095500001201", "PD": "", "PT": "", "SN": "HIGHLAND", "ST": "ST", "SD": "W", "GeoNameID": 2739, "ZN": "LAKELAND", "HouseNumber": "1500", "HouseInt": 1500, "PrimaryAddress": "1500 HIGHLAND ST W #192", "ALIAddress": "1500 HIGHLAND ST W #192", "AddrLocation": "B", "PrimaryName": "HIGHLAND ST W", "ALIName": "HIGHLAND ST W", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emmelibl", "MODIFY_DATE": 20170816.121053, "CREATION_USER": null, "SiteTypeCode": "R3", "Unit": "192", "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "LAKELAND", "ESN_City_Name": "LAKELAND", "City_Code": "LKD", "T_MailingCityNm": "LAKELAND", "FE_OVERRIDE": null, "GlobalID": "{4C8A3147-A4F2-46CE-B708-D5A080397DCE}"}, "geometry": {"x": -81.9830878, "y": 28.0319869}}, {"attributes": {"OBJECTID": 3345109, "MCode": 116, "ESN": 605, "GPSFLG": "N", "LR": "L", "Comments": " ", "Flag": "0", "Flg": 1, "DelRec": 0, "ESiteID": 149253, "SiteType": "R1", "Zip": "33884", "GPSX": -81.66724458, "GPSY": 28.00295255, "StreetID": 14041, "JBoundID": 10, "ParcelNum": "262836663202000040", "PD": "", "PT": "", "SN": "LAKE NED", "ST": "RD", "SD": "", "GeoNameID": 7679, "ZN": "POLK COUNTY", "HouseNumber": "729", "HouseInt": 729, "PrimaryAddress": "729 LAKE NED RD", "ALIAddress": "729 LAKE NED RD", "AddrLocation": "B", "PrimaryName": "LAKE NED RD", "ALIName": "LAKE NED RD", "Alias1": "", "Alias2": "", "Alias3": "", "Alias4": "", "Alias5": "", "CREATION_DATE": null, "C1_EXCEPTION": null, "MODIFY_USER": "emjaclch", "MODIFY_DATE": 20170417.14213, "CREATION_USER": null, "SiteTypeCode": "R1", "Unit": null, "County": null, "City_Ovr": null, "Blg": null, "Apt": null, "Sign": null, "PMOD": null, "FEMOD": null, "P_Override": null, "MailingCity": "WINTER HAVEN", "ESN_City_Name": "WINTER HAVEN UNINCORP EAST", "City_Code": "WHE", "T_MailingCityNm": "WINTER HAVEN", "FE_OVERRIDE": null, "GlobalID": "{BA7359BB-B836-4689-916B-AAE30403E47A}"}, "geometry": {"x": -81.6672478, "y": 28.0029578}}]} -------------------------------------------------------------------------------- /tests/test_esrijson.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from esridump import esri2geojson 4 | 5 | class TestEsriJsonToGeoJson(unittest.TestCase): 6 | def setUp(self): 7 | self.maxDiff = None 8 | 9 | def assertEsriJsonBecomesGeoJson(self, esrijson, geojson): 10 | out_json = esri2geojson(esrijson) 11 | self.assertDictEqual(out_json, geojson) 12 | 13 | 14 | class TestGeoJsonPointConversion(TestEsriJsonToGeoJson): 15 | def test_point(self): 16 | self.assertEsriJsonBecomesGeoJson( 17 | { 18 | "geometry": { 19 | "x": 496814.6, 20 | "y": 265006.2 21 | }, 22 | "attributes": None 23 | }, 24 | 25 | { 26 | "type": "Feature", 27 | "properties": None, 28 | "geometry": { 29 | "type": "Point", 30 | "coordinates": [496814.6, 265006.2], 31 | } 32 | } 33 | ) 34 | 35 | self.assertEsriJsonBecomesGeoJson( 36 | { 37 | "geometry": { 38 | "points": [ 39 | [496814.6, 265006.2], 40 | ] 41 | }, 42 | "attributes": None 43 | }, 44 | 45 | { 46 | "type": "Feature", 47 | "properties": None, 48 | "geometry": { 49 | "type": "Point", 50 | "coordinates": [496814.6, 265006.2], 51 | } 52 | } 53 | ) 54 | 55 | def test_multi_point(self): 56 | self.assertEsriJsonBecomesGeoJson( 57 | { 58 | "geometry": { 59 | "points": [ 60 | [41.83, 71.01], 61 | [56.95, 33.75], 62 | [21.79, 36.56] 63 | ], 64 | }, 65 | "attributes": None 66 | }, 67 | 68 | { 69 | "type": "Feature", 70 | "properties": None, 71 | "geometry": { 72 | "type": "MultiPoint", 73 | "coordinates": [ 74 | [41.83, 71.01], 75 | [56.95, 33.75], 76 | [21.79, 36.56] 77 | ] 78 | } 79 | } 80 | ) 81 | 82 | def test_empty_point(self): 83 | self.assertEsriJsonBecomesGeoJson( 84 | { 85 | "geometry": { 86 | "x": None, 87 | }, 88 | }, 89 | 90 | { 91 | "type": "Feature", 92 | "properties": None, 93 | "geometry": None 94 | } 95 | ) 96 | 97 | 98 | class TestGeoJsonLinestringConversion(TestEsriJsonToGeoJson): 99 | def test_linestring(self): 100 | self.assertEsriJsonBecomesGeoJson( 101 | { 102 | "geometry": { 103 | "paths" : [ 104 | [[-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832]] 105 | ], 106 | } 107 | }, 108 | 109 | { 110 | "type": "Feature", 111 | "properties": None, 112 | "geometry": { 113 | "type": "LineString", 114 | "coordinates": [ 115 | [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] 116 | ], 117 | } 118 | } 119 | ) 120 | 121 | def test_multi_linestring(self): 122 | self.assertEsriJsonBecomesGeoJson( 123 | { 124 | "geometry": { 125 | "paths" : [ 126 | [[-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832]], 127 | [[-97.06326,32.759], [-97.06298,32.755]] 128 | ], 129 | } 130 | }, 131 | 132 | { 133 | "type": "Feature", 134 | "properties": None, 135 | "geometry": { 136 | "type": "MultiLineString", 137 | "coordinates": [ 138 | [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] ], 139 | [ [-97.06326,32.759], [-97.06298,32.755] ] 140 | ], 141 | } 142 | } 143 | ) 144 | 145 | def test_real_linstring(self): 146 | self.assertEsriJsonBecomesGeoJson( 147 | { 148 | "attributes": { 149 | "objectid":187, 150 | "st_length(shape)":1322.4896687156252 151 | }, 152 | "geometry":{ 153 | "paths":[ 154 | [[-95.42428663740543,39.743798710848658],[-95.424285648691338,39.744302699946864],[-95.424279518608387,39.747429247542691]] 155 | ] 156 | } 157 | }, 158 | 159 | { 160 | "type": "Feature", 161 | "properties": { 162 | "objectid": 187, 163 | "st_length(shape)": 1322.4896687156252 164 | }, 165 | "geometry": { 166 | "type": "LineString", 167 | "coordinates": [ 168 | [-95.42428663740543, 39.74379871084866], [-95.42428564869134, 39.744302699946864], [-95.42427951860839, 39.74742924754269] 169 | ] 170 | } 171 | } 172 | ) 173 | 174 | 175 | class TestGeoJsonPolygonConversion(TestEsriJsonToGeoJson): 176 | def test_polygon(self): 177 | self.assertEsriJsonBecomesGeoJson( 178 | { 179 | "geometry": { 180 | "rings" : [ 181 | [ 182 | [1,1], 183 | [1,4], 184 | [4,4], 185 | [4,1], 186 | [1,1] 187 | ] 188 | ], 189 | } 190 | }, 191 | 192 | { 193 | "type": "Feature", 194 | "properties": None, 195 | "geometry": { 196 | "type": "Polygon", 197 | "coordinates": [ 198 | [ 199 | [1,1], 200 | [1,4], 201 | [4,4], 202 | [4,1], 203 | [1,1] 204 | ] 205 | ], 206 | } 207 | } 208 | ) 209 | 210 | def test_polygon_with_hole(self): 211 | self.assertEsriJsonBecomesGeoJson( 212 | { 213 | "geometry": { 214 | "rings" : [ 215 | [ 216 | [1,1], 217 | [1,4], 218 | [4,4], 219 | [4,1], 220 | [1,1] 221 | ], 222 | [ 223 | [2,2], 224 | [3,2], 225 | [3,3], 226 | [2,3], 227 | [2,2] 228 | ] 229 | ], 230 | } 231 | }, 232 | 233 | { 234 | "type": "Feature", 235 | "properties": None, 236 | "geometry": { 237 | "type": "Polygon", 238 | "coordinates": [ 239 | [ 240 | [1,1], 241 | [1,4], 242 | [4,4], 243 | [4,1], 244 | [1,1] 245 | ], 246 | [ 247 | [2,2], 248 | [3,2], 249 | [3,3], 250 | [2,3], 251 | [2,2] 252 | ] 253 | ], 254 | } 255 | } 256 | ) 257 | 258 | def test_polygon_close(self): 259 | # Esri-JSON allows polygons that aren't closed. GeoJSON requires them to be closed. 260 | self.assertEsriJsonBecomesGeoJson( 261 | { 262 | "geometry": { 263 | "rings" : [ 264 | [ 265 | [1,1], 266 | [1,4], 267 | [4,4], 268 | [4,1] 269 | ] 270 | ], 271 | } 272 | }, 273 | 274 | { 275 | "type": "Feature", 276 | "properties": None, 277 | "geometry": { 278 | "type": "Polygon", 279 | "coordinates": [ 280 | [ 281 | [1,1], 282 | [1,4], 283 | [4,4], 284 | [4,1], 285 | [1,1] 286 | ] 287 | ], 288 | } 289 | } 290 | ) 291 | 292 | def test_polygon_strip_invalid_rings(self): 293 | # Esri JSON allows rings with three points (A-B-A) that are essentially lines. GeoJSON doesn't. 294 | self.assertEsriJsonBecomesGeoJson( 295 | { 296 | "geometry": { 297 | "rings" : [ 298 | [ 299 | [1,1], 300 | [1,4], 301 | [4,4], 302 | [4,1] 303 | ], 304 | [ 305 | [1,1], 306 | [1,4], 307 | [1,1] 308 | ] 309 | ], 310 | } 311 | }, 312 | 313 | { 314 | "type": "Feature", 315 | "properties": None, 316 | "geometry": { 317 | "type": "Polygon", 318 | "coordinates": [ 319 | [ 320 | [1,1], 321 | [1,4], 322 | [4,4], 323 | [4,1], 324 | [1,1] 325 | ] 326 | ], 327 | } 328 | } 329 | ) 330 | 331 | def test_polygon_with_empty_geometry(self): 332 | # Esri JSON allows empty rings with 0 points. GeoJSON doesn't. 333 | self.assertEsriJsonBecomesGeoJson( 334 | { 335 | "geometry": { 336 | "rings": [ 337 | [ 338 | [1,1], 339 | [1,4], 340 | [4,4], 341 | [4,1] 342 | ], 343 | [ 344 | ] 345 | ], 346 | } 347 | }, 348 | 349 | { 350 | "type": "Feature", 351 | "properties": None, 352 | "geometry": { 353 | "type": "Polygon", 354 | "coordinates": [ 355 | [ 356 | [1,1], 357 | [1,4], 358 | [4,4], 359 | [4,1], 360 | [1,1] 361 | ] 362 | ], 363 | } 364 | } 365 | ) 366 | 367 | def test_ring_is_clockwise(self): 368 | from esridump.esri2geojson import ring_is_clockwise 369 | self.assertFalse(ring_is_clockwise( 370 | [[-86.3393396, 33.9767272], [-86.3392317, 33.9767215], [-86.3391237, 33.9767234], [-86.3392317, 33.9767215], [-86.3393396, 33.9767272]] 371 | )) 372 | self.assertTrue(ring_is_clockwise( 373 | [[-86.3394465, 33.9767405], [-86.3393396, 33.9767272], [-86.3394465, 33.9767405], [-86.3395516, 33.9767613], [-86.3394465, 33.9767405]] 374 | )) 375 | 376 | def test_skip_bad_ring(self): 377 | self.assertEsriJsonBecomesGeoJson( 378 | { 379 | 'geometry': { 380 | 'rings': [ 381 | [[-86.3393396, 33.9767272], [-86.3392317, 33.9767215], [-86.3391237, 33.9767234], [-86.3392317, 33.9767215], [-86.3393396, 33.9767272]], 382 | [[-86.3394465, 33.9767405], [-86.3393396, 33.9767272], [-86.3394465, 33.9767405], [-86.3395516, 33.9767613], [-86.3394465, 33.9767405]], 383 | [[-86.3385404, 33.9768611], [-86.3385637, 33.9768556], [-86.3385404, 33.9768611], [-86.3385047, 33.9768669], [-86.3384686, 33.9768702], [-86.3385047, 33.9768669], [-86.3385404, 33.9768611]], 384 | [[-86.3373056, 33.9769147], [-86.3373895, 33.9768781], [-86.3373056, 33.9769147], [-86.3372257, 33.9769572], [-86.3373056, 33.9769147]], 385 | [[-86.3383601, 33.9768650], [-86.3383248, 33.9768582], [-86.3382902, 33.9768490], [-86.3383248, 33.9768582], [-86.3383601, 33.9768650]], 386 | [[-86.3413982, 33.9774822], [-86.3413947, 33.9774828], [-86.3413947, 33.9774828], [-86.3413982, 33.9774822]] 387 | ] 388 | }, 389 | 'attributes': {} 390 | }, 391 | 392 | { 393 | 'type': 'Feature', 394 | 'geometry': { 395 | 'type': 'MultiPolygon', 396 | 'coordinates': [ 397 | [ 398 | [[-86.3394465, 33.9767405], [-86.3393396, 33.9767272], [-86.3394465, 33.9767405], [-86.3395516, 33.9767613], [-86.3394465, 33.9767405]], 399 | [[-86.3385404, 33.9768611], [-86.3385637, 33.9768556], [-86.3385404, 33.9768611], [-86.3385047, 33.9768669], [-86.3384686, 33.9768702], [-86.3385047, 33.9768669], [-86.3385404, 33.9768611]], 400 | ], 401 | [ 402 | [[-86.3373056, 33.9769147], [-86.3373895, 33.9768781], [-86.3373056, 33.9769147], [-86.3372257, 33.9769572], [-86.3373056, 33.9769147]], 403 | [[-86.3383601, 33.9768650], [-86.3383248, 33.9768582], [-86.3382902, 33.9768490], [-86.3383248, 33.9768582], [-86.3383601, 33.9768650]], 404 | ], 405 | [ 406 | [[-86.3413982, 33.9774822], [-86.3413947, 33.9774828], [-86.3413947, 33.9774828], [-86.3413982, 33.9774822]] 407 | ], 408 | ] 409 | }, 410 | 'properties': None 411 | } 412 | ) 413 | 414 | def test_multi_polygon(self): 415 | self.assertEsriJsonBecomesGeoJson( 416 | { 417 | "geometry": { 418 | "rings" : [ 419 | [ 420 | [1,1], 421 | [1,4], 422 | [4,4], 423 | [4,1], 424 | [1,1] 425 | ], 426 | [ 427 | [2,2], 428 | [3,2], 429 | [3,3], 430 | [2,3], 431 | [2,2] 432 | ], 433 | [ 434 | [5,1], 435 | [5,4], 436 | [8,4], 437 | [8,1], 438 | [5,1] 439 | ] 440 | ], 441 | } 442 | }, 443 | 444 | { 445 | "type": "Feature", 446 | "properties": None, 447 | "geometry": { 448 | "type": "MultiPolygon", 449 | "coordinates": [ 450 | [ 451 | [ 452 | [1,1], 453 | [1,4], 454 | [4,4], 455 | [4,1], 456 | [1,1] 457 | ], 458 | [ 459 | [2,2], 460 | [3,2], 461 | [3,3], 462 | [2,3], 463 | [2,2] 464 | ] 465 | ], 466 | [ 467 | [ 468 | [5,1], 469 | [5,4], 470 | [8,4], 471 | [8,1], 472 | [5,1] 473 | ] 474 | ] 475 | ], 476 | } 477 | } 478 | ) 479 | 480 | def test_multi_polygon_close(self): 481 | # We should close the rings of a multipolygon if they aren't closed already 482 | self.assertEsriJsonBecomesGeoJson( 483 | { 484 | "geometry": { 485 | "rings" : [ 486 | [ 487 | [1,1], 488 | [1,4], 489 | [4,4], 490 | [4,1] 491 | ], 492 | [ 493 | [2,2], 494 | [3,2], 495 | [3,3], 496 | [2,3], 497 | [2,2] 498 | ], 499 | [ 500 | [5,1], 501 | [5,4], 502 | [8,4], 503 | [8,1] 504 | ] 505 | ], 506 | } 507 | }, 508 | 509 | { 510 | "type": "Feature", 511 | "properties": None, 512 | "geometry": { 513 | "type": "MultiPolygon", 514 | "coordinates": [ 515 | [ 516 | [ 517 | [1,1], 518 | [1,4], 519 | [4,4], 520 | [4,1], 521 | [1,1] 522 | ], 523 | [ 524 | [2,2], 525 | [3,2], 526 | [3,3], 527 | [2,3], 528 | [2,2] 529 | ] 530 | ], 531 | [ 532 | [ 533 | [5,1], 534 | [5,4], 535 | [8,4], 536 | [8,1], 537 | [5,1] 538 | ] 539 | ] 540 | ], 541 | } 542 | } 543 | ) 544 | 545 | def test_empty_polygon(self): 546 | self.assertEsriJsonBecomesGeoJson( 547 | { 548 | "geometry": { 549 | "rings" : [ ] 550 | }, 551 | }, 552 | 553 | { 554 | "type": "Feature", 555 | "properties": None, 556 | "geometry": None 557 | } 558 | ) 559 | -------------------------------------------------------------------------------- /esridump/dumper.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import requests 3 | import json 4 | import socket 5 | import time 6 | from six.moves.urllib.parse import urlencode 7 | 8 | from esridump import esri2geojson 9 | from esridump.errors import EsriDownloadError 10 | 11 | 12 | class EsriDumper(object): 13 | def __init__(self, url, parent_logger=None, 14 | extra_query_args=None, extra_headers=None, 15 | timeout=None, fields=None, request_geometry=True, 16 | outSR=None, proxy=None, 17 | start_with=None, geometry_precision=None, 18 | paginate_oid=False, max_page_size=None, 19 | pause_seconds=10, requests_to_pause=5, 20 | num_of_retry=5, output_format='geojson'): 21 | self._layer_url = url 22 | self._query_params = extra_query_args or {} 23 | self._headers = extra_headers or {} 24 | self._http_timeout = timeout or 30 25 | self._fields = fields or None 26 | self._outSR = outSR or '4326' 27 | self._request_geometry = request_geometry 28 | self._proxy = proxy or None 29 | self._startWith = start_with or 0 30 | self._precision = geometry_precision or 7 31 | self._paginate_oid = paginate_oid 32 | self._max_page_size = max_page_size or 1000 33 | 34 | self._pause_seconds = pause_seconds 35 | self._requests_to_pause = requests_to_pause 36 | self._num_of_retry = num_of_retry 37 | 38 | if output_format not in ('geojson', 'esrijson'): 39 | raise ValueError(f'Invalid output format. Expecting "geojson" or "esrijson", got {output_format}') 40 | 41 | self._output_format = output_format 42 | 43 | if parent_logger: 44 | self._logger = parent_logger.getChild('esridump') 45 | else: 46 | self._logger = logging.getLogger('esridump') 47 | 48 | def _request(self, method, url, **kwargs): 49 | try: 50 | 51 | if self._proxy: 52 | url = self._proxy + url 53 | 54 | params = kwargs.pop('params', None) 55 | if params: 56 | url += '?' + urlencode(params) 57 | 58 | self._logger.debug("%s %s, args %s", method, url, 59 | kwargs.get('params') or kwargs.get('data')) 60 | return requests.request(method, url, timeout=self._http_timeout, **kwargs) 61 | except requests.exceptions.SSLError: 62 | self._logger.warning("Retrying %s without SSL verification", url) 63 | return requests.request(method, url, timeout=self._http_timeout, verify=False, **kwargs) 64 | 65 | def _build_url(self, url=None): 66 | return self._layer_url + url if url else self._layer_url 67 | 68 | def _build_query_args(self, query_args=None): 69 | if query_args: 70 | complete_args = query_args 71 | else: 72 | complete_args = {} 73 | 74 | override_args = dict(**self._query_params) 75 | 76 | override_where = override_args.get('where') 77 | requested_where = query_args.get('where') 78 | if override_where and requested_where and requested_where != '1=1': 79 | # AND the where args together if the user is trying to override 80 | # the where param and we're trying to get 'all the rows' 81 | override_args['where'] = '({}) AND ({})'.format( 82 | requested_where, 83 | override_where, 84 | ) 85 | 86 | complete_args.update(override_args) 87 | 88 | return complete_args 89 | 90 | def _build_headers(self, headers=None): 91 | complete_headers = dict(**self._headers) 92 | if headers: 93 | complete_headers.update(headers) 94 | return complete_headers 95 | 96 | def _handle_esri_errors(self, response, error_message): 97 | if response.status_code != 200: 98 | raise EsriDownloadError('{}: {} HTTP {} {}'.format( 99 | response.request.url, 100 | error_message, 101 | response.status_code, 102 | response.text, 103 | )) 104 | 105 | try: 106 | data = response.json() 107 | except: 108 | self._logger.error("Could not parse response from {} as JSON:\n\n{}".format( 109 | response.request.url, 110 | response.text, 111 | )) 112 | raise 113 | 114 | error = data.get('error') 115 | if error: 116 | raise EsriDownloadError("{}: {} {}" .format( 117 | error_message, 118 | error['message'], 119 | ', '.join(error['details']), 120 | )) 121 | 122 | return data 123 | 124 | def can_handle_pagination(self, query_fields): 125 | check_args = self._build_query_args({ 126 | 'resultOffset': 0, 127 | 'resultRecordCount': 1, 128 | 'where': '1=1', 129 | 'returnGeometry': 'false', 130 | 'outFields': ','.join(query_fields), 131 | 'f': 'json', 132 | }) 133 | headers = self._build_headers() 134 | query_url = self._build_url('/query') 135 | response = self._request( 136 | 'POST', query_url, headers=headers, data=check_args) 137 | 138 | try: 139 | data = response.json() 140 | except: 141 | self._logger.error("Could not parse response from pagination check %s as JSON:\n\n%s", 142 | response.request.url, 143 | response.text, 144 | ) 145 | return False 146 | 147 | return data.get('error') and data['error']['message'] != "Failed to execute query." 148 | 149 | def get_metadata(self): 150 | query_args = self._build_query_args({ 151 | 'f': 'json', 152 | }) 153 | headers = self._build_headers() 154 | url = self._build_url() 155 | response = self._request( 156 | 'GET', url, params=query_args, headers=headers) 157 | metadata_json = self._handle_esri_errors( 158 | response, "Could not retrieve layer metadata") 159 | return metadata_json 160 | 161 | def get_feature_count(self): 162 | query_args = self._build_query_args({ 163 | 'where': '1=1', 164 | 'returnCountOnly': 'true', 165 | 'f': 'json', 166 | }) 167 | headers = self._build_headers() 168 | url = self._build_url('/query') 169 | response = self._request( 170 | 'GET', url, params=query_args, headers=headers) 171 | count_json = self._handle_esri_errors( 172 | response, "Could not retrieve row count") 173 | count = count_json.get('count') 174 | if count is None: 175 | raise EsriDownloadError("Server doesn't support returnCountOnly") 176 | return count_json['count'] 177 | 178 | def _find_oid_field_name(self, metadata): 179 | oid_field_name = metadata.get('objectIdField') 180 | if not oid_field_name: 181 | for f in metadata['fields']: 182 | if f.get('type') == 'esriFieldTypeOID': 183 | oid_field_name = f['name'] 184 | elif f['name'].lower() == 'objectid': 185 | oid_field_name = f['name'] 186 | else: 187 | break 188 | 189 | return oid_field_name 190 | 191 | def _get_layer_min_max(self, oid_field_name): 192 | """ Find the min and max values for the OID field. """ 193 | query_args = self._build_query_args({ 194 | 'f': 'json', 195 | 'outFields': '', 196 | 'outStatistics': json.dumps([ 197 | dict(statisticType='min', onStatisticField=oid_field_name, 198 | outStatisticFieldName='THE_MIN'), 199 | dict(statisticType='max', onStatisticField=oid_field_name, 200 | outStatisticFieldName='THE_MAX'), 201 | ], separators=(',', ':')) 202 | }) 203 | headers = self._build_headers() 204 | url = self._build_url('/query') 205 | response = self._request( 206 | 'GET', url, params=query_args, headers=headers) 207 | metadata = self._handle_esri_errors( 208 | response, "Could not retrieve min/max oid values") 209 | 210 | # Some servers (specifically version 10.11, it seems) will respond with SQL statements 211 | # for the attribute names rather than the requested field names, so pick the min and max 212 | # deliberately rather than relying on the names. 213 | min_max_values = metadata['features'][0]['attributes'].values() 214 | min_value = min(min_max_values) 215 | max_value = max(min_max_values) 216 | query_args = self._build_query_args({ 217 | 'f': 'json', 218 | 'outFields': '*', 219 | 'outStatistics': json.dumps([ 220 | dict(statisticType='min', onStatisticField=oid_field_name, 221 | outStatisticFieldName='THE_MIN'), 222 | dict(statisticType='max', onStatisticField=oid_field_name, 223 | outStatisticFieldName='THE_MAX'), 224 | ], separators=(',', ':')) 225 | }) 226 | query_args = self._build_query_args({ 227 | 'where': '{} = {} OR {} = {}'.format( 228 | oid_field_name, 229 | min_value, 230 | oid_field_name, 231 | max_value 232 | ), 233 | 'returnIdsOnly': 'true', 234 | 'f': 'json', 235 | }) 236 | headers = self._build_headers() 237 | url = self._build_url('/query') 238 | response = self._request( 239 | 'GET', url, params=query_args, headers=headers) 240 | oid_data = self._handle_esri_errors( 241 | response, "Could not check min/max values") 242 | if not oid_data or not oid_data.get('objectIds') or min_value not in oid_data['objectIds'] or max_value not in oid_data['objectIds']: 243 | raise EsriDownloadError('Server returned invalid min/max') 244 | 245 | return (int(min_value), int(max_value)) 246 | 247 | def _get_layer_oids(self): 248 | query_args = self._build_query_args({ 249 | 'where': '1=1', # So we get everything 250 | 'returnIdsOnly': 'true', 251 | 'f': 'json', 252 | }) 253 | url = self._build_url('/query') 254 | headers = self._build_headers() 255 | response = self._request( 256 | 'GET', url, params=query_args, headers=headers) 257 | oid_data = self._handle_esri_errors( 258 | response, "Could not retrieve object IDs") 259 | oids = oid_data.get('objectIds') 260 | if not oids: 261 | raise EsriDownloadError("Server doesn't support returnIdsOnly") 262 | return oids 263 | 264 | def _fetch_bounded_features(self, envelope, outSR): 265 | query_args = self._build_query_args({ 266 | 'geometry': json.dumps(envelope), 267 | 'geometryType': 'esriGeometryEnvelope', 268 | 'spatialRel': 'esriSpatialRelIntersects', 269 | 'returnCountOnly': 'false', 270 | 'returnIdsOnly': 'false', 271 | 'returnGeometry': self._request_geometry, 272 | 'outSR': outSR, 273 | 'outFields': '*', 274 | 'f': 'json' 275 | }) 276 | headers = self._build_headers() 277 | url = self._build_url('/query') 278 | response = self._request( 279 | 'GET', url, params=query_args, headers=headers) 280 | features = self._handle_esri_errors( 281 | response, "Could not retrieve a section of features") 282 | return features['features'] 283 | 284 | def _split_envelope(self, envelope): 285 | half_width = (envelope['xmax'] - envelope['xmin']) / 2.0 286 | half_height = (envelope['ymax'] - envelope['ymin']) / 2.0 287 | return [ 288 | dict( 289 | xmin=envelope['xmin'], 290 | ymin=envelope['ymin'], 291 | xmax=envelope['xmin'] + half_width, 292 | ymax=envelope['ymin'] + half_height, 293 | ), 294 | dict( 295 | xmax=envelope['xmin'] + half_width, 296 | ymin=envelope['ymin'], 297 | xmin=envelope['xmax'], 298 | ymax=envelope['ymin'] + half_height, 299 | ), 300 | dict( 301 | xmin=envelope['xmin'], 302 | ymax=envelope['ymin'] + half_height, 303 | xmax=envelope['xmin'] + half_width, 304 | ymin=envelope['ymax'], 305 | ), 306 | dict( 307 | xmax=envelope['xmin'] + half_width, 308 | ymax=envelope['ymin'] + half_height, 309 | xmin=envelope['xmax'], 310 | ymin=envelope['ymax'], 311 | ), 312 | ] 313 | 314 | def _scrape_an_envelope(self, envelope, outSR, max_records): 315 | features = self._fetch_bounded_features(envelope, outSR) 316 | 317 | if len(features) >= max_records: 318 | self._logger.info( 319 | "Retrieved exactly the maximum record count. Splitting this box and retrieving the children.") 320 | 321 | envelopes = self._split_envelope(envelope) 322 | 323 | for child_envelope in envelopes: 324 | for feature in self._scrape_an_envelope(child_envelope, outSR, max_records): 325 | yield feature 326 | else: 327 | for feature in features: 328 | yield feature 329 | 330 | def __iter__(self): 331 | query_fields = self._fields 332 | metadata = self.get_metadata() 333 | page_size = max(self._max_page_size, 334 | metadata.get('maxRecordCount', 500)) 335 | geometry_type = metadata.get('geometryType') 336 | 337 | row_count = None 338 | 339 | try: 340 | row_count = self.get_feature_count() 341 | except EsriDownloadError: 342 | self._logger.info("Source does not support feature count") 343 | 344 | # If there are no records matching the query, short circuit and return an empty generator. 345 | if row_count == 0: 346 | return 347 | yield 348 | 349 | page_args = [] 350 | 351 | if not self._paginate_oid and row_count is not None and (metadata.get('supportsPagination') or 352 | (metadata.get('advancedQueryCapabilities') and metadata['advancedQueryCapabilities']['supportsPagination'])): 353 | # If the layer supports pagination, we can use resultOffset/resultRecordCount to paginate 354 | 355 | # There's a bug where some servers won't handle these queries in combination with a list of 356 | # fields specified. We'll make a single, 1 row query here to check if the server supports this 357 | # and switch to querying for all fields if specifying the fields fails. 358 | if query_fields and not self.can_handle_pagination(query_fields): 359 | self._logger.info( 360 | "Source does not support pagination with fields specified, so querying for all fields.") 361 | query_fields = None 362 | 363 | for offset in range(self._startWith, row_count, page_size): 364 | query_args = self._build_query_args({ 365 | 'resultOffset': offset, 366 | 'resultRecordCount': page_size, 367 | 'where': '1=1', 368 | 'geometryPrecision': self._precision, 369 | 'returnGeometry': self._request_geometry, 370 | 'outSR': self._outSR, 371 | 'outFields': ','.join(query_fields or ['*']), 372 | 'f': 'json', 373 | }) 374 | page_args.append(query_args) 375 | self._logger.info( 376 | "Built %s requests of size %s using resultOffset method", len(page_args), page_size) 377 | else: 378 | # If not, we can still use the `where` argument to paginate 379 | 380 | use_oids = True 381 | oid_field_name = self._find_oid_field_name(metadata) 382 | 383 | if not oid_field_name: 384 | raise EsriDownloadError( 385 | "Could not find object ID field name for deduplication") 386 | 387 | if metadata.get('supportsStatistics'): 388 | # If the layer supports statistics, we can request maximum and minimum object ID 389 | # to help build the pages 390 | try: 391 | (oid_min, oid_max) = self._get_layer_min_max(oid_field_name) 392 | 393 | for page_min in range(oid_min - 1, oid_max, page_size): 394 | page_max = min(page_min + page_size, oid_max) 395 | query_args = self._build_query_args({ 396 | 'where': '{} > {} AND {} <= {}'.format( 397 | oid_field_name, 398 | page_min, 399 | oid_field_name, 400 | page_max, 401 | ), 402 | 'geometryPrecision': self._precision, 403 | 'returnGeometry': self._request_geometry, 404 | 'outSR': self._outSR, 405 | 'outFields': ','.join(query_fields or ['*']), 406 | 'f': 'json', 407 | }) 408 | page_args.append(query_args) 409 | self._logger.info( 410 | "Built {} requests using OID where clause method".format(len(page_args))) 411 | 412 | # If we reach this point we don't need to fall through to enumerating all object IDs 413 | # because the statistics method worked 414 | use_oids = False 415 | except EsriDownloadError: 416 | self._logger.exception( 417 | "Finding max/min from statistics failed. Trying OID enumeration.") 418 | 419 | if use_oids: 420 | # If the layer does not support statistics, we can request 421 | # all the individual IDs and page through them one chunk at 422 | # a time. 423 | 424 | try: 425 | oids = sorted(map(int, self._get_layer_oids())) 426 | 427 | for i in range(0, len(oids), page_size): 428 | oid_chunk = oids[i:i+page_size] 429 | page_min = oid_chunk[0] 430 | page_max = oid_chunk[-1] 431 | query_args = self._build_query_args({ 432 | 'where': '{} >= {} AND {} <= {}'.format( 433 | oid_field_name, 434 | page_min, 435 | oid_field_name, 436 | page_max, 437 | ), 438 | 'geometryPrecision': self._precision, 439 | 'returnGeometry': self._request_geometry, 440 | 'outSR': self._outSR, 441 | 'outFields': ','.join(query_fields or ['*']), 442 | 'f': 'json', 443 | }) 444 | page_args.append(query_args) 445 | self._logger.info( 446 | "Built %s requests using OID enumeration method", len(page_args)) 447 | except EsriDownloadError: 448 | self._logger.info("Falling back to geo queries") 449 | # Use geospatial queries when none of the ID-based methods will work 450 | bounds = metadata['extent'] 451 | saved = set() 452 | 453 | for feature in self._scrape_an_envelope(bounds, self._outSR, page_size): 454 | attrs = feature['attributes'] 455 | oid = attrs.get(oid_field_name) 456 | if oid in saved: 457 | continue 458 | 459 | yield esri2geojson(feature) 460 | 461 | saved.add(oid) 462 | 463 | return 464 | 465 | query_url = self._build_url('/query') 466 | headers = self._build_headers() 467 | for query_index, query_args in enumerate(page_args, start=1): 468 | download_exception = None 469 | data = None 470 | 471 | # try to do a request "num_of_retry" to increase the probability of fetching data successfully 472 | for retry in range(self._num_of_retry): 473 | try: 474 | # pause every number of "requests_to_pause", that increase the probability for server response 475 | if query_index % self._requests_to_pause == 0: 476 | time.sleep(self._pause_seconds) 477 | self._logger.info( 478 | "pause for %s seconds", self._pause_seconds) 479 | response = self._request( 480 | 'POST', query_url, headers=headers, data=query_args) 481 | data = self._handle_esri_errors( 482 | response, "Could not retrieve this chunk of objects") 483 | # reset the exception state. 484 | download_exception = None 485 | # get out of retry loop, as the request succeeded 486 | break 487 | except socket.timeout as e: 488 | raise EsriDownloadError( 489 | "Timeout when connecting to URL", e) 490 | except ValueError as e: 491 | raise EsriDownloadError("Could not parse JSON", e) 492 | except Exception as e: 493 | download_exception = EsriDownloadError( 494 | "Could not connect to URL", e) 495 | # increase the pause time every retry, to increase the probability of fetching data successfully 496 | time.sleep(self._pause_seconds * (retry + 1)) 497 | self._logger.info("retry pause {0}".format(retry)) 498 | 499 | if download_exception: 500 | raise download_exception 501 | 502 | error = data.get('error') 503 | if error: 504 | raise EsriDownloadError("Problem querying ESRI dataset with args {}. Server said: {}".format( 505 | query_args, error['message'])) 506 | 507 | features = data.get('features') 508 | 509 | for feature in features: 510 | if self._output_format == 'geojson': 511 | yield esri2geojson(feature) 512 | else: 513 | yield feature 514 | -------------------------------------------------------------------------------- /tests/fixtures/us-mo-columbia/us-mo-columbia-0.json: -------------------------------------------------------------------------------- 1 | {"displayFieldName":"PRE_DIR","fieldAliases":{"OBJECTID":"OBJECTID","HOUSENO":"HOUSENO","PRE_DIR":"PRE_DIR","SUFFIX":"SUFFIX","POST_DIR":"POST_DIR","POST_QUAL":"POST_QUAL","APT":"APT","CITY_LIMIT":"CITY_LIMIT","ACCURACY":"ACCURACY","ASSESSOR":"ASSESSOR","PRE_QUAL":"PRE_QUAL","XCOORD":"XCOORD","YCOORD":"YCOORD","STREET":"STREET","HISTORY":"HISTORY","ZIP":"ZIP","NOTES":"NOTES","CITY":"CITY","DRIVEWAY_NUM":"DRIVEWAY_NUM","ADDRESS_NUM":"ADDRESS_NUM","X":"X","Y":"Y","Z":"Z","EDIT_CODE":"EDIT_CODE","ALIAS":"ALIAS","GlobalID":"GlobalID"},"geometryType":"esriGeometryPoint","spatialReference":{"wkid":4326},"fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID"},{"name":"HOUSENO","type":"esriFieldTypeInteger","alias":"HOUSENO"},{"name":"PRE_DIR","type":"esriFieldTypeString","alias":"PRE_DIR","length":1},{"name":"SUFFIX","type":"esriFieldTypeString","alias":"SUFFIX","length":11},{"name":"POST_DIR","type":"esriFieldTypeString","alias":"POST_DIR","length":1},{"name":"POST_QUAL","type":"esriFieldTypeString","alias":"POST_QUAL","length":10},{"name":"APT","type":"esriFieldTypeString","alias":"APT","length":17},{"name":"CITY_LIMIT","type":"esriFieldTypeString","alias":"CITY_LIMIT","length":2},{"name":"ACCURACY","type":"esriFieldTypeString","alias":"ACCURACY","length":10},{"name":"ASSESSOR","type":"esriFieldTypeString","alias":"ASSESSOR","length":16},{"name":"PRE_QUAL","type":"esriFieldTypeString","alias":"PRE_QUAL","length":10},{"name":"XCOORD","type":"esriFieldTypeDouble","alias":"XCOORD"},{"name":"YCOORD","type":"esriFieldTypeDouble","alias":"YCOORD"},{"name":"STREET","type":"esriFieldTypeString","alias":"STREET","length":35},{"name":"HISTORY","type":"esriFieldTypeString","alias":"HISTORY","length":35},{"name":"ZIP","type":"esriFieldTypeString","alias":"ZIP","length":8},{"name":"NOTES","type":"esriFieldTypeString","alias":"NOTES","length":35},{"name":"CITY","type":"esriFieldTypeString","alias":"CITY","length":35},{"name":"DRIVEWAY_NUM","type":"esriFieldTypeInteger","alias":"DRIVEWAY_NUM"},{"name":"ADDRESS_NUM","type":"esriFieldTypeInteger","alias":"ADDRESS_NUM"},{"name":"X","type":"esriFieldTypeDouble","alias":"X"},{"name":"Y","type":"esriFieldTypeDouble","alias":"Y"},{"name":"Z","type":"esriFieldTypeString","alias":"Z","length":8},{"name":"EDIT_CODE","type":"esriFieldTypeString","alias":"EDIT_CODE","length":15},{"name":"ALIAS","type":"esriFieldTypeString","alias":"ALIAS","length":45},{"name":"GlobalID","type":"esriFieldTypeGUID","alias":"GlobalID","length":38}],"features":[{"attributes":{"OBJECTID":64579816,"HOUSENO":4880,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2420010000030001","PRE_QUAL":" ","XCOORD":-92.269846479999998,"YCOORD":38.785711200000001,"STREET":"CLELLIE HARMON","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":26191,"ADDRESS_NUM":110,"X":1706020,"Y":1075026,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.269846484403587,"y":38.785711209318976}},{"attributes":{"OBJECTID":64579817,"HOUSENO":12770,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2330201000270001","PRE_QUAL":" ","XCOORD":-92.329366449999995,"YCOORD":38.800093599999997,"STREET":"ANDREW SAPP","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":24807,"ADDRESS_NUM":9,"X":1689044,"Y":1080226,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.329366454327854,"y":38.800093609123415}},{"attributes":{"OBJECTID":64579818,"HOUSENO":13853,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2510007000010001","PRE_QUAL":" ","XCOORD":-92.197158799999997,"YCOORD":38.785153430000001,"STREET":"BOB VEACH","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":16442,"ADDRESS_NUM":51,"X":1726740,"Y":1074883,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.197158808773224,"y":38.785153439021734}},{"attributes":{"OBJECTID":64579819,"HOUSENO":8000,"PRE_DIR":"E","SUFFIX":"LN","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2490036000100001","PRE_QUAL":" ","XCOORD":-92.221292919999996,"YCOORD":38.718780989999999,"STREET":"GILMORE","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":26404,"ADDRESS_NUM":248,"X":1719934,"Y":1050689,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.221292921392788,"y":38.718780999306482}},{"attributes":{"OBJECTID":64579820,"HOUSENO":1400,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2410007000060301","PRE_QUAL":" ","XCOORD":-92.324465290000006,"YCOORD":38.79040895,"STREET":"LEO SMITH","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":31552,"ADDRESS_NUM":387,"X":1690448,"Y":1076702,"Z":"1","EDIT_CODE":"0604BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.324465299459575,"y":38.790408954345587}},{"attributes":{"OBJECTID":64579821,"HOUSENO":1331,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2410007000060001","PRE_QUAL":" ","XCOORD":-92.326416730000005,"YCOORD":38.789700150000002,"STREET":"LEO SMITH","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":1075,"ADDRESS_NUM":386,"X":1689892,"Y":1076443,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.326416732241753,"y":38.789700153533651}},{"attributes":{"OBJECTID":64579822,"HOUSENO":14250,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2510007000160001","PRE_QUAL":" ","XCOORD":-92.212036889999993,"YCOORD":38.780493929999999,"STREET":"RANGELINE","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":994,"ADDRESS_NUM":445,"X":1722504,"Y":1073172,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.212036890708859,"y":38.780493930977904}},{"attributes":{"OBJECTID":64579823,"HOUSENO":750,"PRE_DIR":"E","SUFFIX":"LN","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2390025000150001","PRE_QUAL":" ","XCOORD":-92.336490080000004,"YCOORD":38.739583850000002,"STREET":"BATYE","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":656,"ADDRESS_NUM":573,"X":1687054,"Y":1058186,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.336490083237265,"y":38.739583857795878}},{"attributes":{"OBJECTID":64579824,"HOUSENO":19600,"PRE_DIR":"S","SUFFIX":"LN","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2720004000010001","PRE_QUAL":" ","XCOORD":-92.277780899999996,"YCOORD":38.716362660000001,"STREET":"FREEMAN","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25947,"ADDRESS_NUM":755,"X":1703820,"Y":1049764,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.277780900813156,"y":38.716362666882688}},{"attributes":{"OBJECTID":64579825,"HOUSENO":24050,"PRE_DIR":"S","SUFFIX":"DR","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2760024000060601","PRE_QUAL":" ","XCOORD":-92.234432260000005,"YCOORD":38.661253379999998,"STREET":"MISSOURI RIVER VIEW","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26497,"ADDRESS_NUM":831,"X":1716246,"Y":1029728,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.234432267308392,"y":38.661253381053385}},{"attributes":{"OBJECTID":64579826,"HOUSENO":6063,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2760023000080701","PRE_QUAL":" ","XCOORD":-92.257460429999995,"YCOORD":38.667493989999997,"STREET":"CLAYSVILLE","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26478,"ADDRESS_NUM":671,"X":1709664,"Y":1031982,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.257460430174049,"y":38.66749399573478}},{"attributes":{"OBJECTID":64579827,"HOUSENO":22500,"PRE_DIR":"S","SUFFIX":"LN","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2750015000180001","PRE_QUAL":" ","XCOORD":-92.268985279999995,"YCOORD":38.675531929999998,"STREET":"COONCE","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":218,"ADDRESS_NUM":698,"X":1706367,"Y":1034901,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.268985284967641,"y":38.675531936778746}},{"attributes":{"OBJECTID":64579828,"HOUSENO":12901,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2410106000180001","PRE_QUAL":" ","XCOORD":-92.325547819999997,"YCOORD":38.799738040000001,"STREET":"JOY","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":24803,"ADDRESS_NUM":376,"X":1690133,"Y":1080099,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.325547824648893,"y":38.799738048715518}},{"attributes":{"OBJECTID":64579829,"HOUSENO":1621,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2410106000320601","PRE_QUAL":" ","XCOORD":-92.320127319999997,"YCOORD":38.79093142,"STREET":"LEO SMITH","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":24785,"ADDRESS_NUM":392,"X":1691684,"Y":1076895,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.320127326184718,"y":38.790931420969969}},{"attributes":{"OBJECTID":64579830,"HOUSENO":17351,"PRE_DIR":"S","SUFFIX":" ","POST_DIR":null,"POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2480227000040101","PRE_QUAL":" ","XCOORD":-92.263505449999997,"YCOORD":38.74385127,"STREET":"OLD HWY 63","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":24732,"ADDRESS_NUM":413,"X":1707867,"Y":1059785,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.263505454740582,"y":38.743851273483024}},{"attributes":{"OBJECTID":64579831,"HOUSENO":17501,"PRE_DIR":"S","SUFFIX":" ","POST_DIR":null,"POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2480227060010001","PRE_QUAL":" ","XCOORD":-92.263419519999999,"YCOORD":38.742488710000003,"STREET":"OLD HWY 63","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":24734,"ADDRESS_NUM":414,"X":1707893,"Y":1059289,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.263419521292363,"y":38.742488713813231}},{"attributes":{"OBJECTID":64579832,"HOUSENO":17801,"PRE_DIR":"S","SUFFIX":" ","POST_DIR":null,"POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2480227000070001","PRE_QUAL":" ","XCOORD":-92.263685229999993,"YCOORD":38.738429080000003,"STREET":"OLD HWY 63","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":24736,"ADDRESS_NUM":416,"X":1707821.0584,"Y":1057811.11515,"Z":"1","EDIT_CODE":"1506BCPZ","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.263685231884111,"y":38.73842907726609}},{"attributes":{"OBJECTID":64579833,"HOUSENO":13331,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2430001000100001","PRE_QUAL":" ","XCOORD":-92.217036750000005,"YCOORD":38.789832820000001,"STREET":"RANGELINE","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":23568,"ADDRESS_NUM":433,"X":1721068,"Y":1076569,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.217036756533744,"y":38.789832823008943}},{"attributes":{"OBJECTID":64579834,"HOUSENO":13710,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2430012000050201","PRE_QUAL":" ","XCOORD":-92.228737960000004,"YCOORD":38.787899930000002,"STREET":"ROBBIE FORBIS","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":25029,"ADDRESS_NUM":454,"X":1717735,"Y":1075855,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"S FORBIS RD, ROBBIE FORBIS RD","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.22873796668074,"y":38.787899938418484}},{"attributes":{"OBJECTID":64579835,"HOUSENO":16651,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2450321020080001","PRE_QUAL":" ","XCOORD":-92.288156209999997,"YCOORD":38.752993949999997,"STREET":"PALIS NICHOLS","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25770,"ADDRESS_NUM":923,"X":1700828,"Y":1063098,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.28815621014104,"y":38.75299395055}},{"attributes":{"OBJECTID":64579836,"HOUSENO":19530,"PRE_DIR":"S","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2480333000250001","PRE_QUAL":" ","XCOORD":-92.277695719999997,"YCOORD":38.7172567,"STREET":"RTE A","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25944,"ADDRESS_NUM":953,"X":1703843,"Y":1050090,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.277695722791947,"y":38.717256700137426}},{"attributes":{"OBJECTID":64579837,"HOUSENO":19700,"PRE_DIR":"S","SUFFIX":" ","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2720004000040201","PRE_QUAL":" ","XCOORD":-92.281390979999998,"YCOORD":38.71515745,"STREET":"RTE A","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25951,"ADDRESS_NUM":961,"X":1702791,"Y":1049323,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.281390988012632,"y":38.715157456523464}},{"attributes":{"OBJECTID":64579838,"HOUSENO":20201,"PRE_DIR":"S","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2720004000080001","PRE_QUAL":" ","XCOORD":-92.288097910000005,"YCOORD":38.709623960000002,"STREET":"RTE A","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":509,"ADDRESS_NUM":970,"X":1700882,"Y":1047303,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.288097917814923,"y":38.709623962504033}},{"attributes":{"OBJECTID":64579839,"HOUSENO":593,"PRE_DIR":"E","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2360024010010001","PRE_QUAL":" ","XCOORD":-92.340530369999996,"YCOORD":38.75012134,"STREET":"RTE M","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26393,"ADDRESS_NUM":999,"X":1685894,"Y":1062021,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"STATE HIGHWAY M","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.34053037688291,"y":38.750121342178076}},{"attributes":{"OBJECTID":64579840,"HOUSENO":881,"PRE_DIR":"E","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2360024000110001","PRE_QUAL":" ","XCOORD":-92.337406689999995,"YCOORD":38.751891800000003,"STREET":"RTE M","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":732,"ADDRESS_NUM":1003,"X":1686784,"Y":1062668,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"STATE HIGHWAY M","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.337406699845815,"y":38.751891800792414}},{"attributes":{"OBJECTID":64579841,"HOUSENO":2801,"PRE_DIR":"E","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2440017000150001","PRE_QUAL":" ","XCOORD":-92.302909940000006,"YCOORD":38.76848502,"STREET":"RTE M","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26306,"ADDRESS_NUM":1032,"X":1696609,"Y":1068730,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"STATE HIGHWAY M","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.302909949784578,"y":38.768485023202132}},{"attributes":{"OBJECTID":64579842,"HOUSENO":260,"PRE_DIR":"W","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2390026000010001","PRE_QUAL":" ","XCOORD":-92.351347739999994,"YCOORD":38.745163650000002,"STREET":"RTE M","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25039,"ADDRESS_NUM":1036,"X":1682812,"Y":1060211,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"STATE HIGHWAY M","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.35134774104327,"y":38.745163654800464}},{"attributes":{"OBJECTID":64579843,"HOUSENO":21855,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2720010000230001","PRE_QUAL":" ","XCOORD":-92.259528860000003,"YCOORD":38.689767400000001,"STREET":"SOUTH MOUNT PLEASANT","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":0,"ADDRESS_NUM":1071,"X":1709053,"Y":1040092,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.25952886335844,"y":38.689767400412919}},{"attributes":{"OBJECTID":64579844,"HOUSENO":22670,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2750015000010001","PRE_QUAL":" ","XCOORD":-92.258238259999999,"YCOORD":38.67907203,"STREET":"SOUTH MOUNT PLEASANT","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":24382,"ADDRESS_NUM":1077,"X":1709431,"Y":1036198,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.258238264396283,"y":38.679072037433144}},{"attributes":{"OBJECTID":64579845,"HOUSENO":20450,"PRE_DIR":"S","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":"","APT":"","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2720203020080001","PRE_QUAL":" ","XCOORD":-92.260532769999998,"YCOORD":38.706219470000001,"STREET":"TURKEY RIDGE","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":24989,"ADDRESS_NUM":1088,"X":1708750,"Y":1046083,"Z":"1","EDIT_CODE":"0607BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.260532771304966,"y":38.706219474031485}},{"attributes":{"OBJECTID":64579846,"HOUSENO":4109,"PRE_DIR":"E","SUFFIX":"LN","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2480128040010001","PRE_QUAL":" ","XCOORD":-92.287345239999993,"YCOORD":38.734779580000001,"STREET":"WEST SNOWY HILLS","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25819,"ADDRESS_NUM":1116,"X":1701075,"Y":1056465,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.287345246245067,"y":38.734779580865208}},{"attributes":{"OBJECTID":64579847,"HOUSENO":22140,"PRE_DIR":"S","SUFFIX":"DR","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2760114000050001","PRE_QUAL":" ","XCOORD":-92.249555549999997,"YCOORD":38.684430069999998,"STREET":"WESTBROOK","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":23611,"ADDRESS_NUM":1133,"X":1711905,"Y":1038156,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"WESTBROOK WAY, WESTBROOK DR","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.249555551779636,"y":38.68443007901206}},{"attributes":{"OBJECTID":64579848,"HOUSENO":6551,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2730002000040101","PRE_QUAL":" ","XCOORD":-92.24565131,"YCOORD":38.713269429999997,"STREET":"ZUMWALT","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26419,"ADDRESS_NUM":1165,"X":1712990,"Y":1048662,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.245651318818645,"y":38.713269431230849}},{"attributes":{"OBJECTID":64579849,"HOUSENO":7281,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2730001000090001","PRE_QUAL":" ","XCOORD":-92.232453989999996,"YCOORD":38.70762053,"STREET":"ZUMWALT","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26425,"ADDRESS_NUM":1173,"X":1716761,"Y":1046615,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.232453995704958,"y":38.70762053920533}},{"attributes":{"OBJECTID":64579850,"HOUSENO":201,"PRE_DIR":"","SUFFIX":"DR","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"1","ACCURACY":"1","ASSESSOR":"2450200030250001","PRE_QUAL":" ","XCOORD":-92.260307100000006,"YCOORD":38.766531620000002,"STREET":"AMANDA","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":0,"ADDRESS_NUM":1226,"X":1708757,"Y":1068048,"Z":"1","EDIT_CODE":"0207BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.260307104839043,"y":38.766531623113075}},{"attributes":{"OBJECTID":64579851,"HOUSENO":302,"PRE_DIR":"","SUFFIX":"DR","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"1","ACCURACY":"1","ASSESSOR":"2450200030210001","PRE_QUAL":" ","XCOORD":-92.258441550000001,"YCOORD":38.765971860000001,"STREET":"AMANDA","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":0,"ADDRESS_NUM":1235,"X":1709290,"Y":1067845,"Z":"1","EDIT_CODE":"0207BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.258441550918803,"y":38.765971865631954}},{"attributes":{"OBJECTID":64579852,"HOUSENO":124,"PRE_DIR":"E","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"1","ACCURACY":"1","ASSESSOR":"2450800040330001","PRE_QUAL":" ","XCOORD":-92.260851829999993,"YCOORD":38.774352360000002,"STREET":"BROADWAY","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":1659,"ADDRESS_NUM":1275,"X":1708595,"Y":1070895,"Z":"1","EDIT_CODE":"0207BCGIS","ALIAS":"STATE HIGHWAY Y","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.260851832632255,"y":38.774352369938121}},{"attributes":{"OBJECTID":64579853,"HOUSENO":107,"PRE_DIR":"W","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"1","ACCURACY":"1","ASSESSOR":"2421900100020001","PRE_QUAL":" ","XCOORD":-92.262789569999995,"YCOORD":38.77485618,"STREET":"BROADWAY","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":2118,"ADDRESS_NUM":1283,"X":1708042,"Y":1071077,"Z":"1","EDIT_CODE":"0207BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.262789574953317,"y":38.774856187708664}},{"attributes":{"OBJECTID":64579854,"HOUSENO":107,"PRE_DIR":"","SUFFIX":"ST","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"1","ACCURACY":"1","ASSESSOR":"2450700020230001","PRE_QUAL":" ","XCOORD":-92.263779880000001,"YCOORD":38.774004150000003,"STREET":"CHURCH","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":2863,"ADDRESS_NUM":1303,"X":1707760,"Y":1070766,"Z":"1","EDIT_CODE":"0207BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.263779880250866,"y":38.774004156929479}},{"attributes":{"OBJECTID":64579855,"HOUSENO":3051,"PRE_DIR":"E","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2440017000100001","PRE_QUAL":" ","XCOORD":-92.299822160000005,"YCOORD":38.773316020000003,"STREET":"RTE M","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":16422,"ADDRESS_NUM":471,"X":1697485,"Y":1070491,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"STATE HIGHWAY M","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.299822160444506,"y":38.773316020812558}},{"attributes":{"OBJECTID":64579856,"HOUSENO":5706,"PRE_DIR":"E","SUFFIX":"RD","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2720203010060001","PRE_QUAL":" ","XCOORD":-92.256810709999996,"YCOORD":38.706080419999999,"STREET":"LEE","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":26445,"ADDRESS_NUM":496,"X":1709813,"Y":1046035,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.256810715086417,"y":38.706080422685346}},{"attributes":{"OBJECTID":64579857,"HOUSENO":4003,"PRE_DIR":"E","SUFFIX":"CT","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2450116040110001","PRE_QUAL":" ","XCOORD":-92.284066339999995,"YCOORD":38.76632506,"STREET":"LIBERTY WOODS","HISTORY":" ","ZIP":"65039","NOTES":" ","CITY":"HARTSBURG","DRIVEWAY_NUM":25743,"ADDRESS_NUM":516,"X":1701983,"Y":1067956,"Z":"1","EDIT_CODE":"0204BCGIS","ALIAS":"","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.284066340456931,"y":38.766325060978652}},{"attributes":{"OBJECTID":64579858,"HOUSENO":7151,"PRE_DIR":"E","SUFFIX":" ","POST_DIR":" ","POST_QUAL":" ","APT":" ","CITY_LIMIT":"0","ACCURACY":"1","ASSESSOR":"2430011010010001","PRE_QUAL":" ","XCOORD":-92.234594970000003,"YCOORD":38.774323180000003,"STREET":"RTE Y","HISTORY":" ","ZIP":"65010","NOTES":" ","CITY":"ASHLAND","DRIVEWAY_NUM":26235,"ADDRESS_NUM":521,"X":1716080,"Y":1070905,"Z":"1","EDIT_CODE":"1102BCGIS","ALIAS":"STATE HIGHWAY Y","GlobalID":"{00000000-0000-0000-0000-000000000000}"},"geometry":{"x":-92.234594978729717,"y":38.774323181741487}}]} 2 | --------------------------------------------------------------------------------