Apps

Heedy’s apps are used as logical entities that interact with external services. In most cases, a plugin defines an app in its heedy.conf, which a user can then add to their account. The plugin then handles the app’s features and synchronization with external data sources.

Apps can also be used directly without associated plugins if they have a access token defined. An access token enables an external service/script to query the Heedy API with the permissions defined in the app’s scope string. This allows an external service to sync with Heedy using an Oauth2 flow (not yet implemented), or explicitly by asking the user to manually create an app with certain permissions and provide it the associated access token.

Once an auth token is obtained, logging into Heedy can be done by initializing the App object:

app = heedy.App("my_access_token",url="http://localhost:1324")
app = heedy.App("my_access_token",url="http://localhost:1324",session="async")

Listing & Accessing

While an app can be obtained directly from its access token, apps are also frequently accessed and used by plugins. Apps can be listed given a set of constraints using the apps attribute of the Plugin object:

# Returns all enabled apps with the given plugin key (usually defined in heedy.conf)
apps = p.apps(plugin="myplugin:myapptype",enabled=True)
# Returns all enabled apps with the given plugin key (usually defined in heedy.conf)
apps = await p.apps(plugin="myplugin:myapptype",enabled=True)

To list the apps beloning to a specific user, the constraint owner="myuser" can be used, or the list can be generated from the apps attribute of the User object, which automatically adds the owner constraint.

If an app’s ID is known, the corresponding App object can be retrieved with:

app = p.apps["appid123"]
print(app.read())
app = p.apps["appid123"]
print(await app.read())

Note

Only plugins can list or read apps - when accessing heedy using an app’s access token, the app can only access itself, and cannot see any other apps.

Creating & Deleting

A Heedy plugin can create/delete apps, but an app logged in with an app token cannot. An app can be added with the create() method:

app = p.apps.create("My App Name",
        owner="myusername"
        plugin=f"{p.name}:myapp"
    )
app = await p.apps.create("My App Name",
        owner="myusername"
        plugin=f"{p.name}:myapp"
    )

The above is equivalent to:

app = p.users["myusername"].apps.create("My App Name",
        plugin=f"{p.name}:myapp"
    )
app = await p.users["myusername"].apps.create("My App Name",
        plugin=f"{p.name}:myapp"
    )

Once the App object is retrieved, it can be deleted with the delete() method:

app.delete()
await app.delete()

Reading & Updating Properties

Just like with user and Object, an App’s properties can be accessed directly as properties or as attributes:

# Does not use a server query - but it might say "self" before read() is called
# if logged in using the app token.
print(app.id) 
# Reads the app's display name from the server
print(app.name)
# Uses the previously read cached data, avoiding a server query
print(app["name"])
# Does not use a server query - but it might say "self" before read() is called
# if logged in using the app token.
print(app.id) 
# Reads the app's display name from the server
print(await app.name)
# Uses the previously read cached data, avoiding a server query
print(app["name"])

To update the corresponding properties, the update function can be used, or if in a sync session, the properties can also be directly set:

app.name = "My App" # Sets the app's display name
# The update function allows setting multiple properties in a single query
app.update(description="Syncs with a cool service")
# The update function allows setting properties for the app:
await app.update(name="My App", description="Syncs with a cool service")

Updating Access Token

An app access token cannot be directly modified. Instead, an update request is sent, and the server generates a new key itself. The newly generated key is returned as part of the query result.

If accessing Heedy using an App token, and the token is updated, the session must be re-created with the new token, since the old token is no longer valid for requests.

result = app.update(access_token=True)

# The old app object is no longer valid if it was logged in with the old access token
newapp = heedy.App(result["access_token"],url=app.session.url)
result = await app.update(access_token=True)

# The old app object is no longer valid if it was logged in with the old access token
newapp = heedy.App(result["access_token"],url=app.session.url)

If the app has its access token set to False or "", the app will lose login capabilities, and will only be accessible from plugins.

API

Apps

class heedy.Apps(constraints, session)[source]

Bases: heedy.base.APIList

Apps is a class implementing a list of apps. It is accessed as a property of users to allow querying apps belonging to a user, or as a property of a plugin object, to allow generic querying of apps. Listing apps is currently only possible when authenticated as a plugin, because an app only has access to itself, and cannot read any other apps.

myuser.apps() # list of apps belonging to myuser
plugin.apps() # list of all apps in heedy
await myuser.apps() # list of apps belonging to myuser
await plugin.apps() # list of all apps in heedy
__call__(**kwargs)[source]

Gets the apps matching the given constraints. If used as a property of a user, the apps are those belonging to the user. Otherwise, if used as a property of a plugin, apps for all users are returned.

# Get all plugins handled by myplugin, with myapptype subkey.
# Include each app's access tokens in the response.
applist = p.apps(plugin="myplugin:myapptype",token=True)
# Get all plugins handled by myplugin, with myapptype subkey.
# Include each app's access tokens in the response.
applist = await p.apps(plugin="myplugin:myapptype",token=True)
Parameters
  • owner (str) – The username of the apps’ owner. Set automatically when accessed using the apps property of a user.

  • plugin (str) – The plugin key of the apps. Allows querying for apps related to specific plugins.

  • enabled (bool,null) – Include only enabled/disabled apps (true/false)

  • icon (bool,False) – Whether to include the icons of the apps in the response.

  • token (bool,False) – Whether to include the access tokens of the apps in the response.

Returns

A list of App matching the given constraints.

Throws:

HeedyException: If the request fails.

__getitem__(appId)[source]

Gets an app by its ID. Each app in heedy has a unique string ID, which can then be used to access the app. The ID can be seen in the URL of the app’s page in the frontend.

app = p.apps["d233rk43o6kkle43kl"]
app = await p.apps["d233rk43o6kkle43kl"]
Returns

The App with the given ID (or promise for the app)

Throws:

HeedyException: If the app does not exist, or insufficient permissions

create(name='', **kwargs)[source]

Creates a new app. Only the first argument, the app name, is required.

app = p.apps.create("My App",
        description="This is my plugin's app",
        icon="fas fa-chart-line",
        owner="myuser", # set automatically when accessed using the apps property of a user
        plugin="myplugin:myapptype"
    )
app = await p.apps.create("My App",
        description="This is my plugin's app",
        icon="fas fa-chart-line",
        owner="myuser", # set automatically when accessed using the apps property of a user
        plugin="myplugin:myapptype"
    )

When creating an app for a plugin, it is useful to set the plugin property in the format plugin_name:app_type. The plugin property allows a plugin to recover which apps are associated with it, and the subkey allows the plugin to distinguish between multiple apps with different functionality that are handled by the same plugin.

Parameters
  • name (str,"") – The name of the app.

  • description (str,"") – A description of the app.

  • icon (str,"") – The app’s icon, either a base64 urlencoded image or fontawesome/material icon id.

  • owner (str) – The username of the app’s owner. Set automatically when accessed using the apps property of a user.

  • plugin (str) – The plugin key of the app. Usually in the format plugin_name:app_type.

  • enabled (bool,True) – Whether the app is enabled.

  • scope (str,"") – space-separated access scopes that are given to the app. Only relevant if the app will be accessed using its access token.

  • settings (dict,{}) – A dictionary of settings for the app.

  • settings_schema (dict,{}) – A JSON Schema describing the settings.

  • access_token (bool,True) – Whether the app should be given an access token.

Returns

The newly created App, with its data cached.

Throws:

HeedyException: If the request fails.

App

class heedy.App(access_token, url='http://localhost:1324', session='sync', cached_data=None)[source]

Bases: heedy.base.APIObject

App is a class representing a Heedy app. Using an access token, you can log into heedy using the App object:

.. tab:: Sync
access_token = "..."
app = heedy.App(access_token,url="http://localhost:1324")
access_token = "..."
app = heedy.App(access_token,url="http://localhost:1324",session="async")

access_token = “…” app = heedy.App(access_token,url=”http://localhost:1324”)

Pre-initialized app objects are also returned when querying for apps from a plugin.

props = {'access_token', 'description', 'icon', 'name', 'settings', 'settings_schema'}

Each element has the above properties available as attributes. In synchronous sessions, they allow you to update the properties directly:

o.name = "My new name"
assert o.name == "My new name"

The above is equivalent to:

o.update(name="My new name")
assert o["name"] == "My new name"

Note that each time you access the properties, they are fetched from the server. In non-interactive scripts it is useful to avoid redundant querying, so each read of data is cached. To use this cached data, you can access the property as a key. Instead of o.name, use o["name"], and call o.read() to create/update the cache. Accessing o["name"] will only work after the data was initially read, otherwise it will lead to a KeyError.

copy(session=None)[source]

Creates a copy of the app object. This function is usually used to switch between sync and async sessions:

app_sync = heedy.App(access_token,url="http://localhost:1324",session="sync")
app_async = app_sync.copy("async")

This function will fail if used on an app object returned from a plugin session. Only App login sessions can be copied.

Parameters

session (str) – The session type to use for the copy (either “sync” or “async”). If not specified, the session type of the current app is used.

Returns

A new App object.

delete(**kwargs)

Calls the element’s URI with the DELETE method. This is a method available for all subclasses of APIObject (objects, apps, users, etc), and removes all associated data from Heedy.

o.delete()
o.read() # Throws error - it longer exists!
await o.delete()
await o.read() # Throws error - it no longer exists!
Parameters

**kwargs – Arguments to pass as query parameters to the server (usually empty)

Raises

HeedyException – If the server returns an error, or when the app does not have permission to delete.

property id

The app’s unique ID. This is directly available, so does not need to be awaited in async sessions:

print(myapp.id)
property kv

The key-value store associated with this app. For details of usage, see KV.

Returns

A heedy.kv.KV object for the element.

notifications

A Notifications object that allows you to access the notifications associated with this element. See Notifications for details.

notify(*args, **kwargs)

Shorthand for self.notifications.notify (see Notifications).

objects

An Objects instance associated with the app, allowing to interact with the objects of the app. For example, listing the objects that are managed by the app can be done with app.objects().

property owner

The user which owns this app:

print(app.owner.username) # Queries the server for the owner, and prints username
print(app["owner"].username) # Uses cached query data to get the owner
print((await app.owner).username) # Queries the server for the owner, and prints username
print(app["owner"].username) # Uses cached query data to get the owner
Returns

The User object of the user which owns this object. The returned user does not have any cached data other than its username.

read(**kwargs)

Sends a GET request to the element’s URI with function arguments as query parameters. This method is available for all subclasses of APIObject (objects, apps, users, etc), and is used to read element’s properties in heedy.

data = o.read(icon=True)
data = await o.read(icon=True)

Caches the result of the read accessible as dict keys:

assert data["name"] == o["name"]

The read or update functions both update the cached data automatically.

Parameters

**kwargs – The url parameters to send with the request.

Returns

The server’s response dict, namely a dict of the element’s properties.

Raises

HeedyException – If the server returns an error.

update(**kwargs)[source]

Sends a PATCH request to element’s URI with arguments as a json object. This method is available for all subclasses of APIObject (objects, apps, users, etc), and is used to update the element’s properties in heedy.

o.update(name="My new name",description="my new description")
assert o["name"] == "My new name"
await o.update(name="My new name",description="my new description")
assert o["name"] == "My new name"
Parameters

**kwargs – The properties to update, sent as the json body of the request.

Returns

The server’s response as a dict, namely the updated element’s properties.

Raises

HeedyException – If the server returns an error, such as when there are insufficient permissions.