So I hopefully have a really simple question here. I am writing a codeblock for the CalculateField_management function but due to the length of my codeblock, and the fact that I will have to repeatedly edit it in the future, I want to put the codeblock into another py text file and then open it within a main script and pass it in as a string for CalculateField_management to interpret.
This sounds very simple, but when trying to google it, I only ever get help on modules and arguments. The problem with creating a module is that I cannot have my codeblock function defined outside of CalculateField, so the input definition needs to go into the codeblock as a string. This is what I tried so far but it does not know that f is suppose to reference my opened file.
File "<string>", line 3, in <module> NameError: name 'f' is not defined Failed to execute (CalculateField).
# Import system modules
import arcpy
# Set local variables
inTable = "Zarza data"
fieldName = "DipDir"
expression = "Strike( !Shape!, !FID! )"
codeblock ="""
open("D:/Alex/someplace/ZarzaModule.py",'r') #opens text file with def for function Strike()
val = f.read()
print(val)
"""
arcpy.CalculateField_management(inTable, fieldName, expression, "PYTHON_9.3", codeblock)
I might also need to operate the code outside of my codeblock and have:
codeblock = str(val)
But I need to fix referencing my opened file first.
If the two scripts are in the same location, the normal approach is to import the script (aka, module) into your main script... use it to produce the results, then you could simply add a field to your existing table and populate that field with its results.
I figured it out, it was a stupid syntax mistake, but perhaps it would help someone with a similar question in the future?
Thank you Dan for your insightful advise! I imagine you would do that with a for loop and cursors if you needed information from other fields to calculate each value? Then you would .append each value to a list and somehow copy the list to your new field?
# Import system modules
import arcpy
# Set local variables
inTable = "Zarza data"
fieldName = "DipDir"
expression = "Strike( !Shape!, !FID! )"
f = open("D:/Alex/someplace/ZarzaModule.py",'r') #opens text file with def for function Strike()
codeblock = f.read()
arcpy.CalculateField_management(inTable, fieldName, expression, "PYTHON_9.3", codeblock)
Although you can do it like that, I think Dan Patterson's suggestion of using "include" is better. Examples:
The include file:
# file is named "fieldcalc.py"
def Strike(a, b):
return "{}, {}".format(a,b)
def AnotherFunct(a, b):
return "{} not {}".format(a,b)
Use it like this:
import fieldcalc
w = "Hello"
x = "world"
y = 3
z = 1
print fieldcalc.Strike(w,x)
# Hello, world
print fieldcalc.AnotherFunct(y,z)
# 3 not 1
Or:
from fieldcalc import Strike, AnotherFunct
w = "Hello"
x = "world"
y = 3
z = 1
print Strike(w,x)
# Hello, world
print AnotherFunct(y,z)
# 3 not 1
I suppose if you want the code block, that will work... here is another
import inspect # the inspect module
import tools # the *.py script that contains your 'def'
# --- getting the code block for 'def leopard' (my homage func)
lines, ln_num = inspect.getsourcelines(tools.leopard) # ---- inspect and retrieve
code = "".join(["{}".format(line) for line in lines]) # ---- join 'em up
code # ---- have a look
'def leopard():\n """some function"""\n print("imported and ready to go""")\n'