Gramex 1.89 release notes

Gramex 1.89 supports case-insensitive search, distributed user logs, feature usage reports, and complexity reports.

FormHandler filters has 2 new operators *= and !*= that match case-insensitively.

?Name*=united matches “united” in any case, e.g. “United” and “UNITED”

ID Name Continent
ARE United Arab Emirates Asia
GBR United Kingdom Europe
USA United States North America

Similarly, ?Name!*=united skips “united” in any case, e.g. “United” and “UNITED”

This currently works for in-memory data frames as well as all SQLAlchemy databases, but not yet for MongoDB, InfluxDB and ServiceNow.

Distributed user logs

When a user logs in or out, Gramex logs the event to a user log store. This is useful for auditing, reporting, and debugging.

Earlier, this was stored as logs/user.csv under $GRAMEXDATA. But this could not be shared across multiple machines.

Now, this is stored in a database. The default database is sqlite:///$GRAMEXDATA/auth.user.db and the default table is userlog. You can change these in gramex.yaml:

storelocations:
  userlog:
    url: postgresql://$USER:$PASS@server/db
    # url: mysql+pymysql://$USER:$PASS@server/db
    # ...
    table: userlog

You can set the columns to log with any key in request logging. Below is the default.

storelocations:
  userlog:
    columns:
      # You MUST add these 3 columns
      event: TEXT # Type of event: login/logout/fail
      datetime: TEXT # Time of event, ISO8601 encoded (YYYY-MM-DD HH:MM:SSZ)
      user: TEXT # User ID (e.g. user name or email address, depending on handler)
      # You can change / update any of these
      port: INTEGER # Port on which Gramex is running
      uri: TEXT # URL where the user logged in
      name: TEXT # Name of the handler
      class: TEXT # Class of the handler (e.g. SimpleAuth, GoogleAuth, etc)
      ip: TEXT # IP address of the client
      browser: TEXT # Browser name
      # request.method: TEXT
      # env.HOME: TEXT

Measure Gramex usage

Run gramex features on any Gramex app to list the features used. Here’s an example:

$ gramex features
      type                       feature  count
0       MS                CaptureHandler      2
1       MS                  ComicHandler      1
2       MS                   FileHandler     67
...
18   KWARG                Access Control     53
19   KWARG                      Security     12
...
27     SVC                  Microservice      2
28     SVC                        Import      0
...
41  ERR-MS     handlerutil.CustomHandler      1
42  ERR-MS      handlerutil.SetupHandler      1

The columns are:

You can render the output in different formats:

Pass multiple folders, e.g. gramex features /project1/ /project2/, to sum features used across folders.

Measure code complexity

Run gramex complexity on any Gramex app to measure the Cyclomatic Complexity of the code.

Here’s an example:

$ gramex complexity
    py   js  gramex
0  121  345    2782

The columns are:

This is useful to see what % of the code re-uses Gramex code, and what % is custom code.

Put another way, without Gramex, the project would have a complexity of 122 + 345 + 2,782 = 3,249.

Gramex reduces 2,782 / 3,249 = 86% of the code.

Backward compatibility & security

Gramex 1.89 is backward compatible with previous releases unless the release notes say otherwise. We ensure this with automated tests.

Every Gramex release is tested for security vulnerabilities using the following tools.

  1. Bandit tests for back-end Python vulnerabilities. See Bandit results
  2. npm-audit tests for front-end JavaScript vulnerabilities. See npm-audit results
  3. Snyk for front-end and back-end vulnerabilities. See Synk results
  4. ClamAV for anti-virus scans. See ClamAV results
  5. Trivy for container scans. See Trivy results

Statistics

The Gramex code base has:

How to install

See the Gramex installation and upgrade instructions.