Skip to content

Commit 28756e9

Browse files
authored
Merge pull request #33 from aerispaha/py3
Python 2/3 Compatibility
2 parents fbf93c4 + c6e11b5 commit 28756e9

31 files changed

+660
-88
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private.py
44
private/
55
# Setuptools distribution folder.
66
/dist/
7+
/build/
78
# Python egg metadata, regenerated from source files by setuptools.
89
/*.egg-info
910
notes/

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: python
22
python:
33
- "2.7"
4-
# - "3.6"
4+
- "3.6"
55
# - "3.7"
66
# command to install dependencies
77
install:

README.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# SWMMIO
2+
3+
[![Build status](https://ci.appveyor.com/api/projects/status/qywujm5w2wm0y2tv?svg=true)](https://ci.appveyor.com/project/aerispaha/swmmio)
4+
25
![Kool Picture](docs/img/impact_of_option.png?raw=true "Impact of Option")
36
SWMMIO is a set of python tools aiming to provide a means for version control and visualizing results from the EPA Stormwater Management Model (SWMM). Command line tools are also provided for running models individually and in parallel via Python's `multiprocessing` module. These tools are being developed specifically for the application of flood risk management, though most functionality is applicable to SWMM modeling in general.
47

@@ -8,7 +11,7 @@ SWMMIO functions primarily by interfacing with .inp and .rpt (input and report)
811

912

1013
### Dependencies
11-
* [pillow](http://python-pillow.org/): 3.0.0
14+
* [pillow](http://python-pillow.org/)
1215
* [matplotlib](http://matplotlib.org/)
1316
* [numpy](http://www.numpy.org/)
1417
* [pandas](https://github.com/pydata/pandas)
@@ -19,10 +22,6 @@ SWMMIO functions primarily by interfacing with .inp and .rpt (input and report)
1922
Before installation, it's recommended to first activate a [virtualenv](https://github.com/pypa/virtualenv) to not crowd your system's package library. If you don't use any of the dependencies listed above, this step is less important. SWMMIO can be installed via pip in your command line:
2023

2124
```bash
22-
#on Windows:
23-
python -m pip install swmmio
24-
25-
#on Unix-type systems, i do this:
2625
pip install swmmio
2726
```
2827

appveyor.yml

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#matrix:
2+
# fast_finish: true
3+
4+
#branches:
5+
# only:
6+
# - master
7+
# - /dev-.*/
8+
9+
environment:
10+
matrix:
11+
# For Python versions available on Appveyor, see
12+
# http://www.appveyor.com/docs/installed-software#python
13+
# The list here is complete (excluding Python 2.6, which
14+
# isn't covered by this document) at the time of writing.
15+
- PYTHON: "C:\\Python27"
16+
- PYTHON: "C:\\Python36"
17+
18+
install:
19+
- "%PYTHON%\\python setup.py develop"
20+
- "%PYTHON%\\python.exe -m pip install -r %APPVEYOR_BUILD_FOLDER%\\requirements.txt -q"
21+
22+
build: off
23+
24+
test_script:
25+
26+
- "%PYTHON%\\Scripts\\pytest %APPVEYOR_BUILD_FOLDER%"
27+
28+
# Asserting pep8 formatting checks (using autopep8 tool)
29+
# - ps: |
30+
# $output = C:\\Python36\\Scripts\\autopep8 -d --recursive .
31+
# if($output)
32+
# {
33+
# echo $output;
34+
# $host.SetShouldExit(1)
35+
# Write-Host "autopep8 failed:
36+
# Please this command locally:
37+
# 'autopep8 -i -a -r .'"
38+
# }

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Build dependencies
22
#python
33
pytest
4-
pillow==3.0.0
4+
pillow
55
numpy
66
pandas
77
pyshp

setup.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ def read(fname):
66
return open(os.path.join(os.path.dirname(__file__), fname)).read()
77

88

9-
VERSION = '0.2.1'
9+
VERSION = '0.3.0'
1010
AUTHOR_NAME = 'Adam Erispaha'
1111
AUTHOR_EMAIL = '[email protected]'
1212

1313
install_requires = [
14-
'pillow==3.0.0',
14+
# 'pillow==3.0.0',
15+
'Pillow',
1516
'numpy',
1617
'pandas',
1718
'pyshp',

swmmio/__main__.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from .run_models.run import run_simple, run_hot_start_sequence
22
from .run_models import start_pool
3-
from swmmio import Model
3+
from .swmmio import Model
44
from itertools import chain
55
import os
66
import argparse
@@ -21,23 +21,23 @@
2121
if args.model_to_run is not None:
2222

2323
models_paths = [os.path.join(wd, f) for f in args.model_to_run]
24-
print 'Adding models to queue:\n\t{}'.format('\n\t'.join(models_paths))
24+
print('Adding models to queue:\n\t{}'.format('\n\t'.join(models_paths)))
2525

2626
#run the models in series (one after the other)
27-
map(run_simple, models_paths)
27+
list(map(run_simple, models_paths))
2828
# run_simple(args.model_to_run)
2929

3030
elif args.hotstart_model_to_run is not None:
3131
models_paths = [os.path.join(wd, f) for f in args.hotstart_model_to_run]
32-
print 'hotstart_model_to_run the model: {}'.format(args.hotstart_model_to_run)
32+
print('hotstart_model_to_run the model: {}'.format(args.hotstart_model_to_run))
3333
# m = Model(args.hotstart_model_to_run)
3434
# run_hot_start_sequence(m)#args.hotstart_model_to_run)
35-
map(run_hot_start_sequence, models_paths)
35+
list(map(run_hot_start_sequence, models_paths))
3636

3737
elif args.start_pool is not None:
3838

3939
models_dirs = [os.path.join(wd, f) for f in args.start_pool]
40-
print 'Searching for models in:\n\t{}'.format('\n\t'.join(models_dirs))
40+
print('Searching for models in:\n\t{}'.format('\n\t'.join(models_dirs)))
4141
#combine the segments and options (combinations) into one iterable
4242
inp_paths = []
4343
for root, dirs, files in chain.from_iterable(os.walk(path) for path in models_dirs):
@@ -50,8 +50,8 @@
5050
#call the main() function in start_pool.py
5151
start_pool.main(inp_paths, args.cores_left)
5252

53-
print "swmmio has completed running {} models".format(len(inp_paths))
53+
print("swmmio has completed running {} models".format(len(inp_paths)))
5454

5555

5656
else:
57-
print 'you need to pass in some args'
57+
print('you need to pass in some args')

swmmio/defs/sectionheaders.py

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
'[INFILTRATION]':'Subcatchment Suction HydCon IMDmax',
2626
'[Polygons]':'Name X Y',
2727
'[REPORT]':'Param Status',
28+
'[TAGS]':'ElementType Name Tag',
2829
#'[CURVES]':'Name Type X-Value Y-Value',
2930
#'[TIMESERIES]':'Name Date Time Value'
3031
}
@@ -41,6 +42,7 @@
4142
'Node Flooding Summary':'Name HoursFlooded MaxQ MaxDay MaxHr TotalFloodVol MaximumPondDepth',
4243
'Node Inflow Summary':'Name Type MaxLatInflow MaxTotalInflow MaxDay MaxHr LatInflowV TotalInflowV FlowBalErrorPerc XXX',
4344
'Node Surcharge Summary':'Name Type HourSurcharged MaxHeightAboveCrown MinDepthBelowRim',
45+
'Storage Volume Summary':'Name AvgVolume AvgPctFull EvapPctLoss ExfilPctLoss MaxVolume MaxPctFull MaxDay MaxFullHr MaxOutflow',
4446
'Node Depth Summary':'Name Type AvgDepth MaxNodeDepth MaxHGL MaxDay MaxHr',
4547
'Link Flow Summary':'Name Type MaxQ MaxDay MaxHr MaxV MaxQPerc MaxDPerc',
4648
'Subcatchment Results': 'Date Time PrecipInchPerHour LossesInchPerHr RunoffCFS',

swmmio/graphics/animate.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
2222
"""
2323
#unpack and update the options
2424
ops = du.default_draw_options()
25-
for key, value in kwargs.iteritems():
25+
for key, value in kwargs.items():
2626
ops.update({key:value})
2727
#return ops
2828
width = ops['width']
@@ -63,8 +63,8 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
6363
if userStartDT < simStartDT or userEndDT > simEndDT or timeStepMod != 0 or userEndDT < userStartDT:
6464
#user has entered fault date times either by not being within the
6565
#availble data in the rpt or by starting at something that doesn't fit the timestep
66-
print "PROBLEM WITH DATETIME ENTERED. Make sure it fits within data and start time rest on factor of timestep in minutes."
67-
print "userStartDT = ", userStartDT, "\nuserEndDT = ", userEndDT, "\nsimStartDT = ", simStartDT, "\nsimEndDT = ", simEndDT, "\nTIMESTEP = ", rpt.timeStepMin
66+
print("PROBLEM WITH DATETIME ENTERED. Make sure it fits within data and start time rest on factor of timestep in minutes.")
67+
print("userStartDT = ", userStartDT, "\nuserEndDT = ", userEndDT, "\nsimStartDT = ", simStartDT, "\nsimEndDT = ", simEndDT, "\nTIMESTEP = ", rpt.timeStepMin)
6868
return None
6969

7070
currentT = datetime.strptime(startDtime, "%b-%d-%Y %H:%M:%S") #SWMM dtime format needed
@@ -81,7 +81,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
8181
if not os.path.isfile(byteLocDictionaryFName):
8282

8383
#this is a heavy operation, allow a few minutes
84-
print "generating byte dictionary..."
84+
print("generating byte dictionary...")
8585
#conduitByteLocationDict = rpt.createByteLocDict("Link Results")
8686
rpt.createByteLocDict("Link Results")
8787
rpt.createByteLocDict("Node Results")
@@ -96,7 +96,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
9696
rpt.elementByteLocations = pickle.load( open(byteLocDictionaryFName, 'r') )
9797
#rpt.byteLocDict = conduitByteLocationDict
9898

99-
print "Started Drawing at " + strftime("%b-%d-%Y %H:%M:%S")
99+
print("Started Drawing at " + strftime("%b-%d-%Y %H:%M:%S"))
100100
log = "Started Drawing at " + strftime("%b-%d-%Y %H:%M:%S") + "\n\nErrors:\n\n"
101101
drawCount = 0
102102
conduitErrorCount = 0
@@ -116,7 +116,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
116116

117117
#DRAW THE CONDUITS
118118
if ops['conduitSymb']:
119-
for id, conduit in conduitDicts.iteritems():
119+
for id, conduit in conduitDicts.items():
120120
#coordPair = coordPairDict['coordinates']
121121
if conduit.coordinates: #this prevents draws if no flow is supplied (RDII and such)
122122

@@ -125,11 +125,11 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
125125

126126
drawCount += 1
127127

128-
if drawCount > 0 and drawCount % 2000 == 0: print str(drawCount) + " pipes drawn - simulation time = " + currentTstr
128+
if drawCount > 0 and drawCount % 2000 == 0: print(str(drawCount) + " pipes drawn - simulation time = " + currentTstr)
129129

130130
#DRAW THE NODES
131131
if ops['nodeSymb']:
132-
for id, node in nodeDicts.iteritems():
132+
for id, node in nodeDicts.items():
133133
if node.coordinates: #this prevents draws if no flow is supplied (RDII and such)
134134
su.drawNode(node, nodeDict, draw, rpt=rpt, dTime=currentTstr, options=ops['nodeSymb'], xplier=xplier)
135135
drawCount += 1
@@ -153,7 +153,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
153153
imgPath = os.path.join(tempImgDir, image)
154154
frames.append(Image.open(imgPath))
155155

156-
print "building gif with " + str(len(glob.glob1(tempImgDir, "*.png"))) + " frames..."
156+
print("building gif with " + str(len(glob.glob1(tempImgDir, "*.png"))) + " frames...")
157157
if not imgName: imgName = inp.name
158158
gifFile = os.path.join(imgDir, imgName) + ".gif"
159159
frameDuration = 1.0 / float(ops['fps'])
@@ -165,7 +165,7 @@ def animateModel(model, startDtime=None, endDtime=None, **kwargs):
165165
with open(os.path.join(imgDir, "log.txt"), 'w') as logFile:
166166
logFile.write(log)
167167

168-
print "Draw Count =" + str(drawCount)
169-
print "Video saved to:\n\t" + gifFile
168+
print("Draw Count =" + str(drawCount))
169+
print("Video saved to:\n\t" + gifFile)
170170

171171
os.startfile(gifFile)#this doesn't seem to work

swmmio/graphics/drawing.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def annotate_streets(df, img, text_col):
136136

137137
#confirm font file location
138138
if not os.path.exists(config.font_file):
139-
print 'Error loading defautl font. Check your config.font_file'
139+
print('Error loading defautl font. Check your config.font_file')
140140
return None
141141

142142
unique_sts = df[text_col].unique()
@@ -244,13 +244,13 @@ def _annotateMap (canvas, model, model2=None, currentTstr = None, options=None,
244244
#Buid the title and files list (handle 1 or two input models)
245245
#this is hideous, or elegant?
246246
files = title = results_string = symbology_string = annotationTxt = ""
247-
files = '\n'.join([m.rpt.path for m in filter(None, [model, model2])])
248-
title = ' to '.join([m.inp.name for m in filter(None, [model, model2])])
249-
symbology_string = ', '.join([s['title'] for s in filter(None, [nodeSymb, conduitSymb, parcelSymb])])
247+
files = '\n'.join([m.rpt.path for m in [_f for _f in [model, model2] if _f]])
248+
title = ' to '.join([m.inp.name for m in [_f for _f in [model, model2] if _f]])
249+
symbology_string = ', '.join([s['title'] for s in [_f for _f in [nodeSymb, conduitSymb, parcelSymb] if _f]])
250250
title += "\n" + symbology_string
251251

252252
#collect results
253-
for result, value in results.iteritems():
253+
for result, value in results.items():
254254
results_string += '\n' + result + ": " + str(value)
255255

256256
#compile the annotation text

swmmio/reporting/batch.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def batch_reports(project_dir, results_file,
4444
if '.inp' in f:
4545
inp_path = os.path.join(path,f)
4646
alt = Model(inp_path)
47-
print 'reporting on {}'.format(alt.name)
47+
print('reporting on {}'.format(alt.name))
4848
#generate the reports
4949
frpt = reporting.FloodReport(alt, parcel_node_join_df)
5050
impact_rpt = reporting.ComparisonReport(baserpt, frpt,
@@ -97,7 +97,7 @@ def batch_cost_estimates(baseline_dir, segments_dir, options_dir, results_file,
9797
costsdf = functions.estimate_cost_of_new_conduits(baseline, alt,
9898
supplemental_cost_data)
9999
cost_estimate = costsdf.TotalCostEstimate.sum() / math.pow(10, 6)
100-
print '{}: ${}M'.format(alt.name, round(cost_estimate,1))
100+
print('{}: ${}M'.format(alt.name, round(cost_estimate,1)))
101101

102102
model_id = os.path.splitext(f)[0]
103103
with open(results_file, 'a') as res:
@@ -131,13 +131,13 @@ def batch_post_process(options_dir, baseline_dir, log_dir, bbox=None, overwrite=
131131
current_dir = os.path.join(options_dir, folder)
132132
report_dir = os.path.join(current_dir, REPORT_DIR_NAME)
133133
if not overwrite and os.path.exists(report_dir):
134-
print 'skipping {}'.format(folder)
134+
print('skipping {}'.format(folder))
135135
continue
136136

137137
else:
138138
#generate the report
139139
current_model = Model(current_dir)
140-
print 'Generating report for {}'.format(current_model.inp.name)
140+
print('Generating report for {}'.format(current_model.inp.name))
141141
#reporting.generate_figures(baseline, current_model, bbox=bbox, imgDir=report_dir, verbose=True)
142142
report = reporting.Report(baseline, current_model)
143143
report.write(report_dir)

swmmio/reporting/reporting.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ def generate_figures(self, rpt_dir, parcel_shp_df, bbox=d68d70):
262262

263263
def __str__(self):
264264
"""print friendly"""
265-
catz = filter(None, self.flood_comparison.Category.unique())
265+
catz = [_f for _f in self.flood_comparison.Category.unique() if _f]
266266
a = ['{}: {}'.format(c, self.impact[c]) for c in catz]
267267
files = [self.baseline_report.model.inp.path,
268268
self.alt_report.model.inp.path]

swmmio/reporting/serialize.py

+4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
from swmmio.utils import spatial
66
from swmmio.graphics import swmm_graphics as sg
77
from swmmio.reporting.reporting import FloodReport
8+
<<<<<<< HEAD
9+
from swmmio.definitions import *
10+
=======
811
from swmmio.defs.config import *
12+
>>>>>>> master
913
import geojson
1014

1115

swmmio/reporting/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def insert_in_file_2(key, string, newfile):
2323

2424
#start writing that thing
2525
key = '{}{}{}'.format('{{', key, '}}') #Django style
26-
print key
26+
print(key)
2727
with open(newfile, 'r') as newmap:
2828
for line in newmap:
2929
if key in line:

swmmio/reporting/visualize.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def create_map(model1, model2=None, bbox=None, crs=None, filename=None,
3939

4040
geometries = [] #array of features
4141
#collect the links
42-
for k,v in model2.list_objects('conduit', bbox, subset=subset).items():
42+
for k,v in list(model2.list_objects('conduit', bbox, subset=subset).items()):
4343
props = {
4444
'MaxQPercent':v.maxQpercent,
4545
'id':v.id,

swmmio/run_models/run.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def run_simple(inp_path, swmm_eng=SWMM_ENGINE_PATH):
1616
"""
1717
run a model once as is.
1818
"""
19-
print 'running {} with {}'.format(inp_path, swmm_eng)
19+
print('running {} with {}'.format(inp_path, swmm_eng))
2020
#inp_path = model.inp.path
2121
rpt_path = os.path.splitext(inp_path)[0] + '.rpt'
2222

@@ -32,7 +32,7 @@ def run_hot_start_sequence(inp_path, swmm_eng=SWMM_ENGINE_PATH):
3232

3333
# if not os.path.exists(hotstart1) and not os.path.exists(hotstart2):
3434
#create new model inp with params to save hotstart1
35-
print 'create new model inp with params to save hotstart1'
35+
print('create new model inp with params to save hotstart1')
3636
s = pd.Series(['SAVE HOTSTART "{}"'.format(hotstart1)])
3737
hot1_df = pd.DataFrame(s, columns=['[FILES]'])
3838
model = replace_inp_section(model.inp.path, '[FILES]', hot1_df)
@@ -42,15 +42,15 @@ def run_hot_start_sequence(inp_path, swmm_eng=SWMM_ENGINE_PATH):
4242

4343
# if os.path.exists(hotstart1) and not os.path.exists(hotstart2):
4444
#create new model inp with params to use hotstart1 and save hotstart2
45-
print 'with params to use hotstart1 and save hotstart2'
45+
print('with params to use hotstart1 and save hotstart2')
4646
s = pd.Series(['USE HOTSTART "{}"'.format(hotstart1), 'SAVE HOTSTART "{}"'.format(hotstart2)])
4747
hot2_df = pd.DataFrame(s, columns=['[FILES]'])
4848
model = replace_inp_section(model.inp.path, '[FILES]', hot2_df)
4949
subprocess.call([swmm_eng, model.inp.path, rpt_path])
5050

5151
# if os.path.exists(hotstart2):
5252
#create new model inp with params to use hotstart2 and not save anything
53-
print 'params to use hotstart2 and not save anything'
53+
print('params to use hotstart2 and not save anything')
5454
s = pd.Series(['USE HOTSTART "{}"'.format(hotstart2)])
5555
hot3_df = pd.DataFrame(s, columns=['[FILES]'])
5656

0 commit comments

Comments
 (0)