D4Vinci/Scrapling · error · NotImplementedError

{self.__class__.__name__} must implement parse_row() method

Error message

{self.__class__.__name__} must implement parse_row() method

What it means

CSVFeedSpider-derived spiders must override parse_row(); the base implementation raises NotImplementedError. The engine decodes the CSV body with DictReader using the configured headers/delimiter/quotechar, then calls parse_row(response, row) once per row as a dict.

Source

Thrown at scrapling/spiders/templates/feed.py:139

        """Read the feed's rows and dispatch each one to `parse_row`."""
        content_type = response.headers.get("content-type") if response.headers else None
        try:
            body = _decompress(response.body, content_type)
        except OSError as e:
            self.logger.warning(f"Failed to decompress feed: {e}")
            return

        text = body.decode(response.encoding or "utf-8", errors="replace")
        reader = DictReader(StringIO(text), fieldnames=self.headers, delimiter=self.delimiter, quotechar=self.quotechar)
        for row in reader:
            async for result in self.parse_row(response, dict(row)):
                yield result

    async def parse_row(
        self, response: "Response", row: Dict[str, Any]
    ) -> AsyncGenerator[Union[Dict[str, Any], Request, None], None]:
        """Override to process one feed row as a `{column: value}` dictionary."""
        raise NotImplementedError(f"{self.__class__.__name__} must implement parse_row() method")
        yield  # Make this a generator for type checkers

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Implement `async def parse_row(self, response, row)` yielding items/Requests/None, where row is a {column: value} dict
  2. Check headers/delimiter configuration too, since DictReader needs them to produce correct columns

Example fix

// before
class CSV(CSVFeedSpider):
    name = "csv"

// after
class CSV(CSVFeedSpider):
    name = "csv"

    async def parse_row(self, response, row):
        yield {"sku": row["sku"], "price": row["price"]}
Defensive patterns

Strategy: validation

Validate before calling

assert CSV.parse_row is not CSVFeedSpider.parse_row, "implement parse_row()"

Type guard

def implements_parse_row(cls) -> bool:
    return cls.parse_row is not CSVFeedSpider.parse_row

Prevention

When it happens

Trigger: Subclassing the CSV feed template without implementing parse_row; defining a differently named method (e.g. parse_line) that never gets called.

Common situations: Scaffolding CSV spiders and forgetting the hook; porting code from other frameworks with different callback names.

Related errors


AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14). Data as JSON: /api/errors/ffeb9a6a101a71aa. Report an issue: GitHub.