From 4643aa3e3ce1cab16d095d07d9f6ff2dc947599e Mon Sep 17 00:00:00 2001
From: Lance Edgar <lance@edbob.org>
Date: Mon, 19 Aug 2024 11:47:21 -0500
Subject: [PATCH 1/3] docs: various improvements to docs, per dust settling

---
 src/wuttaweb/auth.py         | 18 ++++++++--------
 src/wuttaweb/forms/base.py   |  9 ++++++++
 src/wuttaweb/grids/base.py   | 41 ++++++++++++++++++++----------------
 src/wuttaweb/views/master.py |  2 +-
 src/wuttaweb/views/people.py |  1 +
 src/wuttaweb/views/roles.py  |  1 +
 6 files changed, 44 insertions(+), 28 deletions(-)

diff --git a/src/wuttaweb/auth.py b/src/wuttaweb/auth.py
index 88b1fea..e152576 100644
--- a/src/wuttaweb/auth.py
+++ b/src/wuttaweb/auth.py
@@ -150,7 +150,7 @@ class WuttaSecurityPolicy:
         return auth.has_permission(self.db_session, user, permission)
 
 
-def add_permission_group(pyramid_config, key, label=None, overwrite=True):
+def add_permission_group(pyramid_config, groupkey, label=None, overwrite=True):
     """
     Pyramid directive to add a "permission group" to the app's
     awareness.
@@ -169,12 +169,12 @@ def add_permission_group(pyramid_config, key, label=None, overwrite=True):
 
        pyramid_config.add_permission_group('widgets', label="Widgets")
 
-    :param key: Unique key for the permission group.  In the context
-       of a master view, this will be the same as
+    :param groupkey: Unique key for the permission group.  In the
+       context of a master view, this will be the same as
        :attr:`~wuttaweb.views.master.MasterView.permission_prefix`.
 
     :param label: Optional label for the permission group.  If not
-       specified, it is derived from ``key``.
+       specified, it is derived from ``groupkey``.
 
     :param overwrite: If the permission group was already established,
        this flag controls whether the group's label should be
@@ -186,9 +186,9 @@ def add_permission_group(pyramid_config, key, label=None, overwrite=True):
     app = config.get_app()
     def action():
         perms = pyramid_config.get_settings().get('wutta_permissions', {})
-        if overwrite or key not in perms:
-            group = perms.setdefault(key, {'key': key})
-            group['label'] = label or app.make_title(key)
+        if overwrite or groupkey not in perms:
+            group = perms.setdefault(groupkey, {'key': groupkey})
+            group['label'] = label or app.make_title(groupkey)
         pyramid_config.add_settings({'wutta_permissions': perms})
     pyramid_config.action(None, action)
 
@@ -215,8 +215,8 @@ def add_permission(pyramid_config, groupkey, key, label=None):
        pyramid_config.add_permission('widgets', 'widgets.polish',
                                      label="Polish all the widgets")
 
-    :param key: Unique key for the permission group.  In the context
-       of a master view, this will be the same as
+    :param groupkey: Unique key for the permission group.  In the
+       context of a master view, this will be the same as
        :attr:`~wuttaweb.views.master.MasterView.permission_prefix`.
 
     :param key: Unique key for the permission.  This should be the
diff --git a/src/wuttaweb/forms/base.py b/src/wuttaweb/forms/base.py
index 59cdc04..6b16bdd 100644
--- a/src/wuttaweb/forms/base.py
+++ b/src/wuttaweb/forms/base.py
@@ -182,6 +182,8 @@ class Form:
        String name for Vue component tag.  By default this is
        ``'wutta-form'``.  See also :meth:`render_vue_tag()`.
 
+       See also :attr:`vue_component`.
+
     .. attribute:: align_buttons_right
 
        Flag indicating whether the buttons (submit, cancel etc.)
@@ -784,6 +786,13 @@ class Form:
              </form>
            </script>
 
+           <script>
+               WuttaFormData = {}
+               WuttaForm = {
+                   template: 'wutta-form-template',
+               }
+           </script>
+
         .. todo::
 
            Why can't Sphinx render the above code block as 'html' ?
diff --git a/src/wuttaweb/grids/base.py b/src/wuttaweb/grids/base.py
index e193109..9a6b195 100644
--- a/src/wuttaweb/grids/base.py
+++ b/src/wuttaweb/grids/base.py
@@ -86,9 +86,9 @@ class Grid:
 
     .. attribute:: columns
 
-       :class:`~wuttaweb.forms.base.FieldList` instance containing
-       string column names for the grid.  Columns will appear in the
-       same order as they are in this list.
+       :class:`~wuttaweb.util.FieldList` instance containing string
+       column names for the grid.  Columns will appear in the same
+       order as they are in this list.
 
        See also :meth:`set_columns()` and :meth:`get_columns()`.
 
@@ -239,9 +239,9 @@ class Grid:
 
     .. attribute:: paginated
 
-       Boolean indicating whether the grid data should be paginated
-       vs. all data shown at once.  Default is ``False`` which means
-       the full set of grid data is sent for each request.
+       Boolean indicating whether the grid data should be paginated,
+       i.e. split up into pages.  Default is ``False`` which means all
+       data is shown at once.
 
        See also :attr:`pagesize` and :attr:`page`, and
        :attr:`paginate_on_backend`.
@@ -392,7 +392,7 @@ class Grid:
         Explicitly set the list of grid columns.
 
         This will overwrite :attr:`columns` with a new
-        :class:`~wuttaweb.forms.base.FieldList` instance.
+        :class:`~wuttaweb.util.FieldList` instance.
 
         :param columns: List of string column names.
         """
@@ -440,9 +440,8 @@ class Grid:
 
         :param label: New label for the column header.
 
-        See also :meth:`get_label()`.
-
-        Label overrides are tracked via :attr:`labels`.
+        See also :meth:`get_label()`.  Label overrides are tracked via
+        :attr:`labels`.
         """
         self.labels[key] = label
 
@@ -490,7 +489,7 @@ class Grid:
            def render_foo(record, key, value):
               return HTML.literal("<p>this is the final cell value</p>")
 
-           grid = Grid(columns=['foo', 'bar'])
+           grid = Grid(request, columns=['foo', 'bar'])
            grid.set_renderer('foo', render_foo)
 
         Renderer overrides are tracked via :attr:`renderers`.
@@ -509,8 +508,8 @@ class Grid:
         URL for this will be the same as for the "View"
         :class:`GridAction`
         (aka. :meth:`~wuttaweb.views.master.MasterView.view()`).
-        Although of course each cell gets a different link depending
-        on which data record it points to.
+        Although of course each cell in the column gets a different
+        link depending on which data record it points to.
 
         It is typical to enable auto-link for fields relating to ID,
         description etc. or some may prefer to auto-link all columns.
@@ -609,8 +608,8 @@ class Grid:
         The term "model property" is a bit technical, an example
         should help to clarify::
 
-           model = self.app.model
-           grid = Grid(self.request, model_class=model.Person)
+           model = app.model
+           grid = Grid(request, model_class=model.Person)
 
            # explicit property
            sorter = grid.make_sorter(model.Person.full_name)
@@ -633,7 +632,7 @@ class Grid:
            ]
 
            # nb. no model_class, just as an example
-           grid = Grid(self.request, columns=['foo', 'bar'], data=data)
+           grid = Grid(request, columns=['foo', 'bar'], data=data)
 
            def getkey(obj):
                if obj.get('foo')
@@ -725,8 +724,8 @@ class Grid:
         A backend sorter callable must accept ``(data, direction)``
         args and return the sorted data/query, for example::
 
-           model = self.app.model
-           grid = Grid(self.request, model_class=model.Person)
+           model = app.model
+           grid = Grid(request, model_class=model.Person)
 
            def sort_full_name(query, direction):
               sortspec = getattr(model.Person.full_name, direction)
@@ -750,6 +749,10 @@ class Grid:
         """
         Remove the backend sorter for a column.
 
+        Note that this removes the sorter *function*, so there is
+        no way to sort by this column unless another sorter is
+        later defined for it.
+
         See also :meth:`set_sorter()`.
         """
         self.sorters.pop(key, None)
@@ -1140,6 +1143,7 @@ class Grid:
 
         See also these methods which may be called by this one:
 
+        * :meth:`sort_data()`
         * :meth:`paginate_data()`
         """
         data = self.data or []
@@ -1283,6 +1287,7 @@ class Grid:
            {
                'field': 'foo',
                'label': "Foo",
+               'sortable': True,
            }
 
         See also :meth:`get_vue_data()`.
diff --git a/src/wuttaweb/views/master.py b/src/wuttaweb/views/master.py
index cc5af63..d43de9e 100644
--- a/src/wuttaweb/views/master.py
+++ b/src/wuttaweb/views/master.py
@@ -259,7 +259,7 @@ class MasterView(View):
 
     .. attribute:: form_fields
 
-       List of columns for the model form.
+       List of fields for the model form.
 
        This is optional; see also :meth:`get_form_fields()`.
 
diff --git a/src/wuttaweb/views/people.py b/src/wuttaweb/views/people.py
index e216027..5097d06 100644
--- a/src/wuttaweb/views/people.py
+++ b/src/wuttaweb/views/people.py
@@ -101,6 +101,7 @@ class PersonView(MasterView):
 
     @classmethod
     def defaults(cls, config):
+        """ """
         cls._defaults(config)
         cls._people_defaults(config)
 
diff --git a/src/wuttaweb/views/roles.py b/src/wuttaweb/views/roles.py
index 3f2e350..0da0712 100644
--- a/src/wuttaweb/views/roles.py
+++ b/src/wuttaweb/views/roles.py
@@ -246,6 +246,7 @@ class RoleView(MasterView):
 
     @classmethod
     def defaults(cls, config):
+        """ """
         cls._defaults(config)
         cls._role_defaults(config)
 

From 1efaca4e52f3359977a0e6ba3fa78777af15e314 Mon Sep 17 00:00:00 2001
From: Lance Edgar <lance@edbob.org>
Date: Mon, 19 Aug 2024 11:48:52 -0500
Subject: [PATCH 2/3] fix: make `util.get_model_fields()` work with more model
 classes

should not restrict to classes inheriting from wuttjamaican base, any
sqlalchemy class should work
---
 src/wuttaweb/util.py | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/wuttaweb/util.py b/src/wuttaweb/util.py
index 2f0e592..0b230b4 100644
--- a/src/wuttaweb/util.py
+++ b/src/wuttaweb/util.py
@@ -462,14 +462,13 @@ def get_model_fields(config, model_class=None):
     if not model_class:
         return
 
-    app = config.get_app()
-    model = app.model
-    if not issubclass(model_class, model.Base):
-        return
-
-    mapper = sa.inspect(model_class)
-    fields = [prop.key for prop in mapper.iterate_properties]
-    return fields
+    try:
+        mapper = sa.inspect(model_class)
+    except sa.exc.NoInspectionAvailable:
+        pass
+    else:
+        fields = [prop.key for prop in mapper.iterate_properties]
+        return fields
 
 
 def make_json_safe(value, key=None, warn=True):

From dce91a3a96fb7619e68c73eafd037fa44002adde Mon Sep 17 00:00:00 2001
From: Lance Edgar <lance@edbob.org>
Date: Mon, 19 Aug 2024 12:00:46 -0500
Subject: [PATCH 3/3] =?UTF-8?q?bump:=20version=200.10.0=20=E2=86=92=200.10?=
 =?UTF-8?q?.1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CHANGELOG.md   | 6 ++++++
 pyproject.toml | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 76568fe..2c95667 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to wuttaweb will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## v0.10.1 (2024-08-19)
+
+### Fix
+
+- make `util.get_model_fields()` work with more model classes
+
 ## v0.10.0 (2024-08-18)
 
 ### Feat
diff --git a/pyproject.toml b/pyproject.toml
index bfaf855..cc4cdf2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
 
 [project]
 name = "WuttaWeb"
-version = "0.10.0"
+version = "0.10.1"
 description = "Web App for Wutta Framework"
 readme = "README.md"
 authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]