Version 1.7.12

  • Fix? calling functions to*() should output by default to stdout By @juarezr, #632.
  • Add python3.11 for the build and testing By @juarezr, #635.
  • Add support for writing to JSONL files By @mzaeemz, #524.

Version 1.7.11

Version 1.7.10

Version 1.7.9

  • Feature: Add improved support for working with Google Sheets By @juarezr, #615.
  • Maintanance: Improve test helpers testing By @juarezr, #614.

Version 1.7.8

Version 1.7.7

  • New pull request template. No python changes. By @juarezr, #594.

Version 1.7.6

  • Fix convertall does not work when table header has non-string elements By @dnicolodi, #579.
  • Fix todataframe() to do not iterate the table multiple times By @dnicolodi, #578.
  • Fix broken aggregate when supplying single key By @MalayGoel, #552.
  • Migrated to pytest By @arturponinski, #584.
  • Testing python 3.10 on Github Actions. No python changes. By @juarezr, #591.
  • codacity: upgrade to latest/main github action version. No python changes. By @juarezr, #585.
  • Publish releases to PyPI with Github Actions. No python changes. By @juarezr, #593.

Version 1.7.5

Version 1.7.4

  • Use python 3.6 instead of 2.7 for deploy on travis-ci. No python changes. By @juarezr, #550.

Version 1.7.3

  • Fixed SQLAlchemy 1.4 removed the Engine.contextual_connect method By @juarezr, #545.
  • How to use convert with custom function and reference row By @javidy, #542.

Version 1.7.2

  • Allow aggregation over the entire table (without a key) By @bmaggard, #541.
  • Allow specifying output field name for simple aggregation By @bmaggard, #370.
  • Bumped version of package dependency on lxml from 4.4.0 to 4.6.2 By @juarezr, #536.

Version 1.7.1

Version 1.7.0

Version 1.6.8

  • Allow using a custom/restricted xml parser in fromxml(). By @juarezr, #527.

Version 1.6.7

Version 1.6.6

  • Added python version 3.8 and 3.9 to tox.ini for using in newer distros. By @juarezr, #517.
  • Fixed compatibility with python3.8 in petl.timings.clock(). By @juarezr, #484.
  • Added json lines support in fromjson(). By @fahadsiddiqui, #521.

Version 1.6.5

  • Fixed fromxlsx() with read_only crashes. By @juarezr, #514.

Version 1.6.4

  • Fixed exception when writing to S3 with fsspec auto_mkdir=True. By @juarezr, #512.

Version 1.6.3

  • Allowed reading and writing Excel files in remote sources. By @juarezr, #506.
  • Allow toxlsx() to add or replace a worksheet. By @churlrich, #502.
  • Improved avro: improve message on schema or data mismatch. By @juarezr, #507.
  • Fixed build for failed test case. By @juarezr, #508.

Version 1.6.2

  • Fixed boolean type detection in toavro(). By @juarezr, #504.
  • Fix unavoidable warning if fsspec is installed but some optional package is not installed. By @juarezr, #503.

Version 1.6.1

  • Added extras_require for the petl pip package. By @juarezr, #501.
  • Fix unavoidable warning if fsspec is not installed. By @juarezr, #500.

Version 1.6.0

  • Added class using package fsspec for reading and writing files in remote servers by using the protocol in the url for selecting the implementation. By @juarezr, #494.
  • Removed classes as it’s handled by fsspec By @juarezr, #494.
  • Removed classes, and as it’s handled by fsspec. By @juarezr, #494.
  • Fix bug in connection to a JDBC database using jaydebeapi. By @miguelosana, #497.

Version 1.5.0

  • Added functions and for registering custom source helpers for hanlding I/O from remote protocols. By @juarezr, #491.
  • Added function for registering custom helpers for compressing and decompressing files with other algorithms. By @juarezr, #491.
  • Added classes, and for compressing files with XZ and the “state of art” LZ4 and Zstandard algorithms. By @juarezr, #491.
  • Added classes and reading and writing files to remote servers using int url the protocols s3:// and smb://. By @juarezr, #491.

Version 1.4.0

Version 1.3.0


The parameters to the function have changed in this release. The parameters row_offset and col_offset are no longer supported. Please use min_row, min_col, max_row and max_col instead.

Version 1.2.0

Please note that this version drops support for Python 2.6 (#443, #444 - @hugovk).

Version 1.1.0

Version 1.0

Version 1.0 is a new major release of petl. The main purpose of version 1.0 is to introduce support for Python 3.4, in addition to the existing support for Python 2.6 and 2.7. Much of the functionality available in petl versions 0.x has remained unchanged in version 1.0, and most existing code that uses petl should work unchanged with version 1.0 or with minor changes. However there have been a number of API changes, and some functionality has been migrated from the petlx package, described below.

If you have any questions about migrating to version 1.0 or find any problems or issues please email

Text file encoding

Version 1.0 unifies the API for working with ASCII and non-ASCII encoded text files, including CSV and HTML.

The following functions now accept an ‘encoding’ argument, which defaults to the value of locale.getpreferredencoding() (usually ‘utf-8’): fromcsv, tocsv, appendcsv, teecsv, fromtsv, totsv, appendtsv, teetsv, fromtext, totext, appendtext, tohtml, teehtml.

The following functions have been removed as they are now redundant: fromucsv, toucsv, appenducsv, teeucsv, fromutsv, toutsv, appendutsv, teeutsv, fromutext, toutext, appendutext, touhtml, teeuhtml.

To migrate code, in most cases it should be possible to simply replace ‘fromucsv’ with ‘fromcsv’, etc.

pelt.fluent and petl.interactive

The functionality previously available through the petl.fluent and petl.interactive modules is now available through the root petl module.

This means two things.

First, is is now possible to use either functional or fluent (i.e., object-oriented) styles of programming with the root petl module, as described in introductory section on Functional and object-oriented programming styles.

Second, the default representation of table objects uses the petl.util.vis.look() function, so you can simply return a table from the prompt to inspect it, as described in the introductory section on Interactive use.

The petl.fluent and petl.interactive modules have been removed as they are now redundant.

To migrate code, it should be possible to simply replace “import petl.fluent as etl” or “import petl.interactive as etl” with “import petl as etl”.

Note that the automatic caching behaviour of the petl.interactive module has not been retained. If you want to enable caching behaviour for a particular table, make an explicit call to the petl.util.materialise.cache() function. See also Caching.

IPython notebook integration

In version 1.0 petl table container objects implement _repr_html_() so can be returned from a cell in an IPython notebook and will automatically format as an HTML table.

Also, the petl.util.vis.display() and petl.util.vis.displayall() functions have been migrated across from the petlx.ipython package. If you are working within the IPython notebook these functions give greater control over how tables are rendered. For some examples, see:

Database extract/load functions

The function now supports automatic table creation, inferring a schema from data in the table to be loaded. This functionality has been migrated across from the petlx package, and requires SQLAlchemy to be installed.

The functions fromsqlite3, tosqlite3 and appendsqlite3 have been removed as they duplicate functionality available from the existing functions, and These existing functions have been modified so that if a string is provided as the dbo argument it is interpreted as the name of an sqlite3 file. It should be possible to migrate code by simply replacing ‘fromsqlite3’ with ‘fromdb’, etc.

Other functions removed or renamed

The following functions have been removed because they are overly complicated and/or hardly ever used. If you use any of these functions and would like to see them re-instated then please email rangefacet, rangerowreduce, rangeaggregate, rangecounts, multirangeaggregate, lenstats.

The following functions were marked as deprecated in petl 0.x and have been removed in version 1.0: dataslice (use data instead), fieldconvert (use convert instead), fieldselect (use select instead), parsenumber (use numparser instead), recordmap (use rowmap instead), recordmapmany (use rowmapmany instead), recordreduce (use rowreduce instead), recordselect (use rowselect instead), valueset (use table.values(‘foo’).set() instead).

The following functions are no longer available in the root petl namespace, but are still available from a subpackage if you really need them: iterdata (use data instead), iterdicts (use dicts instead), iternamedtuples (use namedtuples instead), iterrecords (use records instead), itervalues (use values instead).

The following functions have been renamed: isordered (renamed to issorted), StringSource (renamed to MemorySource).

The function selectre has been removed as it duplicates functionality, use search instead.

Sorting and comparison

A major difference between Python 2 and Python 3 involves comparison and sorting of objects of different types. Python 3 is a lot stricter about what you can compare with what, e.g., None < 1 < 'foo' works in Python 2.x but raises an exception in Python 3. The strict comparison behaviour of Python 3 is generally a problem for typical usages of petl, where data can be highly heterogeneous and a column in a table may have a mixture of values of many different types, including None for missing.

To maintain the usability of petl in this type of scenario, and to ensure that the behaviour of petl is as consistent as possible across different Python versions, the petl.transform.sorts.sort() function and anything that depends on it (as well as any other functions making use of rich comparisons) emulate the relaxed comparison behaviour that is available under Python 2.x. In fact petl goes further than this, allowing comparison of a wider range of types than is possible under Python 2.x (e.g., datetime with None).

As the underlying code to achieve this has been completely reworked, there may be inconsistencies or unexpected behaviour, so it’s worth testing carefully the results of any code previously run using petl 0.x, especially if you are also migrating from Python 2 to Python 3.

The different comparison behaviour under different Python versions may also give unexpected results when selecting rows of a table. E.g., the following will work under Python 2.x but raise an exception under Python 3.4:

>>> import petl as etl
>>> table = [['foo', 'bar'],
...          ['a', 1],
...          ['b', None]]
>>> # raises exception under Python 3
..., 'bar', lambda v: v > 0)

To get the more relaxed behaviour under Python 3.4, use the petl.transform.selects.selectgt function, or wrap values with petl.comparison.Comparable, e.g.:

>>> # works under Python 3
... etl.selectgt(table, 'bar', 0)
| foo | bar |
| 'a' |   1 |

>>> # or ...
..., 'bar', lambda v: v > etl.Comparable(0))
| foo | bar |
| 'a' |   1 |

New extract/load modules

Several new extract/load modules have been added, migrating functionality previously available from the petlx package:

These modules all have dependencies on third party packages, but these have been kept as optional dependencies so are not required for installing petl.

New validate function

A new petl.transform.validation.validate() function has been added to provide a convenient interface when validating a table against a set of constraints.

New intervals module

A new module has been added providing transformation functions based on intervals, migrating functionality previously available from the petlx package:

This module requires the intervaltree module.

New configuration module

All configuration variables have been brought together into a new petl.config module. See the source code for the variables available, they should be self-explanatory.

petl.push moved to petlx

The petl.push module remains in an experimental state and has been moved to the petlx extensions project.

Argument names and other minor changes

Argument names for a small number of functions have been changed to create consistency across the API.

There are some other minor changes as well. If you are migrating from petl version 0.x the best thing is to run your code and inspect any errors. Email if you have any questions.

Source code reorganisation

The source code has been substantially reorganised. This should not affect users of the petl package however as all functions in the public API are available through the root petl namespace.