{"id":7563,"library":"pygeofilter","title":"pygeofilter","description":"pygeofilter is a pure Python library for parsing and evaluating OGC filtering standards, including Filter Encoding 2.0 and CQL2. It provides robust tools to parse filter expressions from various formats (e.g., CQL2-TEXT, CQL2-JSON) and evaluate them against Python data structures or translate them into SQL queries. The current version is 0.3.3, and it receives active development with regular patch and minor releases.","status":"active","version":"0.3.3","language":"en","source_language":"en","source_url":"https://github.com/geopython/pygeofilter","tags":["OGC","filter","cql2","geospatial","sqlalchemy","parsing","evaluation"],"install":[{"cmd":"pip install pygeofilter","lang":"bash","label":"Base installation"},{"cmd":"pip install pygeofilter[sql]","lang":"bash","label":"With SQL backend support (SQLAlchemy, SQLModel)"}],"dependencies":[{"reason":"Required for parsing filter expressions.","package":"lark"},{"reason":"Required for geometry operations in filter evaluation.","package":"shapely"},{"reason":"Required for generating SQLAlchemy expressions from filters, used by the 'sql' extra.","package":"sqlalchemy","optional":true},{"reason":"Required for generating SQLModel queries from filters, used by the 'sql' extra.","package":"sqlmodel","optional":true}],"imports":[{"note":"The `cql2` module was split into format-specific parsers. Use `cql2_text` for text-based CQL2 or `cql2_json` for JSON.","wrong":"from pygeofilter.parsers.cql2 import parse","symbol":"parse","correct":"from pygeofilter.parsers.cql2_text import parse"},{"symbol":"evaluate","correct":"from pygeofilter.evaluate import evaluate"},{"symbol":"to_sqlalchemy","correct":"from pygeofilter.backends.sqlalchemy import to_sqlalchemy"}],"quickstart":{"code":"from pygeofilter.parsers.cql2_text import parse\nfrom pygeofilter.evaluate import evaluate\n\n# Define a CQL2 filter expression\ncql_filter_string = \"(name = 'test-feature' AND temperature > 25) OR (id IN ('A1', 'B2'))\"\n\n# Parse the filter expression\nparsed_filter = parse(cql_filter_string)\n\n# Define a data item (dictionary representing feature properties)\ndata_item = {\n    \"name\": \"test-feature\",\n    \"temperature\": 28.5,\n    \"id\": \"A1\",\n    \"timestamp\": \"2024-01-01T10:00:00Z\"\n}\n\n# Evaluate the filter against the data item\nresult = evaluate(parsed_filter, data_item)\n\nprint(f\"Filter expression: {cql_filter_string}\")\nprint(f\"Data item: {data_item}\")\nprint(f\"Evaluation result: {result}\")\n\n# Example with a different data item (should fail the filter)\ndata_item_fail = {\n    \"name\": \"other-feature\",\n    \"temperature\": 20.0,\n    \"id\": \"C3\",\n    \"timestamp\": \"2024-01-01T11:00:00Z\"\n}\nresult_fail = evaluate(parsed_filter, data_item_fail)\nprint(f\"Evaluation result for other item: {result_fail}\")","lang":"python","description":"This quickstart demonstrates how to parse a CQL2-TEXT filter string and then evaluate it against a Python dictionary representing a data item's properties. It showcases both a successful and a failing evaluation."},"warnings":[{"fix":"Upgrade `pygeofilter` to version 0.3.0 or newer. If you must remain on an older 0.2.x version, ensure your `SQLAlchemy` installation is version `< 2.0.0`.","message":"Versions of `pygeofilter` prior to 0.3.0 (specifically 0.2.x releases) explicitly pinned the `SQLAlchemy` dependency to version `< 2.0.0`. Attempting to use these older `pygeofilter` versions with `SQLAlchemy` 2.x will lead to runtime errors, particularly when using SQL backend generation features. The explicit pin was removed in 0.3.0, implying compatibility with SQLAlchemy 2.x.","severity":"breaking","affected_versions":"< 0.3.0"},{"fix":"Explicitly use `ILIKE` in your CQL2 filter expressions when case-insensitivity is desired for SQL backend generation (e.g., `PROPERTY ILIKE '%value%'`).","message":"As of `pygeofilter` v0.3.3, the use of `ILIKE` (case-insensitive `LIKE`) in SQL backend generation has become opt-in. If your filter expressions previously used `LIKE` and implicitly relied on case-insensitivity when generating SQL queries (e.g., for PostgreSQL), those queries might now be case-sensitive. This change was implemented to align better with SQL standards where `LIKE` is typically case-sensitive unless collation specifies otherwise.","severity":"gotcha","affected_versions":">= 0.3.3"},{"fix":"Always ensure spatial filter geometries are in a valid and expected format (e.g., WKT, GeoJSON) and that their CRS (if specified) is consistent with your data. Refer to the OGC Filter Encoding and CQL2 specifications for details on geometry literals.","message":"Incorrect or unsupported geometry encodings or Coordinate Reference Systems (CRS) in spatial filter predicates can lead to parsing errors or incorrect evaluation results. `pygeofilter` expects geometries in WKT (Well-Known Text) or GeoJSON representations for certain operations, and CRS handling might require careful input.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Use `from pygeofilter.parsers.cql2_text import parse` for text-based CQL2 filters or `from pygeofilter.parsers.cql2_json import parse` for JSON-based CQL2 filters.","cause":"You are attempting to import from an old or incorrect path for CQL2 parsers. The `cql2` module was refactored into format-specific parsers.","error":"ModuleNotFoundError: No module named 'pygeofilter.parsers.cql2'"},{"fix":"Carefully review your filter string for typos, incorrect operators, mismatched parentheses, or unsupported functions. Ensure it strictly adheres to the specified OGC filter standard (e.g., CQL2-TEXT specification) that the parser expects.","cause":"The filter expression provided is syntactically incorrect according to the OGC standard (e.g., CQL2-TEXT) or contains elements not supported by the parser's grammar.","error":"lark.exceptions.UnexpectedInput: No rule matches the current input"},{"fix":"Ensure the Python data types used in your filter values are compatible with the corresponding SQLAlchemy column types. For `datetime` objects, ensure consistent timezone awareness (or naivety) and proper handling during the `to_sqlalchemy` conversion, possibly by providing explicit type mappers if needed for custom types.","cause":"When translating a filter to a SQLAlchemy expression, a type mismatch occurred between a Python value in your filter and what SQLAlchemy expects for a column type or bind parameter. This is common with `datetime` or other complex types.","error":"sqlalchemy.exc.CompileError: (in _create_bind_param) Type annotation for parameter '...' must be a SQLAlchemy Type, not 'datetime'"}]}