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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
# fmt: off
"""Helper functions for Flask WSGI-app."""
from typing import Dict, List, Optional, Tuple
from ase.db.core import Database
from ase.db.table import Table, all_columns
class Session:
"""Seesion object.
Stores stuff that the jinja2 templetes (like templates/table.html)
need to show. Example from table.html::
Displaying rows {{ s.row1 }}-{{ s.row2 }} out of {{ s.nrows }}
where *s* is the session object.
"""
next_id = 1
sessions: Dict[int, 'Session'] = {}
def __init__(self, project_name: str):
self.id = Session.next_id
Session.next_id += 1
Session.sessions[self.id] = self
if len(Session.sessions) > 2000:
# Forget old sessions:
for id in sorted(Session.sessions)[:400]:
del Session.sessions[id]
self.columns: Optional[List[str]] = None
self.nrows: Optional[int] = None
self.nrows_total: Optional[int] = None
self.page = 0
self.limit = 25
self.sort = ''
self.query = ''
self.project_name = project_name
def __str__(self) -> str:
return str(self.__dict__)
@staticmethod
def get(id: int) -> 'Session':
return Session.sessions[id]
def update(self,
what: str,
x: str,
args: Dict[str, str],
project) -> None:
if self.columns is None:
self.columns = list(project.default_columns)
if what == 'query':
self.query = project.handle_query(args)
self.nrows = None
self.page = 0
elif what == 'sort':
if x == self.sort:
self.sort = '-' + x
elif '-' + x == self.sort:
self.sort = 'id'
else:
self.sort = x
self.page = 0
elif what == 'limit':
self.limit = int(x)
self.page = 0
elif what == 'page':
self.page = int(x)
elif what == 'toggle':
column = x
if column == 'reset':
self.columns = list(project.default_columns)
else:
if column in self.columns:
self.columns.remove(column)
if column == self.sort.lstrip('-'):
self.sort = 'id'
self.page = 0
else:
self.columns.append(column)
@property
def row1(self) -> int:
return self.page * self.limit + 1
@property
def row2(self) -> int:
assert self.nrows is not None
return min((self.page + 1) * self.limit, self.nrows)
def paginate(self) -> List[Tuple[int, str]]:
"""Helper function for pagination stuff."""
assert self.nrows is not None
npages = (self.nrows + self.limit - 1) // self.limit
p1 = min(5, npages)
p2 = max(self.page - 4, p1)
p3 = min(self.page + 5, npages)
p4 = max(npages - 4, p3)
pgs = list(range(p1))
if p1 < p2:
pgs.append(-1)
pgs += list(range(p2, p3))
if p3 < p4:
pgs.append(-1)
pgs += list(range(p4, npages))
pages = [(self.page - 1, 'previous')]
for p in pgs:
if p == -1:
pages.append((-1, '...'))
elif p == self.page:
pages.append((-1, str(p + 1)))
else:
pages.append((p, str(p + 1)))
nxt = min(self.page + 1, npages - 1)
if nxt == self.page:
nxt = -1
pages.append((nxt, 'next'))
return pages
def create_table(self,
db: Database,
uid_key: str,
keys: List[str]) -> Table:
query = self.query
if self.nrows_total is None:
self.nrows_total = db.count()
if self.nrows is None:
try:
self.nrows = db.count(query)
except (ValueError, KeyError) as e:
error = ', '.join(['Bad query'] + list(e.args))
from flask import flash
flash(error)
query = 'id=0' # this will return no rows
self.nrows = 0
table = Table(db, uid_key)
table.select(query, self.columns, self.sort,
self.limit, offset=self.page * self.limit,
show_empty_columns=True)
table.format()
assert self.columns is not None
table.addcolumns = sorted(column for column in
[*all_columns, *keys]
if column not in self.columns)
return table
|