-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathcontext7.json
More file actions
40 lines (40 loc) · 5.34 KB
/
Copy pathcontext7.json
File metadata and controls
40 lines (40 loc) · 5.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
"$schema": "https://context7.com/schema/context7.json",
"projectTitle": "rss-parser (Python)",
"description": "Typed Python RSS/Atom parser: parses RSS 2.0/0.9x, Atom 1.0 and RSS 1.0 (RDF) into pydantic v2 models. Python package `rss-parser` (import `rss_parser`), not the npm package of the same name.",
"branch": "master",
"excludeFolders": [
"tests",
"scripts",
".github",
".vscode"
],
"excludeFiles": [
"LICENSE",
"contributing.md"
],
"rules": [
"This is the Python package `rss-parser` (import `rss_parser`), not the JavaScript/npm package with the same name. Code samples must be Python.",
"Requires Python 3.10+ and pydantic v2 (>=2.7). Versions 3.x and below are pydantic v1 era and have a different API - see the migration guide.",
"Use `from rss_parser import parse` for automatic feed-type detection; it returns an `RSS`, `Atom` or `RDF` model based on the XML root element. Use `RSSParser`, `AtomParser`, `RDFParser` or `PodcastParser` when the feed type is known.",
"Every XML tag is wrapped in `Tag[T]`: text in `.content`, XML attributes in `.attributes` (the `@` prefix is stripped and keys are snake_cased).",
"`str(tag)` returns the content and attribute access is forwarded to it, so `feed.channel.title` and `item.title.upper()` work without touching `.content`.",
"Repeatable tags are always lists via `OnlyList`, and the fields are plural: `channel.items`, `item.links`, `item.categories`, `item.enclosures`.",
"Self-closing tags such as `<enclosure url=... />` have `content=None`; read their data from `.attributes`, e.g. `item.enclosures[0].attributes[\"url\"]`.",
"Extend the schema by subclassing and parametrizing generics: `class MyItem(Item)` then `RSSParser.parse(data, schema=RSS[Channel[MyItem]])`. Namespaced tags need an explicit alias, e.g. `Field(alias=\"dc:creator\")`.",
"Undeclared tags are never dropped - they are available in `model_extra`, e.g. `rss.channel.content.model_extra[\"itunes:author\"]`.",
"For podcasts use `PodcastParser` (or the `ITunesChannelMixin`/`ITunesItemMixin` mixins) to get typed `itunes:*` fields instead of writing a custom schema.",
"`model_dump()` keeps the content/attributes structure; `dict_plain()` and `json_plain()` flatten every Tag to its plain content value.",
"Errors: malformed XML raises `InvalidXMLError`, an unknown root element raises `UnknownFeedTypeError` (both subclass `ValueError`), and schema violations raise pydantic's `ValidationError`.",
"A document declaring DTD entities raises `EntitiesDisabledError` (message `entities are disabled`, a `ValueError` but not an `InvalidXMLError`, since the document is well-formed), so XXE and entity-expansion feeds are rejected before expansion. It was a bare `ValueError` from xmltodict before 4.3.0.",
"Atom text constructs (`title`, `subtitle`, `rights`, `summary`, `content`) are `Tag[TextConstruct]`, i.e. `Union[str, Dict[str, Any]]`: a `str` for `type=\"text\"`/`type=\"html\"`, but for `type=\"xhtml\"` the content is the xmltodict **dict** of the inline XHTML elements, not a markup string, because xmltodict cannot preserve mixed-content order. The `type` is in `.attributes[\"type\"]`; check `isinstance(tag.content, str)` before treating it as text.",
"There is a CLI since 4.3.0: `rss-parser validate|parse|items [FILE|-]` (also `python -m rss_parser`). It does not fetch - pipe with `curl -sSL <url> | rss-parser validate -`. `validate` is the useful verb (exit 0/1, `--json` reports `error.code`, `--strict` flags declared date fields that did not parse); `parse` dumps the typed model and `items` emits NDJSON, one item per line, with `--flat` for `jq -r '.title'`. Exit codes: 0 ok, 1 feed rejected, 2 usage error, 141 stdout closed.",
"Feed text is returned as-is: HTML inside `<description>`/`<content>` (often CDATA) is not sanitized, so escape it before rendering.",
"There is no `parseURL`/`parseString` and no HTTP client inside: `parse()` takes feed text you already fetched, e.g. `parse(requests.get(url, timeout=10).text)`.",
"`parse()` accepts `str` or `bytes` (bytes since 4.2.0). Prefer bytes, e.g. `parse(response.content)`: they reach the XML parser untouched so the document's `<?xml encoding=...?>` declaration is honored.",
"For polling, deduplicate items by `item.guid` (fall back to `item.links[0]`) in RSS and by `entry.id` in Atom; `<guid isPermaLink=\"false\">` shows up as `item.guid.attributes[\"is_perma_link\"]`.",
"Cross-format reading: RSS uses `feed.channel.items` with `item.pub_date`, Atom uses `feed.feed.entries` with `entry.published`/`entry.updated`, RSS 1.0 (RDF) uses `feed.items` with `item.attributes[\"rdf:about\"]`.",
"Namespace prefixes are kept literally, never resolved against xmlns: alias fields exactly as they appear (`Field(alias=\"dc:creator\")`), or accept several spellings with pydantic's `AliasChoices`.",
"Since 4.4.0, `to_json_feed(feed, *, feed_url=None)` maps an `RSS`/`Atom`/`RDF`/`Podcast` model to a JSON Feed 1.1 dict, returning `(document, JsonFeedReport)`; the CLI equivalent is `rss-parser jsonfeed` (also `rss-parser items --jsonfeed` for NDJSON item objects). It is lossy on purpose: an item with no derivable id is dropped rather than synthesized, there is no `itunes:*` mapping, and Atom `xhtml` content falls back to `<summary>` and finally an empty `content_text` because it cannot be safely re-serialized."
]
}