{"id":851,"library":"daff","title":"Daff: Data Diff and Patch Tables","description":"daff (data diff) is a Python library for comparing tables, producing a summary of their differences, and applying such summaries as patch files. It is optimized for comparing tables that share a common origin, effectively tracking changes between versions of the 'same' table. The library is actively maintained with frequent updates.","status":"active","version":"1.4.2","language":"python","source_language":"en","source_url":"https://github.com/paulfitz/daff","tags":["data diff","table comparison","patch","data transformation","csv","sqlite"],"install":[{"cmd":"pip install daff","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Used for diffing SQLite databases; updated in v1.3.37. It's an optional dependency handled internally.","package":"sqlite3","optional":true}],"imports":[{"symbol":"daff","correct":"import daff"}],"quickstart":{"code":"import daff\n\ndata1 = [\n    ['Country', 'Capital'],\n    ['Ireland', 'Dublin'],\n    ['France', 'Paris'],\n    ['Spain', 'Barcelona']\n]\n\ndata2 = [\n    ['Country', 'Code', 'Capital'],\n    ['Ireland', 'ie', 'Dublin'],\n    ['France', 'fr', 'Paris'],\n    ['Spain', 'es', 'Madrid'],\n    ['Germany', 'de', 'Berlin']\n]\n\n# Create table views for the data\ntable1 = daff.PythonTableView(data1)\ntable2 = daff.PythonTableView(data2)\n\n# Compare tables to get alignment information\nalignment = daff.Coopy.compareTables(table1, table2).align()\n\n# Prepare an empty table to hold the diff results\ndata_diff = []\ntable_diff = daff.PythonTableView(data_diff)\nflags = daff.CompareFlags()\nhighlighter = daff.TableDiff(alignment, flags)\nhighlighter.hilite(table_diff)\n\n# Render the diff to HTML for visualization\ndiff_render = daff.DiffRender()\ndiff_render.usePrettyArrows(False) # Optional: control arrow style\ndiff_render.render(table_diff)\ntable_diff_html = diff_render.html()\n\nprint(\"Original Table 1:\", data1)\nprint(\"Modified Table 2:\", data2)\nprint(\"\\nHTML Diff:\\n\", table_diff_html)","lang":"python","description":"This quickstart demonstrates how to compare two Python list-of-lists tables using `daff`, generate a diff, and render it as an HTML string for visualization. It uses `PythonTableView` to adapt standard Python data structures for `daff`'s comparison algorithms."},"warnings":[{"fix":"Rename any identifiers named `async` to avoid conflict with the reserved keyword. A common convention is to use `async_` instead.","message":"The keyword `async` became a reserved keyword in Python 3.7. If you were using `async` as a variable name, function parameter, or identifier in your code that interacts with `daff`, it will now cause a `SyntaxError` in Python 3.7 and newer.","severity":"breaking","affected_versions":">=3.7.0"},{"fix":"If encountering unexpected behavior when diffing SQLite databases, review the changes between SQLite versions 3 and 4 or ensure your environment's SQLite library is compatible with `daff`'s expectations.","message":"The optional `sqlite3` dependency was updated from version 3 to 4 in `daff` v1.3.37. While `sqlite3` is a built-in Python module, this update might subtly affect behavior or introduce incompatibilities if your application relies on specific, advanced features or versions of SQLite that `daff` interacts with, especially when using `--input-format sqlite`.","severity":"gotcha","affected_versions":">=1.3.37"},{"fix":"Avoid using mutable objects as default arguments in your own functions. Instead, use `None` as the default and initialize the mutable object inside the function if it's `None`. Be mindful of this pattern when extending or integrating with `daff`'s API.","message":"Like many Python libraries, `daff`'s API might expose functions or methods where mutable objects (e.g., lists, dictionaries) are used as default arguments. Using mutable defaults can lead to unexpected side effects across multiple function calls, as the default object is created only once when the function is defined.","severity":"gotcha","affected_versions":"<all>"}],"env_vars":null,"last_verified":"2026-05-12T20:22:34.272Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"fix":"Install the daff library using pip: `pip install daff`","cause":"The 'daff' library is not installed in the Python environment where the code is being run.","error":"ModuleNotFoundError: No module named 'daff'"},{"fix":"Ensure that the input data to daff's table view functions is a list of lists, where each inner list represents a row and contains cell values. Example: `data = [['header1', 'header2'], [1, 2], [3, 4]]`.","cause":"This typically occurs when passing incorrectly structured data (e.g., a flat list of numbers instead of a list of lists/rows) to `daff.PythonTableView` or similar table construction methods, as the library expects an iterable of iterables for rows and cells.","error":"TypeError: 'int' object is not iterable"},{"fix":"Verify that the file paths provided to the `daff` command or functions are correct and that the files exist in the specified locations.","cause":"When using the `daff` command-line tool or its Python functions that read from files (e.g., `daff.diff_tables_from_csv`), this error occurs if the specified input CSV or other data files do not exist at the given path.","error":"FileNotFoundError: [Errno 2] No such file or directory"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":null,"quickstart_tag":null,"pypi_latest":"1.4.2","cli_name":"daff","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.8,"disk_size":"18.5M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.8,"disk_size":"18.5M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.02,"mem_mb":2.8,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":2.8,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":3.5,"disk_size":"20.6M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":3.5,"disk_size":"20.6M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.8,"import_time_s":0.08,"mem_mb":3.5,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.5,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3.3,"disk_size":"12.4M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.3,"disk_size":"12.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.07,"mem_mb":3.3,"disk_size":"13M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.3,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":4.2,"disk_size":"12.2M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.8,"disk_size":"12.1M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.08,"mem_mb":4.2,"disk_size":"13M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":3.8,"disk_size":"13M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":2.6,"disk_size":"18.0M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.6,"disk_size":"18.0M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2,"import_time_s":0.03,"mem_mb":2.6,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.6,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}