In Arcpy, what's the best way to switch between workspaces for multiple functions?

2285
6
05-14-2019 03:45 PM
JamesBurton1
New Contributor III

I have a script with several functions in it that use arcpy.ListFeatureClasses(). I'm having trouble pointing each function at the proper workspace. It seems like if I change the workspace inside a function then all the function calls after that use the wrong workspace. But if I set the arcpy.env.workspace inside each function it throws errors saying 

''ERROR 000732: Input Table: filename does not exist or is not supported''

How do I point each function at its proper workspace? Images of a couple of the functions are below:

0 Kudos
6 Replies
JamesBurton1
New Contributor III

Do you know anything about functions and workspacesJoe Borgione‌?

0 Kudos
RandyBurton
MVP Regular Contributor

After a quick look at your functions, you might set and then pass the workspace to your function:

def someFunction(ws):
    workspace = ws
    # more code
    return something

workspace1 = r'C:\Some\Path\to\data1.gdb'
x = someFunction(workspace1)

workspace2 = r'C:\Some\Path\to\data2.gdb'
y = someFunction(workspace2)

Is this what you are looking for?

JoeBorgione
MVP Esteemed Contributor

James- Along with what @Randy_Burton suggests, using 

import arcpy
arcpy.env.workspace = r'X\some\path\to\your.gdb'‍‍

sets it explicitly.  With ListFeatureClasses and ListTables() both need the workspace set as shown above, and I don't think either of them take an argument. If you are going to set a workspace with env and copy data to a different out workspace, just set a variable:

arcpy.env.workspace = r'T:\GIS Documents\MOW\SDE_Surrogate.gdb'
outWS = r'T:\GIS Documents\MOW\ClientCount.gdb'
fields = ['Month','Year']
arcpy.SplitByAttributes_analysis('MasterDelivery2018',outWS,fields)‍‍‍‍

Notice how line one sets the env while line 2 sets where I want the output of SplitByAttributes() to go.

Another example:

arcpy.env.workspace = r'T:\GIS Documents\MOW\ClientCountSum2.gdb'
outWS = arcpy.env.workspace
inFeatures = r'I:\GIS\ArcSDE\SuperUser\is\slco@slcopub.sde\slcopub.SLCO.Administration\slcopub.SLCO.ZipCodes'
layerName = 'zipLayer'
joinField1 = 'ZIP_CD'
joinfield2 = 'FIRST_Residential_Zipcode'

for t in arcpy.ListTables():
    try:
        joinTable = t
        outFeature = '{}\{}joined'.format(outWS,t)
        arcpy.MakeFeatureLayer_management (inFeatures,  layerName)
        arcpy.AddJoin_management(layerName, joinField1, joinTable, joinfield2)
        arcpy.CopyFeatures_management(layerName, outFeature)
        print('Success: created month feature class')
    except Exception as err:
        print('Error')
        print(err)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Line 2 sets the outWS explicitly so I can use it a little later in line 11 where I name the out feature class using the original table name with the word 'joined' pasted to the end of it.

and finally, one more example  I just wrote for the same meals on wheels project I working on:

arcpy.env.workspace = r'T:\GIS Documents\MOW\ClientCountSum2.gdb'
target = r'T:\GIS Documents\MOW\SDE_Surrogate.gdb\ClientCountByZip'
for x in arcpy.ListFeatureClasses():
    arcpy.Append_management(x,target,'NO_TEST')

Glad to see you are writing python at your new job!

That should just about do it....
JamesBurton1
New Contributor III

Thanks for the tips Joe! After some testing today I've come to the conclusion that I am having issues with the environment Spyder is set up in. I was messing with the PYTHONPATH and PATH last week to try and work with QGIS tools as well and now I'm getting unexpected behavior from Spyder IDE, which is installed in the cloned environment. My functions run great in IDLE and the ArcGIS Pro python window but not in Spyder.

It sure is fun stuff to try and figure out  /s.  I re-cloned my environment and downloaded spyder into that but I am still getting the same error. Not sure what my next move is.

JoeBorgione
MVP Esteemed Contributor

Shoot....  You lost me at QGIS ... ;)

I guess you may want to go back and reset PYTHONPATH and PATH and start over?

That should just about do it....
0 Kudos
Luke_Pinner_DAWE
New Contributor II

It seems like if I change the workspace inside a function then all the function calls after that use the wrong workspace.

Yep. If you change the workspace, you need to change it back.

What I do is use a context manager to temporarily set arcpy.env values and then automatically reset them to the original values.

from contextlib import contextmanager

import arcpy

@contextmanager
def env(**kwargs):
    """ context manager for arcpy.env vars """

    try:
        # Copy old env then set new values
        old_env = {}
        for key, val in kwargs.items():
            old_env[key] = getattr(arcpy.env, key)
            setattr(arcpy.env, key, val)
        yield

    finally:
        # Restore old values
        for key, val in old_env.items():
            setattr(arcpy.env, key, val)



def some_function():
    print(arcpy.env.workspace)


if __name__ == '__main__':
    arcpy.env.workspace = 'C:/Temp'

    some_function()
    with env(workspace='D:/GIS'):
        some_function()
    some_function()
    with env(workspace='G:/Work'):
        some_function()
    some_function()

 This outputs:

C:/temp
D:/GIS
C:/temp
G:/Work
C:/temp