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__)
[Link] = True
class PrefixMiddleware(object):
#class for URL sorting
def __init__(self, app, prefix=''):
[Link] = app
[Link] = 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([Link]):
environ['PATH_INFO'] = environ['PATH_INFO'].lower().replace
('/pythonflaskredirect','')[len([Link]):]
environ['SCRIPT_NAME'] = [Link]
return [Link](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')
@[Link]('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
@[Link]('/v1/test/get/response', methods=['GET'])
def api_all():
response = [
{'id': 0,
'desc': 'xxxx'},
{'id': 1,
'desc': 'xxxx'}
]
return jsonify(response)
@[Link]('/v1/export', methods=['GET'])
def api_export():
args = [Link]
token = args['token']
query = "[Link]
/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 =[Link](query)
return [Link]()
if __name__ == '__main__':
#print([Link]())
[Link](host='[Link]',port=9010)
Running python in IIS
Below is the guide I used: [Link]
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
[Link]
Confirming FastCGI on IIS
Create application on default site and add the following to the [Link] (if there isn’t one, create one)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<[Link]>
<handlers>
<add name="Python FastCGI" path="*" verb="*"
modules="FastCgiModule" scriptProcessor="C:
\Users\vtay\Documents\vstuff\PythonEnv\ws_usage_matrix\arcgispro-py3-
elasticsearch\[Link]|C:
\Users\vtay\Documents\vstuff\PythonEnv\ws_usage_matrix\arcgispro-py3-
elasticsearch\Lib\site-packages\[Link]" resourceType="Unspecified"
requireAccess="Script" />
</handlers>
<directoryBrowse enabled="true" />
</[Link]>
<appSettings>
<!-- Required settings -->
<add key="WSGI_HANDLER" value="[Link]" />
<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 ([Link] 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 [Link]
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 ".\[Link]", line 5, in <module>
import arcpy
File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\__init__.py",
line 74, in <module>
from [Link] 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 [Link] 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\\[Link]', '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\\[Link]', '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*[Link]
\\mycache*[Link]
'FOR_DISABLE_CONSOLE_CTRL_HANDLER': '1', 'WSGI_HANDLER': '[Link]',
'PYTHONPATH': 'D:\\bitbucket\\Esri Australia\\pythonFlaskIIS',
'WSGI_LOG': 'D:\\bitbucket\\Esri Australia\\pythonFlaskIIS\\[Link]'}
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([Link])
_environ['USERNAME'] = 'vtey'
_environ['USERPROFILE'] = 'C:\\Users\\vtay'
[Link]()
[Link](_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([Link])
_environ['USERNAME'] = 'vtey'
_environ['USERPROFILE'] = 'C:\\Users\\vtay'
[Link]()
[Link](_environ)
import arcpy
from [Link] import GIS
app = Flask(__name__)
[Link] = True
class PrefixMiddleware(object):
#class for URL sorting
def __init__(self, app, prefix=''):
[Link] = app
[Link] = prefix
#[Link](config.portal_url, config.
portal_username, config.portal_password)
def __call__(self, environ, start_response):
#start_response('404', [('Content-Type', 'text/plain')])
#return [[Link]]
#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([Link]):
environ['PATH_INFO'] = environ['PATH_INFO'].lower().replace
('/pythonflaskredirect','')[len([Link]):]
environ['SCRIPT_NAME'] = [Link]
return [Link](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')
@[Link]('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
@[Link]('/v1/test/get/response', methods=['GET'])
def api_all():
response = [
{'id': 0,
'desc': 'xxxx'},
{'id': 1,
'desc': 'xxxx'}
]
return jsonify(response)
@[Link]('/v1/export', methods=['GET'])
def api_export():
args = [Link]
token = args['token']
query = "[Link]
/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 =[Link](query)
return [Link]()
@[Link]('/v1/arcgis', methods=['GET'])
def api_arcgis():
gis = GIS(config.portal_url,
username=config.portal_username,
password=config.portal_password,
verify_cert=False)
fl = [Link]('b8103c3d1cce42fab0df686e2510d0a4')
layer = [Link][0]
return ([Link]().to_json)
@[Link]('/v1/arcpy', methods=['GET'])
def api_arcpy():
fc = r"D:\SDE connection\[Link]\[Link]"
fields = ['name', 'description', 'height', 'test','SHAPE@XY']
l = [row for row in [Link](fc, fields)]
return jsonify(l)
if __name__ == '__main__':
#print([Link]())
[Link](host='[Link]',port=9010)
Some screenshot of successful results, seem to be happy.
More testing require to add and edit to properly test this