123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- """CSS selector structure items."""
- import copyreg
- from .pretty import pretty
- from typing import Any, Type, Tuple, Union, Dict, Iterator, Hashable, Optional, Pattern, Iterable, Mapping
- __all__ = (
- 'Selector',
- 'SelectorNull',
- 'SelectorTag',
- 'SelectorAttribute',
- 'SelectorContains',
- 'SelectorNth',
- 'SelectorLang',
- 'SelectorList',
- 'Namespaces',
- 'CustomSelectors'
- )
- SEL_EMPTY = 0x1
- SEL_ROOT = 0x2
- SEL_DEFAULT = 0x4
- SEL_INDETERMINATE = 0x8
- SEL_SCOPE = 0x10
- SEL_DIR_LTR = 0x20
- SEL_DIR_RTL = 0x40
- SEL_IN_RANGE = 0x80
- SEL_OUT_OF_RANGE = 0x100
- SEL_DEFINED = 0x200
- SEL_PLACEHOLDER_SHOWN = 0x400
- class Immutable:
- """Immutable."""
- __slots__: Tuple[str, ...] = ('_hash',)
- _hash: int
- def __init__(self, **kwargs: Any) -> None:
- """Initialize."""
- temp = []
- for k, v in kwargs.items():
- temp.append(type(v))
- temp.append(v)
- super(Immutable, self).__setattr__(k, v)
- super(Immutable, self).__setattr__('_hash', hash(tuple(temp)))
- @classmethod
- def __base__(cls) -> "Type[Immutable]":
- """Get base class."""
- return cls
- def __eq__(self, other: Any) -> bool:
- """Equal."""
- return (
- isinstance(other, self.__base__()) and
- all([getattr(other, key) == getattr(self, key) for key in self.__slots__ if key != '_hash'])
- )
- def __ne__(self, other: Any) -> bool:
- """Equal."""
- return (
- not isinstance(other, self.__base__()) or
- any([getattr(other, key) != getattr(self, key) for key in self.__slots__ if key != '_hash'])
- )
- def __hash__(self) -> int:
- """Hash."""
- return self._hash
- def __setattr__(self, name: str, value: Any) -> None:
- """Prevent mutability."""
- raise AttributeError("'{}' is immutable".format(self.__class__.__name__))
- def __repr__(self) -> str: # pragma: no cover
- """Representation."""
- return "{}({})".format(
- self.__class__.__name__, ', '.join(["{}={!r}".format(k, getattr(self, k)) for k in self.__slots__[:-1]])
- )
- __str__ = __repr__
- def pretty(self) -> None: # pragma: no cover
- """Pretty print."""
- print(pretty(self))
- class ImmutableDict(Mapping[Any, Any]):
- """Hashable, immutable dictionary."""
- def __init__(
- self,
- arg: Union[Dict[Any, Any], Iterable[Tuple[Any, Any]]]
- ) -> None:
- """Initialize."""
- self._validate(arg)
- self._d = dict(arg)
- self._hash = hash(tuple([(type(x), x, type(y), y) for x, y in sorted(self._d.items())]))
- def _validate(self, arg: Union[Dict[Any, Any], Iterable[Tuple[Any, Any]]]) -> None:
- """Validate arguments."""
- if isinstance(arg, dict):
- if not all([isinstance(v, Hashable) for v in arg.values()]):
- raise TypeError('{} values must be hashable'.format(self.__class__.__name__))
- elif not all([isinstance(k, Hashable) and isinstance(v, Hashable) for k, v in arg]):
- raise TypeError('{} values must be hashable'.format(self.__class__.__name__))
- def __iter__(self) -> Iterator[Any]:
- """Iterator."""
- return iter(self._d)
- def __len__(self) -> int:
- """Length."""
- return len(self._d)
- def __getitem__(self, key: Any) -> Any:
- """Get item: `namespace['key']`."""
- return self._d[key]
- def __hash__(self) -> int:
- """Hash."""
- return self._hash
- def __repr__(self) -> str: # pragma: no cover
- """Representation."""
- return "{!r}".format(self._d)
- __str__ = __repr__
- class Namespaces(ImmutableDict):
- """Namespaces."""
- def __init__(self, arg: Union[Dict[str, str], Iterable[Tuple[str, str]]]) -> None:
- """Initialize."""
- super().__init__(arg)
- def _validate(self, arg: Union[Dict[str, str], Iterable[Tuple[str, str]]]) -> None:
- """Validate arguments."""
- if isinstance(arg, dict):
- if not all([isinstance(v, str) for v in arg.values()]):
- raise TypeError('{} values must be hashable'.format(self.__class__.__name__))
- elif not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]):
- raise TypeError('{} keys and values must be Unicode strings'.format(self.__class__.__name__))
- class CustomSelectors(ImmutableDict):
- """Custom selectors."""
- def __init__(self, arg: Union[Dict[str, str], Iterable[Tuple[str, str]]]) -> None:
- """Initialize."""
- super().__init__(arg)
- def _validate(self, arg: Union[Dict[str, str], Iterable[Tuple[str, str]]]) -> None:
- """Validate arguments."""
- if isinstance(arg, dict):
- if not all([isinstance(v, str) for v in arg.values()]):
- raise TypeError('{} values must be hashable'.format(self.__class__.__name__))
- elif not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]):
- raise TypeError('{} keys and values must be Unicode strings'.format(self.__class__.__name__))
- class Selector(Immutable):
- """Selector."""
- __slots__ = (
- 'tag', 'ids', 'classes', 'attributes', 'nth', 'selectors',
- 'relation', 'rel_type', 'contains', 'lang', 'flags', '_hash'
- )
- tag: Optional['SelectorTag']
- ids: Tuple[str, ...]
- classes: Tuple[str, ...]
- attributes: Tuple['SelectorAttribute', ...]
- nth: Tuple['SelectorNth', ...]
- selectors: Tuple['SelectorList', ...]
- relation: 'SelectorList'
- rel_type: Optional[str]
- contains: Tuple['SelectorContains', ...]
- lang: Tuple['SelectorLang', ...]
- flags: int
- def __init__(
- self,
- tag: Optional['SelectorTag'],
- ids: Tuple[str, ...],
- classes: Tuple[str, ...],
- attributes: Tuple['SelectorAttribute', ...],
- nth: Tuple['SelectorNth', ...],
- selectors: Tuple['SelectorList', ...],
- relation: 'SelectorList',
- rel_type: Optional[str],
- contains: Tuple['SelectorContains', ...],
- lang: Tuple['SelectorLang', ...],
- flags: int
- ):
- """Initialize."""
- super().__init__(
- tag=tag,
- ids=ids,
- classes=classes,
- attributes=attributes,
- nth=nth,
- selectors=selectors,
- relation=relation,
- rel_type=rel_type,
- contains=contains,
- lang=lang,
- flags=flags
- )
- class SelectorNull(Immutable):
- """Null Selector."""
- def __init__(self) -> None:
- """Initialize."""
- super().__init__()
- class SelectorTag(Immutable):
- """Selector tag."""
- __slots__ = ("name", "prefix", "_hash")
- name: str
- prefix: Optional[str]
- def __init__(self, name: str, prefix: Optional[str]) -> None:
- """Initialize."""
- super().__init__(name=name, prefix=prefix)
- class SelectorAttribute(Immutable):
- """Selector attribute rule."""
- __slots__ = ("attribute", "prefix", "pattern", "xml_type_pattern", "_hash")
- attribute: str
- prefix: str
- pattern: Optional[Pattern[str]]
- xml_type_pattern: Optional[Pattern[str]]
- def __init__(
- self,
- attribute: str,
- prefix: str,
- pattern: Optional[Pattern[str]],
- xml_type_pattern: Optional[Pattern[str]]
- ) -> None:
- """Initialize."""
- super().__init__(
- attribute=attribute,
- prefix=prefix,
- pattern=pattern,
- xml_type_pattern=xml_type_pattern
- )
- class SelectorContains(Immutable):
- """Selector contains rule."""
- __slots__ = ("text", "own", "_hash")
- text: Tuple[str, ...]
- own: bool
- def __init__(self, text: Iterable[str], own: bool) -> None:
- """Initialize."""
- super().__init__(text=tuple(text), own=own)
- class SelectorNth(Immutable):
- """Selector nth type."""
- __slots__ = ("a", "n", "b", "of_type", "last", "selectors", "_hash")
- a: int
- n: bool
- b: int
- of_type: bool
- last: bool
- selectors: 'SelectorList'
- def __init__(self, a: int, n: bool, b: int, of_type: bool, last: bool, selectors: 'SelectorList') -> None:
- """Initialize."""
- super().__init__(
- a=a,
- n=n,
- b=b,
- of_type=of_type,
- last=last,
- selectors=selectors
- )
- class SelectorLang(Immutable):
- """Selector language rules."""
- __slots__ = ("languages", "_hash",)
- languages: Tuple[str, ...]
- def __init__(self, languages: Iterable[str]):
- """Initialize."""
- super().__init__(languages=tuple(languages))
- def __iter__(self) -> Iterator[str]:
- """Iterator."""
- return iter(self.languages)
- def __len__(self) -> int: # pragma: no cover
- """Length."""
- return len(self.languages)
- def __getitem__(self, index: int) -> str: # pragma: no cover
- """Get item."""
- return self.languages[index]
- class SelectorList(Immutable):
- """Selector list."""
- __slots__ = ("selectors", "is_not", "is_html", "_hash")
- selectors: Tuple[Union['Selector', 'SelectorNull'], ...]
- is_not: bool
- is_html: bool
- def __init__(
- self,
- selectors: Optional[Iterable[Union['Selector', 'SelectorNull']]] = None,
- is_not: bool = False,
- is_html: bool = False
- ) -> None:
- """Initialize."""
- super().__init__(
- selectors=tuple(selectors) if selectors is not None else tuple(),
- is_not=is_not,
- is_html=is_html
- )
- def __iter__(self) -> Iterator[Union['Selector', 'SelectorNull']]:
- """Iterator."""
- return iter(self.selectors)
- def __len__(self) -> int:
- """Length."""
- return len(self.selectors)
- def __getitem__(self, index: int) -> Union['Selector', 'SelectorNull']:
- """Get item."""
- return self.selectors[index]
- def _pickle(p: Any) -> Any:
- return p.__base__(), tuple([getattr(p, s) for s in p.__slots__[:-1]])
- def pickle_register(obj: Any) -> None:
- """Allow object to be pickled."""
- copyreg.pickle(obj, _pickle)
- pickle_register(Selector)
- pickle_register(SelectorNull)
- pickle_register(SelectorTag)
- pickle_register(SelectorAttribute)
- pickle_register(SelectorContains)
- pickle_register(SelectorNth)
- pickle_register(SelectorLang)
- pickle_register(SelectorList)
|