diff --git a/docs/sphinx/source/whatsnew/v0.10.0.rst b/docs/sphinx/source/whatsnew/v0.10.0.rst index f7ad2b7d7c..e9a605657c 100644 --- a/docs/sphinx/source/whatsnew/v0.10.0.rst +++ b/docs/sphinx/source/whatsnew/v0.10.0.rst @@ -28,6 +28,8 @@ Enhancements ~~~~~~~~~~~~ * Added `map_variables` parameter to :py:func:`pvlib.iotools.read_srml` and :py:func:`pvlib.iotools.read_srml_month_from_solardat` (:pull:`1773`) +* Improved `ModelChainResult.__repr__` (:pull:`1236`) + Bug fixes ~~~~~~~~~ @@ -52,3 +54,5 @@ Contributors ~~~~~~~~~~~~ * Taos Transue (:ghuser:`reepoi`) * Adam R. Jensen (:ghuser:`AdamRJensen`) +* Cliff Hansen (:ghuser:`cwhanse`) + diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py index f6fad98975..1a8a0cabaa 100644 --- a/pvlib/modelchain.py +++ b/pvlib/modelchain.py @@ -254,6 +254,33 @@ def get_orientation(strategy, **kwargs): return surface_tilt, surface_azimuth +def _getmcattr(self, attr): + """ + Helper for __repr__ methods, needed to avoid recursion in property + lookups + """ + out = getattr(self, attr) + try: + out = out.__name__ + except AttributeError: + pass + return out + + +def _mcr_repr(obj): + ''' + Helper for ModelChainResult.__repr__ + ''' + if isinstance(obj, tuple): + return "Tuple (" + ", ".join([_mcr_repr(o) for o in obj]) + ")" + if isinstance(obj, pd.DataFrame): + return "DataFrame ({} rows x {} columns)".format(*obj.shape) + if isinstance(obj, pd.Series): + return "Series (length {})".format(len(obj)) + # scalar, None, other? + return repr(obj) + + # Type for fields that vary between arrays T = TypeVar('T') @@ -385,6 +412,33 @@ def __setattr__(self, key, value): value = self._result_type(value) super().__setattr__(key, value) + def __repr__(self): + mc_attrs = dir(self) + + def _head(obj): + try: + return obj[:3] + except: + return obj + + if type(self.dc) is tuple: + num_arrays = len(self.dc) + else: + num_arrays = 1 + + desc1 = ('=== ModelChainResult === \n') + desc2 = (f'Number of Arrays: {num_arrays} \n') + attr = 'times' + desc3 = ('times (first 3)\n' + + f'{_head(_getmcattr(self, attr))}' + + '\n') + lines = [] + for attr in mc_attrs: + if not (attr.startswith('_') or attr=='times'): + lines.append(f' {attr}: ' + _mcr_repr(getattr(self, attr))) + desc4 = '\n'.join(lines) + return (desc1 + desc2 + desc3 + desc4) + class ModelChain: """ @@ -678,18 +732,8 @@ def __repr__(self): 'airmass_model', 'dc_model', 'ac_model', 'aoi_model', 'spectral_model', 'temperature_model', 'losses_model' ] - - def getmcattr(self, attr): - """needed to avoid recursion in property lookups""" - out = getattr(self, attr) - try: - out = out.__name__ - except AttributeError: - pass - return out - return ('ModelChain: \n ' + '\n '.join( - f'{attr}: {getmcattr(self, attr)}' for attr in attrs)) + f'{attr}: {_getmcattr(self, attr)}' for attr in attrs)) @property def dc_model(self): diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 62b71f2042..ee975f3d21 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -2063,3 +2063,36 @@ def test__irrad_for_celltemp(): assert len(poa) == 2 assert_series_equal(poa[0], effect_irrad) assert_series_equal(poa[1], effect_irrad) + + +def test_ModelChain___repr__(sapm_dc_snl_ac_system, location): + + mc = ModelChain(sapm_dc_snl_ac_system, location, + name='my mc') + + expected = '\n'.join([ + 'ModelChain: ', + ' name: my mc', + ' clearsky_model: ineichen', + ' transposition_model: haydavies', + ' solar_position_method: nrel_numpy', + ' airmass_model: kastenyoung1989', + ' dc_model: sapm', + ' ac_model: sandia_inverter', + ' aoi_model: sapm_aoi_loss', + ' spectral_model: sapm_spectral_loss', + ' temperature_model: sapm_temp', + ' losses_model: no_extra_losses' + ]) + + assert mc.__repr__() == expected + + +def test_ModelChainResult___repr__(sapm_dc_snl_ac_system, location, weather): + mc = ModelChain(sapm_dc_snl_ac_system, location) + mc.run_model(weather) + mcres = mc.results.__repr__() + mc_attrs = dir(mc.results) + mc_attrs = [a for a in mc_attrs if not a.startswith('_')] + assert all([a in mcres for a in mc_attrs]) + \ No newline at end of file