diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index 733fd3bd39b52..6a98497aa1bfe 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -47,6 +47,7 @@ import itertools import csv +from functools import partial common_docstring = """ Parameters @@ -109,7 +110,7 @@ def _get_footer(self): if self.length: if footer: footer += ', ' - footer += "Length: %d" % len(self.categorical) + footer += "Length: {length}".format(length=len(self.categorical)) level_info = self.categorical._repr_categories_info() @@ -135,7 +136,7 @@ def to_string(self): fmt_values = self._get_formatted_values() - result = ['%s' % i for i in fmt_values] + result = [u('{i}').format(i=i) for i in fmt_values] result = [i.strip() for i in result] result = u(', ').join(result) result = [u('[') + result + u(']')] @@ -191,7 +192,7 @@ def _get_footer(self): footer = u('') if getattr(self.series.index, 'freq', None) is not None: - footer += 'Freq: %s' % self.series.index.freqstr + footer += 'Freq: {freq}'.format(freq=self.series.index.freqstr) if self.name is not False and name is not None: if footer: @@ -199,20 +200,21 @@ def _get_footer(self): series_name = pprint_thing(name, escape_chars=('\t', '\r', '\n')) - footer += ("Name: %s" % series_name) if name is not None else "" + footer += ((u"Name: {sname}".format(sname=series_name)) + if name is not None else "") if (self.length is True or (self.length == 'truncate' and self.truncate_v)): if footer: footer += ', ' - footer += 'Length: %d' % len(self.series) + footer += 'Length: {length}'.format(length=len(self.series)) if self.dtype is not False and self.dtype is not None: name = getattr(self.tr_series.dtype, 'name', None) if name: if footer: footer += ', ' - footer += 'dtype: %s' % pprint_thing(name) + footer += u'dtype: {typ}'.format(typ=pprint_thing(name)) # level infos are added to the end and in a new line, like it is done # for Categoricals @@ -509,8 +511,10 @@ def _to_str_columns(self): else: if is_list_like(self.header): if len(self.header) != len(self.columns): - raise ValueError(('Writing %d cols but got %d aliases' - % (len(self.columns), len(self.header)))) + raise ValueError(('Writing {ncols} cols but got {nalias} ' + 'aliases' + .format(ncols=len(self.columns), + nalias=len(self.header)))) str_columns = [[label] for label in self.header] else: str_columns = self._get_formatted_column_labels(frame) @@ -578,10 +582,10 @@ def to_string(self): frame = self.frame if len(frame.columns) == 0 or len(frame.index) == 0: - info_line = (u('Empty %s\nColumns: %s\nIndex: %s') % - (type(self.frame).__name__, - pprint_thing(frame.columns), - pprint_thing(frame.index))) + info_line = (u('Empty {name}\nColumns: {col}\nIndex: {idx}') + .format(name=type(self.frame).__name__, + col=pprint_thing(frame.columns), + idx=pprint_thing(frame.index))) text = info_line else: @@ -630,8 +634,8 @@ def to_string(self): self.buf.writelines(text) if self.should_show_dimensions: - self.buf.write("\n\n[%d rows x %d columns]" % - (len(frame), len(frame.columns))) + self.buf.write("\n\n[{nrows} rows x {ncols} columns]" + .format(nrows=len(frame), ncols=len(frame.columns))) def _join_multiline(self, *strcols): lwidth = self.line_width @@ -805,7 +809,8 @@ def _get_formatted_index(self, frame): # empty space for columns if show_col_names: - col_header = ['%s' % x for x in self._get_column_name_list()] + col_header = ['{x}'.format(x=x) + for x in self._get_column_name_list()] else: col_header = [''] * columns.nlevels @@ -861,9 +866,10 @@ def write_result(self, buf): # string representation of the columns if len(self.frame.columns) == 0 or len(self.frame.index) == 0: - info_line = (u('Empty %s\nColumns: %s\nIndex: %s') % - (type(self.frame).__name__, self.frame.columns, - self.frame.index)) + info_line = (u('Empty {name}\nColumns: {col}\nIndex: {idx}') + .format(name=type(self.frame).__name__, + col=self.frame.columns, + idx=self.frame.index)) strcols = [[info_line]] else: strcols = self.fmt._to_str_columns() @@ -906,14 +912,16 @@ def get_col_type(dtype): column_format = index_format + column_format elif not isinstance(column_format, compat.string_types): # pragma: no cover - raise AssertionError('column_format must be str or unicode, not %s' - % type(column_format)) + raise AssertionError('column_format must be str or unicode, ' + 'not {typ}'.format(typ=type(column_format))) if not self.longtable: - buf.write('\\begin{tabular}{%s}\n' % column_format) + buf.write('\\begin{{tabular}}{{{fmt}}}\n' + .format(fmt=column_format)) buf.write('\\toprule\n') else: - buf.write('\\begin{longtable}{%s}\n' % column_format) + buf.write('\\begin{{longtable}}{{{fmt}}}\n' + .format(fmt=column_format)) buf.write('\\toprule\n') ilevels = self.frame.index.nlevels @@ -948,7 +956,7 @@ def get_col_type(dtype): crow = [x if x else '{}' for x in row] if self.bold_rows and self.fmt.index: # bold row labels - crow = ['\\textbf{%s}' % x + crow = ['\\textbf{{{x}}}'.format(x=x) if j < ilevels and x.strip() not in ['', '{}'] else x for j, x in enumerate(crow)] if i < clevels and self.fmt.header and self.multicolumn: @@ -986,9 +994,9 @@ def _format_multicolumn(self, row, ilevels): def append_col(): # write multicolumn if needed if ncol > 1: - row2.append('\\multicolumn{{{0:d}}}{{{1:s}}}{{{2:s}}}' - .format(ncol, self.multicolumn_format, - coltext.strip())) + row2.append('\\multicolumn{{{ncol:d}}}{{{fmt:s}}}{{{txt:s}}}' + .format(ncol=ncol, fmt=self.multicolumn_format, + txt=coltext.strip())) # don't modify where not needed else: row2.append(coltext) @@ -1027,8 +1035,8 @@ def _format_multirow(self, row, ilevels, i, rows): break if nrow > 1: # overwrite non-multirow entry - row[j] = '\\multirow{{{0:d}}}{{*}}{{{1:s}}}'.format( - nrow, row[j].strip()) + row[j] = '\\multirow{{{nrow:d}}}{{*}}{{{row:s}}}'.format( + nrow=nrow, row=row[j].strip()) # save when to end the current block with \cline self.clinebuf.append([i + nrow - 1, j + 1]) return row @@ -1039,7 +1047,8 @@ def _print_cline(self, buf, i, icol): """ for cl in self.clinebuf: if cl[0] == i: - buf.write('\cline{{{0:d}-{1:d}}}\n'.format(cl[1], icol)) + buf.write('\cline{{{cl:d}-{icol:d}}}\n' + .format(cl=cl[1], icol=icol)) # remove entries that have been written to buffer self.clinebuf = [x for x in self.clinebuf if x[0] != i] @@ -1076,7 +1085,8 @@ def write(self, s, indent=0): def write_th(self, s, indent=0, tags=None): if self.fmt.col_space is not None and self.fmt.col_space > 0: tags = (tags or "") - tags += 'style="min-width: %s;"' % self.fmt.col_space + tags += ('style="min-width: {colspace};"' + .format(colspace=self.fmt.col_space)) return self._write_cell(s, kind='th', indent=indent, tags=tags) @@ -1085,9 +1095,9 @@ def write_td(self, s, indent=0, tags=None): def _write_cell(self, s, kind='td', indent=0, tags=None): if tags is not None: - start_tag = '<%s %s>' % (kind, tags) + start_tag = '<{kind} {tags}>'.format(kind=kind, tags=tags) else: - start_tag = '<%s>' % kind + start_tag = '<{kind}>'.format(kind=kind) if self.escape: # escape & first to prevent double escaping of & @@ -1096,7 +1106,8 @@ def _write_cell(self, s, kind='td', indent=0, tags=None): else: esc = {} rs = pprint_thing(s, escape_chars=esc).strip() - self.write('%s%s' % (start_tag, rs, kind), indent) + self.write(u'{start}{rs}' + .format(start=start_tag, rs=rs, kind=kind), indent) def write_tr(self, line, indent=0, indent_delta=4, header=False, align=None, tags=None, nindex_levels=0): @@ -1106,7 +1117,8 @@ def write_tr(self, line, indent=0, indent_delta=4, header=False, if align is None: self.write('', indent) else: - self.write('' % align, indent) + self.write('' + .format(align=align), indent) indent += indent_delta for i, s in enumerate(line): @@ -1146,8 +1158,8 @@ def write_result(self, buf): if isinstance(self.classes, str): self.classes = self.classes.split() if not isinstance(self.classes, (list, tuple)): - raise AssertionError('classes must be list or tuple, ' - 'not %s' % type(self.classes)) + raise AssertionError('classes must be list or tuple, not {typ}' + .format(typ=type(self.classes))) _classes.extend(self.classes) if self.notebook: @@ -1159,12 +1171,11 @@ def write_result(self, buf): except (ImportError, AttributeError): pass - self.write(''.format(div_style)) + self.write(''.format(style=div_style)) self.write_style() - self.write('' % (self.border, - ' '.join(_classes)), - indent) + self.write('
' + .format(border=self.border, cls=' '.join(_classes)), indent) indent += self.indent_delta indent = self._write_header(indent) @@ -1173,8 +1184,10 @@ def write_result(self, buf): self.write('
', indent) if self.should_show_dimensions: by = chr(215) if compat.PY3 else unichr(215) # × - self.write(u('

%d rows %s %d columns

') % - (len(frame), by, len(frame.columns))) + self.write(u('

{rows} rows {by} {cols} columns

') + .format(rows=len(frame), + by=by, + cols=len(frame.columns))) if self.notebook: self.write('') @@ -1199,7 +1212,7 @@ def _column_header(): row.append(single_column_table(self.columns.names)) else: row.append('') - style = "text-align: %s;" % self.fmt.justify + style = "text-align: {just};".format(just=self.fmt.justify) row.extend([single_column_table(c, self.fmt.justify, style) for c in self.columns]) else: @@ -1214,7 +1227,7 @@ def _column_header(): indent += self.indent_delta if isinstance(self.columns, MultiIndex): - template = 'colspan="%d" halign="left"' + template = 'colspan="{span:d}" halign="left"' if self.fmt.sparsify: # GH3547 @@ -1282,7 +1295,7 @@ def _column_header(): for i, v in enumerate(values): if i in records: if records[i] > 1: - tags[j] = template % records[i] + tags[j] = template.format(span=records[i]) else: continue j += 1 @@ -1372,7 +1385,7 @@ def _write_regular_rows(self, fmt_values, indent): nindex_levels=1) def _write_hierarchical_rows(self, fmt_values, indent): - template = 'rowspan="%d" valign="top"' + template = 'rowspan="{span}" valign="top"' truncate_h = self.fmt.truncate_h truncate_v = self.fmt.truncate_v @@ -1447,7 +1460,7 @@ def _write_hierarchical_rows(self, fmt_values, indent): for records, v in zip(level_lengths, idx_values[i]): if i in records: if records[i] > 1: - tags[j] = template % records[i] + tags[j] = template.format(span=records[i]) else: sparse_offset += 1 continue @@ -1615,8 +1628,9 @@ def _save_header(self): return if has_aliases: if len(header) != len(cols): - raise ValueError(('Writing %d cols but got %d aliases' - % (len(cols), len(header)))) + raise ValueError(('Writing {ncols} cols but got {nalias} ' + 'aliases'.format(ncols=len(cols), + nalias=len(header)))) else: write_cols = header else: @@ -1790,8 +1804,9 @@ def _format_strings(self): if self.float_format is None: float_format = get_option("display.float_format") if float_format is None: - fmt_str = '%% .%dg' % get_option("display.precision") - float_format = lambda x: fmt_str % x + fmt_str = ('{{x: .{prec:d}g}}' + .format(prec=get_option("display.precision"))) + float_format = lambda x: fmt_str.format(x=x) else: float_format = self.float_format @@ -1807,10 +1822,10 @@ def _format(x): return 'NaT' return self.na_rep elif isinstance(x, PandasObject): - return '%s' % x + return u'{x}'.format(x=x) else: # object dtype - return '%s' % formatter(x) + return u'{x}'.format(x=formatter(x)) vals = self.values if isinstance(vals, Index): @@ -1824,11 +1839,11 @@ def _format(x): fmt_values = [] for i, v in enumerate(vals): if not is_float_type[i] and leading_space: - fmt_values.append(' %s' % _format(v)) + fmt_values.append(u' {v}'.format(v=_format(v))) elif is_float_type[i]: fmt_values.append(float_format(v)) else: - fmt_values.append(' %s' % _format(v)) + fmt_values.append(u' {v}'.format(v=_format(v))) return fmt_values @@ -1864,7 +1879,7 @@ def _value_formatter(self, float_format=None, threshold=None): # because str(0.0) = '0.0' while '%g' % 0.0 = '0' if float_format: def base_formatter(v): - return (float_format % v) if notna(v) else self.na_rep + return float_format(value=v) if notna(v) else self.na_rep else: def base_formatter(v): return str(v) if notna(v) else self.na_rep @@ -1925,10 +1940,14 @@ def format_values_with(float_format): # There is a special default string when we are fixed-width # The default is otherwise to use str instead of a formatting string - if self.float_format is None and self.fixed_width: - float_format = '%% .%df' % self.digits + if self.float_format is None: + if self.fixed_width: + float_format = partial('{value: .{digits:d}f}'.format, + digits=self.digits) + else: + float_format = self.float_format else: - float_format = self.float_format + float_format = lambda value: self.float_format % value formatted_values = format_values_with(float_format) @@ -1955,7 +1974,8 @@ def format_values_with(float_format): (abs_vals > 0)).any() if has_small_values or (too_long and has_large_values): - float_format = '%% .%de' % self.digits + float_format = partial('{value: .{digits:d}e}'.format, + digits=self.digits) formatted_values = format_values_with(float_format) return formatted_values @@ -1971,7 +1991,7 @@ def _format_strings(self): class IntArrayFormatter(GenericArrayFormatter): def _format_strings(self): - formatter = self.formatter or (lambda x: '% d' % x) + formatter = self.formatter or (lambda x: '{x: d}'.format(x=x)) fmt_values = [formatter(x) for x in self.values] return fmt_values @@ -2023,7 +2043,7 @@ def _format_strings(self): # periods may contains different freq values = Index(self.values, dtype='object').to_native_types() - formatter = self.formatter or (lambda x: '%s' % x) + formatter = self.formatter or (lambda x: '{x}'.format(x=x)) fmt_values = [formatter(x) for x in values] return fmt_values @@ -2223,7 +2243,7 @@ def _formatter(x): x = Timedelta(x) result = x._repr_base(format=format) if box: - result = "'{0}'".format(result) + result = "'{res}'".format(res=result) return result return _formatter @@ -2278,12 +2298,12 @@ def _cond(values): def single_column_table(column, align=None, style=None): table = '%s' % str(i)) + table += ('{i!s}'.format(i=i)) table += '' return table @@ -2291,7 +2311,7 @@ def single_column_table(column, align=None, style=None): def single_row_table(row): # pragma: no cover table = '' for i in row: - table += ('' % str(i)) + table += (''.format(i=i)) table += '
%s{i!s}
' return table @@ -2385,18 +2405,19 @@ def __call__(self, num): prefix = self.ENG_PREFIXES[int_pow10] else: if int_pow10 < 0: - prefix = 'E-%02d' % (-int_pow10) + prefix = 'E-{pow10:02d}'.format(pow10=-int_pow10) else: - prefix = 'E+%02d' % int_pow10 + prefix = 'E+{pow10:02d}'.format(pow10=int_pow10) mant = sign * dnum / (10**pow10) if self.accuracy is None: # pragma: no cover - format_str = u("% g%s") + format_str = u("{mant: g}{prefix}") else: - format_str = (u("%% .%if%%s") % self.accuracy) + format_str = (u("{{mant: .{acc:d}f}}{{prefix}}") + .format(acc=self.accuracy)) - formatted = format_str % (mant, prefix) + formatted = format_str.format(mant=mant, prefix=prefix) return formatted # .strip()