Advanced configuration topics.¶
Support for the self-hosted Grist.¶
The Grist API works the same way for both the regular SaaS Grist (the one you get at www.getgrist.com) and the self-managed version - and so does Pygrister.
To learn about the self-hosted version of Grist read the Grist documentation.
If you want to use Pygrister against a self-hosted Grist instance, you need to set up a few more configuration options.
First, set GRIST_SELF_MANAGED to Y. Then, you need to set
GRIST_SELF_MANAGED_HOME to the “home page” url of your Grist server, eg.
https://grist.mysite.com. The suggested default http://localhost:8484
is the usual access point of a test instance running locally.
Please note: if you are serving Grist from a public host, then Pygrister’s
GRIST_SELF_MANAGED_HOME must be set to the same url of the APP_HOME_URL
variable that you will provide to the Grist environment.
Finally, if you are running the single-team flavour of Grist, you need to
set GRIST_SELF_MANAGED_SINGLE_ORG to Y (the default). The name of
the team must then be specified in GRIST_TEAM_SITE (which you should never
change at runtime, of course).
Again, remember that you will still need to provide a GRIST_SINGLE_ORG
variable to the Grist environment, set to the same team name as in Pygrister’s
GRIST_TEAM_SITE.
(A little duplication here is inevitable, since Pygrister and Grist will usually run in completely separate environments, and they can’t access each other’s variables.)
When GRIST_SELF_MANAGED is set Y and the self-hosted Grist support is
enabled in Pygrister, the configuration keys GRIST_SERVER_PROTOCOL and
GRIST_API_SERVER will be ignored, and GRIST_SELF_MANAGED_HOME
will be used instead. The remaining configuration keys will work as usual.
Support for Grist Desktop.¶
Grist Desktop is basically a
self-hosted Grist, packaged as an Electron application: hence, Pygrister will
work just fine there too. The only catch is that you should provide a
GRIST_DESKTOP_AUTH env variable to enable API calls, which are disabled by
default (for instance you may set it to =none, see
this forum thread
for more details).
Also, keep in mind that Grist Deskop will use port 47478 by default. All things considered, a Pygrister configuration like this should work for Grist Desktop:
{
'GRIST_API_KEY': '<your_api_key_here>',
'GRIST_SELF_MANAGED': 'Y',
'GRIST_SELF_MANAGED_HOME': 'http://localhost:47478',
'GRIST_SELF_MANAGED_SINGLE_ORG': 'N',
'GRIST_TEAM_SITE': 'docs',
}
Just set GRIST_DESKTOP_AUTH, start Grist Deskop, generate an API key
there, and you should be able to place API calls with Pygrister as well.
App-specific configuration.¶
Having multiple config json files for different applications/workflows is not supported. However, this is hardly a problem: just provide your custom json file and load it at runtime:
with open('myconfig.json', 'r') as f:
myconfig = json.loads(f.read())
grist = GristApi(config=myconfig)
If you change things, and then you need to revert to your starting config, then you just have to call
grist.reconfig(config=myconfig)
“Cross-site” access.¶
We call it a cross-site access when you try reaching an object belonging to a
team site “from” a different team site, that is, calling
https://mysite.getgrist.com/api/... to reach something that does not belong
to mysite.
The general rule, here, is that all the /docs APIs do not allow cross-site
operations, while other endpoints are fine with it. For example, trying to reach
a call to https://<site>.getgrist.com/api/docs/<doc_id> will result in an
HTTP 404 if <doc_id> does not belong to <site>. On the other hand,
something like https://<site>.getgrist.com/api/workspaces/<ws_id> will work,
even if the workspace is not in <site>.
In terms of Pygrister’s own interface, there’s little we can do about this. Most of the time, you will work with a single team site, so you’ll do the right thing anyway. If your workflow involves switching between sites, be aware that the resource you’re trying to contact must belong to your “current” team site (as per configuration). For instance, this will not work:
doc1 = '<doc1_ID>' # belongs to "myteam1"
doc2 = '<doc2_ID>' # belongs to "myteam2"
g = GristApi(config={'GRIST_TEAM_SITE': 'myteam1'})
g.see_doc(doc1) # ok
g.see_doc(doc2) # HTTP 404
In such cases, it is always better to pass the arguments explicitly, to avoid confusion:
g.see_doc(doc1, team_id='myteam1')
g.see_doc(doc2, team_id='myteam2')
Extending the configuration.¶
If you are extending Pygrister in your custom application, know that you may also add other config keys as needed, besides the standard set provided by Pygrister.
Pygrister will simply incorporate any additional configuration key that
you may provide in the configuration mechanism explained earlier. Your
GristApi instance (of custom subclass) may then use the added
configuration as you please.
For instance, our test suite runs a standard GristApi instance, but also
adds several custom keys to the configuration file, to include or skip some
test, depending on the environment.
Custom configurators.¶
A “configurator” class deals with the Pygrister configuration behind the scenes.
The default configurator is pygrister.config.Configurator, and the
GristApi class will load it when instantiated.
You may want to write your own, different configurator, deriving from
config.Configurator. Then, you can pass it to the GristApi
constructor as the custom_configurator argument:
class MyConfigurator(Configurator):
pass # do your own thing here
my_configurator = MyConfigurator(config={...})
grist = GristApi(custom_configurator=my_configurator)
You may pass both the config and custom_configurator
arguments to the GristApi class constructor: the custom configurator
will be instantiated first, then config will be applied on top of it.
The internal configurator object is exposed as the GristApi.configurator
attribute of your GristApi instance. Swapping configurator at runtime
is possible… but not straighforward: in fact, you will have to consider
the “Api caller” object too. We are going to clarify this point further
when we discuss custom api callers.
Now that you know about config.Configurator, you should also know that
GristApi.reconfig is just an alias for GristApi.configurator.reconfig,
and GristApi.update_config is really GristApi.configurator.update_config.
(All that being said - why would you want to write a custom configurator, after
all? For instance, you may want a different way of storing the “static”
configurations keys: just ovveride Configurator.get_config and provide
your own logic. Our Gry command line tool
makes use of a custom configurator to support different locations
for the json configuration file: read the source code in cli.py
for an example of a custom configurator at work.)