allow {key} in slug + allow sorting and hashing

This commit is contained in:
relikd
2022-04-06 13:11:49 +02:00
parent d6df547682
commit a6d9f715f9

View File

@@ -31,33 +31,35 @@ class GroupBySource(VirtualSourceObject):
record: Record, record: Record,
group: str, group: str,
config: Config, config: Config,
children: Optional[Dict[Record, List[object]]] = None, children: Optional[Dict[Record, List[Any]]] = None,
) -> None: ) -> None:
super().__init__(record) super().__init__(record)
self.key = config.slugify(group) self.key = config.slugify(group)
self.group = group self.group = group
self.config = config self.config = config
# make sure children are on the same pad
self._children = {} # type: Dict[Record, List[object]]
for child, extras in (children or {}).items():
if child.pad != record.pad:
child = record.pad.get(child.path)
self._children[child] = extras
self._reverse_reference_records()
# evaluate slug Expression # evaluate slug Expression
if '{key}' in config.slug: if config.slug and '{key}' in config.slug:
self.slug = config.slug.replace('{key}', self.key) self.slug = config.slug.replace('{key}', self.key)
else: else:
self.slug = self._eval(config.slug, field='slug') self.slug = self._eval(config.slug, field='slug')
assert self.slug != Ellipsis, 'invalid config: ' + config.slug assert self.slug != Ellipsis, 'invalid config: ' + config.slug
if self.slug and self.slug.endswith('/index.html'): if self.slug and self.slug.endswith('/index.html'):
self.slug = self.slug[:-10] self.slug = self.slug[:-10]
# make sure children are on the same pad
self._children = {} # type: Dict[Record, List[Any]]
for child, extras in (children or {}).items():
if child.pad != record.pad:
child = record.pad.get(child.path)
self._children[child] = extras
self._reverse_reference_records()
# extra fields # extra fields
for attr, expr in config.fields.items(): for attr, expr in config.fields.items():
setattr(self, attr, self._eval(expr, field='fields.' + attr)) setattr(self, attr, self._eval(expr, field='fields.' + attr))
def _eval(self, value: str, *, field: str) -> Any: def _eval(self, value: Any, *, field: str) -> Any:
''' Internal only: evaluates Lektor config file field expression. ''' ''' Internal only: evaluates Lektor config file field expression. '''
if not isinstance(value, str):
return value
pad = self.record.pad pad = self.record.pad
alt = self.record.alt alt = self.record.alt
try: try:
@@ -80,14 +82,6 @@ class GroupBySource(VirtualSourceObject):
# Actual path to resource as seen by the browser # Actual path to resource as seen by the browser
return build_url([self.record.path, self.slug]) # slug can be None! return build_url([self.record.path, self.slug]) # slug can be None!
def __getitem__(self, name: str) -> object:
# needed for preview in admin UI
if name == '_path':
return self.path
elif name == '_alt':
return self.record.alt
return None
def iter_source_filenames(self) -> Iterator[str]: def iter_source_filenames(self) -> Iterator[str]:
''' Enumerate all dependencies ''' ''' Enumerate all dependencies '''
if self.config.dependencies: if self.config.dependencies:
@@ -100,7 +94,8 @@ class GroupBySource(VirtualSourceObject):
# ----------------------- # -----------------------
@property @property
def children(self) -> Dict[Record, List[object]]: def children(self) -> Dict[Record, List[Any]]:
''' Returns dict with page record key and (optional) extra value. '''
return self._children return self._children
@property @property
@@ -111,17 +106,36 @@ class GroupBySource(VirtualSourceObject):
return None return None
@property @property
def first_extra(self) -> Optional[object]: def first_extra(self) -> Optional[Any]:
''' Returns first additional / extra info object of first page. ''' ''' Returns first additional / extra info object of first page. '''
if not self._children: if not self._children:
return None return None
val = iter(self._children.values()).__next__() val = iter(self._children.values()).__next__()
return val[0] if val else None return val[0] if val else None
def __getitem__(self, key: str) -> Any:
# Used for virtual path resolver and |sort(attribute="x") filter
if key in ('_path', '_alt'):
return getattr(self, key[1:])
if hasattr(self, key):
return getattr(self, key)
return None
def __lt__(self, other: 'GroupBySource') -> bool: def __lt__(self, other: 'GroupBySource') -> bool:
''' The "group" attribute is used for sorting. ''' # Used for |sort filter ("group" is the provided original string)
return self.group < other.group return self.group < other.group
def __eq__(self, other: object) -> bool:
# Used for |unique filter
if self is other:
return True
return isinstance(other, GroupBySource) and \
self.path == other.path and self.slug == other.slug
def __hash__(self) -> int:
# Used for hashing in set and dict
return hash((self.path, self.slug))
def __repr__(self) -> str: def __repr__(self) -> str:
return '<GroupBySource path="{}" children={}>'.format( return '<GroupBySource path="{}" children={}>'.format(
self.path, len(self._children)) self.path, len(self._children))