Reviving an Arcpy Addins Extension

663
6
09-28-2018 12:00 PM
JoeBorgione
MVP Emeritus

A year or so ago I was working with Arcpy Addins. I had created an extension that  used to run a def openDocument() that creates a numpy array out of a table view:

class ExtensionClass1(object):
    """Implementation for AddressValidatorExtension_addin.extension2 (Extension)"""
    def __init__(self):
        # For performance considerations, please remove all unused methods in this class.
        self.enabled = True
    def openDocument(self):       
                    myTable = r"I:\GIS\ArcSDE\SuperUser\slcogis\gdb_ADD\gdb_ADD@slcogis.sde\SLCOGIS.gdb_ADD.JoesArray_vw"
          fields = ['FULLNAME', 'LowCoordName', 'HighCoordName','Alias1','Alias2','Alias3','Alias4','STR2_LOW_RANGE','STR2_HIGH_RANGE']
          global arr
          arr = arcpy.da.TableToNumPyArray(myTable,fields)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 The problem is when I try to execute the other functionalities of the extension it errors out at the first call to that array: 

Traceback (most recent call last):
  File "C:\Users\JBorgione\AppData\Local\ESRI\Desktop10.5\AssemblyCache\{FB53601C-244C-4DF3-87C2-E18F723FA707}\AddressValidatorExtension_addin.py", line 71, in onEnter
    name = arr[np.where(arr['FULLNAME'] == enteredName)]
NameError: global name 'arr' is not defined
‍‍‍‍‍‍‍‍‍

Not sure what I'm missing, and hoping another set of eyes can catch it

That should just about do it....
0 Kudos
6 Replies
DanPatterson_Retired
MVP Emeritus

I don't like your path isn't the last bit supposed to be a table (but it is in SDEvil so I am not sure)

This works... but if you have any <null> values in your table, you have to skip them or go through some hoops.  I have the hoop code if you need it.  If you have nulls and don't provide null substitutes based on field types they you get an unfriendly error.

But that is for later.

def da_func():
    from arcpy.da import TableToNumPyArray
    myTable = r'C:/Git_Dan/arraytools/array_tools_testing/array_tools.gdb/pnts_2000'
    fields = "*"
    global arr
    arr = TableToNumPyArray(myTable,fields, skip_nulls=True)
    print(arr)
    

da_func()
[(   2, [ 303006., 5031740.],    1,  9.99,  650, 'B', 'e', 303006., 5031740.,  3,  3., 'D4',  953, 34, 34)
 (   4, [ 303987., 5026385.],    3, 11.57, 1605, 'D', 'b', 303987., 5026385.,  1,  1., 'D9', 1620, 84, 84)
 (   6, [ 309159., 5026073.],    5, 10.09,  521, 'B', 'c', 309159., 5026073.,  8,  8., 'J9', 1272, 90, 90)
 ...
 (1996, [ 307515., 5034669.], 1995, 11.75, 1759, 'D', 'b', 307515., 5034669.,  4,  4., 'H1', 1875,  8,  8)
 (1997, [ 300882., 5028630.], 1996, 10.82,  940, 'B', 'a', 300882., 5028630., 10, 10., 'A7',  565, 61, 61)
 (1999, [ 305835., 5032342.], 1998, 10.33,  697, 'B', 'a', 305835., 5032342.,  5,  5., 'F3', 1383, 26, 26)]
JoeBorgione
MVP Emeritus

It's a table 'view' that is created on the SQL/SDEvil back end.  I'll try the skip_nulls=True part on monday as I'm quite sure there are null alias# values. Maybe I need to apply arcpy.MakeTableView() to it;  I'll try that as well.  (The good news is this puts me back into the numpy thought process; the bad news is it's that addressing project from last year...)

That should just about do it....
0 Kudos
DanPatterson_Retired
MVP Emeritus

Joe... in the first instance, set skillnulls to true or whatever.  If there are any nulls in the fields you select, that row will be skipped

If you don't want rows that contain nulls skipped, I can provide you with the null dictionary that will provide acceptable null values so that the rows aren't skipped... it is a bit of an issue since <null> isn't 'None' in all cases, especially for integer fields etc.

If nulls isn't an issue, disregard everthing after Joe...

JoeBorgione
MVP Emeritus

I can't afford to skip a row if one of the lesser-used fields has a null or empty value, so I need to take that into consideration.  Just to get it up and running I can substitute a more ArcGIS friendly datasource (feature class or table and then make feature layer or make table view as needed) for the SQL view.  We have the SQL view in place because (if you recall) the data is actually stored in a mainframe and we get a db dump from it and then SQL-view the dump.  Big fun....

That should just about do it....
0 Kudos
DanPatterson_Retired
MVP Emeritus

This is what I use sometimes.  It needs field objects, just not their name (edit the code otherwise).

You can change what you want as the returned value.  I normally just return the min for the data type.  For string/text, just the string representation of text

def null_dict(flds):
    """Produce a null dictionary from a list of fields
    These must be field objects and not just their name.
    """
    dump_flds = ["OBJECTID","Shape_Length", "Shape_Area", "Shape"]
    flds_oth = [f for f in flds
                if f.name not in dump_flds]
    nulls = {'Double':np.nan,
             'Single':np.nan,
             'Short':np.iinfo(np.int16).min,
             'SmallInteger':np.iinfo(np.int16).min,
             'Long':np.iinfo(np.int32).min,
             'Float':np.nan,
             'Integer':np.iinfo(np.int32).min,
             'String':str(None),
             'Text':str(None)}
    fld_dict = {i.name: i.type for i in flds_oth}
    nulls = {f.name:nulls[fld_dict[f.name]] for f in flds_oth}
    return nulls
0 Kudos
JoeBorgione
MVP Emeritus

I'm thinking there is something wrong with the way I using the openDocument() method within the extension itself.  I just took a took look at ArcMap Python Add In Extension does not execute  where Darren Wiens‌ provides a means to test.  I created an extension that only does one thing: open a message box.  However, with the extension added to an mxd, when I open that mxd, no message box appears....

##### this is the entire python script for my TestOnOpen extension...


import arcpy
import pythonaddins

class ExtensionClass1(object):
    """Implementation for TestOnOpen_addin.extension2 (Extension)"""
    def __init__(self):
        # For performance considerations, please remove all unused methods in this class.
        self.enabled = True
    def openDocument(self):
        pythonaddins.MessageBox('It Ran!!!','INFO',0)
That should just about do it....
0 Kudos