I'm working in 10.2.2 (and 10.3.1...and testing in Pro). I'm trying to use a standard set of "connection files" for .sde, .and ags, connection files so running the scripts will work on multiple machines. However, I'm trying to keep it generic enough in case someone else uses with a different (local) connection file type. This is a program that is pretty specific to our needs, but is run often (currently only by me, but that will change).
Typically these connection files are stored in a path similar to
C:\Users\<user>\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog
I would like to store them in a shared network folder with the UNC pathname, e.g.
\\<server>\GISStaff\myConnection@database.sde
The problem:
It seems that if I use the connection file, the arcpy.CopyFeatures_management (and probably any other command) it wants:
Database Connections\myConnection@database.sde\master.DBO.theMasters\thePolys
If I use the UNC connection file, the command wants (note "master.DBO" in bold near end):
\\newserver\GISStaff\myConnection@database.sde\master.DBO.theMasters\master.DBO.thePolys
Question:
Other than checking for the string "Database Connections" in my variable, does anyone know a way to check whether the .sde file is in the local connection folder vs. a UNC path? If I can test for it reliably, I can strip the data I need and add it to the string before I add the featureclass name. (I'll be able to handle that)
Interesting (?) side note: in previous ArcGIS versions (maybe 9.x or 10.0), I always had to have the additional info in the path. Then in one of the updates to ArcGIS, that broken the script and I had take it back to just the featureclass name.....seems this is a combination or maybe a remnant of the old way. (??)
I'm trying to keep it simple, but flexible, without having to hard code the path.
This is arcpy/python specific, but cross posting since GDB/SDE related Geodatabase
Thanks for any suggestions!
EDIT: it may be that I will just do the test for the "database Connection' string like this:
if 'Database Connection' in masterGDB2: <leave as is> else: <add the database.owner>
So in that case, can anyone tell me how to strip everything before and including ".sde\\' from before my database.owner?
Message was edited by: Rebecca Strauch Revised, in case no easy test....then would just need "strip" syntax help.
Solved! Go to Solution.
And to include the missing part:
import os def main(): unc_path = r"\\newserver\GISStaff\myConnection@database.sde\master.DBO.theMasters\thePolys" normal_path = r"C:\Users\blahblah\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog\myConnection@database.sde\master.DBO.theMasters\thePolys" db_path = r"Database Connections\myConnection@database.sde\master.DBO.theMasters\thePolys" lst = [unc_path, normal_path, db_path] for p in lst: if isuncpath(p): lst = os.path.split(p) print os.path.join(lst[0], 'master.DBO.{0}'.format(lst[1])) else: print p def isuncpath(a_path): return os.path.splitunc(a_path)[0] != '' if __name__ == '__main__': main()
which will yield:
\\newserver\GISStaff\myConnection@database.sde\master.DBO.theMasters\master.DBO.thePolys C:\Users\blahblah\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog\myConnection@database.sde\master.DBO.theMasters\thePolys Database Connections\myConnection@database.sde\master.DBO.theMasters\thePolys
In Python there is not much support for UNC paths (as to check for them or to define credentials to connect to them). You could use something like this:
def main(): unc_path = r"\\newserver\GISStaff\myConnection@database.sde" normal_path = r"C:\Users\blahblah\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog\myConnection@database.sde" db_path = r"Database Connections\myConnection@database.sde" lst = [unc_path, normal_path, db_path] for p in lst: print isuncpath(p), p def isuncpath(a_path): import os return os.path.splitunc(a_path)[0] != '' if __name__ == '__main__': main()
... which will return this:
True \\newserver\GISStaff\myConnection@database.sde False C:\Users\blahblah\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog\myConnection@database.sde False Database Connections\myConnection@database.sde
And to include the missing part:
import os def main(): unc_path = r"\\newserver\GISStaff\myConnection@database.sde\master.DBO.theMasters\thePolys" normal_path = r"C:\Users\blahblah\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog\myConnection@database.sde\master.DBO.theMasters\thePolys" db_path = r"Database Connections\myConnection@database.sde\master.DBO.theMasters\thePolys" lst = [unc_path, normal_path, db_path] for p in lst: if isuncpath(p): lst = os.path.split(p) print os.path.join(lst[0], 'master.DBO.{0}'.format(lst[1])) else: print p def isuncpath(a_path): return os.path.splitunc(a_path)[0] != '' if __name__ == '__main__': main()
which will yield:
\\newserver\GISStaff\myConnection@database.sde\master.DBO.theMasters\master.DBO.thePolys C:\Users\blahblah\AppData\Roaming\ESRI\Desktop10.x\ArcCatalog\myConnection@database.sde\master.DBO.theMasters\thePolys Database Connections\myConnection@database.sde\master.DBO.theMasters\thePolys
Hi Xander,
Between the isuncpath and the lst = os.path.split(p) I'm getting really close. But I can't hard code the "master.DBO" since that will change.
In my case, lst[1] is actually 'sde_wcgis_master.DBO.DWCMasters'
What is the correct syntax to end up with just the 'sde_wcgis_master.DBO.' portion (since the lst[1] could change). I'm assuming it is a flavor of strip, I just haven't found the right combo yet. (still testing though)
EDIT: getting my last question figured out. I was trying to use strip instead of split
zz = lst[1].split('.')
I can work with that.
Thanks for your help Xander. I think I'm ready to roll in the morning on this!
I'm adding this summary for anyone that might need to do a similar thing. I'm using Xander Bakker 'isuncpath' function to check whether it is a local (mapped) drive or a UNC path. Then based on the results, I'm building the sdePath variable as need to get the path that arcpy needs for input to the CopyFeatures command (and most likely others).
If within your target geodatabase you are trying to write to a feature dataset vs the root of the database, look at how I'm assigning the targetFC variable (commented out since I'm not providing the other variables in this sample)
The sample below doesn't do anything but print out the sdePath and the paths for the FCs in the For loop. To test with the different types of local vs UNC paths, switch (un-comment) the other masterGDB attribute assignment line.
import arcpy import os # function to see if the masterGDB path is UNC or "local" def isuncpath(a_path): return os.path.splitunc(a_path)[0] != '' def main(): #set path to one of the below masterGDB = r'Database Connections\me@master.sde\myDatabase.DBO.Masters' #masterGDB = r'\\newserver\Staff\___gisStaffConnections\me@master.sde\myDatabase.DBO.DWCMasters' if isuncpath(masterGDB): lstSdeFDS = os.path.split(masterGDB) lstDbOwnerFDS = lstSdeFDS[1].split(".") sdePath = ('{0}\\{1}.{2}.'.format(masterGDB, lstDbOwnerFDS[0], lstDbOwnerFDS[1])) print('sdePath: {0}'.format(sdePath)) else: sdePath = masterGDB + "\\" print('sdePath: {0}'.format(sdePath)) #then for using in my comands for fdsToCopy in ['Fclass1', 'FClass2', 'FClass3']: #print(' Copying Master database {0} to temporary Master_update FGDB: ... '.format(fdsToCopy) ) sourceFC = sdePath + fdsToCopy print('sourceFC path: {0}'.format(sourceFC)) # next two lines are commented out since I'm not showing the setting of # the updateFGDN and MasterFDS variables...but showing so others can get the gist #targetFC = updateFGDB + '\\' + masterFDS + '\\' + fdsToCopy #arcpy.CopyFeatures_management (sourceFC, targetFC) # End main function if __name__ == '__main__': main()
To get back to your question to exclude the last part of a string separated by points, you could do this:
s = 'sde_wcgis_master.DBO.DWCMasters' # split the string on the point and exclude the last element and join it with pionts print '.'.join(s.split('.')[:-1]) # then I noticed the rpartition that splits on the last occurrence (first from right), take the first part. print s.rpartition('.')[0] # to include to point at the end print '{0}.'.format('.'.join(s.split('.')[:-1])) print '{0}.'.format(s.rpartition('.')[0]) # or shorter, just add the point print '.'.join(s.split('.')[:-1]) + '.' print s.rpartition('.')[0] + '.'
Thanks Xander. Those are all slick. I may try to merge those into my script at some point (but working, so moved on to next script) but it is definitely good reference for next time. I appreciate the additional options. I'm still trying to get in the habit of cleaner looking code....still do a lot of brunt force with python (but getting better).