def test_fieldnames(): table = (('foo', 'bar'), ('a', 1), ('b', 2)) actual = fieldnames(table) expect = ('foo', 'bar') eq_(expect, actual) class CustomField(object): def __init__(self, key, description): self.key = key self.description = description def __str__(self): return self.key def __repr__(self): return 'CustomField(%r, %r)' % (self.key, self.description) table = ((CustomField('foo', 'Get some foo.'), CustomField('bar', 'A lot of bar.')), ('a', 1), ('b', 2)) actual = fieldnames(table) expect = ('foo', 'bar') eq_(expect, actual)
def _build_schema_from_values(table, sample): # table2: try not advance iterators samples, table2 = iterpeek(table, sample + 1) props = fieldnames(samples) peek = skip(samples, 1) schema_fields = _build_schema_fields_from_values(peek, props) schema_source = _build_schema_with(schema_fields) return schema_source, table2
def _fix_missing_headers(table, schema): '''add missing columns headers from schema''' if schema is None or 'fields' not in schema: return table # table2: try not advance iterators sample, table2 = iterpeek(table, 2) cols = fieldnames(sample) headers = _get_schema_header_names(schema) if len(cols) >= len(headers): return table2 table3 = setheader(table2, headers) return table3
def _fix_missing_headers(table, schema): '''add missing columns headers from schema''' if schema is None or not 'fields' in schema: return table # table2: try not advance iterators sample, table2 = iterpeek(table, 2) cols = fieldnames(sample) fields = schema.get('fields') if len(cols) >= len(fields): return table2 header = [field.get('name') for field in fields] table3 = setheader(table2, header) return table3
def convertall(table, *args, **kwargs): """ Convenience function to convert all fields in the table using a common function or mapping. See also :func:`convert`. The ``where`` keyword argument can be given with a callable or expression which is evaluated on each row and which should return True if the conversion should be applied on that row, else False. """ # TODO don't read the data twice! return convert(table, fieldnames(table), *args, **kwargs)
def toxml(table, target=None, root=None, head=None, rows=None, prologue=None, epilogue=None, style='tag', encoding='utf-8'): """ Write the table into a new xml file according to elements defined in the function arguments. The `root`, `head` and `rows` (string, optional) arguments define the tags and the nesting of the xml file. Each one defines xml elements with tags separated by slashes (`/`) like in `root/level/tag`. They can have a arbitrary number of tags that will reflect in more nesting levels for the header or record/row written in the xml file. For details on tag naming and nesting rules check xml `specification`_ or xml `references`_. The `rows` argument define the elements for each row of data to be written in the xml file. When specified, it must have at least 2 tags for defining the tags for `row/column`. Additional tags will add nesting enclosing all records/rows/lines. The `head` argument is similar to the rows, but aplies only to one line/row of header with fieldnames. When specified, it must have at least 2 tags for `fields/name` and the remaining will increase nesting. The `root` argument defines the elements enclosing `head` and `rows` and is required when using `head` for specifying valid xml documents. When none of this arguments are specified, they will default to tags that generate output similar to a html table: `root='table', head='there/tr/td', rows='tbody/tr/td'`. The `prologue` argument (string, optional) could be a snippet of valid xml that will be inserted before other elements in the xml. It can optionally specify the `XML Prolog` of the file. The `epilogue` argument (string, optional) could be a snippet of valid xml that will be inserted after all other xml elements except the root closing tag. It must specify a closing tag if the `root` argument is not specified. The `style` argument select the format of the elements in the xml file. It can be `tag` (default), `name`, `attribute` or a custom string to format each row via `str.format <http://docs.python.org/library/stdtypes.html#str.format>`_. Example usage for writing files:: >>> import petl as etl >>> table1 = [['foo', 'bar'], ... ['a', 1], ... ['b', 2]] >>> etl.toxml(table1, 'example.file4.xml') >>> # see what we did is similar a html table: >>> print(open('example.file4.xml').read()) <?xml version="1.0" encoding="UTF-8"?> <table><thead> <tr><th>foo</th><th>bar</th></tr> </thead><tbody> <tr><td>a</td><td>1</td></tr> <tr><td>b</td><td>2</td></tr> </tbody></table> >>> # define the nesting in xml file: >>> etl.toxml(table1, 'example.file5.xml', rows='plan/line/cell') >>> print(open('example.file5.xml').read()) <?xml version="1.0" encoding="UTF-8"?> <plan> <line><cell>a</cell><cell>1</cell></line> <line><cell>b</cell><cell>2</cell></line> </plan> >>> # choose other style: >>> etl.toxml(table1, 'example.file6.xml', rows='row/col', style='attribute') >>> print(open('example.file6.xml').read()) <?xml version="1.0" encoding="UTF-8"?> <row> <col foo="a" bar="1" /> <col foo="b" bar="2" /> </row> >>> etl.toxml(table1, 'example.file6.xml', rows='row/col', style='name') >>> print(open('example.file6.xml').read()) <?xml version="1.0" encoding="UTF-8"?> <row> <col><foo>a</foo><bar>1</bar></col> <col><foo>b</foo><bar>2</bar></col> </row> The `toxml()` function is just a wrapper over :func:`petl.io.text.totext`. For advanced cases use a template with `totext()` for generating xml files. .. versionadded:: 1.7.0 .. _specification: https://www.w3.org/TR/xml/ .. _references: https://www.w3schools.com/xml/xml_syntax.asp """ if not root and not head and not rows: root = 'table' head = 'thead/tr/th' rows = 'tbody/tr/td' sample, table2 = iterpeek(table, 2) props = fieldnames(sample) top = _build_xml_header(style, props, root, head, rows, prologue, encoding) template = _build_cols(style, props, rows, True) bottom = _build_xml_footer(style, epilogue, rows, root) totext(table2, source=target, encoding=encoding, errors='strict', template=template, prologue=top, epilogue=bottom)