Administration

Network and user administration, reached as client.networks and client.users on a client built with an API client’s client_id and client_secret. Every call acts on that API client’s own organization, and is bounded by the scopes it was granted.

The examples here are fragments: they take client as already bound, and every type they return is from memcoai.types.

Networks

Reached as client.networks.

class NetworkOperations(stub, call)[source]

Bases: object

Memory networks, their members and their groups, on a synchronous client.

Reached as networks; not constructed directly.

Example

>>> with Memco(client_id="...", client_secret="...") as client:
...     root = client.networks.list(parent_id="root", domain="coding").networks[0]
...     acme = client.networks.create(name="Acme", parent_ids=[root.id], scope="customer")
Parameters:
  • stub (Any)

  • call (Callable[..., Any])

list(*, name=None, scope=None, owner=None, domain=None, parent_id=None, ids=None, page=None, page_size=None, timeout=None)[source]

List one page of your organization’s memory networks, narrowed by the filters given.

Every filter is optional, and those given must all match.

Parameters:
  • name (str | None) – Keeps networks with this name, matched case-insensitively.

  • scope (str | None) – Keeps networks of this scope: "internal", "customer", or "none" for networks without one.

  • owner (str | None) – Keeps networks with this owner, matched case-insensitively.

  • domain (str | None) – Keeps networks of this memory domain.

  • parent_id (str | None) – Keeps the children of this network. "root" keeps the root networks, one per memory domain.

  • ids (Iterable[str] | None) – Keeps only these networks. The service bounds how many one call may name. An empty collection filters nothing, since on the wire it reads as not given.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many networks a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of networks, and how many match in all.

Raises:
Return type:

NetworkList

Example

>>> page = client.networks.list(parent_id="root", domain="coding")
>>> [(network.id, network.name) for network in page.networks]
create(*, name, parent_id=None, parent_ids=None, domain=None, scope=None, owner=None, description=None, timeout=None)[source]

Create a memory network.

A network is either a root, placed in a memory domain, or the child of other networks, whose domain it takes.

Parameters:
  • name (str) – The network’s name.

  • parent_id (str | None) – Deprecated: use parent_ids, never both. The network to create this one under, read as parent_ids holding that one network.

  • parent_ids (Iterable[str] | None) – The networks to create this one under, each named once and all in one domain, which the new network takes. Consumed exactly once. Omitted or empty, the new network is a root.

  • domain (str | None) – The memory domain of a root network. Omitted, your organization’s default. A child must not name one.

  • scope (str | None) – "internal" or "customer", where your organization uses scopes. An external user can be placed only in a customer network.

  • owner (str | None) – Who the network’s knowledge belongs to.

  • description (str | None) – What the network is for.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The network as created.

Raises:
Return type:

Network

Example

>>> acme = client.networks.create(name="Acme", parent_ids=["network-root"])
>>> acme.domain  # taken from its parent
'coding'
create_or_get(*, name, parent_id=None, parent_ids=None, domain=None, scope=None, owner=None, description=None, timeout=None)[source]

Create a memory network, or return the one already holding its name.

Safe when two callers race to create one network: the loser is handed the winner’s. The existing network is returned only if it has the owner asked for (no owner matches a network without one) and, when a domain or a scope is given, that domain and scope; a network that merely shares the name is never adopted. Names are matched exactly, case included.

Parameters:
  • name (str) – The network’s name.

  • parent_id (str | None) – Deprecated: use parent_ids, never both. As for create().

  • parent_ids (Iterable[str] | None) – The networks to create this one under, as for create().

  • domain (str | None) – The memory domain of a root network. Omitted, your organization’s default, and an existing network in any domain matches.

  • scope (str | None) – "internal" or "customer", as for create(). Omitted, an existing network of any scope matches.

  • owner (str | None) – Who the network’s knowledge belongs to.

  • description (str | None) – What the network is for.

  • timeout (float | None) – Deadline in seconds for each call made, including any wait for a credential. Defaults to the client’s.

Returns:

The network as created, or as it already was.

Raises:
  • MemcoAlreadyExistsError – If the name is held by a network with another owner, domain or scope, or by one that cannot be listed.

  • MemcoAPIError – If the service returns an error status.

Return type:

Network

Example

>>> acme = client.networks.create_or_get(
...     name="acme", domain="knowledge", scope="customer", owner="acme"
... )
update(network_id, *, name=None, parent_id=None, parent_ids=None, scope=None, owner=None, description=None, timeout=None)[source]

Change a network’s name, parent, scope, owner or description.

Only what is passed changes. A field left as None stays as it is; an empty string is sent, and clears the field where the service allows it to be cleared.

Parameters:
  • network_id (str) – The network to change.

  • name (str | None) – The new name.

  • parent_id (str | None) – Deprecated: use parent_ids, never both. The network to move this one under, replacing every other parent; "" makes it a root.

  • parent_ids (Iterable[str] | None) – The network’s whole new parent set, replacing the current one. Consumed exactly once. Empty makes it a root.

  • scope (str | None) – The new scope, "internal" or "customer".

  • owner (str | None) – The new owner.

  • description (str | None) – The new description.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The network as it now is.

Raises:
Return type:

Network

Example

>>> client.networks.update("network-a", name="Acme Corp", description="")
delete(network_id, *, timeout=None)[source]

Delete a network, and everything that hangs off it.

Cannot be undone. The result reports what the deletion removed with the network, so its cost can be seen.

Parameters:
  • network_id (str) – The network to delete.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The network deleted, and how much the cascade removed from each table.

Raises:
Return type:

DeletedNetwork

Example

>>> deleted = client.networks.delete("network-a")
>>> dict(deleted.removed)
{'memories': 3, 'network_members': 1}
list_members(network_id, *, search=None, page=None, page_size=None, timeout=None)[source]

List one page of the users placed in a network.

Parameters:
  • network_id (str) – The network whose members to list.

  • search (str | None) – Keeps members matching this text.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many members a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of members, and how many match in all.

Raises:
Return type:

MemberList

Example

>>> page = client.networks.list_members("network-a", search="ada")
>>> [member.email for member in page.members]
add_member(network_id, user_id, *, force=False, timeout=None)[source]

Place a user in a network.

A user holds one network per memory domain. One already placed in another network of the same domain is refused, naming that network, unless force is set, which moves them. An external user can be placed only in a customer network; any other is refused with MemcoPreconditionFailedError.

Parameters:
  • network_id (str) – The network to place the user in.

  • user_id (str) – The user to place. For an external user, this is id, not your own id for them.

  • force (bool) – Whether to move a user already placed in another network of the same memory domain. Off by default, so moving someone is never the accidental outcome.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

Where the user was placed, and the network they were moved out of, if any.

Raises:
Return type:

MemberPlacement

Example

>>> placed = client.networks.add_member("network-acme", user.id, force=True)
>>> placed.moved_from  # the network they were moved out of, if any
remove_member(network_id, user_id, *, timeout=None)[source]

Take a user out of a network.

Parameters:
  • network_id (str) – The network to take the user out of.

  • user_id (str) – The user to take out.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> client.networks.remove_member("network-acme", "user-a")
list_groups(*, name=None, network_id=None, ids=None, page=None, page_size=None, timeout=None)[source]

List one page of your organization’s identity-provider groups.

Groups are how an enterprise organization places its people in networks, and are available to enterprise organizations only; the service refuses this call for any other.

Parameters:
  • name (str | None) – Keeps groups with this name, matched case-insensitively.

  • network_id (str | None) – Keeps groups assigned to this network.

  • ids (Iterable[str] | None) – Keeps only these groups. The service bounds how many one call may name. An empty collection filters nothing, since on the wire it reads as not given.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many groups a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of groups, and how many match in all.

Raises:
Return type:

GroupList

Example

>>> page = client.networks.list_groups(name="Support")
>>> [(group.id, group.member_count) for group in page.groups]
list_group_members(group_id, *, timeout=None)[source]

List the users in an identity-provider group.

The identity provider manages who is in a group; this only reads it. Available to enterprise organizations only.

Parameters:
  • group_id (str) – The group whose members to list.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The group’s members.

Raises:
Return type:

tuple[Member, …]

Example

>>> [member.email for member in client.networks.list_group_members("group-a")]
add_group(network_id, group_id, *, limit_assignable_roles=None, timeout=None)[source]

Assign an identity-provider group to a network, placing its members there.

A group holds one network per memory domain, so this replaces the group’s network in this network’s domain. A group limited to moderation instead keeps its others, and may be bound to several networks in one domain. Available to enterprise organizations only.

Parameters:
  • network_id (str) – The network to assign the group to.

  • group_id (str) – The group to assign.

  • limit_assignable_roles (Iterable[str] | None) – The roles the group may give its members on every network it is bound to: ["content_moderator"] gives moderation only, and adds this network beside the group’s others. Omitted or empty, the group’s limit stays as it is. The limit changes only while the group is bound to this network alone.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> client.networks.add_group("network-support", "group-a")
>>> client.networks.add_group(
...     "network-review",
...     "group-moderators",
...     limit_assignable_roles=["content_moderator"],
... )
remove_group(network_id, group_id, *, timeout=None)[source]

Take an identity-provider group out of a network.

The group’s networks in other memory domains are unaffected. Available to enterprise organizations only.

Parameters:
  • network_id (str) – The network to take the group out of.

  • group_id (str) – The group to take out.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> client.networks.remove_group("network-support", "group-a")
class AsyncNetworkOperations(stub, call)[source]

Bases: object

Memory networks, their members and their groups, on an asyncio client.

Reached as networks; not constructed directly. Mirrors NetworkOperations method for method.

Example

>>> async with AsyncMemco(client_id="...", client_secret="...") as client:
...     acme = await client.networks.create(name="Acme", parent_ids=["network-root"])
Parameters:
  • stub (Any)

  • call (Callable[..., Any])

async list(*, name=None, scope=None, owner=None, domain=None, parent_id=None, ids=None, page=None, page_size=None, timeout=None)[source]

List one page of your organization’s memory networks, narrowed by the filters given.

Every filter is optional, and those given must all match.

Parameters:
  • name (str | None) – Keeps networks with this name, matched case-insensitively.

  • scope (str | None) – Keeps networks of this scope: "internal", "customer", or "none" for networks without one.

  • owner (str | None) – Keeps networks with this owner, matched case-insensitively.

  • domain (str | None) – Keeps networks of this memory domain.

  • parent_id (str | None) – Keeps the children of this network. "root" keeps the root networks, one per memory domain.

  • ids (Iterable[str] | None) – Keeps only these networks. The service bounds how many one call may name. An empty collection filters nothing, since on the wire it reads as not given.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many networks a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of networks, and how many match in all.

Raises:
Return type:

NetworkList

Example

>>> page = await client.networks.list(parent_id="root", domain="coding")
>>> [(network.id, network.name) for network in page.networks]
async create(*, name, parent_id=None, parent_ids=None, domain=None, scope=None, owner=None, description=None, timeout=None)[source]

Create a memory network.

A network is either a root, placed in a memory domain, or the child of other networks, whose domain it takes.

Parameters:
  • name (str) – The network’s name.

  • parent_id (str | None) – Deprecated: use parent_ids, never both. The network to create this one under, read as parent_ids holding that one network.

  • parent_ids (Iterable[str] | None) – The networks to create this one under, each named once and all in one domain, which the new network takes. Consumed exactly once. Omitted or empty, the new network is a root.

  • domain (str | None) – The memory domain of a root network. Omitted, your organization’s default. A child must not name one.

  • scope (str | None) – "internal" or "customer", where your organization uses scopes. An external user can be placed only in a customer network.

  • owner (str | None) – Who the network’s knowledge belongs to.

  • description (str | None) – What the network is for.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The network as created.

Raises:
Return type:

Network

Example

>>> acme = await client.networks.create(name="Acme", parent_ids=["network-root"])
>>> acme.domain  # taken from its parent
'coding'
async create_or_get(*, name, parent_id=None, parent_ids=None, domain=None, scope=None, owner=None, description=None, timeout=None)[source]

Create a memory network, or return the one already holding its name.

Safe when two callers race to create one network: the loser is handed the winner’s. The existing network is returned only if it has the owner asked for (no owner matches a network without one) and, when a domain or a scope is given, that domain and scope; a network that merely shares the name is never adopted. Names are matched exactly, case included.

Parameters:
  • name (str) – The network’s name.

  • parent_id (str | None) – Deprecated: use parent_ids, never both. As for create().

  • parent_ids (Iterable[str] | None) – The networks to create this one under, as for create().

  • domain (str | None) – The memory domain of a root network. Omitted, your organization’s default, and an existing network in any domain matches.

  • scope (str | None) – "internal" or "customer", as for create(). Omitted, an existing network of any scope matches.

  • owner (str | None) – Who the network’s knowledge belongs to.

  • description (str | None) – What the network is for.

  • timeout (float | None) – Deadline in seconds for each call made, including any wait for a credential. Defaults to the client’s.

Returns:

The network as created, or as it already was.

Raises:
  • MemcoAlreadyExistsError – If the name is held by a network with another owner, domain or scope, or by one that cannot be listed.

  • MemcoAPIError – If the service returns an error status.

Return type:

Network

Example

>>> acme = await client.networks.create_or_get(
...     name="acme", domain="knowledge", scope="customer", owner="acme"
... )
async update(network_id, *, name=None, parent_id=None, parent_ids=None, scope=None, owner=None, description=None, timeout=None)[source]

Change a network’s name, parent, scope, owner or description.

Only what is passed changes. A field left as None stays as it is; an empty string is sent, and clears the field where the service allows it to be cleared.

Parameters:
  • network_id (str) – The network to change.

  • name (str | None) – The new name.

  • parent_id (str | None) – Deprecated: use parent_ids, never both. The network to move this one under, replacing every other parent; "" makes it a root.

  • parent_ids (Iterable[str] | None) – The network’s whole new parent set, replacing the current one. Consumed exactly once. Empty makes it a root.

  • scope (str | None) – The new scope, "internal" or "customer".

  • owner (str | None) – The new owner.

  • description (str | None) – The new description.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The network as it now is.

Raises:
Return type:

Network

Example

>>> await client.networks.update("network-a", name="Acme Corp", description="")
async delete(network_id, *, timeout=None)[source]

Delete a network, and everything that hangs off it.

Cannot be undone. The result reports what the deletion removed with the network, so its cost can be seen.

Parameters:
  • network_id (str) – The network to delete.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The network deleted, and how much the cascade removed from each table.

Raises:
Return type:

DeletedNetwork

Example

>>> deleted = await client.networks.delete("network-a")
>>> dict(deleted.removed)
{'memories': 3, 'network_members': 1}
async list_members(network_id, *, search=None, page=None, page_size=None, timeout=None)[source]

List one page of the users placed in a network.

Parameters:
  • network_id (str) – The network whose members to list.

  • search (str | None) – Keeps members matching this text.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many members a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of members, and how many match in all.

Raises:
Return type:

MemberList

Example

>>> page = await client.networks.list_members("network-a", search="ada")
>>> [member.email for member in page.members]
async add_member(network_id, user_id, *, force=False, timeout=None)[source]

Place a user in a network.

A user holds one network per memory domain. One already placed in another network of the same domain is refused, naming that network, unless force is set, which moves them. An external user can be placed only in a customer network; any other is refused with MemcoPreconditionFailedError.

Parameters:
  • network_id (str) – The network to place the user in.

  • user_id (str) – The user to place. For an external user, this is id, not your own id for them.

  • force (bool) – Whether to move a user already placed in another network of the same memory domain. Off by default, so moving someone is never the accidental outcome.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

Where the user was placed, and the network they were moved out of, if any.

Raises:
Return type:

MemberPlacement

Example

>>> placed = await client.networks.add_member("network-acme", user.id, force=True)
>>> placed.moved_from  # the network they were moved out of, if any
async remove_member(network_id, user_id, *, timeout=None)[source]

Take a user out of a network.

Parameters:
  • network_id (str) – The network to take the user out of.

  • user_id (str) – The user to take out.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> await client.networks.remove_member("network-acme", "user-a")
async list_groups(*, name=None, network_id=None, ids=None, page=None, page_size=None, timeout=None)[source]

List one page of your organization’s identity-provider groups.

Groups are how an enterprise organization places its people in networks, and are available to enterprise organizations only; the service refuses this call for any other.

Parameters:
  • name (str | None) – Keeps groups with this name, matched case-insensitively.

  • network_id (str | None) – Keeps groups assigned to this network.

  • ids (Iterable[str] | None) – Keeps only these groups. The service bounds how many one call may name. An empty collection filters nothing, since on the wire it reads as not given.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many groups a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of groups, and how many match in all.

Raises:
Return type:

GroupList

Example

>>> page = await client.networks.list_groups(name="Support")
>>> [(group.id, group.member_count) for group in page.groups]
async list_group_members(group_id, *, timeout=None)[source]

List the users in an identity-provider group.

The identity provider manages who is in a group; this only reads it. Available to enterprise organizations only.

Parameters:
  • group_id (str) – The group whose members to list.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The group’s members.

Raises:
Return type:

tuple[Member, …]

Example

>>> members = await client.networks.list_group_members("group-a")
>>> [member.email for member in members]
async add_group(network_id, group_id, *, limit_assignable_roles=None, timeout=None)[source]

Assign an identity-provider group to a network, placing its members there.

A group holds one network per memory domain, so this replaces the group’s network in this network’s domain. A group limited to moderation instead keeps its others, and may be bound to several networks in one domain. Available to enterprise organizations only.

Parameters:
  • network_id (str) – The network to assign the group to.

  • group_id (str) – The group to assign.

  • limit_assignable_roles (Iterable[str] | None) – The roles the group may give its members on every network it is bound to: ["content_moderator"] gives moderation only, and adds this network beside the group’s others. Omitted or empty, the group’s limit stays as it is. The limit changes only while the group is bound to this network alone.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> await client.networks.add_group("network-support", "group-a")
>>> await client.networks.add_group(
...     "network-review",
...     "group-moderators",
...     limit_assignable_roles=["content_moderator"],
... )
async remove_group(network_id, group_id, *, timeout=None)[source]

Take an identity-provider group out of a network.

The group’s networks in other memory domains are unaffected. Available to enterprise organizations only.

Parameters:
  • network_id (str) – The network to take the group out of.

  • group_id (str) – The group to take out.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> await client.networks.remove_group("network-support", "group-a")

Users

Reached as client.users.

class UserOperations(stub, call)[source]

Bases: object

External users and their API keys, on a synchronous client.

Reached as users; not constructed directly. Every method names a user by your own id for them, the external_id they were created with.

Example

>>> with Memco(client_id="...", client_secret="...") as client:
...     user = client.users.create("customer-42", roles=["reader", "creator"])
Parameters:
  • stub (Any)

  • call (Callable[..., Any])

list(*, search=None, page=None, page_size=None, timeout=None)[source]

List one page of your organization’s external users.

Parameters:
  • search (str | None) – Keeps users whose external id, name or email matches this text, case-insensitively.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many users a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of users, and how many match in all.

Raises:

MemcoAPIError – If the service returns an error status.

Return type:

ExternalUserList

Example

>>> page = client.users.list(search="acme")
>>> [user.external_id for user in page.external_users]
get(external_id, *, timeout=None)[source]

Fetch one external user, by your own id for them.

Parameters:
  • external_id (str) – Your id for the user.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user.

Raises:
Return type:

ExternalUser

Example

>>> client.users.get("customer-42").roles
('reader', 'creator')
create(external_id, *, roles, name=None, email=None, timeout=None)[source]

Create an external user: one of your own users, known to Memco by your id for them.

The user has no sign-in of its own, and never holds admin. It starts in no network: place it in a customer network with NetworkOperations.add_member(), passing the created user’s id.

Parameters:
  • external_id (str) – Your id for the user, unique within your organization. It cannot be changed later.

  • roles (Iterable[str]) – The content roles the user holds, from "reader", "creator" and "auditor". At least one.

  • name (str | None) – The user’s name.

  • email (str | None) – The user’s email address.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user as created.

Raises:
Return type:

ExternalUser

Example

>>> user = client.users.create("customer-42", roles=["reader", "creator"], name="Ada")
create_or_get(external_id, *, roles, name=None, email=None, timeout=None)[source]

Create an external user, or return the one already holding its id.

Safe when two callers race to create one user: the loser is handed the winner’s. The existing user is returned as it is; its roles, name and email are not compared with the arguments or changed.

Parameters:
  • external_id (str) – Your id for the user, unique within your organization.

  • roles (Iterable[str]) – The content roles the user holds, as for create().

  • name (str | None) – The user’s name.

  • email (str | None) – The user’s email address.

  • timeout (float | None) – Deadline in seconds for each call made, including any wait for a credential. Defaults to the client’s.

Returns:

The user as created, or as it already was.

Raises:
Return type:

ExternalUser

Example

>>> user = client.users.create_or_get("customer-42", roles=["reader", "creator"])
update(external_id, *, name=None, email=None, roles=None, timeout=None)[source]

Change an external user’s name, email or roles.

Only what is passed changes. A field left as None stays as it is; an empty name or email is sent, and clears it. The external id itself cannot be changed.

Parameters:
  • external_id (str) – Your id for the user to change.

  • name (str | None) – The new name.

  • email (str | None) – The new email address.

  • roles (Iterable[str] | None) – The roles to replace the user’s with. At least one: to leave them as they are, omit this.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user as it now is.

Raises:
Return type:

ExternalUser

Example

>>> client.users.update("customer-42", roles=["reader"])
delete(external_id, *, timeout=None)[source]

Delete an external user, and every API key it holds.

Parameters:
  • external_id (str) – Your id for the user to delete.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> client.users.delete("customer-42")
list_keys(external_id, *, timeout=None)[source]

List an external user’s API keys, without their values.

Parameters:
  • external_id (str) – Your id for the user whose keys to list.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user’s keys. A value is shown only once, when its key is created, so none is here.

Raises:
Return type:

tuple[ExternalUserKey, …]

Example

>>> [(key.name, key.valid_until) for key in client.users.list_keys("customer-42")]
create_key(external_id, *, preset, name=None, valid_until=None, timeout=None)[source]

Create an API key acting as an external user.

The key’s value is returned here and never again, so store it now.

Parameters:
  • external_id (str) – Your id for the user the key acts as.

  • preset (str) – The kind of key: "mcp_rw", "mcp_ro" or "audit". It must be within the user’s roles.

  • name (str | None) – A name to recognise the key by.

  • valid_until (datetime | None) – When the key expires, as a timezone-aware datetime, at most three months ahead. Omitted, three months.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The key’s description, and its value.

Raises:
Return type:

CreatedKey

Example

>>> created = client.users.create_key("customer-42", preset="mcp_ro", name="ci")
>>> store_secret(created.value)  # shown only this once
delete_key(external_id, key_id, *, timeout=None)[source]

Revoke one of an external user’s API keys.

Parameters:
  • external_id (str) – Your id for the user the key belongs to.

  • key_id (str) – The key to revoke, as id gives it.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> client.users.delete_key("customer-42", created.key.id)
class AsyncUserOperations(stub, call)[source]

Bases: object

External users and their API keys, on an asyncio client.

Reached as users; not constructed directly. Mirrors UserOperations method for method.

Example

>>> async with AsyncMemco(client_id="...", client_secret="...") as client:
...     user = await client.users.create("customer-42", roles=["reader", "creator"])
Parameters:
  • stub (Any)

  • call (Callable[..., Any])

async list(*, search=None, page=None, page_size=None, timeout=None)[source]

List one page of your organization’s external users.

Parameters:
  • search (str | None) – Keeps users whose external id, name or email matches this text, case-insensitively.

  • page (int | None) – The page to return, counting from 1. Omitted, the first.

  • page_size (int | None) – How many users a page holds. Omitted, the service’s default.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The page of users, and how many match in all.

Raises:

MemcoAPIError – If the service returns an error status.

Return type:

ExternalUserList

Example

>>> page = await client.users.list(search="acme")
>>> [user.external_id for user in page.external_users]
async get(external_id, *, timeout=None)[source]

Fetch one external user, by your own id for them.

Parameters:
  • external_id (str) – Your id for the user.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user.

Raises:
Return type:

ExternalUser

Example

>>> (await client.users.get("customer-42")).roles
('reader', 'creator')
async create(external_id, *, roles, name=None, email=None, timeout=None)[source]

Create an external user: one of your own users, known to Memco by your id for them.

The user has no sign-in of its own, and never holds admin. It starts in no network: place it in a customer network with AsyncNetworkOperations.add_member(), passing the created user’s id.

Parameters:
  • external_id (str) – Your id for the user, unique within your organization. It cannot be changed later.

  • roles (Iterable[str]) – The content roles the user holds, from "reader", "creator" and "auditor". At least one.

  • name (str | None) – The user’s name.

  • email (str | None) – The user’s email address.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user as created.

Raises:
Return type:

ExternalUser

Example

>>> user = await client.users.create("customer-42", roles=["reader"], name="Ada")
async create_or_get(external_id, *, roles, name=None, email=None, timeout=None)[source]

Create an external user, or return the one already holding its id.

Safe when two callers race to create one user: the loser is handed the winner’s. The existing user is returned as it is; its roles, name and email are not compared with the arguments or changed.

Parameters:
  • external_id (str) – Your id for the user, unique within your organization.

  • roles (Iterable[str]) – The content roles the user holds, as for create().

  • name (str | None) – The user’s name.

  • email (str | None) – The user’s email address.

  • timeout (float | None) – Deadline in seconds for each call made, including any wait for a credential. Defaults to the client’s.

Returns:

The user as created, or as it already was.

Raises:
Return type:

ExternalUser

Example

>>> user = await client.users.create_or_get(
...     "customer-42", roles=["reader", "creator"]
... )
async update(external_id, *, name=None, email=None, roles=None, timeout=None)[source]

Change an external user’s name, email or roles.

Only what is passed changes. A field left as None stays as it is; an empty name or email is sent, and clears it. The external id itself cannot be changed.

Parameters:
  • external_id (str) – Your id for the user to change.

  • name (str | None) – The new name.

  • email (str | None) – The new email address.

  • roles (Iterable[str] | None) – The roles to replace the user’s with. At least one: to leave them as they are, omit this.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user as it now is.

Raises:
Return type:

ExternalUser

Example

>>> await client.users.update("customer-42", roles=["reader"])
async delete(external_id, *, timeout=None)[source]

Delete an external user, and every API key it holds.

Parameters:
  • external_id (str) – Your id for the user to delete.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> await client.users.delete("customer-42")
async list_keys(external_id, *, timeout=None)[source]

List an external user’s API keys, without their values.

Parameters:
  • external_id (str) – Your id for the user whose keys to list.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The user’s keys. A value is shown only once, when its key is created, so none is here.

Raises:
Return type:

tuple[ExternalUserKey, …]

Example

>>> keys = await client.users.list_keys("customer-42")
>>> [(key.name, key.valid_until) for key in keys]
async create_key(external_id, *, preset, name=None, valid_until=None, timeout=None)[source]

Create an API key acting as an external user.

The key’s value is returned here and never again, so store it now.

Parameters:
  • external_id (str) – Your id for the user the key acts as.

  • preset (str) – The kind of key: "mcp_rw", "mcp_ro" or "audit". It must be within the user’s roles.

  • name (str | None) – A name to recognise the key by.

  • valid_until (datetime | None) – When the key expires, as a timezone-aware datetime, at most three months ahead. Omitted, three months.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Returns:

The key’s description, and its value.

Raises:
Return type:

CreatedKey

Example

>>> created = await client.users.create_key("customer-42", preset="mcp_ro")
>>> store_secret(created.value)  # shown only this once
async delete_key(external_id, key_id, *, timeout=None)[source]

Revoke one of an external user’s API keys.

Parameters:
  • external_id (str) – Your id for the user the key belongs to.

  • key_id (str) – The key to revoke, as id gives it.

  • timeout (float | None) – Deadline in seconds for the whole call, including any wait for a credential. Defaults to the client’s.

Raises:
Return type:

None

Example

>>> await client.users.delete_key("customer-42", created.key.id)