[go: up one dir, main page]

0% found this document useful (0 votes)
34 views11 pages

Arcgis

This document provides steps to deploy a Flask application in Python that uses APIs in IIS. It includes installing dependencies, creating an application in IIS, and configuring the web.config file and handlers to run the Python application. Potential errors are also discussed around importing ArcPy or ArcGIS modules.

Uploaded by

tung vu son
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views11 pages

Arcgis

This document provides steps to deploy a Flask application in Python that uses APIs in IIS. It includes installing dependencies, creating an application in IIS, and configuring the web.config file and handlers to run the Python application. Potential errors are also discussed around importing ArcPy or ArcGIS modules.

Uploaded by

tung vu son
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Deploying Flask(Python Rest) in IIS

Getting started

Import dependency

Pipe install flask

Sample script

from flask import Flask, url_for ,render_template, jsonify, request


import config
import requests
#import arcgis
import os, getpass

app = Flask(__name__)
app.debug = True

class PrefixMiddleware(object):
#class for URL sorting
def __init__(self, app, prefix=''):
self.app = app
self.prefix = prefix

def __call__(self, environ, start_response):

#in this line I'm doing a replace of the word


pythonflaskredirectwhich is my app name in IIS to ensure proper URL
redirect
if environ['PATH_INFO'].lower().replace('
/pythonflaskredirect','').startswith(self.prefix):
environ['PATH_INFO'] = environ['PATH_INFO'].lower().replace
('/pythonflaskredirect','')[len(self.prefix):]
environ['SCRIPT_NAME'] = self.prefix
return self.app(environ, start_response)
else:
start_response('404', [('Content-Type', 'text/plain')])
return ["This url does not belong to the app.".encode()]

app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/api')

@app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))

@app.route('/v1/test/get/response', methods=['GET'])
def api_all():
response = [
{'id': 0,
'desc': 'xxxx'},
{'id': 1,
'desc': 'xxxx'}
]
return jsonify(response)

@app.route('/v1/export', methods=['GET'])
def api_export():
args = request.args
token = args['token']

query = "https://services1.arcgis.com/vHnIGBHHqDR6y0CR/arcgis/rest
/services/vicfeaturelayer/FeatureServer/0/query?f=json&where=1%
3D1&returnGeometry=false&spatialRel=esriSpatialRelIntersects&outFields=*
&orderByFields=OBJECTID%
20ASC&resultOffset=0&resultRecordCount=50&cacheHint=true&token=" + token

results =requests.get(query)
return results.json()

if __name__ == '__main__':
#print(getpass.getuser())
app.run(host='0.0.0.0',port=9010)

Running python in IIS

Below is the guide I used: https://medium.com/@rajesh.r6r/deploying-a-python-flask-rest-api-on-iis-d8d9ebf886e9

This is something I have been meaning to try, running python code with arcpy via rest API. This can be extremely helpful when working with web
hooks in survey123.

The followings are records of steps I took to achieve this.

Open command prompt as Administrator:

Pip install wfastcgi (I ran pip from the arcgis pro script folder)
Enable wfastcgi (I ran wfastcgi-enable from the arcgis pro script folder)

Enable CGI on IIS

https://docs.microsoft.com/en-us/iis/configuration/system.webserver/fastcgi/
Confirming FastCGI on IIS

Create application on default site and add the following to the web.config (if there isn’t one, create one)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="Python FastCGI" path="*" verb="*"
modules="FastCgiModule" scriptProcessor="C:
\Users\vtay\Documents\vstuff\PythonEnv\ws_usage_matrix\arcgispro-py3-
elasticsearch\python.exe|C:
\Users\vtay\Documents\vstuff\PythonEnv\ws_usage_matrix\arcgispro-py3-
elasticsearch\Lib\site-packages\wfastcgi.py" resourceType="Unspecified"
requireAccess="Script" />
</handlers>
<directoryBrowse enabled="true" />
</system.webServer>
<appSettings>
<!-- Required settings -->
<add key="WSGI_HANDLER" value="myapp.app" />
<add key="PYTHONPATH" value="D:\bitbucket\Esri
Australia\pythonFlaskIIS" />
</appSettings>
</configuration>

Set read/write/execute to py C:\Users\vtay\Documents\vstuff\PythonEnv\ws_usage_matrix\arcgispro-py3-elasticsearch

Set read/write/execute to py Flask application

To be able to import arcpy, the pool identity have to be set or given access to ArcGIS Pro (I provide access to ArcGIS pro on the root level but it
wasn’t enough, changing the identity pool to myself works however)

Alternatively, you may also set permission to the following

python environment (Python.exe root dir)


your python application
ArcGIS Pro directory
for ISUR to access by running the following command

icacls . /grant "NT AUTHORITY\IUSR:(OI)(CI)(RX)"


icacls . /grant "Builtin\IIS_IUSRS:(OI)(CI)(RX)"

You should be able to hit https://your.machine.com/pythonFlaskRedirect/api/bar

Errors and workarounds:


Ideally everything would just work, unfortunately we know that is not always the case.

import arcgis error

ValueError: underlying buffer has been detached

If you have import arcgis, you will encounter the error (Underlying buffer detached). Workaround is to run pip uninstall ipython (i recommend you
make a copy of the python environment)

import arcpy error:

File ".\myapp.py", line 5, in <module>


import arcpy
File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\__init__.py",
line 74, in <module>
from arcpy.geoprocessing import gp
File "C:\Program
Files\ArcGIS\Pro\Resources\ArcPy\arcpy\geoprocessing\__init__.py", line
14, in <module>
from ._base import *
File "C:\Program
Files\ArcGIS\Pro\Resources\ArcPy\arcpy\geoprocessing\_base.py", line
14, in <module>
import arcgisscripting
RuntimeError: Not signed into Portal.

Still working on this, most likely the user it is running as doesn’t have a environment directory. E.G.

C:\Users\vtay\AppData\Roaming\ESRI\ArcGISPro.

Examining the os.environ we get the following:

{'_FCGI_SHUTDOWN_EVENT_': '1088', '_FCGI_X_PIPE_': '\\\\.


\\pipe\\IISFCGI-d75c9450-226c-4d3b-834a-d07c4ef85de6', 'AGSDATASTORE':
'D:\\Program Files\\ArcGIS\\DataStore\\',
'AGSDESKTOPJAVA': 'C:\\Program Files (x86)\\ArcGIS\\Desktop10.7\\',
'AGSDEVKITJAVA': 'C:\\Program Files (x86)\\ArcGIS\\DeveloperKit10.6\\',
'AGSENGINEJAVA': 'C:\\Program Files (x86)\\ArcGIS\\DeveloperKit10.
6\\java\\tools\\eclipse_plugin\\arcgis_update_site\\arcobjects\\plugins'
, 'AGSPORTAL': 'D:\\Program Files\\ArcGIS\\Portal\\',
'AGSSERVER': 'D:\\Program Files\\ArcGIS\\Server\\', 'ALLUSERSPROFILE':
'C:\\ProgramData', 'APPDATA': 'C:
\\WINDOWS\\system32\\config\\systemprofile\\AppData\\Roaming',
'APP_POOL_CONFIG': 'C:\\inetpub\\temp\\apppools\\TestPool\\TestPool.
config', 'APP_POOL_ID': 'TestPool', 'COMMONPROGRAMFILES': 'C:\\Program
Files\\Common Files',
'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files',
'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files',
'COMPUTERNAME': 'LEA-304867',
'COMSPEC': 'C:\\WINDOWS\\system32\\cmd.exe', 'DRIVERDATA': 'C:
\\Windows\\System32\\Drivers\\DriverData', 'FLEXLM_TIMEOUT': '2000000',
'JAVA_HOME': 'C:\\Program Files\\Java\\jdk-11.0.2',
'LOCALAPPDATA': 'C:
\\WINDOWS\\system32\\config\\systemprofile\\AppData\\Local',
'MSMPI_BIN': 'C:\\Program Files\\Microsoft MPI\\Bin\\',
'NUMBER_OF_PROCESSORS': '8', 'OANOCACHE': '1',
'ONEDRIVE': 'C:\\WINDOWS\\system32\\config\\systemprofile\\OneDrive',
'OPENSSL_CONF': 'C:\\OpenSSL\\bin\\openssl.cfg', 'OS': 'Windows_NT',
'PATH': 'c:
\\users\\vtay\\documents\\vstuff\\pythonenv\\ws_usage_matrix\\arcgispro-
py3-elasticsearch\\Library\\bin;c:
\\users\\vtay\\documents\\vstuff\\pythonenv\\ws_usage_matrix\\arcgispro-
py3-elasticsearch\\lib\\site-packages\\pywin32_system32;C:\\Program
Files\\ArcGIS\\Pro\\bin;C:\\Program Files (x86)\\Common
Files\\Oracle\\Java\\javapath;C:\\Program Files\\Microsoft MPI\\Bin\\;C:
\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:
\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;
C:\\Program Files\\Git\\cmd;C:\\Program Files\\Git\\mingw64\\bin;C:
\\Program Files\\Git\\usr\\bin;D:
\\vprogram\\mssql2016\\sharedfeature\\x86\\130\\Tools\\Binn\\;
D:\\vprogram\\mssql2016\\sharedfeature\\x64\\130\\Tools\\Binn\\;D:
\\vprogram\\mssql2016\\sharedfeature\\x86\\130\\DTS\\Binn\\;D:
\\vprogram\\mssql2016\\sharedfeature\\x64\\130\\DTS\\Binn\\;
D:\\vprogram\\mssql2016\\sharedfeature\\x64\\Client
SDK\\ODBC\\130\\Tools\\Binn\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:
\\Program Files\\dotnet\\;C:\\Program Files\\FME\\;C:\\Program
Files\\nodejs\\;
C:\\Program Files (x86)\\Yarn\\bin\\;D:
\\vprogram\\mssql2016\\sharedfeature\\x86\\150\\DTS\\Binn\\;C:\\Program
Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common
Files\\Intel\\WirelessCommon\\;
C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine
Components\\DAL;C:\\Program Files\\Intel\\Intel(R) Management Engine
Components\\DAL;D:\\vprogram\\sqlite\\sqlite-dll-win64-x64-3320100;
C:\\Users\\vtay\\AppData\\Local\\Microsoft\\WindowsApps;C:
\\Users\\vtay\\.dotnet\\tools',
'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64
Family 6 Model 158 Stepping 9, GenuineIntel',
'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '9e09', 'PROGRAMDATA':
'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files', 'PROGRAMFILES
(X86)': 'C:\\Program Files (x86)',
'PROGRAMW6432': 'C:\\Program Files', 'PSMODULEPATH': 'C:\\Program
Files\\WindowsPowerShell\\Modules;C:
\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules;C:\\Program Files
(x86)\\AWS Tools\\PowerShell\\',
'PUBLIC': 'C:\\Users\\Public', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:
\\WINDOWS', 'TEMP': 'C:\\WINDOWS\\TEMP', 'TMP': 'C:\\WINDOWS\\TEMP',
'UATDATA': 'C:\\WINDOWS\\CCM\\UATData\\D9F8C395-CAB8-491d-B8AC-
179A1FE1BE77',
'USERDOMAIN': 'SERVICES', 'USERNAME': 'LEA-304867$', 'USERPROFILE':
'C:\\WINDOWS\\system32\\config\\systemprofile',
'WINDIR': 'C:\\WINDOWS', '_NT_SYMBOL_PATH': 'srv*c:
\\mycache*http://downloads2.esri.com/Support/symbols/;srv*c:
\\mycache*https://msdl.microsoft.com/download/symbols',
'FOR_DISABLE_CONSOLE_CTRL_HANDLER': '1', 'WSGI_HANDLER': 'myapp.app',
'PYTHONPATH': 'D:\\bitbucket\\Esri Australia\\pythonFlaskIIS',
'WSGI_LOG': 'D:\\bitbucket\\Esri Australia\\pythonFlaskIIS\\log.txt'}

Most likely the profile is wrong

'USERNAME': 'LEA-304867$', 'USERPROFILE': 'C:\\WINDOWS\\system32\\config\\systemprofile',

Check

however it still didn’t work. So I attempted the following:

_environ = dict(os.environ)
_environ['USERNAME'] = 'vtey'
_environ['USERPROFILE'] = 'C:\\Users\\vtay'
os.environ.clear()
os.environ.update(_environ)

import arcpy

My complete code below


from flask import Flask, url_for ,render_template, jsonify, request
import config
import requests
import os, getpass
_environ = dict(os.environ)
_environ['USERNAME'] = 'vtey'
_environ['USERPROFILE'] = 'C:\\Users\\vtay'
os.environ.clear()
os.environ.update(_environ)

import arcpy
from arcgis.gis import GIS

app = Flask(__name__)
app.debug = True

class PrefixMiddleware(object):
#class for URL sorting
def __init__(self, app, prefix=''):
self.app = app
self.prefix = prefix
#arcpy.SignInToPortal(config.portal_url, config.
portal_username, config.portal_password)

def __call__(self, environ, start_response):


#start_response('404', [('Content-Type', 'text/plain')])
#return [os.environ]

#in this line I'm doing a replace of the word


pythonflaskredirect which is my app name in IIS to ensure proper URL
redirect
if environ['PATH_INFO'].lower().replace('
/pythonflaskredirect','').startswith(self.prefix):
environ['PATH_INFO'] = environ['PATH_INFO'].lower().replace
('/pythonflaskredirect','')[len(self.prefix):]
environ['SCRIPT_NAME'] = self.prefix
return self.app(environ, start_response)
else:
start_response('404', [('Content-Type', 'text/plain')])
return ["This url does not belong to the app.".encode()]

app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/api')

@app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))

@app.route('/v1/test/get/response', methods=['GET'])
def api_all():
response = [
{'id': 0,
'desc': 'xxxx'},
{'id': 1,
'desc': 'xxxx'}
]
return jsonify(response)

@app.route('/v1/export', methods=['GET'])
def api_export():
args = request.args
token = args['token']

query = "https://services1.arcgis.com/vHnIGBHHqDR6y0CR/arcgis/rest
/services/vicfeaturelayer/FeatureServer/0/query?f=json&where=1%
3D1&returnGeometry=false&spatialRel=esriSpatialRelIntersects&outFields=*
&orderByFields=OBJECTID%
20ASC&resultOffset=0&resultRecordCount=50&cacheHint=true&token=" + token

results =requests.get(query)
return results.json()

@app.route('/v1/arcgis', methods=['GET'])
def api_arcgis():

gis = GIS(config.portal_url,
username=config.portal_username,
password=config.portal_password,
verify_cert=False)
fl = gis.content.get('b8103c3d1cce42fab0df686e2510d0a4')
layer = fl.layers[0]
return (layer.query().to_json)

@app.route('/v1/arcpy', methods=['GET'])
def api_arcpy():

fc = r"D:\SDE connection\LEA-304867.sde\arcgis.DBO.point"

fields = ['name', 'description', 'height', 'test','SHAPE@XY']

l = [row for row in arcpy.da.SearchCursor(fc, fields)]


return jsonify(l)
if __name__ == '__main__':
#print(getpass.getuser())
app.run(host='0.0.0.0',port=9010)

Some screenshot of successful results, seem to be happy.


More testing require to add and edit to properly test this

You might also like