Compare commits
	
		
			6 commits
		
	
	
		
			bb2bde5ecd
			...
			c1a14b4869
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c1a14b4869 | |||
| 027ace91f4 | |||
| 8b905289de | |||
| fdeb0eeeb2 | |||
| 6424432f1b | |||
| e6c495b40d | 
					 24 changed files with 210 additions and 191 deletions
				
			
		| 
						 | 
				
			
			@ -3,5 +3,10 @@
 | 
			
		|||
[MESSAGES CONTROL]
 | 
			
		||||
disable=all
 | 
			
		||||
enable=
 | 
			
		||||
        empty-docstring,
 | 
			
		||||
        inconsistent-return-statements,
 | 
			
		||||
        no-else-return,
 | 
			
		||||
        redefined-argument-from-local,
 | 
			
		||||
        too-many-branches,
 | 
			
		||||
        too-many-instance-attributes,
 | 
			
		||||
        too-many-return-statements,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
################################################################################
 | 
			
		||||
#
 | 
			
		||||
#  wuttaweb -- Web App for Wutta Framework
 | 
			
		||||
#  Copyright © 2024 Lance Edgar
 | 
			
		||||
#  Copyright © 2024-2025 Lance Edgar
 | 
			
		||||
#
 | 
			
		||||
#  This file is part of Wutta Framework.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ class WuttaWebConfigExtension(WuttaConfigExtension):
 | 
			
		|||
 | 
			
		||||
    key = "wuttaweb"
 | 
			
		||||
 | 
			
		||||
    def configure(self, config):
 | 
			
		||||
    def configure(self, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        config.setdefault(
 | 
			
		||||
            "wutta_continuum.wutta_plugin_spec",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,14 +43,14 @@ else:
 | 
			
		|||
        # TODO: should find a better way, threadlocals are bad?
 | 
			
		||||
        # https://docs.pylonsproject.org/projects/pyramid/en/latest/api/threadlocal.html#pyramid.threadlocal.get_current_request
 | 
			
		||||
 | 
			
		||||
        def get_remote_addr(self, uow, session):
 | 
			
		||||
        def get_remote_addr(self, uow, session):  # pylint: disable=empty-docstring
 | 
			
		||||
            """ """
 | 
			
		||||
            request = get_current_request()
 | 
			
		||||
            if request:
 | 
			
		||||
                return request.client_addr
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        def get_user_id(self, uow, session):
 | 
			
		||||
        def get_user_id(self, uow, session):  # pylint: disable=empty-docstring
 | 
			
		||||
            """ """
 | 
			
		||||
            request = get_current_request()
 | 
			
		||||
            if request and request.user:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
################################################################################
 | 
			
		||||
#
 | 
			
		||||
#  wuttaweb -- Web App for Wutta Framework
 | 
			
		||||
#  Copyright © 2024 Lance Edgar
 | 
			
		||||
#  Copyright © 2024-2025 Lance Edgar
 | 
			
		||||
#
 | 
			
		||||
#  This file is part of Wutta Framework.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ class feedback(EmailSetting):
 | 
			
		|||
 | 
			
		||||
    default_subject = "User Feedback"
 | 
			
		||||
 | 
			
		||||
    def sample_data(self):
 | 
			
		||||
    def sample_data(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        person = model.Person(full_name="Barney Rubble")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -592,7 +592,7 @@ class Form:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
        self.set_widget(key, widget)
 | 
			
		||||
        self.add_grid_vue_context(grid)
 | 
			
		||||
 | 
			
		||||
    def add_grid_vue_context(self, grid):
 | 
			
		||||
    def add_grid_vue_context(self, grid):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if not grid.key:
 | 
			
		||||
            raise ValueError("grid must have a key!")
 | 
			
		||||
| 
						 | 
				
			
			@ -777,7 +777,7 @@ class Form:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
            self.config, model_class=model_class or self.model_class
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def get_schema(self):
 | 
			
		||||
    def get_schema(self):  # pylint: disable=too-many-branches
 | 
			
		||||
        """
 | 
			
		||||
        Return the :class:`colander:colander.Schema` object for the
 | 
			
		||||
        form, generating it automatically if necessary.
 | 
			
		||||
| 
						 | 
				
			
			@ -1146,7 +1146,7 @@ class Form:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
 | 
			
		||||
    # TODO: for tailbone compat, should document?
 | 
			
		||||
    # (ideally should remove this and find a better way)
 | 
			
		||||
    def get_vue_field_value(self, key):
 | 
			
		||||
    def get_vue_field_value(self, key):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if key not in self.fields:
 | 
			
		||||
            return None
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ class WuttaDateTime(colander.DateTime):
 | 
			
		|||
    the Buefy datepicker + timepicker widgets.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def deserialize(  # pylint: disable=inconsistent-return-statements
 | 
			
		||||
    def deserialize(  # pylint: disable=inconsistent-return-statements,empty-docstring
 | 
			
		||||
        self, node, cstruct
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ class WuttaEnum(colander.Enum):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def widget_maker(self, **kwargs):
 | 
			
		||||
    def widget_maker(self, **kwargs):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        if "values" not in kwargs:
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +181,7 @@ class WuttaDictEnum(colander.String):
 | 
			
		|||
        self.app = self.config.get_app()
 | 
			
		||||
        self.enum_dct = enum_dct
 | 
			
		||||
 | 
			
		||||
    def widget_maker(self, **kwargs):
 | 
			
		||||
    def widget_maker(self, **kwargs):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if "values" not in kwargs:
 | 
			
		||||
            kwargs["values"] = [(k, v) for k, v in self.enum_dct.items()]
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +210,7 @@ class WuttaMoney(colander.Money):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def widget_maker(self, **kwargs):
 | 
			
		||||
    def widget_maker(self, **kwargs):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if self.scale:
 | 
			
		||||
            kwargs.setdefault("scale", self.scale)
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +234,7 @@ class WuttaQuantity(colander.Decimal):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def serialize(self, node, appstruct):
 | 
			
		||||
    def serialize(self, node, appstruct):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if appstruct in (colander.null, None):
 | 
			
		||||
            return colander.null
 | 
			
		||||
| 
						 | 
				
			
			@ -324,7 +324,7 @@ class ObjectRef(colander.SchemaType):
 | 
			
		|||
        class_name = self.__class__.__name__
 | 
			
		||||
        raise NotImplementedError(f"you must define {class_name}.model_class")
 | 
			
		||||
 | 
			
		||||
    def serialize(self, node, appstruct):
 | 
			
		||||
    def serialize(self, node, appstruct):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        # nb. normalize to empty option if no object ref, so that
 | 
			
		||||
        # works as expected
 | 
			
		||||
| 
						 | 
				
			
			@ -353,7 +353,7 @@ class ObjectRef(colander.SchemaType):
 | 
			
		|||
        """
 | 
			
		||||
        return obj.uuid.hex
 | 
			
		||||
 | 
			
		||||
    def deserialize(self, node, cstruct):
 | 
			
		||||
    def deserialize(self, node, cstruct):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if not cstruct:
 | 
			
		||||
            return colander.null
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +361,7 @@ class ObjectRef(colander.SchemaType):
 | 
			
		|||
        # nb. use shortcut to fetch model instance from DB
 | 
			
		||||
        return self.objectify(cstruct)
 | 
			
		||||
 | 
			
		||||
    def dictify(self, obj):
 | 
			
		||||
    def dictify(self, obj):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # TODO: would we ever need to do something else?
 | 
			
		||||
| 
						 | 
				
			
			@ -466,16 +466,16 @@ class PersonRef(ObjectRef):
 | 
			
		|||
    """
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def model_class(self):
 | 
			
		||||
    def model_class(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        return model.Person
 | 
			
		||||
 | 
			
		||||
    def sort_query(self, query):
 | 
			
		||||
    def sort_query(self, query):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return query.order_by(self.model_class.full_name)
 | 
			
		||||
 | 
			
		||||
    def get_object_url(self, person):
 | 
			
		||||
    def get_object_url(self, person):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return self.request.route_url("people.view", uuid=person.uuid)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -490,16 +490,16 @@ class RoleRef(ObjectRef):
 | 
			
		|||
    """
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def model_class(self):
 | 
			
		||||
    def model_class(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        return model.Role
 | 
			
		||||
 | 
			
		||||
    def sort_query(self, query):
 | 
			
		||||
    def sort_query(self, query):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return query.order_by(self.model_class.name)
 | 
			
		||||
 | 
			
		||||
    def get_object_url(self, role):
 | 
			
		||||
    def get_object_url(self, role):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return self.request.route_url("roles.view", uuid=role.uuid)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -514,16 +514,16 @@ class UserRef(ObjectRef):
 | 
			
		|||
    """
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def model_class(self):
 | 
			
		||||
    def model_class(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        return model.User
 | 
			
		||||
 | 
			
		||||
    def sort_query(self, query):
 | 
			
		||||
    def sort_query(self, query):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return query.order_by(self.model_class.username)
 | 
			
		||||
 | 
			
		||||
    def get_object_url(self, user):
 | 
			
		||||
    def get_object_url(self, user):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return self.request.route_url("users.view", uuid=user.uuid)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -641,7 +641,7 @@ class FileDownload(colander.String):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def widget_maker(self, **kwargs):
 | 
			
		||||
    def widget_maker(self, **kwargs):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        kwargs.setdefault("url", self.url)
 | 
			
		||||
        return widgets.FileDownloadWidget(self.request, **kwargs)
 | 
			
		||||
| 
						 | 
				
			
			@ -653,13 +653,14 @@ class EmailRecipients(colander.String):
 | 
			
		|||
    (``To``, ``Cc``, ``Bcc``).
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def serialize(self, node, appstruct):
 | 
			
		||||
    def serialize(self, node, appstruct):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if appstruct is colander.null:
 | 
			
		||||
            return colander.null
 | 
			
		||||
 | 
			
		||||
        return "\n".join(parse_list(appstruct))
 | 
			
		||||
 | 
			
		||||
    def deserialize(self, node, cstruct):
 | 
			
		||||
    def deserialize(self, node, cstruct):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if cstruct is colander.null:
 | 
			
		||||
            return colander.null
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,7 +110,9 @@ class ObjectRefWidget(SelectWidget):
 | 
			
		|||
        self.request = request
 | 
			
		||||
        self.url = url
 | 
			
		||||
 | 
			
		||||
    def get_template_values(self, field, cstruct, kw):
 | 
			
		||||
    def get_template_values(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, field, cstruct, kw
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        values = super().get_template_values(field, cstruct, kw)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +213,7 @@ class WuttaDateWidget(DateInputWidget):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        readonly = kw.get("readonly", self.readonly)
 | 
			
		||||
        if readonly and cstruct:
 | 
			
		||||
| 
						 | 
				
			
			@ -248,7 +250,7 @@ class WuttaDateTimeWidget(DateTimeInputWidget):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        readonly = kw.get("readonly", self.readonly)
 | 
			
		||||
        if readonly and cstruct:
 | 
			
		||||
| 
						 | 
				
			
			@ -286,7 +288,7 @@ class WuttaMoneyInputWidget(MoneyInputWidget):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        readonly = kw.get("readonly", self.readonly)
 | 
			
		||||
        if readonly:
 | 
			
		||||
| 
						 | 
				
			
			@ -327,7 +329,7 @@ class FileDownloadWidget(Widget):
 | 
			
		|||
        self.config = self.request.wutta_config
 | 
			
		||||
        self.app = self.config.get_app()
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        # nb. readonly is the only way this rolls
 | 
			
		||||
        kw["readonly"] = True
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +350,7 @@ class FileDownloadWidget(Widget):
 | 
			
		|||
        values = self.get_template_values(field, cstruct, kw)
 | 
			
		||||
        return field.renderer(template, **values)
 | 
			
		||||
 | 
			
		||||
    def readable_size(self, path):
 | 
			
		||||
    def readable_size(self, path):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        try:
 | 
			
		||||
            size = os.path.getsize(path)
 | 
			
		||||
| 
						 | 
				
			
			@ -407,7 +409,7 @@ class RoleRefsWidget(WuttaCheckboxChoiceWidget):
 | 
			
		|||
 | 
			
		||||
    readonly_template = "readonly/rolerefs"
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -461,7 +463,7 @@ class PermissionsWidget(WuttaCheckboxChoiceWidget):
 | 
			
		|||
    template = "permissions"
 | 
			
		||||
    readonly_template = "readonly/permissions"
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        kw.setdefault("permissions", self.permissions)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -493,7 +495,7 @@ class EmailRecipientsWidget(TextAreaWidget):
 | 
			
		|||
 | 
			
		||||
    readonly_template = "readonly/email_recips"
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        readonly = kw.get("readonly", self.readonly)
 | 
			
		||||
        if readonly:
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +503,7 @@ class EmailRecipientsWidget(TextAreaWidget):
 | 
			
		|||
 | 
			
		||||
        return super().serialize(field, cstruct, **kw)
 | 
			
		||||
 | 
			
		||||
    def deserialize(self, field, pstruct):
 | 
			
		||||
    def deserialize(self, field, pstruct):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if pstruct is colander.null:
 | 
			
		||||
            return colander.null
 | 
			
		||||
| 
						 | 
				
			
			@ -520,7 +522,7 @@ class BatchIdWidget(Widget):
 | 
			
		|||
    zero-padded 8-char string
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):
 | 
			
		||||
    def serialize(self, field, cstruct, **kw):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if cstruct is colander.null:
 | 
			
		||||
            return colander.null
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -426,8 +426,8 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
        self.set_columns(columns or self.get_columns())
 | 
			
		||||
        self.renderers = {}
 | 
			
		||||
        if renderers:
 | 
			
		||||
            for key, val in renderers.items():
 | 
			
		||||
                self.set_renderer(key, val)
 | 
			
		||||
            for k, val in renderers.items():
 | 
			
		||||
                self.set_renderer(k, val)
 | 
			
		||||
        self.set_default_renderers()
 | 
			
		||||
        self.set_tools(tools)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -470,8 +470,8 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
 | 
			
		||||
        # enums
 | 
			
		||||
        self.enums = {}
 | 
			
		||||
        for key in enums:
 | 
			
		||||
            self.set_enum(key, enums[key])
 | 
			
		||||
        for k in enums:
 | 
			
		||||
            self.set_enum(k, enums[k])
 | 
			
		||||
 | 
			
		||||
    def get_columns(self):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -1462,7 +1462,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
    # configuration methods
 | 
			
		||||
    ##############################
 | 
			
		||||
 | 
			
		||||
    def load_settings(self, persist=True):
 | 
			
		||||
    def load_settings(self, persist=True):  # pylint: disable=too-many-branches
 | 
			
		||||
        """
 | 
			
		||||
        Load all effective settings for the grid.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1594,7 +1594,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
            self.pagesize = settings["pagesize"]
 | 
			
		||||
            self.page = settings["page"]
 | 
			
		||||
 | 
			
		||||
    def request_has_settings(self, typ):
 | 
			
		||||
    def request_has_settings(self, typ):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        if typ == "filter" and self.filterable:
 | 
			
		||||
| 
						 | 
				
			
			@ -1615,7 +1615,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def get_setting(
 | 
			
		||||
    def get_setting(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, settings, key, src="session", default=None, normalize=lambda v: v
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
| 
						 | 
				
			
			@ -1641,7 +1641,9 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
        # okay then, default it is
 | 
			
		||||
        return default
 | 
			
		||||
 | 
			
		||||
    def update_filter_settings(self, settings, src=None):
 | 
			
		||||
    def update_filter_settings(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, settings, src=None
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        if not self.filterable:
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -1674,7 +1676,9 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
                    settings, f"{prefix}.value", src="session", default=""
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    def update_sort_settings(self, settings, src=None):
 | 
			
		||||
    def update_sort_settings(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, settings, src=None
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        if not (self.sortable and self.sort_on_backend):
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -1704,7 +1708,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
                    skey = f"sorters.{i}.{key}"
 | 
			
		||||
                    settings[skey] = self.get_setting(settings, skey, src="session")
 | 
			
		||||
 | 
			
		||||
    def update_page_settings(self, settings):
 | 
			
		||||
    def update_page_settings(self, settings):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if not (self.paginated and self.paginate_on_backend):
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -1731,7 +1735,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
            if page is not None:
 | 
			
		||||
                settings["page"] = int(page)
 | 
			
		||||
 | 
			
		||||
    def persist_settings(self, settings, dest=None):
 | 
			
		||||
    def persist_settings(self, settings, dest=None):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if dest not in ("session",):
 | 
			
		||||
            raise ValueError(f"invalid dest identifier: {dest}")
 | 
			
		||||
| 
						 | 
				
			
			@ -2316,7 +2320,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
            )
 | 
			
		||||
        return filters
 | 
			
		||||
 | 
			
		||||
    def object_to_dict(self, obj):
 | 
			
		||||
    def object_to_dict(self, obj):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        try:
 | 
			
		||||
            dct = dict(obj)
 | 
			
		||||
| 
						 | 
				
			
			@ -2392,7 +2396,7 @@ class Grid:  # pylint: disable=too-many-instance-attributes
 | 
			
		|||
            "row_classes": row_classes,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def get_vue_data(self):
 | 
			
		||||
    def get_vue_data(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        warnings.warn(
 | 
			
		||||
            "grid.get_vue_data() is deprecated; "
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ from wuttjamaican.util import UNSPECIFIED
 | 
			
		|||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VerbNotSupported(Exception):
 | 
			
		||||
class VerbNotSupported(Exception):  # pylint: disable=empty-docstring
 | 
			
		||||
    """ """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, verb):
 | 
			
		||||
| 
						 | 
				
			
			@ -510,7 +510,7 @@ class StringAlchemyFilter(AlchemyFilter):
 | 
			
		|||
 | 
			
		||||
    default_verbs = ["contains", "does_not_contain", "equal", "not_equal"]
 | 
			
		||||
 | 
			
		||||
    def coerce_value(self, value):
 | 
			
		||||
    def coerce_value(self, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if value is not None:
 | 
			
		||||
            value = str(value)
 | 
			
		||||
| 
						 | 
				
			
			@ -577,7 +577,7 @@ class IntegerAlchemyFilter(NumericAlchemyFilter):
 | 
			
		|||
    Subclass of :class:`NumericAlchemyFilter`.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def coerce_value(self, value):
 | 
			
		||||
    def coerce_value(self, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if value:
 | 
			
		||||
            try:
 | 
			
		||||
| 
						 | 
				
			
			@ -596,7 +596,7 @@ class BooleanAlchemyFilter(AlchemyFilter):
 | 
			
		|||
 | 
			
		||||
    default_verbs = ["is_true", "is_false"]
 | 
			
		||||
 | 
			
		||||
    def get_verbs(self):
 | 
			
		||||
    def get_verbs(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # get basic verbs from caller, or default list
 | 
			
		||||
| 
						 | 
				
			
			@ -617,7 +617,7 @@ class BooleanAlchemyFilter(AlchemyFilter):
 | 
			
		|||
 | 
			
		||||
        return verbs
 | 
			
		||||
 | 
			
		||||
    def coerce_value(self, value):
 | 
			
		||||
    def coerce_value(self, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if value is not None:
 | 
			
		||||
            return bool(value)
 | 
			
		||||
| 
						 | 
				
			
			@ -676,7 +676,7 @@ class DateAlchemyFilter(AlchemyFilter):
 | 
			
		|||
        # 'between':              "between",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def coerce_value(self, value):
 | 
			
		||||
    def coerce_value(self, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if value:
 | 
			
		||||
            if isinstance(value, datetime.date):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
################################################################################
 | 
			
		||||
#
 | 
			
		||||
#  wuttaweb -- Web App for Wutta Framework
 | 
			
		||||
#  Copyright © 2024 Lance Edgar
 | 
			
		||||
#  Copyright © 2024-2025 Lance Edgar
 | 
			
		||||
#
 | 
			
		||||
#  This file is part of Wutta Framework.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +213,7 @@ class MenuHandler(GenericHandler):
 | 
			
		|||
    # default internal logic
 | 
			
		||||
    ##############################
 | 
			
		||||
 | 
			
		||||
    def do_make_menus(self, request, **kwargs):
 | 
			
		||||
    def do_make_menus(self, request, **kwargs):  # pylint: disable=too-many-branches
 | 
			
		||||
        """
 | 
			
		||||
        This method is responsible for constructing the final menu
 | 
			
		||||
        set.  It first calls :meth:`make_menus()` to get the basic
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,14 +113,14 @@ class SessionProgress(ProgressBase):  # pylint: disable=too-many-instance-attrib
 | 
			
		|||
        self.session.save()
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def clear(self):
 | 
			
		||||
    def clear(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        self.session.clear()
 | 
			
		||||
        self.session["complete"] = False
 | 
			
		||||
        self.session["error"] = False
 | 
			
		||||
        self.session.save()
 | 
			
		||||
 | 
			
		||||
    def update(self, value):
 | 
			
		||||
    def update(self, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        self.session.load()
 | 
			
		||||
        self.session["value"] = value
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,7 +141,7 @@ def get_form_data(request):
 | 
			
		|||
    return request.POST
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_libver(
 | 
			
		||||
def get_libver(  # pylint: disable=too-many-return-statements,too-many-branches
 | 
			
		||||
    request,
 | 
			
		||||
    key,
 | 
			
		||||
    configured_only=False,
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +281,7 @@ def get_libver(
 | 
			
		|||
    return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_liburl(
 | 
			
		||||
def get_liburl(  # pylint: disable=too-many-return-statements,too-many-branches
 | 
			
		||||
    request,
 | 
			
		||||
    key,
 | 
			
		||||
    configured_only=False,
 | 
			
		||||
| 
						 | 
				
			
			@ -401,57 +401,57 @@ def get_liburl(
 | 
			
		|||
            return liburl + static.buefy_js.relpath
 | 
			
		||||
        return f"https://unpkg.com/buefy@{version}/dist/buefy.min.js"
 | 
			
		||||
 | 
			
		||||
    elif key == "buefy.css":
 | 
			
		||||
    if key == "buefy.css":
 | 
			
		||||
        if static and hasattr(static, "buefy_css"):
 | 
			
		||||
            return liburl + static.buefy_css.relpath
 | 
			
		||||
        return f"https://unpkg.com/buefy@{version}/dist/buefy.min.css"
 | 
			
		||||
 | 
			
		||||
    elif key == "vue":
 | 
			
		||||
    if key == "vue":
 | 
			
		||||
        if static and hasattr(static, "vue_js"):
 | 
			
		||||
            return liburl + static.vue_js.relpath
 | 
			
		||||
        return f"https://unpkg.com/vue@{version}/dist/vue.min.js"
 | 
			
		||||
 | 
			
		||||
    elif key == "vue_resource":
 | 
			
		||||
    if key == "vue_resource":
 | 
			
		||||
        if static and hasattr(static, "vue_resource_js"):
 | 
			
		||||
            return liburl + static.vue_resource_js.relpath
 | 
			
		||||
        return f"https://cdn.jsdelivr.net/npm/vue-resource@{version}"
 | 
			
		||||
 | 
			
		||||
    elif key == "fontawesome":
 | 
			
		||||
    if key == "fontawesome":
 | 
			
		||||
        if static and hasattr(static, "fontawesome_js"):
 | 
			
		||||
            return liburl + static.fontawesome_js.relpath
 | 
			
		||||
        return f"https://use.fontawesome.com/releases/v{version}/js/all.js"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_vue":
 | 
			
		||||
    if key == "bb_vue":
 | 
			
		||||
        if static and hasattr(static, "bb_vue_js"):
 | 
			
		||||
            return liburl + static.bb_vue_js.relpath
 | 
			
		||||
        return f"https://unpkg.com/vue@{version}/dist/vue.esm-browser.prod.js"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_oruga":
 | 
			
		||||
    if key == "bb_oruga":
 | 
			
		||||
        if static and hasattr(static, "bb_oruga_js"):
 | 
			
		||||
            return liburl + static.bb_oruga_js.relpath
 | 
			
		||||
        return f"https://unpkg.com/@oruga-ui/oruga-next@{version}/dist/oruga.mjs"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_oruga_bulma":
 | 
			
		||||
    if key == "bb_oruga_bulma":
 | 
			
		||||
        if static and hasattr(static, "bb_oruga_bulma_js"):
 | 
			
		||||
            return liburl + static.bb_oruga_bulma_js.relpath
 | 
			
		||||
        return f"https://unpkg.com/@oruga-ui/theme-bulma@{version}/dist/bulma.js"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_oruga_bulma_css":
 | 
			
		||||
    if key == "bb_oruga_bulma_css":
 | 
			
		||||
        if static and hasattr(static, "bb_oruga_bulma_css"):
 | 
			
		||||
            return liburl + static.bb_oruga_bulma_css.relpath
 | 
			
		||||
        return f"https://unpkg.com/@oruga-ui/theme-bulma@{version}/dist/bulma.css"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_fontawesome_svg_core":
 | 
			
		||||
    if key == "bb_fontawesome_svg_core":
 | 
			
		||||
        if static and hasattr(static, "bb_fontawesome_svg_core_js"):
 | 
			
		||||
            return liburl + static.bb_fontawesome_svg_core_js.relpath
 | 
			
		||||
        return f"https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-svg-core@{version}/+esm"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_free_solid_svg_icons":
 | 
			
		||||
    if key == "bb_free_solid_svg_icons":
 | 
			
		||||
        if static and hasattr(static, "bb_free_solid_svg_icons_js"):
 | 
			
		||||
            return liburl + static.bb_free_solid_svg_icons_js.relpath
 | 
			
		||||
        return f"https://cdn.jsdelivr.net/npm/@fortawesome/free-solid-svg-icons@{version}/+esm"
 | 
			
		||||
 | 
			
		||||
    elif key == "bb_vue_fontawesome":
 | 
			
		||||
    if key == "bb_vue_fontawesome":
 | 
			
		||||
        if static and hasattr(static, "bb_vue_fontawesome_js"):
 | 
			
		||||
            return liburl + static.bb_vue_fontawesome_js.relpath
 | 
			
		||||
        return (
 | 
			
		||||
| 
						 | 
				
			
			@ -546,7 +546,7 @@ def get_model_fields(config, model_class, include_fk=False):
 | 
			
		|||
    return fields
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def prop_is_fk(mapper, prop):
 | 
			
		||||
def prop_is_fk(mapper, prop):  # pylint: disable=empty-docstring
 | 
			
		||||
    """ """
 | 
			
		||||
    if not isinstance(prop, orm.ColumnProperty):
 | 
			
		||||
        return False
 | 
			
		||||
| 
						 | 
				
			
			@ -581,18 +581,18 @@ def make_json_safe(value, key=None, warn=True):
 | 
			
		|||
    if value is colander.null:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    elif isinstance(value, dict):
 | 
			
		||||
    if isinstance(value, dict):
 | 
			
		||||
        # recursively convert dict
 | 
			
		||||
        parent = dict(value)
 | 
			
		||||
        for key, value in parent.items():
 | 
			
		||||
            parent[key] = make_json_safe(value, key=key, warn=warn)
 | 
			
		||||
        for k, v in parent.items():
 | 
			
		||||
            parent[k] = make_json_safe(v, key=k, warn=warn)
 | 
			
		||||
        value = parent
 | 
			
		||||
 | 
			
		||||
    elif isinstance(value, list):
 | 
			
		||||
        # recursively convert list
 | 
			
		||||
        parent = list(value)
 | 
			
		||||
        for i, value in enumerate(parent):
 | 
			
		||||
            parent[i] = make_json_safe(value, key=key, warn=warn)
 | 
			
		||||
        for i, v in enumerate(parent):
 | 
			
		||||
            parent[i] = make_json_safe(v, key=key, warn=warn)
 | 
			
		||||
        value = parent
 | 
			
		||||
 | 
			
		||||
    elif isinstance(value, _uuid.UUID):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,8 +86,7 @@ class AuthView(View):
 | 
			
		|||
                headers = login_user(self.request, user)
 | 
			
		||||
                return self.redirect(referrer, headers=headers)
 | 
			
		||||
 | 
			
		||||
            else:
 | 
			
		||||
                self.request.session.flash("Invalid user credentials", "error")
 | 
			
		||||
            self.request.session.flash("Invalid user credentials", "error")
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            "index_title": self.app.get_title(),
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +190,7 @@ class AuthView(View):
 | 
			
		|||
 | 
			
		||||
        return {"index_title": str(self.request.user), "form": form}
 | 
			
		||||
 | 
			
		||||
    def change_password_make_schema(self):
 | 
			
		||||
    def change_password_make_schema(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        schema = colander.Schema()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,7 +121,7 @@ class BatchMasterView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return super().render_to_response(template, context)
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
| 
						 | 
				
			
			@ -144,20 +144,20 @@ class BatchMasterView(MasterView):
 | 
			
		|||
        # description
 | 
			
		||||
        g.set_link("description")
 | 
			
		||||
 | 
			
		||||
    def render_batch_id(self, batch, key, value):
 | 
			
		||||
    def render_batch_id(self, batch, key, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if value:
 | 
			
		||||
            batch_id = int(value)
 | 
			
		||||
            return f"{batch_id:08d}"
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def get_instance_title(self, batch):
 | 
			
		||||
    def get_instance_title(self, batch):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if batch.description:
 | 
			
		||||
            return f"{batch.id_str} {batch.description}"
 | 
			
		||||
        return batch.id_str
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=too-many-branches,empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
        batch = f.model_instance
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +378,7 @@ class BatchMasterView(MasterView):
 | 
			
		|||
    ##############################
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_row_model_class(cls):
 | 
			
		||||
    def get_row_model_class(cls):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if hasattr(cls, "row_model_class"):
 | 
			
		||||
            return cls.row_model_class
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +396,7 @@ class BatchMasterView(MasterView):
 | 
			
		|||
        query = self.Session.query(BatchRow).filter(BatchRow.batch == batch)
 | 
			
		||||
        return query
 | 
			
		||||
 | 
			
		||||
    def configure_row_grid(self, g):
 | 
			
		||||
    def configure_row_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_row_grid(g)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ class BatchMasterView(MasterView):
 | 
			
		|||
 | 
			
		||||
        g.set_renderer("status_code", self.render_row_status)
 | 
			
		||||
 | 
			
		||||
    def render_row_status(self, row, key, value):
 | 
			
		||||
    def render_row_status(self, row, key, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return row.STATUS.get(value, value)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -413,7 +413,7 @@ class BatchMasterView(MasterView):
 | 
			
		|||
    ##############################
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        cls._defaults(config)
 | 
			
		||||
        cls._batch_defaults(config)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ class CommonView(View):
 | 
			
		|||
        """
 | 
			
		||||
        return {"index_title": self.app.get_title()}
 | 
			
		||||
 | 
			
		||||
    def feedback(self):
 | 
			
		||||
    def feedback(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        session = Session()
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ class CommonView(View):
 | 
			
		|||
 | 
			
		||||
        return {"ok": True}
 | 
			
		||||
 | 
			
		||||
    def feedback_make_schema(self):
 | 
			
		||||
    def feedback_make_schema(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        schema = colander.Schema()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +132,7 @@ class CommonView(View):
 | 
			
		|||
 | 
			
		||||
        return schema
 | 
			
		||||
 | 
			
		||||
    def feedback_send(self, context):
 | 
			
		||||
    def feedback_send(self, context):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        self.app.send_email("feedback", context)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,7 +89,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
            data.append(self.normalize_setting(setting))
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def normalize_setting(self, setting):
 | 
			
		||||
    def normalize_setting(self, setting):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        key = setting.__name__
 | 
			
		||||
        return {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +107,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
            "enabled": self.email_handler.is_enabled(key),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
        # to
 | 
			
		||||
        g.set_renderer("to", self.render_to_short)
 | 
			
		||||
 | 
			
		||||
    def render_to_short(self, setting, field, value):
 | 
			
		||||
    def render_to_short(self, setting, field, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        recips = value
 | 
			
		||||
        if not recips:
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +134,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
        recips = ", ".join(recips[:2])
 | 
			
		||||
        return f"{recips}, ..."
 | 
			
		||||
 | 
			
		||||
    def get_instance(self):
 | 
			
		||||
    def get_instance(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        key = self.request.matchdict["key"]
 | 
			
		||||
        setting = self.email_handler.get_email_setting(key, instance=False)
 | 
			
		||||
| 
						 | 
				
			
			@ -143,11 +143,11 @@ class EmailSettingView(MasterView):
 | 
			
		|||
 | 
			
		||||
        raise self.notfound()
 | 
			
		||||
 | 
			
		||||
    def get_instance_title(self, setting):
 | 
			
		||||
    def get_instance_title(self, setting):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return setting["subject"]
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +173,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
        # enabled
 | 
			
		||||
        f.set_node("enabled", colander.Boolean())
 | 
			
		||||
 | 
			
		||||
    def persist(self, setting):
 | 
			
		||||
    def persist(self, setting):  # pylint: disable=too-many-branches,empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        session = self.Session()
 | 
			
		||||
        key = self.request.matchdict["key"]
 | 
			
		||||
| 
						 | 
				
			
			@ -233,7 +233,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
        # enabled
 | 
			
		||||
        save("enabled", "true" if setting["enabled"] else "false")
 | 
			
		||||
 | 
			
		||||
    def render_to_response(self, template, context):
 | 
			
		||||
    def render_to_response(self, template, context):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if self.viewing:
 | 
			
		||||
            setting = context["instance"]
 | 
			
		||||
| 
						 | 
				
			
			@ -270,7 +270,7 @@ class EmailSettingView(MasterView):
 | 
			
		|||
        return self.request.response
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        cls._email_defaults(config)
 | 
			
		||||
        cls._defaults(config)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -483,15 +483,15 @@ class MasterView(View):
 | 
			
		|||
                    context["pager_stats"] = grid.get_vue_pager_stats()
 | 
			
		||||
                return self.json_response(context)
 | 
			
		||||
 | 
			
		||||
            else:  # full, not partial
 | 
			
		||||
            # full, not partial
 | 
			
		||||
 | 
			
		||||
                # nb. when user asks to reset view, it is via the query
 | 
			
		||||
                # string.  if so we then redirect to discard that.
 | 
			
		||||
                if self.request.GET.get("reset-view"):
 | 
			
		||||
            # nb. when user asks to reset view, it is via the query
 | 
			
		||||
            # string.  if so we then redirect to discard that.
 | 
			
		||||
            if self.request.GET.get("reset-view"):
 | 
			
		||||
 | 
			
		||||
                    # nb. we want to preserve url hash if applicable
 | 
			
		||||
                    kw = {"_query": None, "_anchor": self.request.GET.get("hash")}
 | 
			
		||||
                    return self.redirect(self.request.current_route_url(**kw))
 | 
			
		||||
                # nb. we want to preserve url hash if applicable
 | 
			
		||||
                kw = {"_query": None, "_anchor": self.request.GET.get("hash")}
 | 
			
		||||
                return self.redirect(self.request.current_route_url(**kw))
 | 
			
		||||
 | 
			
		||||
            context["grid"] = grid
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -801,21 +801,21 @@ class MasterView(View):
 | 
			
		|||
            self.delete_bulk_action(data)
 | 
			
		||||
            return self.redirect(self.get_index_url())
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
        # start thread for delete; show progress page
 | 
			
		||||
        route_prefix = self.get_route_prefix()
 | 
			
		||||
        key = f"{route_prefix}.delete_bulk"
 | 
			
		||||
        progress = self.make_progress(key, success_url=self.get_index_url())
 | 
			
		||||
        thread = threading.Thread(
 | 
			
		||||
            target=self.delete_bulk_thread,
 | 
			
		||||
            args=(data,),
 | 
			
		||||
            kwargs={"progress": progress},
 | 
			
		||||
        )
 | 
			
		||||
        thread.start()
 | 
			
		||||
        return self.render_progress(progress)
 | 
			
		||||
 | 
			
		||||
            # start thread for delete; show progress page
 | 
			
		||||
            route_prefix = self.get_route_prefix()
 | 
			
		||||
            key = f"{route_prefix}.delete_bulk"
 | 
			
		||||
            progress = self.make_progress(key, success_url=self.get_index_url())
 | 
			
		||||
            thread = threading.Thread(
 | 
			
		||||
                target=self.delete_bulk_thread,
 | 
			
		||||
                args=(data,),
 | 
			
		||||
                kwargs={"progress": progress},
 | 
			
		||||
            )
 | 
			
		||||
            thread.start()
 | 
			
		||||
            return self.render_progress(progress)
 | 
			
		||||
 | 
			
		||||
    def delete_bulk_thread(self, query, success_url=None, progress=None):
 | 
			
		||||
    def delete_bulk_thread(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, query, success_url=None, progress=None
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        model_title_plural = self.get_model_title_plural()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -867,7 +867,7 @@ class MasterView(View):
 | 
			
		|||
            delete, data, progress, message=f"Deleting {model_title_plural}"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def delete_bulk_make_button(self):
 | 
			
		||||
    def delete_bulk_make_button(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        route_prefix = self.get_route_prefix()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1111,7 +1111,9 @@ class MasterView(View):
 | 
			
		|||
        :param progress: Optional progress indicator factory.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
    def execute_thread(self, key, user_uuid, progress=None):
 | 
			
		||||
    def execute_thread(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, key, user_uuid, progress=None
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        model_title = self.get_model_title()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
################################################################################
 | 
			
		||||
#
 | 
			
		||||
#  wuttaweb -- Web App for Wutta Framework
 | 
			
		||||
#  Copyright © 2024 Lance Edgar
 | 
			
		||||
#  Copyright © 2024-2025 Lance Edgar
 | 
			
		||||
#
 | 
			
		||||
#  This file is part of Wutta Framework.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ class PersonView(MasterView):
 | 
			
		|||
        "users",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ class PersonView(MasterView):
 | 
			
		|||
        # last_name
 | 
			
		||||
        g.set_link("last_name")
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
        person = f.model_instance
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,7 @@ class PersonView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return grid
 | 
			
		||||
 | 
			
		||||
    def objectify(self, form):
 | 
			
		||||
    def objectify(self, form):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        person = super().objectify(form)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +138,7 @@ class PersonView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return person
 | 
			
		||||
 | 
			
		||||
    def autocomplete_query(self, term):
 | 
			
		||||
    def autocomplete_query(self, term):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        session = self.Session()
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ class PersonView(MasterView):
 | 
			
		|||
        query = query.filter(sa.and_(*criteria)).order_by(model.Person.full_name)
 | 
			
		||||
        return query
 | 
			
		||||
 | 
			
		||||
    def view_profile(self, session=None):
 | 
			
		||||
    def view_profile(self, session=None):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        person = self.get_instance(session=session)
 | 
			
		||||
        context = {
 | 
			
		||||
| 
						 | 
				
			
			@ -156,13 +156,13 @@ class PersonView(MasterView):
 | 
			
		|||
        }
 | 
			
		||||
        return self.render_to_response("view_profile", context)
 | 
			
		||||
 | 
			
		||||
    def make_user(self):
 | 
			
		||||
    def make_user(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        self.request.session.flash("TODO: this feature is not yet supported", "error")
 | 
			
		||||
        return self.redirect(self.request.get_referrer())
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # nb. Person may come from custom model
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
################################################################################
 | 
			
		||||
#
 | 
			
		||||
#  wuttaweb -- Web App for Wutta Framework
 | 
			
		||||
#  Copyright © 2024 Lance Edgar
 | 
			
		||||
#  Copyright © 2024-2025 Lance Edgar
 | 
			
		||||
#
 | 
			
		||||
#  This file is part of Wutta Framework.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -72,14 +72,16 @@ class ReportView(MasterView):
 | 
			
		|||
        super().__init__(request, context=context)
 | 
			
		||||
        self.report_handler = self.app.get_report_handler()
 | 
			
		||||
 | 
			
		||||
    def get_grid_data(self, columns=None, session=None):
 | 
			
		||||
    def get_grid_data(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, columns=None, session=None
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        data = []
 | 
			
		||||
        for report in self.report_handler.get_reports().values():
 | 
			
		||||
            data.append(self.normalize_report(report))
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def normalize_report(self, report):
 | 
			
		||||
    def normalize_report(self, report):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return {
 | 
			
		||||
            "report_key": report.report_key,
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +89,7 @@ class ReportView(MasterView):
 | 
			
		|||
            "help_text": report.__doc__,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +103,7 @@ class ReportView(MasterView):
 | 
			
		|||
        # help_text
 | 
			
		||||
        g.set_searchable("help_text")
 | 
			
		||||
 | 
			
		||||
    def get_instance(self):
 | 
			
		||||
    def get_instance(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        key = self.request.matchdict["report_key"]
 | 
			
		||||
        report = self.report_handler.get_report(key)
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +112,7 @@ class ReportView(MasterView):
 | 
			
		|||
 | 
			
		||||
        raise self.notfound()
 | 
			
		||||
 | 
			
		||||
    def get_instance_title(self, report):
 | 
			
		||||
    def get_instance_title(self, report):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return report["report_title"]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +151,7 @@ class ReportView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return self.render_to_response("view", context)
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
        key = self.request.matchdict["report_key"]
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +212,7 @@ class ReportView(MasterView):
 | 
			
		|||
        context["report_generated"] = datetime.datetime.now()
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def normalize_columns(self, columns):
 | 
			
		||||
    def normalize_columns(self, columns):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        normal = []
 | 
			
		||||
        for column in columns:
 | 
			
		||||
| 
						 | 
				
			
			@ -220,7 +222,7 @@ class ReportView(MasterView):
 | 
			
		|||
            normal.append(column)
 | 
			
		||||
        return normal
 | 
			
		||||
 | 
			
		||||
    def get_download_data(self):
 | 
			
		||||
    def get_download_data(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        key = self.request.matchdict["report_key"]
 | 
			
		||||
        report = self.report_handler.get_report(key)
 | 
			
		||||
| 
						 | 
				
			
			@ -229,14 +231,14 @@ class ReportView(MasterView):
 | 
			
		|||
        data = self.report_handler.make_report_data(report, params)
 | 
			
		||||
        return params, columns, data
 | 
			
		||||
 | 
			
		||||
    def get_download_path(self, data, ext):
 | 
			
		||||
    def get_download_path(self, data, ext):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        tempdir = tempfile.mkdtemp()
 | 
			
		||||
        filename = f"{data['output_title']}.{ext}"
 | 
			
		||||
        return os.path.join(tempdir, filename)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        cls._defaults(config)
 | 
			
		||||
        cls._report_defaults(config)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
################################################################################
 | 
			
		||||
#
 | 
			
		||||
#  wuttaweb -- Web App for Wutta Framework
 | 
			
		||||
#  Copyright © 2024 Lance Edgar
 | 
			
		||||
#  Copyright © 2024-2025 Lance Edgar
 | 
			
		||||
#
 | 
			
		||||
#  This file is part of Wutta Framework.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -59,13 +59,13 @@ class RoleView(MasterView):
 | 
			
		|||
    sort_defaults = "name"
 | 
			
		||||
 | 
			
		||||
    # TODO: master should handle this, possibly via configure_form()
 | 
			
		||||
    def get_query(self, session=None):
 | 
			
		||||
    def get_query(self, session=None):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        query = super().get_query(session=session)
 | 
			
		||||
        return query.order_by(model.Role.name)
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ class RoleView(MasterView):
 | 
			
		|||
        # notes
 | 
			
		||||
        g.set_renderer("notes", self.grid_render_notes)
 | 
			
		||||
 | 
			
		||||
    def is_editable(self, role):
 | 
			
		||||
    def is_editable(self, role):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        session = self.app.get_session(role)
 | 
			
		||||
        auth = self.app.get_auth_handler()
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ class RoleView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def is_deletable(self, role):
 | 
			
		||||
    def is_deletable(self, role):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        session = self.app.get_session(role)
 | 
			
		||||
        auth = self.app.get_auth_handler()
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ class RoleView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
        role = f.model_instance
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +171,7 @@ class RoleView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return grid
 | 
			
		||||
 | 
			
		||||
    def unique_name(self, node, value):
 | 
			
		||||
    def unique_name(self, node, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        session = Session()
 | 
			
		||||
| 
						 | 
				
			
			@ -266,7 +266,7 @@ class RoleView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return available
 | 
			
		||||
 | 
			
		||||
    def objectify(self, form):
 | 
			
		||||
    def objectify(self, form):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        # normal logic first
 | 
			
		||||
        role = super().objectify(form)
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +276,7 @@ class RoleView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return role
 | 
			
		||||
 | 
			
		||||
    def update_permissions(self, role, form):
 | 
			
		||||
    def update_permissions(self, role, form):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if "permissions" not in form.validated:
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -293,7 +293,7 @@ class RoleView(MasterView):
 | 
			
		|||
                    auth.revoke_permission(role, pkey)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        cls._defaults(config)
 | 
			
		||||
        cls._role_defaults(config)
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +340,7 @@ class PermissionView(MasterView):
 | 
			
		|||
        "permission",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_query(self, **kwargs):
 | 
			
		||||
    def get_query(self, **kwargs):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        query = super().get_query(**kwargs)
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +350,7 @@ class PermissionView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return query
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
| 
						 | 
				
			
			@ -363,7 +363,7 @@ class PermissionView(MasterView):
 | 
			
		|||
        # permission
 | 
			
		||||
        g.set_link("permission")
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,7 +71,9 @@ class AppInfoView(MasterView):
 | 
			
		|||
    # TODO: for tailbone backward compat with get_liburl() etc.
 | 
			
		||||
    weblib_config_prefix = None
 | 
			
		||||
 | 
			
		||||
    def get_grid_data(self, columns=None, session=None):
 | 
			
		||||
    def get_grid_data(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, columns=None, session=None
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # nb. init with empty data, only load it upon user request
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +93,7 @@ class AppInfoView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +105,7 @@ class AppInfoView(MasterView):
 | 
			
		|||
        # editable_project_location
 | 
			
		||||
        g.set_searchable("editable_project_location")
 | 
			
		||||
 | 
			
		||||
    def get_weblibs(self):
 | 
			
		||||
    def get_weblibs(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return OrderedDict(
 | 
			
		||||
            [
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +124,7 @@ class AppInfoView(MasterView):
 | 
			
		|||
            ]
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def configure_get_simple_settings(self):
 | 
			
		||||
    def configure_get_simple_settings(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        simple_settings = [
 | 
			
		||||
            # basics
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +173,7 @@ class AppInfoView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return simple_settings
 | 
			
		||||
 | 
			
		||||
    def configure_get_context(self, **kwargs):
 | 
			
		||||
    def configure_get_context(self, **kwargs):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        context = super().configure_get_context(**kwargs)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -240,14 +242,14 @@ class SettingView(MasterView):
 | 
			
		|||
    sort_defaults = "name"
 | 
			
		||||
 | 
			
		||||
    # TODO: master should handle this (per model key)
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
 | 
			
		||||
        # name
 | 
			
		||||
        g.set_link("name")
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +260,7 @@ class SettingView(MasterView):
 | 
			
		|||
        # TODO: master should handle this (per column nullable)
 | 
			
		||||
        f.set_required("value", False)
 | 
			
		||||
 | 
			
		||||
    def unique_name(self, node, value):
 | 
			
		||||
    def unique_name(self, node, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        session = self.Session()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
 | 
			
		||||
    sort_defaults = ("created", "desc")
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
        )
 | 
			
		||||
        g.set_filter("executed_by", Executor.username, label="Executed By Username")
 | 
			
		||||
 | 
			
		||||
    def grid_row_class(self, upgrade, data, i):
 | 
			
		||||
    def grid_row_class(self, upgrade, data, i):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
        if upgrade.status == enum.UpgradeStatus.EXECUTING:
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +119,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
            return "has-background-warning"
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +213,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
 | 
			
		||||
        super().delete_instance(upgrade)
 | 
			
		||||
 | 
			
		||||
    def objectify(self, form):
 | 
			
		||||
    def objectify(self, form):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        upgrade = super().objectify(form)
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
| 
						 | 
				
			
			@ -225,13 +225,15 @@ class UpgradeView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return upgrade
 | 
			
		||||
 | 
			
		||||
    def download_path(self, upgrade, filename):
 | 
			
		||||
    def download_path(self, upgrade, filename):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if filename:
 | 
			
		||||
            return self.get_upgrade_filepath(upgrade, filename)
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def get_upgrade_filepath(self, upgrade, filename=None, create=True):
 | 
			
		||||
    def get_upgrade_filepath(  # pylint: disable=empty-docstring
 | 
			
		||||
        self, upgrade, filename=None, create=True
 | 
			
		||||
    ):
 | 
			
		||||
        """ """
 | 
			
		||||
        uuid = str(upgrade.uuid)
 | 
			
		||||
        path = self.app.get_appdir(
 | 
			
		||||
| 
						 | 
				
			
			@ -287,7 +289,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
        else:
 | 
			
		||||
            upgrade.status = enum.UpgradeStatus.FAILURE
 | 
			
		||||
 | 
			
		||||
    def execute_progress(self):
 | 
			
		||||
    def execute_progress(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        route_prefix = self.get_route_prefix()
 | 
			
		||||
        upgrade = self.get_instance()
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +331,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def configure_get_simple_settings(self):
 | 
			
		||||
    def configure_get_simple_settings(self):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        script = self.config.get(f"{self.app.appname}.upgrades.command")
 | 
			
		||||
| 
						 | 
				
			
			@ -342,7 +344,7 @@ class UpgradeView(MasterView):
 | 
			
		|||
        ]
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # nb. Upgrade may come from custom model
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ class UserView(MasterView):
 | 
			
		|||
        "api_tokens",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def get_query(self, session=None):
 | 
			
		||||
    def get_query(self, session=None):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        query = super().get_query(session=session)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ class UserView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return query
 | 
			
		||||
 | 
			
		||||
    def configure_grid(self, g):
 | 
			
		||||
    def configure_grid(self, g):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_grid(g)
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
| 
						 | 
				
			
			@ -100,13 +100,13 @@ class UserView(MasterView):
 | 
			
		|||
        g.set_sorter("person", model.Person.full_name)
 | 
			
		||||
        g.set_filter("person", model.Person.full_name, label="Person Full Name")
 | 
			
		||||
 | 
			
		||||
    def grid_row_class(self, user, data, i):
 | 
			
		||||
    def grid_row_class(self, user, data, i):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        if not user.active:
 | 
			
		||||
            return "has-background-warning"
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def is_editable(self, user):
 | 
			
		||||
    def is_editable(self, user):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # only root can edit certain users
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ class UserView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def configure_form(self, f):
 | 
			
		||||
    def configure_form(self, f):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        super().configure_form(f)
 | 
			
		||||
        user = f.model_instance
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +161,7 @@ class UserView(MasterView):
 | 
			
		|||
        else:
 | 
			
		||||
            f.remove("api_tokens")
 | 
			
		||||
 | 
			
		||||
    def unique_username(self, node, value):
 | 
			
		||||
    def unique_username(self, node, value):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        session = self.Session()
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +175,7 @@ class UserView(MasterView):
 | 
			
		|||
        if query.count():
 | 
			
		||||
            node.raise_invalid("Username must be unique")
 | 
			
		||||
 | 
			
		||||
    def objectify(self, form):
 | 
			
		||||
    def objectify(self, form):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        model = self.app.model
 | 
			
		||||
        auth = self.app.get_auth_handler()
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +221,7 @@ class UserView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return user
 | 
			
		||||
 | 
			
		||||
    def update_roles(self, user, form):
 | 
			
		||||
    def update_roles(self, user, form):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        # TODO
 | 
			
		||||
        # if not self.has_perm('edit_roles'):
 | 
			
		||||
| 
						 | 
				
			
			@ -311,7 +311,7 @@ class UserView(MasterView):
 | 
			
		|||
 | 
			
		||||
        return grid
 | 
			
		||||
 | 
			
		||||
    def normalize_api_token(self, token):
 | 
			
		||||
    def normalize_api_token(self, token):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
        return {
 | 
			
		||||
            "uuid": token.uuid.hex,
 | 
			
		||||
| 
						 | 
				
			
			@ -366,7 +366,7 @@ class UserView(MasterView):
 | 
			
		|||
        return {}
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def defaults(cls, config):
 | 
			
		||||
    def defaults(cls, config):  # pylint: disable=empty-docstring
 | 
			
		||||
        """ """
 | 
			
		||||
 | 
			
		||||
        # nb. User may come from custom model
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,7 +121,7 @@ class TestUpgradeView(WebTestCase):
 | 
			
		|||
        model = self.app.model
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
 | 
			
		||||
        appdir = self.mkdir("app")
 | 
			
		||||
        appdir = self.mkdtemp()
 | 
			
		||||
        self.config.setdefault("wutta.appdir", appdir)
 | 
			
		||||
        self.assertEqual(self.app.get_appdir(), appdir)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +150,7 @@ class TestUpgradeView(WebTestCase):
 | 
			
		|||
        model = self.app.model
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
 | 
			
		||||
        appdir = self.mkdir("app")
 | 
			
		||||
        appdir = self.mkdtemp()
 | 
			
		||||
        self.config.setdefault("wutta.appdir", appdir)
 | 
			
		||||
        self.assertEqual(self.app.get_appdir(), appdir)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +181,7 @@ class TestUpgradeView(WebTestCase):
 | 
			
		|||
        model = self.app.model
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
 | 
			
		||||
        appdir = self.mkdir("app")
 | 
			
		||||
        appdir = self.mkdtemp()
 | 
			
		||||
        self.config.setdefault("wutta.appdir", appdir)
 | 
			
		||||
        self.assertEqual(self.app.get_appdir(), appdir)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +219,7 @@ class TestUpgradeView(WebTestCase):
 | 
			
		|||
        model = self.app.model
 | 
			
		||||
        enum = self.app.enum
 | 
			
		||||
 | 
			
		||||
        appdir = self.mkdir("app")
 | 
			
		||||
        appdir = self.mkdtemp()
 | 
			
		||||
        self.config.setdefault("wutta.appdir", appdir)
 | 
			
		||||
        self.assertEqual(self.app.get_appdir(), appdir)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue