I know there's a ton of other material here and @ SE regarding this subject, but conceptually i'm just stuck. In an effort to improve the modularity of my code, I'm trying to get better at importing existing functions into scripts. I'm stuck on successfully passing arguments captured within the script to the imported module. Ideally I just want to use the script and pass it a handful of client identifiers (arguments) and have those cascade down into several modules called up in the script. Like: functiontest2('identifier')
some crude code:
functiontest2.py
from HarvestTable import HarvestTableReport
import sys
HarvestThing = sys.argv[1]
HarvestTableReport(HarvestThing)
HarvestTable.py
import numpy as np
import pandas as pd
import arcpy
def HarvestTableReport(HarvestID):
table = "\\\\fileshare\SDE_CONNECTIONS\\LV_NEXUS.sde\\LV_NEXUS.DATAOWNER.NORTHEAST\\clientGDB.featureclass"
HUID = HarvestID
whereClause = """ "LV_HARVEST_UNIT_ID" = '{0}' """.format(HUID)
tableArray = arcpy.da.TableToNumPyArray(table, ['SUPER_TYPE','STRATA', 'OS_TYPE', 'STAND_NUMB', 'SILV_PRES', 'ACRES'], where_clause = whereClause)
df = round(pd.DataFrame(tableArray),1)
report = df.groupby(['SUPER_TYPE']).apply(lambda sub_df: sub_df.pivot_table(index=['STRATA', 'OS_TYPE', 'STAND_NUMB', 'SILV_PRES'], values=['ACRES'],aggfunc=np.sum, margins=True,margins_name= 'TOTAL'))
# this is creating a new row at level(1) called grand total
# set it equal to the sum of ACRES where level(1) != 'Total' so you are not counting the calculated totals in the total sum
report.loc[('', 'GRAND TOTAL','','',''), :] = report[report.index.get_level_values(1) != 'TOTAL'].sum()
print(whereClause)
return np.round(report,1)
if __name__ == '__main__':
HarvestTableReport()
Solved! Go to Solution.
The line
HarvestThing = sys.argv[1]
is saying to take the first command line argument and pass it to HarvestThing. Since you are importing the module and not calling it from the command line with arguments, you are getting an IndexError.
line 5, first script... you passed to the imported function, and it tried to return something, but you didn't do anything with it
i_m_Back = HarvestTableReport(HarvestThing) # ---- returned from your imported
print("Returned to you {}".format(i_m_Back))
So what errors or unexpected behaviors are you getting? If errors, please post specific errors with traceback. If unexpected results, please post what you expect and what you are actually getting.
I've had so many different tweaks to this it's been hard to keep track (kinda banging my head against the wall here). In the current permutation shown above if I attempt to import functiontest2 into the python window in Pro I receive the following error:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "\\fileshare\SCRIPTS\functiontest2.py", line 3, in <module>
HarvestThing = sys.argv[1]
IndexError: list index out of range
The line
HarvestThing = sys.argv[1]
is saying to take the first command line argument and pass it to HarvestThing. Since you are importing the module and not calling it from the command line with arguments, you are getting an IndexError.
ok, that makes way more sense and I had success using the python cmd prompt and supplying an arrangement. thanks so much!
So is there a way to run a script from the interactive python window, or is my solution more like creating a master module that just calls up a bunch of my other single-purpose modules? Let me try to explain what I'm hoping to achieve. Often while working along in Pro (although I could be doing the same in Jupyter Lab I guess) I want to pull some info for a given client or property. So each module might have a single function that generates a report. Rather than run each module, I want to run all of them in one script/master module. The only argument that needs to be passed to each module is like a client identifier so this should be pretty straightforward. I'd prefer to not have to jump out to the python command prompt but also don't want the overhead of rolling these up into a script tool in a Pro toolbox.
See if this helps: What is an alternative to execfile in Python 3? - Stack Overflow
Got pulled back to project work. This is all very helpful. As I start to wrap my head around this more I'm understanding a bit better the need for modularity and organization...it's just applying that which is still the challenge for me.
Based on everything I've read in this thread, so far it seems like what will benefit me the most in this situation is to organize several related functions into one module. I can then call them up as needed.
Thanks so much to everyone!
EDIT: I recently saw this article in my inbox regarding building command line interfaces with Python if anyone is interested.
If I understand it correctly, you want to call a script from another, passing variables set up in the first script? If so, here is the basic template with which to do so.
# -*- coding: utf-8 -*-
"""
Created on Thu May 16 14:20:43 2019
@author: JBorgione
save this as script1.py
"""
var1 = 'A'
var2 = 'B'
var3 = 'C'
import Script2
# -*- coding: utf-8 -*-
"""
Created on Thu May 16 14:31:01 2019
@author: JBorgione
script2.py is called from script1.py
"""
from __main__ import *
def main():
print(var3)
print(var2)
print(var1)
if __name__ == 'Script2':
main()
It's my understanding that when you call a second script from a first script, __name__ = main in the first script but not in the second script: __name__ = the script name itself (sans .py extension) and both of them need to be in the same directory.
See a post of mine earlier this spring which directs you to this site
It's my understanding that when you call a second script from a first script, __name__ = main in the first script but not in the second script: __name__ = the script name itself (sans .py extension) and both of them need to be in the same directory.
This right here is something I really need to get my head around! I keep getting confused on this.