Skip to content

Commit 289e473

Browse files
Jonathan Gaffiotwholmgren
authored andcommitted
Fix issue #352 and homogenize string concatenation across the code (#353)
* Fix bug in __repr__ method of ModelChain * Homogenize the string concatenation and the __repr__ method across the code. * Upate the test of ModelChain.__repr__ thanks to the code given by wholmgren in the comments discussing pull request #353 * Update the whatsnew/v0.4.6.rst file with the bug fix and the test update.
1 parent 8d2650a commit 289e473

File tree

8 files changed

+44
-43
lines changed

8 files changed

+44
-43
lines changed

docs/sphinx/source/whatsnew/v0.4.6.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Bug fixes
1010
* Method of multi-inheritance has changed to make it possible to use kwargs in
1111
the parent classes of LocalizedPVSystem and LocalizedSingleAxisTracker
1212
(:issue:`330`)
13+
* Fix the `__repr__` method of `ModelChain`, crashing when
14+
`orientation_strategy` is set to `'None'` (:issue:`352`)
1315

1416

1517
Enhancements
@@ -28,6 +30,7 @@ Testing
2830
~~~~~~~
2931

3032
* Added explicit tests for aoi and aoi_projection functions.
33+
* Update test of `ModelChain.__repr__` to take in account :issue:`352`
3134

3235

3336
Contributors
@@ -37,3 +40,4 @@ Contributors
3740
* Uwe Krien
3841
* Alaina Kafkes
3942
* Birgit Schachler
43+
* Jonathan Gaffiot

pvlib/location.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def __init__(self, latitude, longitude, tz='UTC', altitude=0,
8282
def __repr__(self):
8383
attrs = ['name', 'latitude', 'longitude', 'altitude', 'tz']
8484
return ('Location: \n ' + '\n '.join(
85-
(attr + ': ' + str(getattr(self, attr)) for attr in attrs)))
85+
('{}: {}'.format(attr, getattr(self, attr)) for attr in attrs)))
8686

8787
@classmethod
8888
def from_tmy(cls, tmy_metadata, tmy_data=None, **kwargs):
@@ -226,8 +226,8 @@ def get_clearsky(self, times, model='ineichen', solar_position=None,
226226
apparent_elevation, pressure=pressure, dni_extra=dni_extra,
227227
**kwargs)
228228
else:
229-
raise ValueError(('{} is not a valid clear sky model. Must be ' +
230-
'one of ineichen, simplified_solis, haurwitz')
229+
raise ValueError('{} is not a valid clear sky model. Must be '
230+
'one of ineichen, simplified_solis, haurwitz'
231231
.format(model))
232232

233233
return cs

pvlib/modelchain.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def basic_chain(times, latitude, longitude,
112112
surface_tilt, surface_azimuth = \
113113
get_orientation(orientation_strategy, latitude=latitude)
114114
else:
115-
raise ValueError('orientation_strategy or surface_tilt and ' +
115+
raise ValueError('orientation_strategy or surface_tilt and '
116116
'surface_azimuth must be provided')
117117

118118
times = times
@@ -208,7 +208,7 @@ def get_orientation(strategy, **kwargs):
208208
surface_azimuth = 180
209209
surface_tilt = 0
210210
else:
211-
raise ValueError('invalid orientation strategy. strategy must ' +
211+
raise ValueError('invalid orientation strategy. strategy must '
212212
'be one of south_at_latitude, flat,')
213213

214214
return surface_tilt, surface_azimuth
@@ -344,7 +344,7 @@ def getmcattr(self, attr):
344344
return out
345345

346346
return ('ModelChain: \n ' + '\n '.join(
347-
(attr + ': ' + getmcattr(self, attr) for attr in attrs)))
347+
('{}: {}'.format(attr, getmcattr(self, attr)) for attr in attrs)))
348348

349349
@property
350350
def orientation_strategy(self):
@@ -391,7 +391,7 @@ def infer_dc_model(self):
391391
elif set(['pdc0', 'gamma_pdc']) <= params:
392392
return self.pvwatts_dc
393393
else:
394-
raise ValueError('could not infer DC model from ' +
394+
raise ValueError('could not infer DC model from '
395395
'system.module_parameters')
396396

397397
def sapm(self):
@@ -455,7 +455,7 @@ def infer_ac_model(self):
455455
elif set(['pdc0']) <= module_params:
456456
return self.pvwatts_inverter
457457
else:
458-
raise ValueError('could not infer AC model from ' +
458+
raise ValueError('could not infer AC model from '
459459
'system.inverter_parameters')
460460

461461
def snlinverter(self):
@@ -502,7 +502,7 @@ def infer_aoi_model(self):
502502
elif set(['b']) <= params:
503503
return self.ashrae_aoi_loss
504504
else:
505-
raise ValueError('could not infer AOI model from ' +
505+
raise ValueError('could not infer AOI model from '
506506
'system.module_parameters')
507507

508508
def ashrae_aoi_loss(self):
@@ -547,7 +547,7 @@ def infer_spectral_model(self):
547547
if set(['A4', 'A3', 'A2', 'A1', 'A0']) <= params:
548548
return self.sapm_spectral_loss
549549
else:
550-
raise ValueError('could not infer spectral model from ' +
550+
raise ValueError('could not infer spectral model from '
551551
'system.module_parameters')
552552

553553
def first_solar_spectral_loss(self):

pvlib/pvsystem.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def __repr__(self):
156156
attrs = ['name', 'surface_tilt', 'surface_azimuth', 'module',
157157
'inverter', 'albedo', 'racking_model']
158158
return ('PVSystem: \n ' + '\n '.join(
159-
(attr + ': ' + str(getattr(self, attr)) for attr in attrs)))
159+
('{}: {}'.format(attr, getattr(self, attr)) for attr in attrs)))
160160

161161
def get_aoi(self, solar_zenith, solar_azimuth):
162162
"""Get the angle of incidence on the system.
@@ -593,7 +593,7 @@ def __repr__(self):
593593
'surface_azimuth', 'module', 'inverter', 'albedo', 'racking_model'
594594
]
595595
return ('LocalizedPVSystem: \n ' + '\n '.join(
596-
(attr + ': ' + str(getattr(self, attr)) for attr in attrs)))
596+
('{}: {}'.format(attr, getattr(self, attr)) for attr in attrs)))
597597

598598

599599
def systemdef(meta, surface_tilt, surface_azimuth, albedo, modules_per_string,
@@ -2084,8 +2084,8 @@ def adrinverter(v_dc, p_dc, inverter, vtol=0.10):
20842084
See Notes for required keys.
20852085
20862086
vtol : numeric, default 0.1
2087-
A unit-less fraction that determines how far the efficiency model is
2088-
allowed to extrapolate beyond the inverter's normal input voltage
2087+
A unit-less fraction that determines how far the efficiency model is
2088+
allowed to extrapolate beyond the inverter's normal input voltage
20892089
operating range. 0.0 <= vtol <= 1.0
20902090
20912091
Returns
@@ -2109,21 +2109,21 @@ def adrinverter(v_dc, p_dc, inverter, vtol=0.10):
21092109
Column Description
21102110
======= ============================================================
21112111
p_nom The nominal power value used to normalize all power values,
2112-
typically the DC power needed to produce maximum AC power
2112+
typically the DC power needed to produce maximum AC power
21132113
output, (W).
21142114
2115-
v_nom The nominal DC voltage value used to normalize DC voltage
2116-
values, typically the level at which the highest efficiency
2115+
v_nom The nominal DC voltage value used to normalize DC voltage
2116+
values, typically the level at which the highest efficiency
21172117
is achieved, (V).
21182118
2119-
pac_max The maximum AC output power value, used to clip the output
2119+
pac_max The maximum AC output power value, used to clip the output
21202120
if needed, (W).
21212121
21222122
ce_list This is a list of 9 coefficients that capture the influence
21232123
of input voltage and power on inverter losses, and thereby
21242124
efficiency.
21252125
2126-
p_nt ac-power consumed by inverter at night (night tare) to
2126+
p_nt ac-power consumed by inverter at night (night tare) to
21272127
maintain circuitry required to sense PV array voltage, (W).
21282128
======= ============================================================
21292129

pvlib/test/test_modelchain.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -417,17 +417,18 @@ def test_basic_chain_altitude_pressure(sam_data):
417417
assert_series_equal(ac, expected, check_less_precise=2)
418418

419419

420-
def test_ModelChain___repr__(system, location):
421-
422-
strategy = 'south_at_latitude_tilt'
420+
@pytest.mark.parametrize('strategy, strategy_str', [
421+
('south_at_latitude_tilt', 'south_at_latitude_tilt'),
422+
(None, 'None')]) # GitHub issue 352
423+
def test_ModelChain___repr__(system, location, strategy, strategy_str):
423424

424425
mc = ModelChain(system, location, orientation_strategy=strategy,
425426
name='my mc')
426427

427428
expected = '\n'.join([
428429
'ModelChain: ',
429430
' name: my mc',
430-
' orientation_strategy: south_at_latitude_tilt',
431+
' orientation_strategy: ' + strategy_str,
431432
' clearsky_model: ineichen',
432433
' transposition_model: haydavies',
433434
' solar_position_method: nrel_numpy',
@@ -442,7 +443,6 @@ def test_ModelChain___repr__(system, location):
442443

443444
assert mc.__repr__() == expected
444445

445-
446446
@requires_scipy
447447
def test_weather_irradiance_input(system, location):
448448
"""Test will raise a warning and should be removed in future versions."""

pvlib/test/test_pvsystem.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ def test_PVSystem_sapm_celltemp():
570570

571571
def test_adrinverter(sam_data):
572572
inverters = sam_data['adrinverter']
573-
testinv = 'Ablerex_Electronics_Co___Ltd___' + \
573+
testinv = 'Ablerex_Electronics_Co___Ltd___' \
574574
'ES_2200_US_240__240_Vac__240V__CEC_2011_'
575575
vdcs = pd.Series([135, 154, 390, 420, 551])
576576
pdcs = pd.Series([135, 1232, 1170, 420, 551])
@@ -582,7 +582,7 @@ def test_adrinverter(sam_data):
582582

583583
def test_adrinverter_vtol(sam_data):
584584
inverters = sam_data['adrinverter']
585-
testinv = 'Ablerex_Electronics_Co___Ltd___' + \
585+
testinv = 'Ablerex_Electronics_Co___Ltd___' \
586586
'ES_2200_US_240__240_Vac__240V__CEC_2011_'
587587
vdcs = pd.Series([135, 154, 390, 420, 551])
588588
pdcs = pd.Series([135, 1232, 1170, 420, 551])
@@ -594,7 +594,7 @@ def test_adrinverter_vtol(sam_data):
594594

595595
def test_adrinverter_float(sam_data):
596596
inverters = sam_data['adrinverter']
597-
testinv = 'Ablerex_Electronics_Co___Ltd___' + \
597+
testinv = 'Ablerex_Electronics_Co___Ltd___' \
598598
'ES_2200_US_240__240_Vac__240V__CEC_2011_'
599599
vdcs = 154.
600600
pdcs = 1232.

pvlib/tmy.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ def readtmy3(filename=None, coerce_year=None, recolumn=True):
158158
try:
159159
filename = _interactive_load()
160160
except:
161-
raise Exception('Interactive load failed. Tkinter not supported ' +
162-
'on this system. Try installing X-Quartz and ' +
161+
raise Exception('Interactive load failed. Tkinter not supported '
162+
'on this system. Try installing X-Quartz and '
163163
'reloading')
164164

165165
head = ['USAF', 'Name', 'State', 'TZ', 'latitude', 'longitude', 'altitude']
@@ -467,20 +467,17 @@ def _read_tmy2(string, columns, hdr_columns, fname):
467467
try:
468468
val = float(val)
469469
except:
470-
raise Exception('WARNING: In' + fname +
471-
' Read value is not an integer " ' +
472-
val + ' " ')
470+
raise Exception('WARNING: In {} Read value is not an '
471+
'integer " {} " '.format(fname, val))
473472
elif marker[-1] == 's':
474473
try:
475474
val = str(val)
476475
except:
477-
raise Exception('WARNING: In' + fname +
478-
' Read value is not a string" ' +
479-
val + ' " ')
476+
raise Exception('WARNING: In {} Read value is not a '
477+
'string " {} " '.format(fname, val))
480478
else:
481-
raise Exception('WARNING: In' + __name__ +
482-
'Improper column DataFrame " %' +
483-
marker + ' " ')
479+
raise Exception('WARNING: In {} Improper column DataFrame '
480+
'" %{} " '.format(__name__, marker))
484481

485482
part.append(val)
486483

pvlib/tracking.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, axis_tilt=0, axis_azimuth=0,
5959
def __repr__(self):
6060
attrs = ['axis_tilt', 'axis_azimuth', 'max_angle', 'backtrack', 'gcr']
6161
sat_repr = ('SingleAxisTracker: \n ' + '\n '.join(
62-
(attr + ': ' + str(getattr(self, attr)) for attr in attrs)))
62+
('{}: {}'.format(attr, getattr(self, attr)) for attr in attrs)))
6363
# get the parent PVSystem info
6464
pvsystem_repr = super(SingleAxisTracker, self).__repr__()
6565
# remove the first line (contains 'PVSystem: \n')
@@ -196,8 +196,8 @@ def __repr__(self):
196196
attrs = ['latitude', 'longitude', 'altitude', 'tz']
197197
return ('Localized' +
198198
super(LocalizedSingleAxisTracker, self).__repr__() + '\n ' +
199-
'\n '.join(
200-
(attr + ': ' + str(getattr(self, attr)) for attr in attrs)))
199+
'\n '.join(('{}: {}'.format(attr, getattr(self, attr))
200+
for attr in attrs)))
201201

202202

203203
def singleaxis(apparent_zenith, apparent_azimuth,
@@ -280,7 +280,7 @@ def singleaxis(apparent_zenith, apparent_azimuth,
280280

281281
pvl_logger.debug('tracking.singleaxis')
282282

283-
pvl_logger.debug('axis_tilt=%s, axis_azimuth=%s, max_angle=%s, ' +
283+
pvl_logger.debug('axis_tilt=%s, axis_azimuth=%s, max_angle=%s, '
284284
'backtrack=%s, gcr=%.3f',
285285
axis_tilt, axis_azimuth, max_angle, backtrack, gcr)
286286

@@ -310,7 +310,7 @@ def singleaxis(apparent_zenith, apparent_azimuth,
310310
pd.util.testing.assert_index_equal(apparent_azimuth.index,
311311
apparent_zenith.index)
312312
except AssertionError:
313-
raise ValueError('apparent_azimuth.index and ' +
313+
raise ValueError('apparent_azimuth.index and '
314314
'apparent_zenith.index must match.')
315315

316316
times = apparent_azimuth.index

0 commit comments

Comments
 (0)