Skip to content

Commit dd381a5

Browse files
authored
Merge pull request #121 from nmpeterson/master
Added utility script for exporting highway project coding
2 parents 2fd4239 + 33740d1 commit dd381a5

5 files changed

Lines changed: 269 additions & 145 deletions

File tree

MHN.py

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
'''
33
MHN.py
44
Author: npeterson
5-
Revised: 9/4/18
5+
Revised: 12/19/18
66
---------------------------------------------------------------------------
77
A class for importing into MHN processing scripts, containing frequently
88
used methods and variables.
@@ -27,21 +27,6 @@ class MasterHighwayNetwork(object):
2727
}
2828

2929
centroid_ranges = {
30-
# ## zones09
31-
# 'CBD': range( 1, 48), # NB. range(i,j) includes i & excludes j
32-
# 'Chicago': range( 1, 310),
33-
# 'Cook': range( 1, 855),
34-
# 'McHenry': range( 855, 959),
35-
# 'Lake': range( 959, 1134),
36-
# 'Kane': range(1134, 1279),
37-
# 'DuPage': range(1279, 1503),
38-
# 'Will': range(1503, 1691),
39-
# 'Kendall': range(1691, 1712),
40-
# 'CMAP': range( 1, 1712),
41-
# 'MHN': range( 1, 1962),
42-
# 'POE': range(1945, 1962)
43-
44-
## zones17
4530
'CBD': range( 1, 48), # NB. range(i,j) includes i & excludes j
4631
'Chicago': range( 1, 718),
4732
'Cook': range( 1, 1733),
@@ -58,6 +43,20 @@ class MasterHighwayNetwork(object):
5843
'Grundy_Part': range(2949, 2950),
5944
'DeKalb_Part': range(2977, 2978)
6045
}
46+
47+
# ## zones09 (C18Q3 and earlier)
48+
# 'CBD': range( 1, 48), # NB. range(i,j) includes i & excludes j
49+
# 'Chicago': range( 1, 310),
50+
# 'Cook': range( 1, 855),
51+
# 'McHenry': range( 855, 959),
52+
# 'Lake': range( 959, 1134),
53+
# 'Kane': range(1134, 1279),
54+
# 'DuPage': range(1279, 1503),
55+
# 'Will': range(1503, 1691),
56+
# 'Kendall': range(1691, 1712),
57+
# 'CMAP': range( 1, 1712),
58+
# 'MHN': range( 1, 1962),
59+
# 'POE': range(1945, 1962)
6160
}
6261

6362
min_node_id = 5001 # 1-5000 reserved for zone centroids/POEs
@@ -108,7 +107,7 @@ class MasterHighwayNetwork(object):
108107
'"AM_SHARE" >= 0.5')
109108
}
110109

111-
ampm_tods ={
110+
ampm_tods = {
112111
'1': ('1', '2', '3', '4', '5', '6', '7', '8', 'am'), # All periods
113112
'2': ('2', '3', '4', '5', 'am'), # AM periods
114113
'3': ('1', '6', '7', '8'), # PM periods
@@ -267,7 +266,7 @@ def __init__(self, mhn_gdb_path, zone_gdb_path=None):
267266
}
268267
self.pnr_name = 'parknride'
269268
self.pnr = os.path.join(self.gdb, self.pnr_name)
270-
self.projection = arcpy.Describe(self.hwynet).spatialReference
269+
self.projection = arcpy.Describe(self.arc).spatialReference
271270

272271
# Zone geodatabase structure (default to zone_systems.gdb in same dir as MHN gdb)
273272
if zone_gdb_path:
@@ -372,25 +371,46 @@ def calculate_itin_measures(self, itin_table):
372371
return itin_table
373372

374373

374+
@staticmethod
375+
def check_edit_session(lyr):
376+
''' Check for an active edit session on a specified layer by trying to
377+
open two cursors simultaneously. '''
378+
edit_session = True
379+
try:
380+
OID = arcpy.Describe(lyr).OIDFieldName
381+
with arcpy.da.UpdateCursor(lyr, OID) as rows:
382+
row = next(rows)
383+
with arcpy.da.UpdateCursor(lyr, OID) as rows2:
384+
row2 = next(rows2)
385+
except RuntimeError as e:
386+
if str(e) == "workspace already in transaction mode":
387+
edit_session = False # No active edit session
388+
else:
389+
raise # Some other RuntimeError
390+
return edit_session
391+
392+
375393
@staticmethod
376394
def check_selection(lyr):
377395
''' Check whether specified layer has a selection. '''
378-
desc = arcpy.Describe(lyr)
379-
selected = desc.FIDSet
380-
if len(selected) == 0:
396+
try:
397+
if len(arcpy.Describe(lyr).FIDSet) == 0:
398+
return False
399+
else:
400+
return True
401+
except AttributeError:
402+
# `lyr` is not a feature layer or table view
381403
return False
382-
else:
383-
return True
384404

385405

386406
@staticmethod
387407
def delete_if_exists(filepath):
388408
''' Check if a file exists, and delete it if so. '''
389409
if arcpy.Exists(filepath):
390410
arcpy.Delete_management(filepath)
391-
message = filepath + ' successfully deleted.'
411+
message = '{} successfully deleted.'.format(filepath)
392412
else:
393-
message = filepath + ' does not exist.'
413+
message = '{} does not exist.'.format(filepath)
394414
return message
395415

396416

@@ -417,9 +437,7 @@ def determine_arc_bearing(line_geom):
417437
@staticmethod
418438
def determine_OID_fieldname(fc):
419439
''' Determines the Object ID fieldname for the specified fc/table. '''
420-
describe = arcpy.Describe(fc)
421-
OID_name = describe.OIDFieldName
422-
return OID_name
440+
return arcpy.Describe(fc).OIDFieldName
423441

424442

425443
@staticmethod
@@ -439,7 +457,7 @@ def determine_tolltype(vdf, cost):
439457
@staticmethod
440458
def die(error_message=''):
441459
''' End processing prematurely. '''
442-
arcpy.AddError('\n' + error_message + '\n')
460+
arcpy.AddError('\n{}\n'.format(error_message))
443461
sys.exit()
444462
return None
445463

@@ -487,7 +505,7 @@ def get_yearless_hwyproj(self):
487505
''' Check hwyproj completion years and return list of invalid projects'
488506
TIPIDs. '''
489507
common_id_field = self.route_systems[self.hwyproj][1]
490-
invalid_year_query = '"{0}" = 0 OR "{0}" IS NULL'.format('COMPLETION_YEAR')
508+
invalid_year_query = "{0} = 0 OR {0} IS NULL".format('COMPLETION_YEAR')
491509
invalid_year_lyr = self.make_skinny_table_view(self.hwyproj, 'invalid_year_lyr', ['COMPLETION_YEAR', common_id_field], invalid_year_query)
492510
invalid_year_count = int(arcpy.GetCount_management(invalid_year_lyr).getOutput(0))
493511
if invalid_year_count > 0:
@@ -520,12 +538,11 @@ def make_attribute_dict(fc, key_field, attr_list=['*']):
520538
- NOTE 2: using attr_list=[] will essentially build a list of unique
521539
key_field values. '''
522540
attr_dict = {}
523-
fc_field_objects = arcpy.ListFields(fc)
524-
fc_fields = [field.name for field in fc_field_objects if field.type != 'Geometry']
541+
fc_fields = [f.name for f in arcpy.ListFields(fc) if f.type != 'Geometry']
525542
if attr_list == ['*']:
526543
valid_fields = fc_fields
527544
else:
528-
valid_fields = [field for field in attr_list if field in fc_fields]
545+
valid_fields = [f for f in attr_list if f in fc_fields]
529546
# Ensure that key_field is always the first field in the field list
530547
cursor_fields = [key_field] + list(set(valid_fields) - set([key_field]))
531548
with arcpy.da.SearchCursor(fc, cursor_fields) as cursor:
@@ -555,9 +572,9 @@ def make_skinny(is_geo, in_obj, out_obj, keep_fields_list=None, where_clause=Non
555572
keep_fields_list = []
556573
for field in input_fields:
557574
if field.name in keep_fields_list:
558-
field_info_str += field.name + ' ' + field.name + ' VISIBLE;'
575+
field_info_str += '{0} {0} VISIBLE;'.format(field.name)
559576
else:
560-
field_info_str += field.name + ' ' + field.name + ' HIDDEN;'
577+
field_info_str += '{0} {0} HIDDEN;'.format(field.name)
561578
field_info_str.rstrip(';') # Remove trailing semicolon
562579
if is_geo:
563580
arcpy.MakeFeatureLayer_management(in_obj, out_obj, where_clause, field_info=field_info_str)
@@ -580,14 +597,14 @@ def set_nulls(value, fc, fields):
580597
valid_types = ['String']
581598
else:
582599
valid_types = ['String', 'SmallInteger', 'Integer', 'Single', 'Double']
583-
matched_fields = [field for field in arcpy.ListFields(fc) if field.name in fields and field.type in valid_types]
600+
matched_fields = [f for f in arcpy.ListFields(fc) if f.name in fields and f.type in valid_types]
584601
for field in matched_fields:
585602
if field.type == 'String':
586-
expression = "'{0}'".format(value)
603+
expression = "'{}'".format(value)
587604
else:
588-
expression = '{0}'.format(value)
605+
expression = "{}".format(value)
589606
null_view = 'null_view'
590-
arcpy.MakeTableView_management(fc, null_view, '"{0}" IS NULL'.format(field.name))
607+
arcpy.MakeTableView_management(fc, null_view, "{} IS NULL".format(field.name))
591608
if int(arcpy.GetCount_management(null_view).getOutput(0)) > 0:
592609
arcpy.CalculateField_management(null_view, field.name, expression, 'PYTHON')
593610
arcpy.Delete_management(null_view)
@@ -611,7 +628,7 @@ def submit_sas(self, sas_file, sas_log, sas_lst, arg_list=None):
611628
if not arg_list:
612629
arg_str = ''
613630
else:
614-
arg_str = '$'.join((str(arg) for arg in arg_list))
631+
arg_str = '$'.join(str(arg) for arg in arg_list)
615632
bat = os.path.join(self.prog_dir, 'sasrun.bat')
616633
cmd = [bat, sas_file, arg_str, sas_log, sas_lst]
617634
return subprocess.check_call(cmd, startupinfo=startupinfo)
@@ -654,7 +671,7 @@ def tipid_from_int(self, n):
654671
''' Format an integer < 100,000,000 as a TIPID string. '''
655672
try:
656673
n_str = str(int(n)).zfill(8)
657-
tipid = '-'.join((n_str[:2], n_str[2:4], n_str[4:]))
674+
tipid = '-'.join([n_str[:2], n_str[2:4], n_str[4:]])
658675
except:
659676
return None
660677
return tipid if self.is_tipid(tipid) else None
@@ -725,15 +742,15 @@ def write_arc_flag_file(self, flag_file, flag_query, csv_mode=False):
725742
w.write('ANODE,BNODE\n')
726743
else:
727744
row_prefix = 'l='
728-
w.write('~# {0} links\n'.format(flag_query.strip()))
745+
w.write('~# {} links\n'.format(flag_query.strip()))
729746
with arcpy.da.SearchCursor(flag_lyr, ['ANODE', 'BNODE', 'DIRECTIONS']) as cursor:
730747
for row in cursor:
731748
anode = row[0]
732749
bnode = row[1]
733750
directions = int(row[2])
734-
w.write('{2}{0},{1}\n'.format(anode, bnode, row_prefix))
751+
w.write('{0}{1},{2}\n'.format(row_prefix, anode, bnode))
735752
if directions > 1:
736-
w.write('{2}{1},{0}\n'.format(anode, bnode, row_prefix))
753+
w.write('{0}{2},{1}\n'.format(row_prefix, anode, bnode))
737754
arcpy.Delete_management(flag_lyr)
738755
return flag_file
739756

@@ -743,12 +760,11 @@ def write_attribute_csv(in_obj, textfile, field_list=None, include_headers=True)
743760
''' Write attributes of a feature class/table to a specified text file.
744761
Input field_list allows output field order to be specified. Defaults to
745762
all non-shape fields. '''
746-
all_field_objects = arcpy.ListFields(in_obj)
747-
valid_field_names = [field.name for field in all_field_objects if field.name != '' and field.type != 'Geometry']
763+
valid_field_names = [f.name for f in arcpy.ListFields(in_obj) if f.name != '' and f.type != 'Geometry']
748764
if not field_list:
749765
fields = valid_field_names
750766
else:
751-
fields = [field for field in field_list if field in valid_field_names]
767+
fields = [f for f in field_list if f in valid_field_names]
752768
csv = open(textfile,'w')
753769
if include_headers:
754770
csv.write(','.join(fields) + '\n')

0 commit comments

Comments
 (0)