This adds the Python copy of `hash_util.parse_narrow`. In the web app,
it will mainly be used in the import process later on. So, although it
has the same purpose as its frontend twin, there are differences:
- This doesn't convert a user-id-slug into a list of user emails. It
will instead parse it into a list of user IDs, as that is the preferred
form for those kinds of operators. It will also help in later operations
to remap the object IDs during import.
- To the same effect as the first point, operands can be an actual list
or int instead of a list or int as a string (e.g., "12,14,15" or "93").
- It has fewer validations than its frontend counterpart. It doesn't
look up the parsed object IDs for validity. This is partly because of
its main use case in import.
Previously `NarrowTerm` is only used in our event-handling paths and to
a lesser extent in the `detect_narrowed_window` in `view/home.py`. Both
of which haven't yet support or handle the `negated` term.
Since we're planning to parse a narrow URL into narrow terms (like in
`hash_util.ts`) in the web app, we're going to need a `NarrowTerm`
dataclass with all three flags.
This commit adds the `negated` term to `NarrowTerm` and adds a
`NeverNegatedNarrowTerm` which is a subclass of `NarrowTerm` that always
has the `negated` flag as `False`, so functionally it is the same as the
current `NarrowTerm`.