lino 24.9.4__py3-none-any.whl → 24.10.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lino/__init__.py +1 -5
- lino/api/doctest.py +18 -1
- lino/core/actions.py +15 -8
- lino/core/actors.py +82 -8
- lino/core/constants.py +20 -4
- lino/core/dashboard.py +1 -3
- lino/core/dbtables.py +33 -50
- lino/core/elems.py +26 -33
- lino/core/fields.py +13 -7
- lino/core/kernel.py +3 -3
- lino/core/model.py +1 -0
- lino/core/renderer.py +33 -20
- lino/core/requests.py +18 -18
- lino/core/store.py +11 -11
- lino/core/tablerequest.py +5 -5
- lino/core/tables.py +39 -25
- lino/mixins/dupable.py +1 -1
- lino/modlib/checkdata/models.py +1 -1
- lino/modlib/comments/mixins.py +2 -2
- lino/modlib/comments/ui.py +83 -77
- lino/modlib/dupable/models.py +1 -1
- lino/modlib/export_excel/models.py +0 -3
- lino/modlib/extjs/ext_renderer.py +8 -8
- lino/modlib/extjs/views.py +6 -16
- lino/modlib/help/management/commands/makehelp.py +1 -1
- lino/modlib/notify/models.py +1 -1
- lino/modlib/printing/actions.py +0 -5
- lino/modlib/publisher/ui.py +3 -3
- lino/modlib/publisher/views.py +10 -10
- lino/modlib/search/models.py +2 -2
- lino/modlib/system/mixins.py +0 -10
- lino/modlib/uploads/mixins.py +6 -3
- lino/modlib/uploads/ui.py +2 -2
- lino/modlib/users/mixins.py +5 -5
- lino/sphinxcontrib/actordoc.py +1 -1
- lino/sphinxcontrib/logo/static/linodocs.css +1 -8
- lino/utils/choosers.py +1 -1
- lino/utils/report.py +1 -1
- {lino-24.9.4.dist-info → lino-24.10.0.dist-info}/METADATA +1 -1
- {lino-24.9.4.dist-info → lino-24.10.0.dist-info}/RECORD +43 -43
- {lino-24.9.4.dist-info → lino-24.10.0.dist-info}/WHEEL +0 -0
- {lino-24.9.4.dist-info → lino-24.10.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-24.9.4.dist-info → lino-24.10.0.dist-info}/licenses/COPYING +0 -0
lino/core/kernel.py
CHANGED
@@ -877,12 +877,12 @@ class Kernel(object):
|
|
877
877
|
|
878
878
|
if isinstance(h, tables.TableHandle):
|
879
879
|
he = set(h.actor.hidden_columns | h.actor.hidden_elements)
|
880
|
-
|
880
|
+
gl = layouts.ColumnsLayout(
|
881
881
|
h.actor.get_column_names(ar), h.actor, hidden_elements=he
|
882
882
|
)
|
883
|
-
h.
|
883
|
+
h.grid_layout = gl.get_layout_handle()
|
884
884
|
else:
|
885
|
-
h.
|
885
|
+
h.grid_layout = None
|
886
886
|
|
887
887
|
if h.actor.params_layout:
|
888
888
|
h.params_layout_handle = h.actor.make_params_layout_handle()
|
lino/core/model.py
CHANGED
lino/core/renderer.py
CHANGED
@@ -197,7 +197,7 @@ class HtmlRenderer(Renderer):
|
|
197
197
|
import rstgen
|
198
198
|
|
199
199
|
if display_mode == constants.DISPLAY_MODE_CARDS:
|
200
|
-
layout = ar.actor.card_layout or actor.list_layout
|
200
|
+
layout = ar.actor.card_layout or ar.actor.list_layout
|
201
201
|
lh = layout.get_layout_handle()
|
202
202
|
else:
|
203
203
|
lh = ar.bound_action.get_layout_handel()
|
@@ -275,14 +275,18 @@ class HtmlRenderer(Renderer):
|
|
275
275
|
Silently ignores the parameters `stripped` and `header_links`
|
276
276
|
since for HTML these options have no meaning.
|
277
277
|
"""
|
278
|
-
# print("20231227")
|
279
278
|
if display_mode is None:
|
280
279
|
display_mode = ar.actor.get_display_mode()
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
280
|
+
if nosummary and display_mode == constants.DISPLAY_MODE_SUMMARY:
|
281
|
+
display_mode = constants.DISPLAY_MODE_GRID
|
282
|
+
else:
|
283
|
+
assert display_mode in ar.actor.extra_display_modes | constants.BASIC_DISPLAY_MODES
|
284
|
+
if nosummary:
|
285
|
+
raise Exception("Both nosummary and display_mode were specified")
|
286
|
+
|
287
|
+
if display_mode == constants.DISPLAY_MODE_SUMMARY:
|
288
|
+
yield ar.actor.get_table_summary(ar.master_instance, ar)
|
289
|
+
return
|
286
290
|
|
287
291
|
if header_level is not None:
|
288
292
|
k = "h" + str(header_level)
|
@@ -294,6 +298,10 @@ class HtmlRenderer(Renderer):
|
|
294
298
|
yield ar.actor.get_table_as_list(ar.master_instance, ar)
|
295
299
|
return
|
296
300
|
|
301
|
+
if display_mode == constants.DISPLAY_MODE_STORY:
|
302
|
+
yield ar.actor.get_table_story(ar.master_instance, ar)
|
303
|
+
return
|
304
|
+
|
297
305
|
yield ar.table2xhtml(**kwargs)
|
298
306
|
|
299
307
|
# if show_toolbar:
|
@@ -810,7 +818,7 @@ class TextRenderer(HtmlRenderer):
|
|
810
818
|
stripped=True,
|
811
819
|
show_urls=False,
|
812
820
|
display_mode=None,
|
813
|
-
**kwargs
|
821
|
+
**kwargs
|
814
822
|
):
|
815
823
|
"""
|
816
824
|
Render the given table request as reStructuredText to stdout. See
|
@@ -819,19 +827,24 @@ class TextRenderer(HtmlRenderer):
|
|
819
827
|
self.show_urls = show_urls
|
820
828
|
if display_mode is None:
|
821
829
|
display_mode = ar.actor.get_display_mode()
|
822
|
-
|
823
|
-
|
830
|
+
if nosummary and display_mode == constants.DISPLAY_MODE_SUMMARY:
|
831
|
+
display_mode = constants.DISPLAY_MODE_GRID
|
832
|
+
else:
|
833
|
+
if display_mode not in ar.actor.extra_display_modes | constants.BASIC_DISPLAY_MODES:
|
834
|
+
raise Exception(f"Invalid display mode {display_mode} for {ar.actor}")
|
835
|
+
if nosummary:
|
836
|
+
raise Exception("Both nosummary and display_mode were specified")
|
837
|
+
# print(f"20240929 {nosummary} {display_mode} {ar}")
|
824
838
|
# yield "20240506 {}".format(ar)
|
825
|
-
if
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
return
|
839
|
+
if display_mode == constants.DISPLAY_MODE_SUMMARY:
|
840
|
+
s = to_rst(
|
841
|
+
ar.actor.get_table_summary(ar.master_instance, ar),
|
842
|
+
stripped=stripped,
|
843
|
+
)
|
844
|
+
if stripped:
|
845
|
+
s = s.strip()
|
846
|
+
yield s
|
847
|
+
return
|
835
848
|
|
836
849
|
if display_mode == constants.DISPLAY_MODE_CARDS:
|
837
850
|
for row in ar.sliced_data_iterator:
|
lino/core/requests.py
CHANGED
@@ -633,13 +633,16 @@ class BaseRequest(object):
|
|
633
633
|
"""
|
634
634
|
# ~ print 20131003, selected_pks
|
635
635
|
self.selected_rows = []
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
636
|
+
for pk in selected_pks:
|
637
|
+
if pk and pk != "-99998" and pk != "-99999":
|
638
|
+
self.selected_rows.append(self.get_row_by_pk(pk))
|
639
|
+
# try:
|
640
|
+
# for pk in selected_pks:
|
641
|
+
# if pk and pk != "-99998" and pk != "-99999":
|
642
|
+
# self.selected_rows.append(self.get_row_by_pk(pk))
|
643
|
+
# except ObjectDoesNotExist as e:
|
644
|
+
# raise exceptions.BadRequest(
|
645
|
+
# "Invalid primary key {0} for {1} ({2})".format(pk, self.actor, e)) from None
|
643
646
|
# self.selected_rows = filter(lambda x: x, self.selected_rows)
|
644
647
|
# note: ticket #523 was because the GET contained an empty pk ("&sr=")
|
645
648
|
|
@@ -661,11 +664,11 @@ class BaseRequest(object):
|
|
661
664
|
return False
|
662
665
|
if not self.bound_action.action.select_rows:
|
663
666
|
return True
|
664
|
-
# raise Exception("20160814 {}".format(self.bound_action))
|
665
667
|
for obj in self.selected_rows:
|
666
668
|
# obj = self.selected_rows[0]
|
667
669
|
state = self.bound_action.actor.get_row_state(obj)
|
668
670
|
if not self.bound_action.get_row_permission(self, obj, state):
|
671
|
+
# raise Exception(f"20241001 {self.bound_action}")
|
669
672
|
return False
|
670
673
|
return True
|
671
674
|
# obj = state = None
|
@@ -1078,17 +1081,16 @@ class BaseRequest(object):
|
|
1078
1081
|
set to ``((None, DISPLAY_MODE_SUMMARY), )``,
|
1079
1082
|
force rendering it as a table.
|
1080
1083
|
|
1081
|
-
:display_mode: override the table's
|
1082
|
-
<lino.core.tables.AbstractTable.
|
1084
|
+
:display_mode: override the table's default display_mode specified by
|
1085
|
+
:attr:`default_display_modes <lino.core.tables.AbstractTable.default_display_modes>`.
|
1083
1086
|
|
1084
1087
|
Unlike `nosummary` this can be used to ask a summary for
|
1085
1088
|
a table that would not show as summary by default.
|
1086
1089
|
Instead of saying `nosummary=True` you can say
|
1087
|
-
`display_mode=
|
1088
|
-
`display_mode=
|
1089
|
-
|
1090
|
-
|
1091
|
-
tested spec).
|
1090
|
+
`display_mode=DISPLAY_MODE_GRID` or
|
1091
|
+
`display_mode=DISPLAY_MODE_HTML` (The display
|
1092
|
+
modes DISPLAY_MODE_GRID and DISPLAY_MODE_HTML have the
|
1093
|
+
same result in a printed document or in a tested spec).
|
1092
1094
|
|
1093
1095
|
:header_level: show also the table header (using specified level)
|
1094
1096
|
|
@@ -1426,9 +1428,7 @@ class BaseRequest(object):
|
|
1426
1428
|
if ar.actor.parameters:
|
1427
1429
|
rec.update(
|
1428
1430
|
param_values=ar.actor.params_layout.params_store.pv2dict(
|
1429
|
-
ar, ar.param_values
|
1430
|
-
)
|
1431
|
-
)
|
1431
|
+
ar, ar.param_values))
|
1432
1432
|
|
1433
1433
|
return rec
|
1434
1434
|
|
lino/core/store.py
CHANGED
@@ -1192,7 +1192,7 @@ class Store(BaseStore):
|
|
1192
1192
|
# temporary dict used by collect_fields and add_field_for
|
1193
1193
|
# self.df2sf = {}
|
1194
1194
|
self.all_fields = []
|
1195
|
-
self.
|
1195
|
+
self.grid_fields = []
|
1196
1196
|
self.detail_fields = []
|
1197
1197
|
self.card_fields = []
|
1198
1198
|
self.item_fields = []
|
@@ -1202,11 +1202,11 @@ class Store(BaseStore):
|
|
1202
1202
|
if not isinstance(sf, StoreField):
|
1203
1203
|
raise Exception("20210623 {} is not a StoreField".format(sf))
|
1204
1204
|
self.all_fields.append(sf)
|
1205
|
-
self.
|
1205
|
+
self.grid_fields.append(sf)
|
1206
1206
|
self.detail_fields.append(sf)
|
1207
1207
|
|
1208
1208
|
if not issubclass(rh.actor, frames.Frame):
|
1209
|
-
self.collect_fields(self.
|
1209
|
+
self.collect_fields(self.grid_fields, rh.get_grid_layout())
|
1210
1210
|
|
1211
1211
|
form = rh.actor.detail_layout
|
1212
1212
|
if form:
|
@@ -1235,7 +1235,7 @@ class Store(BaseStore):
|
|
1235
1235
|
if self.pk is not None:
|
1236
1236
|
self.pk_index = 0
|
1237
1237
|
found = False
|
1238
|
-
for fld in self.
|
1238
|
+
for fld in self.grid_fields:
|
1239
1239
|
"""
|
1240
1240
|
Django's Field.__cmp__() does::
|
1241
1241
|
|
@@ -1251,8 +1251,8 @@ class Store(BaseStore):
|
|
1251
1251
|
self.pk_index += fld.list_values_count
|
1252
1252
|
if not found:
|
1253
1253
|
raise Exception(
|
1254
|
-
"Primary key %r not found in
|
1255
|
-
% (self.pk, [f.field for f in self.
|
1254
|
+
"Primary key %r not found in grid_fields %s"
|
1255
|
+
% (self.pk, [f.field for f in self.grid_fields])
|
1256
1256
|
)
|
1257
1257
|
|
1258
1258
|
actor_editable = True # not rh.actor.hide_editing(None)
|
@@ -1273,14 +1273,14 @@ class Store(BaseStore):
|
|
1273
1273
|
f for f in self.all_fields if not isinstance(f, VirtStoreField)
|
1274
1274
|
] + [f for f in self.all_fields if isinstance(f, VirtStoreField)]
|
1275
1275
|
self.all_fields = tuple(self.all_fields)
|
1276
|
-
self.
|
1276
|
+
self.grid_fields = tuple(self.grid_fields)
|
1277
1277
|
self.detail_fields = tuple(self.detail_fields)
|
1278
1278
|
self.card_fields = tuple(self.card_fields)
|
1279
1279
|
self.item_fields = tuple(self.item_fields)
|
1280
1280
|
|
1281
1281
|
def collect_fields(self, fields, *layouts):
|
1282
1282
|
"""`fields` is a pointer to either `self.detail_fields` or
|
1283
|
-
`self.
|
1283
|
+
`self.grid_fields`. Each of these must contain a primary key
|
1284
1284
|
field.
|
1285
1285
|
|
1286
1286
|
"""
|
@@ -1370,7 +1370,7 @@ class Store(BaseStore):
|
|
1370
1370
|
|
1371
1371
|
def column_names(self):
|
1372
1372
|
l = []
|
1373
|
-
for fld in self.
|
1373
|
+
for fld in self.grid_fields:
|
1374
1374
|
l += fld.column_names()
|
1375
1375
|
return l
|
1376
1376
|
|
@@ -1390,10 +1390,10 @@ class Store(BaseStore):
|
|
1390
1390
|
# logger.info("20120107 Store %s row2list(%s)", self.report.model, dd.obj2str(row))
|
1391
1391
|
l = []
|
1392
1392
|
if isinstance(row, PhantomRow):
|
1393
|
-
for fld in self.
|
1393
|
+
for fld in self.grid_fields:
|
1394
1394
|
fld.value2list(ar, None, l, row)
|
1395
1395
|
else:
|
1396
|
-
for fld in self.
|
1396
|
+
for fld in self.grid_fields:
|
1397
1397
|
if fld.delayed_value:
|
1398
1398
|
# self.actor.collect_extra_fields(fld)
|
1399
1399
|
v = DelayedValue(ar, fld.name, row)
|
lino/core/tablerequest.py
CHANGED
@@ -472,7 +472,7 @@ class TableRequest(ActionRequest):
|
|
472
472
|
tble.attrib.update(self.renderer.tableattrs)
|
473
473
|
tble.attrib.setdefault("name", self.bound_action.full_name())
|
474
474
|
|
475
|
-
grid = ar.ah.
|
475
|
+
grid = ar.ah.grid_layout.main
|
476
476
|
# from lino.core.widgets import GridWidget
|
477
477
|
# if not isinstance(grid, GridWidget):
|
478
478
|
# raise Exception("20160529 %r is not a GridElement", grid)
|
@@ -549,14 +549,14 @@ class TableRequest(ActionRequest):
|
|
549
549
|
ah = ar.actor.get_handle()
|
550
550
|
for i, cn in enumerate(columns):
|
551
551
|
col = None
|
552
|
-
for e in ah.
|
552
|
+
for e in ah.grid_layout.main.columns:
|
553
553
|
if e.name == cn:
|
554
554
|
col = e
|
555
555
|
break
|
556
556
|
if col is None:
|
557
557
|
raise Exception(
|
558
558
|
"No column named %r in %s"
|
559
|
-
% (cn, ar.ah.
|
559
|
+
% (cn, ar.ah.grid_layout.main.columns)
|
560
560
|
)
|
561
561
|
if not hiddens[i]:
|
562
562
|
fields.append(col)
|
@@ -570,8 +570,8 @@ class TableRequest(ActionRequest):
|
|
570
570
|
else:
|
571
571
|
ah = ar.actor.get_request_handle(ar)
|
572
572
|
|
573
|
-
columns = ah.
|
574
|
-
# print(20160530, ah, columns, ah.
|
573
|
+
columns = ah.grid_layout.main.columns
|
574
|
+
# print(20160530, ah, columns, ah.grid_layout.main)
|
575
575
|
|
576
576
|
# render them so that babelfields in hidden_languages
|
577
577
|
# get hidden:
|
lino/core/tables.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2009-
|
2
|
+
# Copyright 2009-2024 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
"""Defines the classes :class:`AbstractTable` and
|
5
5
|
:class:`VirtualTable`.
|
@@ -15,6 +15,7 @@ from django.db import models
|
|
15
15
|
from django.db.utils import OperationalError, ProgrammingError
|
16
16
|
from django.conf import settings
|
17
17
|
from django.utils.translation import gettext_lazy as _
|
18
|
+
from django.core.exceptions import BadRequest
|
18
19
|
|
19
20
|
from lino.core import actors
|
20
21
|
from lino.core import actions
|
@@ -114,7 +115,7 @@ class TableHandle(object):
|
|
114
115
|
def setup_layouts(self):
|
115
116
|
if self._layouts is not None:
|
116
117
|
return
|
117
|
-
self._layouts = [self.
|
118
|
+
self._layouts = [self.grid_layout]
|
118
119
|
|
119
120
|
def get_actor_url(self, *args, **kw):
|
120
121
|
return settings.SITE.kernel.get_actor_url(self.actor, *args, **kw)
|
@@ -122,12 +123,12 @@ class TableHandle(object):
|
|
122
123
|
def submit_elems(self):
|
123
124
|
return []
|
124
125
|
|
125
|
-
def
|
126
|
+
def get_grid_layout(self):
|
126
127
|
self.setup_layouts()
|
127
128
|
return self._layouts[0]
|
128
129
|
|
129
130
|
def get_columns(self):
|
130
|
-
lh = self.
|
131
|
+
lh = self.get_grid_layout()
|
131
132
|
# ~ print 20110315, layout._main.columns
|
132
133
|
return lh.main.columns
|
133
134
|
|
@@ -315,32 +316,44 @@ class AbstractTable(actors.Actor):
|
|
315
316
|
Usually such a warning means that there is something wrong.
|
316
317
|
"""
|
317
318
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
319
|
+
default_display_modes = {
|
320
|
+
70: constants.DISPLAY_MODE_SUMMARY,
|
321
|
+
None: constants.DISPLAY_MODE_GRID
|
322
|
+
}
|
322
323
|
"""
|
323
|
-
|
324
|
-
|
324
|
+
Which :term:`display mode` to use in a :term:`slave panel`,
|
325
|
+
depending on available width.
|
325
326
|
|
326
|
-
|
327
|
-
|
328
|
-
See also :meth:`get_display_mode` and :ref:`dev.format`.
|
327
|
+
See :ref:`dg.table.default_display_modes`.
|
329
328
|
"""
|
330
329
|
|
331
330
|
@classmethod
|
332
|
-
def get_display_mode(cls, available_width=None):
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
331
|
+
# def get_display_mode(cls, available_width=None):
|
332
|
+
def get_display_mode(cls):
|
333
|
+
"""Return the fallback :term:`display mode` to use."""
|
334
|
+
return cls.default_display_modes[None]
|
335
|
+
# rv = cls.default_display_modes[None]
|
336
|
+
# if available_width is not None:
|
337
|
+
# found = None
|
338
|
+
# for w, v in cls.default_display_modes.items():
|
339
|
+
# if w is not None and w <= available_width:
|
340
|
+
# if found is None:
|
341
|
+
# found = w
|
342
|
+
# rv = v
|
343
|
+
# elif found > w:
|
344
|
+
# found = w
|
345
|
+
# rv = v
|
346
|
+
# return rv
|
347
|
+
# current_choice = (0, None)
|
348
|
+
# for dmi in cls.display_mode:
|
349
|
+
# if available_width is not None:
|
350
|
+
# if dmi[0] is None and current_choice[0] == 0:
|
351
|
+
# current_choice = (0, dmi[1])
|
352
|
+
# elif available_width > dmi[0] > current_choice[0]:
|
353
|
+
# current_choice = dmi
|
354
|
+
# elif dmi[0] is None:
|
355
|
+
# return dmi[1]
|
356
|
+
# return current_choice[1]
|
344
357
|
|
345
358
|
max_render_depth = 2
|
346
359
|
"""
|
@@ -613,6 +626,7 @@ method in order to sort the rows of the queryset.
|
|
613
626
|
logger.warning(msg)
|
614
627
|
# raise Exception(msg)
|
615
628
|
# raise PermissionDenied(msg)
|
629
|
+
# raise BadRequest(msg)
|
616
630
|
# master_instance = None
|
617
631
|
return # cannot add rows to this table
|
618
632
|
kw[self.master_field.name] = master_instance
|
lino/mixins/dupable.py
CHANGED
@@ -266,7 +266,7 @@ DupableChecker.activate()
|
|
266
266
|
class SimilarObjects(dd.VirtualTable):
|
267
267
|
"""Shows the other objects that are similar to this one."""
|
268
268
|
|
269
|
-
|
269
|
+
default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
|
270
270
|
master = dd.Model
|
271
271
|
abstract = True
|
272
272
|
|
lino/modlib/checkdata/models.py
CHANGED
@@ -180,7 +180,7 @@ class MessagesByOwner(Messages):
|
|
180
180
|
|
181
181
|
master_key = "owner"
|
182
182
|
column_names = "message checker user #fixable *"
|
183
|
-
|
183
|
+
default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
|
184
184
|
|
185
185
|
|
186
186
|
# This was the first use case of a slave table with something else than a model
|
lino/modlib/comments/mixins.py
CHANGED
@@ -51,7 +51,7 @@ class AddCommentField(dd.VirtualField):
|
|
51
51
|
"""
|
52
52
|
|
53
53
|
editable = True
|
54
|
-
simple_elem = True
|
54
|
+
# simple_elem = True
|
55
55
|
|
56
56
|
def __init__(self, slave_table):
|
57
57
|
t = models.TextField(_("Add comment"), blank=True)
|
@@ -94,7 +94,7 @@ class Commentable(MemoReferrable):
|
|
94
94
|
|
95
95
|
create_comment_template = _("Created new {model} {obj}.")
|
96
96
|
|
97
|
-
add_comment = AddCommentField("comments.CommentsByRFC")
|
97
|
+
# add_comment = AddCommentField("comments.CommentsByRFC")
|
98
98
|
|
99
99
|
def on_commented(self, comment, ar, cw):
|
100
100
|
pass
|