def _pprint_base_impl(self, ostream, verbose, prefix, _name, _doc, _constructed, _attr, _data, _header, _fcn): if ostream is None: ostream = sys.stdout if prefix: ostream = StreamIndenter(ostream, prefix) # FIXME: HACK for backwards compatability with suppressing the # header for the top block if not _attr and self.parent_block() is None: _name = '' # We only indent everything if we printed the header if _attr or _name or _doc: ostream = StreamIndenter(ostream, self._PPRINT_INDENT) # The first line should be a hanging indent (i.e., not indented) ostream.newline = False if self.is_reference(): _attr = list(_attr) if _attr else [] _attr.append(('ReferenceTo', self.referent)) if _name: ostream.write(_name + " : ") if _doc: ostream.write(_doc + '\n') if _attr: ostream.write(", ".join("%s=%s" % (k, v) for k, v in _attr)) if _attr or _name or _doc: ostream.write("\n") if not _constructed: # HACK: for backwards compatability, Abstract blocks will # still print their assigned components. Should we instead # always pprint unconstructed components (possibly # suppressing the table header if the table is empty)? if self.parent_block() is not None: ostream.write("Not constructed\n") return if type(_fcn) is tuple: _fcn, _fcn2 = _fcn else: _fcn2 = None if _header is not None: if _fcn2 is not None: _data_dict = dict(_data) _data = _data_dict.items() tabular_writer(ostream, '', _data, _header, _fcn) if _fcn2 is not None: for _key in sorted_robust(_data_dict): _fcn2(ostream, _key, _data_dict[_key]) elif _fcn is not None: _data_dict = dict(_data) for _key in sorted_robust(_data_dict): _fcn(ostream, _key, _data_dict[_key]) elif _data is not None: ostream.write(_data)
def test_user_key(self): # ensure it doesn't throw an error # Test for issue https://github.com/Pyomo/pyomo/issues/2019 sorted_robust( [ (("10_1", 2), None), ((10, 2), None) ], key=lambda x: x[0] )
def test_unknown_types(self): orig = [ LikeFloat(4), # 0 Comparable('hello'), # 1 LikeFloat(1), # 2 2., # 3 Comparable('world'), # 4 ToStr(1), # 5 NoStr('bogus'), # 6 ToStr('a'), # 7 ToStr('A'), # 8 3, # 9 ] ref = [orig[i] for i in (1, 4, 6, 5, 8, 7, 2, 3, 9, 0)] ans = sorted_robust(orig) self.assertEqual(len(orig), len(ans)) for _r, _a in zip(ref, ans): self.assertIs(_r, _a) self.assertEqual(_robust_sort_keyfcn._typemap[LikeFloat], (1, float.__name__)) self.assertEqual(_robust_sort_keyfcn._typemap[Comparable], (1, Comparable.__name__)) self.assertEqual(_robust_sort_keyfcn._typemap[ToStr], (2, ToStr.__name__)) self.assertEqual(_robust_sort_keyfcn._typemap[NoStr], (3, NoStr.__name__))
def _generate_component_items(components): if type(components) not in {list, tuple}: components = (components, ) for comp in components: if comp.is_indexed(): for idx in sorted_robust(comp): yield idx, comp[idx] else: yield _NotAnIndex, comp
def test_sorted_robust(self): # Note: as types are sorted by name, int < str < tuple a = sorted_robust([3, 2, 1]) self.assertEqual(a, [1, 2, 3]) # Testthat ints and floats are sorted as "numbers" a = sorted_robust([3, 2.1, 1]) self.assertEqual(a, [1, 2.1, 3]) a = sorted_robust([3, '2', 1]) self.assertEqual(a, [1, 3, '2']) a = sorted_robust([('str1', 'str1'), (1, 'str2')]) self.assertEqual(a, [(1, 'str2'), ('str1', 'str1')]) a = sorted_robust([((1,), 'str2'), ('str1', 'str1')]) self.assertEqual(a, [('str1', 'str1'), ((1,), 'str2')]) a = sorted_robust([('str1', 'str1'), ((1,), 'str2')]) self.assertEqual(a, [('str1', 'str1'), ((1,), 'str2')])
def keys(self, ordered=False): """Return an iterator over the component data keys This method sets the ordering of component data objects within this IndexedComponent container. For consistency, :py:meth:`__init__()`, :py:meth:`values`, and :py:meth:`items` all leverage this method to ensure consistent ordering. Parameters ---------- ordered: bool If True, then the keys are returned in a deterministic order. If the underlying indexing set is ordered then that ordering is used. Otherwise, the keys are sorted using :py:func:`sorted_robust`. """ sort_needed = ordered if hasattr(self._index_set, 'isfinite') and not \ self._index_set.isfinite(): # # If the index set is virtual (e.g., Any) then return the # data iterator. Note that since we cannot check the length # of the underlying Set, there should be no warning if the # user iterates over the set when the _data dict is empty. # ans = self._data.__iter__() elif self.is_reference(): ans = self._data.__iter__() elif len(self) == len(self._index_set): # # If the data is dense then return the index iterator. # ans = self._index_set.__iter__() if ordered and self._index_set.isordered(): # As this iterator is ordered, we do not need to sort it sort_needed = False else: if not self._data and self._index_set and \ PyomoOptions.paranoia_level: logger.warning("""Iterating over a Component (%s) defined by a non-empty concrete set before any data objects have actually been added to the Component. The iterator will be empty. This is usually caused by Concrete models where you declare the component (e.g., a Var) and apply component-level operations (e.g., x.fix(0)) before you use the component members (in something like a constraint). You can silence this warning by one of three ways: 1) Declare the component to be dense with the 'dense=True' option. This will cause all data objects to be immediately created and added to the Component. 2) Defer component-level iteration until after the component data members have been added (through explicit use). 3) If you intend to iterate over a component that may be empty, test if the component is empty first and avoid iteration in the case where it is empty. """ % (self.name, )) if not hasattr(self._index_set, 'isordered') or \ not self._index_set.isordered(): # # If the index set is not ordered, then return the # data iterator. This is in an arbitrary order, which is # fine because the data is unordered. # ans = self._data.__iter__() else: # # Test each element of a sparse data with an ordered # index set in order. This is potentially *slow*: if # the component is in fact very sparse, we could be # iterating over a huge (dense) index in order to sort a # small number of indices. However, this provides a # consistent ordering that the user expects. # ans = filter(self._data.__contains__, self._index_set) # As the iterator is ordered, we do not need to sort it sort_needed = False if sort_needed: return iter(sorted_robust(ans)) else: return ans
def tabular_writer(ostream, prefix, data, header, row_generator): """Output data in tabular form Parameters ---------- ostream: io.TextIOBase the stream to write to prefix: str prefix each generated line with this string data: iterable an iterable object that returns (key, value) pairs (e.g., from iteritems()) defining each row in the table header: List[str] list of column headers row_generator: function a function that accepts the `key` and `value` from `data` and returns either a tuple defining the entries for a single row, or a generator that returns a sequence of table rows to be output for the specified `key` """ prefix = tostr(prefix) _rows = {} # NB: _width is a list because we will change these values if header: header = (u"Key",) + tuple(tostr(x) for x in header) _width = [len(x) for x in header] else: _width = None _minWidth = 0 for _key, _val in data: try: _rowSet = row_generator(_key, _val) if isinstance(_rowSet, types.GeneratorType): _rowSet = list(_rowSet) else: _rowSet = [_rowSet] except ValueError: # A ValueError can be raised when row_generator is called # (if it is a function), or when it is exhausted generating # the list (if it is a generator) _minWidth = 4 # Ensure columns are wide enough to output "None" _rows[_key] = None continue _rows[_key] = [ ((tostr("" if i else _key),) if header else ()) + tuple(tostr(x) for x in _r) for i, _r in enumerate(_rowSet) ] if not _rows[_key]: _minWidth = 4 elif not _width: _width = [0]*len(_rows[_key][0]) for _row in _rows[_key]: for col, x in enumerate(_row): _width[col] = max(_width[col], len(x), col and _minWidth) # NB: left-justify header entries if header: # Note: do not right-pad the last header with unnecessary spaces tmp = _width[-1] _width[-1] = 0 ostream.write(prefix + " : ".join( "%%-%ds" % _width[i] % x for i,x in enumerate(header) ) + "\n") _width[-1] = tmp # If there is no data, we are done... if not _rows: return # right-justify data, except for the last column if there are spaces # in the data (probably an expression or vector) _width = ["%"+str(i)+"s" for i in _width] if any( ' ' in r[-1] for x in _rows.values() if x is not None for r in x ): _width[-1] = '%s' for _key in sorted_robust(_rows): _rowSet = _rows[_key] if not _rowSet: _rowSet = [ [_key] + [None]*(len(_width)-1) ] for _data in _rowSet: ostream.write( prefix + " : ".join( _width[i] % x for i,x in enumerate(_data) ) + "\n")