Other modules#

Module

Contents

plone_client.operations

Tasks that take several requests in the right order, with a result that lists every request.

plone_client.mcp_server

The MCP server; needs the mcp extra.

plone_client.auth

Authentication flows for httpx: basic, JWT, and a static token.

plone_client.blocks

Build Volto blocks, including blocks of any type and blocks that hold others, such as grids; convert Markdown and HTML to blocks; and walk blocks and their links.

plone_client.profiles

Connection profiles and the configuration file.

plone_client.credentials

Secrets of profiles: keyring, environment variable, or command.

plone_client.utils

UID references and resolveuid links.

Operations#

Function

Requests, in order

create_with_files()

GET @types/<type>, create the item, one upload per file, PATCH preview_image_link when the type keeps its lead image there, the transition, and GET of the item.

create_page()

Create the page, then the transition and GET of the page.

upload_tree()

GET of the folder, then one create or upload per entry, depth first, and a transition after each new page.

copy_items(), move_items()

GET of the folder, a @search count per item, @copy or @move, and a @search count per new item.

Transitions run only when publish is given. With a dry_run client, the requests that change the site are recorded and skipped, and created entries have "planned": true with the path the item would most likely get. Steps that need an answer from the site, such as the final GET and the counts after a copy, are left out.

High-level operations: tasks that take several requests, in the right order.

Each operation gets a task right on any Plone 6 site, Volto sites included, where doing it request by request means knowing the content model: a News Item has no image field there, and its lead image is a relation to an Image stored inside it.

Every operation returns an OperationResult that lists what it created or changed and every request it sent. With a dry_run client, nothing is sent: the result shows the planned requests, with the paths the new items would most likely get. A read-only client refuses the first change. When a request fails part way, the operation raises PloneOperationError, whose result lists what was already done, so the caller can clean up or resume.

Example:

from plone_client import PloneClient
from plone_client import operations

with PloneClient.from_profile("blog") as site:
    result = operations.create_with_files(
        site,
        "/news",
        "News Item",
        ["lead.jpg", "photo-2.jpg"],
        title="Our new office",
        publish="publish",
    )
    print(result.item["@id"])
plone_client.operations.ITEM_KEYS = ('@id', '@type', 'UID', 'id', 'title', 'review_state')#

Keys kept from an item in a result.

plone_client.operations.PAGE_FORMATS: dict[str, Literal['markdown', 'html']] = {'.htm': 'html', '.html': 'html', '.markdown': 'markdown', '.md': 'markdown'}#

Extensions of the files that upload_tree() can turn into pages.

plone_client.operations.INDEX_NAMES = ('index.md', 'README.md', 'index.html')#

Files that hold the content of their folder’s page in upload_tree().

class plone_client.operations.OperationResult(operation, dry_run, item=None, created=<factory>, changed=<factory>, requests=<factory>, error=None)[source]#

Bases: object

What an operation did.

Parameters:
  • operation (str) – Name of the operation.

  • dry_run (bool) – Whether the requests that change the site were skipped.

  • item (dict[str, Any] | None) – The main item, for operations that create one.

  • created (list[dict[str, Any]]) – Items created, in order; source names the local file or folder they came from, and planned marks a path guessed in a dry run.

  • changed (list[dict[str, Any]]) – Items changed, with what changed.

  • requests (list[dict[str, Any]]) – Every request sent or skipped: method, url, status and, when skipped, dry_run.

  • error (dict[str, Any] | None) – Type and message of the error that stopped the operation.

to_dict()[source]#

The result as JSON-ready data.

Returns:

Every field; item and error only when set.

Return type:

dict[str, Any]

plone_client.operations.slug(text)[source]#

A likely id for a title, close to what Plone generates.

Only used to name items in a dry run, before Plone picks the real id.

Parameters:

text (str) – The title or file name.

Returns:

Lower case ASCII words joined by -; dots of file names kept.

Return type:

str

plone_client.operations.create_with_files(client, parent, portal_type, files, *, data=None, lead_image='first', publish=None, **fields)[source]#

Create an item, upload files and images inside it, and set its lead image.

The lead image goes where the type keeps it: in the image field when the type has one (the file is then not uploaded again), or otherwise as an Image inside the item that preview_image_link points to, which is how News Items work on Volto sites. Files are uploaded as Image or File items, in order. Types with blocks get title and description blocks unless blocks are given.

The item must be folderish to hold the files: on Volto sites, Documents and News Items are.

Parameters:
  • client (PloneClient) – The client.

  • parent (str) – Path or URL of the folder.

  • portal_type (str) – Content type, such as News Item.

  • files (Iterable[str | Path]) – Paths of the files to upload inside the item.

  • data (Mapping[str, Any] | None) – Field values of the item.

  • lead_image (int | Literal['first'] | None) – Index of the lead image in files, "first" for the first image (skipped when the type has no lead image), or None for no lead image.

  • publish (str | None) – Workflow transition to run at the end, such as publish.

  • fields (Any) – More field values, merged over data.

Returns:

The result; item is the new item.

Raises:
  • ValueError – If a file is missing, or the lead image is not an image or cannot be stored by the type. Nothing is changed then.

  • PloneOperationError – If a request fails.

Return type:

OperationResult

plone_client.operations.split_title(source, source_format)[source]#

Take a leading level 1 heading out of Markdown or HTML.

Parameters:
  • source (str) – The Markdown or HTML.

  • source_format (Literal['markdown', 'html']) – markdown or html.

Returns:

The heading text (empty when there is none) and the rest.

Return type:

tuple[str, str]

plone_client.operations.page_data(source, source_format='markdown', *, title=None, description=None, default_title='')[source]#

Field values of a page made from Markdown or HTML.

The page gets a title block, a description block and the converted content. Without a title, the leading level 1 heading is the title, and is not repeated in the content.

Parameters:
  • source (str) – The Markdown or HTML.

  • source_format (Literal['markdown', 'html']) – markdown or html.

  • title (str | None) – Title of the page.

  • description (str | None) – Description of the page.

  • default_title (str) – Title when there is neither title nor a leading heading, such as the name of the file.

Returns:

title, maybe description, blocks and blocks_layout.

Raises:
Return type:

dict[str, Any]

plone_client.operations.create_page(client, parent, source, *, source_format='markdown', portal_type='Document', title=None, description=None, data=None, publish=None)[source]#

Create a page from Markdown or HTML, converted to blocks.

See page_data() for how the page is built. Needs the markdown extra (Python 3.12 or later).

Parameters:
  • client (PloneClient) – The client.

  • parent (str) – Path or URL of the folder.

  • source (str) – The Markdown or HTML text.

  • source_format (Literal['markdown', 'html']) – markdown or html.

  • portal_type (str) – Content type; it must have blocks.

  • title (str | None) – Title; the leading # heading by default.

  • description (str | None) – Description.

  • data (Mapping[str, Any] | None) – More field values, such as id or subjects.

  • publish (str | None) – Workflow transition to run at the end.

Returns:

The result; item is the new page.

Raises:
Return type:

OperationResult

plone_client.operations.upload_tree(client, source, parent, *, folder_type='Document', convert_pages=False, include_hidden=False, publish=None)[source]#

Upload the contents of a local folder, keeping its structure.

Folders become folderish pages (Document by default, which is folderish on Volto sites), images become Image items, and other files File items. The contents of source go inside parent, which must exist, as with rsync source/ parent.

With convert_pages, Markdown and HTML files become pages (see page_data()), and a folder’s index.md, README.md or index.html becomes the content of the folder’s own page. This needs the markdown extra.

Parameters:
  • client (PloneClient) – The client.

  • source (str | Path) – Local folder.

  • parent (str) – Path or URL of the folder in the site.

  • folder_type (str) – Content type for folders.

  • convert_pages (bool) – Turn Markdown and HTML files into pages.

  • include_hidden (bool) – Also upload files and folders whose name starts with a dot.

  • publish (str | None) – Workflow transition to run on each new page, such as publish; files and images follow their folder.

Returns:

The result; each created entry names its local source.

Raises:
Return type:

OperationResult

plone_client.operations.copy_items(client, sources, target)[source]#

Copy items, folders with their contents, into a folder.

Plone may rename a copy whose id is taken (copy_of_news), so read the @id of each created entry.

Parameters:
  • client (PloneClient) – The client.

  • sources (str | Iterable[str]) – Path, URL or UID reference of an item, or several.

  • target (str) – Path or URL of the folder.

Returns:

The result; each created entry has the source, the new @id, and the number of items (the item and everything inside it) before and, unless in a dry run, after the copy.

Raises:

PloneOperationError – If a request fails.

Return type:

OperationResult

plone_client.operations.move_items(client, sources, target)[source]#

Move items, folders with their contents, into a folder.

Parameters:
  • client (PloneClient) – The client.

  • sources (str | Iterable[str]) – Path, URL or UID reference of an item, or several.

  • target (str) – Path or URL of the folder.

Returns:

The result; each changed entry has the old source, the new @id and the number of items before and after the move.

Raises:

PloneOperationError – If a request fails.

Return type:

OperationResult

MCP server#

An MCP server for Plone sites, built on the client and its operations.

The server gives chat assistants and agents without a shell the same access the command line gives: the same profiles, secrets in the keyring, and the same read_only and dry_run switches. It speaks over standard input and output, for one site or several:

pip install 'plone-client[mcp]'
plone-client mcp --profile blog
plone-client mcp --site blog --site docs
plone-client mcp --group customer
plone-client mcp --all

Rather than one tool per plone.restapi service, it offers the everyday reads, the high-level operations of plone_client.operations, and one tool for any other service. With several sites, every tool takes a site argument, and list_sites describes them. Tools that change a site are only offered when at least one site accepts changes; a change to a read-only site is refused before it is sent.

plone_client.mcp_server.tool_errors(func)[source]#

Report the errors of a tool to the model, as JSON.

Unexpected exceptions reach the model only as “Error executing tool”, so the errors a caller can act on are turned into ToolError.

Parameters:

func (Callable[[...], Any]) – The tool.

Returns:

The wrapped tool.

Return type:

Callable[[…], Any]

class plone_client.mcp_server.Site(name, url, description='', read_only=False, factory=None, client=None)[source]#

Bases: object

A site the server works on.

Parameters:
  • name (str) – Name the model picks it by: the profile name.

  • url (str) – URL of the site.

  • description (str) – What the site is, for the model.

  • read_only (bool) – Whether changes to it are refused.

  • factory (Callable[[], PloneClient] | None) – Builds its client, on first use.

  • client (PloneClient | None)

summary()[source]#

The site, as list_sites reports it.

Returns:

name, url, description and read_only.

Return type:

dict[str, Any]

class plone_client.mcp_server.Sites(sites, *, dry_run=False)[source]#

Bases: object

The sites of one server, each with a client created on first use.

Creating a client looks up its secret, so a site whose secret is missing only fails when a tool uses it.

Parameters:
  • sites (Iterable[Site]) – The sites, in the order the model sees them.

  • dry_run (bool) – Whether the clients skip the requests that change a site.

Raises:

ValueError – If there is no site, or two have the same name.

classmethod from_client(client, name='site')[source]#

One site, served with a client that already exists.

Parameters:
  • client (PloneClient) – The client.

  • name (str) – Name of the site.

Returns:

The sites.

Return type:

Sites

classmethod from_profiles(profiles, *, read_only=False, dry_run=False, factory=<class 'plone_client.client.PloneClient'>)[source]#

Sites for profiles.

Parameters:
  • profiles (Iterable[Profile]) – The profiles.

  • read_only (bool) – Refuse changes to every site, whatever its profile.

  • dry_run (bool) – Skip the requests that change a site.

  • factory (Callable[[...], PloneClient]) – Builds a client from keyword arguments.

Returns:

The sites.

Return type:

Sites

property names: list[str]#

Names of the sites, in order.

property multiple: bool#

Whether there is more than one site.

property writable: bool#

Whether at least one site accepts changes.

client(name=None)[source]#

The client of a site, created on first use.

Parameters:

name (str | None) – Site name; the only site when there is one.

Returns:

The client.

Raises:

PloneConfigurationError – If the site is unknown, or its secret cannot be found.

Return type:

PloneClient

close()[source]#

Close the clients that were created.

Return type:

None

plone_client.mcp_server.has_html2blocks()[source]#

Whether collective.html2blocks is installed.

Returns:

True if it can be imported.

Return type:

bool

plone_client.mcp_server.build_server(target)[source]#

An MCP server whose tools work on one site or several.

Parameters:

target (PloneClient | Sites) – A client, for one site, or the sites. Each client’s read_only and dry_run settings apply to its tools.

Returns:

The server, ready to run().

Return type:

MCPServer

plone_client.mcp_server.serve(target)[source]#

Serve the tools over standard input and output.

Parameters:

target (PloneClient | Sites) – A client, for one site, or the sites; their clients are closed when the server stops.

Return type:

None

Authentication#

Authentication strategies for PloneClient.

Three ways to authenticate against plone.restapi are supported:

  • HTTP basic authentication (httpx.BasicAuth), the simplest option and the default when a username and password are given;

  • a JWT obtained from @login (JWTAuth), which logs in again when the token expires;

  • a token issued beforehand (TokenAuth).

Any other httpx.Auth can be passed to the client as well.

class plone_client.auth.TokenAuth(token)[source]#

Bases: Auth

Send a token issued beforehand as Authorization: Bearer.

Parameters:

token (str) – The JWT.

auth_flow(request)[source]#

Execute the authentication flow.

To dispatch a request, yield it:

` yield request `

The client will .send() the response back into the flow generator. You can access it like so:

` response = yield request `

A return (or reaching the end of the generator) will result in the client returning the last response obtained from the server.

You can dispatch as many requests as is necessary.

Parameters:

request (Request)

Return type:

Generator[Request, Response, None]

class plone_client.auth.JWTAuth(username, password, login_url)[source]#

Bases: Auth

Log in with POST @login and send the JWT it returns.

The login happens on the first request. When the site answers 401, the token is assumed to be expired: the flow logs in again and repeats the request once.

Parameters:
  • username (str) – Login name.

  • password (str) – Password.

  • login_url (str) – Absolute URL of the site’s @login service.

auth_flow(request)[source]#

Execute the authentication flow.

To dispatch a request, yield it:

` yield request `

The client will .send() the response back into the flow generator. You can access it like so:

` response = yield request `

A return (or reaching the end of the generator) will result in the client returning the last response obtained from the server.

You can dispatch as many requests as is necessary.

Parameters:

request (Request)

Return type:

Generator[Request, Response, None]

plone_client.auth.build_auth(*, username='', password='', token='', method='basic', login_url='')[source]#

Pick the authentication for a set of credentials.

A token wins over a username and password. Without any credential the client is anonymous.

Parameters:
  • username (str) – Login name.

  • password (str) – Password.

  • token (str) – JWT issued beforehand.

  • method (Literal['basic', 'jwt']) – basic or jwt, used with a username and password.

  • login_url (str) – Absolute URL of @login, needed by jwt.

Returns:

The authentication, or None for anonymous access.

Raises:

ValueError – If the method is unknown or only half of the username/password pair is given.

Return type:

Auth | None

Blocks#

Helpers for Volto blocks: build them, walk them, find their links.

A page built with Volto stores its content in two fields: blocks, a mapping of block ids to block data, and blocks_layout, whose items list the block ids in order. A page without both renders empty.

Example:

from plone_client import blocks

page = blocks.build(
    blocks.title(),
    blocks.description(),
    blocks.text("Hello!"),
)
site.content.create("/", "Document", title="Hello", **page)

Blocks this module has no helper for, such as those of an add-on, are built with block(), and blocks that hold other blocks with container(). A grid of four teasers:

paths = ["/news/a", "/news/b", "/news/c", "/news/d"]
page = blocks.build(
    blocks.title(),
    blocks.grid(*(blocks.teaser(path) for path in paths)),
)

Markdown and HTML can be converted to blocks with convert().

Keys whose string values are links.

plone_client.blocks.new_id()[source]#

A fresh block id.

Returns:

A random UUID, the way Volto writes block ids.

Return type:

str

plone_client.blocks.build(*items)[source]#

blocks and blocks_layout for blocks in order.

Parameters:

items (Mapping[str, Any]) – Block data, each with an @type.

Returns:

A mapping with blocks and blocks_layout, ready to merge into the data of an item.

Return type:

dict[str, Any]

plone_client.blocks.title()[source]#

A title block, which shows the item’s title.

Returns:

The block.

Return type:

dict[str, Any]

plone_client.blocks.description()[source]#

A description block, which shows the item’s description.

Returns:

The block.

Return type:

dict[str, Any]

plone_client.blocks.text(value)[source]#

A text block with one plain paragraph.

The value is plain text, not Markdown: * and < are kept as they are. Runs of whitespace, newlines included, become one space, as in an HTML paragraph. With collective.html2blocks installed, it builds the block, as it does for convert(); without it, the block is built here, the same way.

Parameters:

value (str) – The text.

Returns:

A slate block.

Return type:

dict[str, Any]

plone_client.blocks.block(block_type, /, **data)[source]#

Any block, given its type and its data.

For blocks this module has no helper for, such as those of an add-on. client.block_types describes the data each block of a site takes.

Parameters:
  • block_type (str) – The block’s @type, such as listing.

  • data (Any) – The block’s data.

Returns:

The block.

Return type:

dict[str, Any]

plone_client.blocks.container(block_type, /, *items, **data)[source]#

A block that holds other blocks, such as a grid.

The blocks inside get their own blocks and blocks_layout, as a page has; see build().

Parameters:
  • block_type (str) – The block’s @type, such as gridBlock.

  • items (Mapping[str, Any]) – The blocks inside, in order.

  • data (Any) – The container’s own data, such as a headline.

Returns:

The block.

Return type:

dict[str, Any]

plone_client.blocks.grid(*items, **data)[source]#

A Volto grid, which shows its blocks side by side.

Volto allows up to four blocks in a grid, unless the site changes that.

Parameters:
  • items (Mapping[str, Any]) – The blocks inside, in order, such as teaser() blocks.

  • data (Any) – The grid’s own data, such as a headline.

Returns:

A gridBlock block.

Return type:

dict[str, Any]

plone_client.blocks.teaser(target, title='', **data)[source]#

A teaser: a card linking to one item, with its title and image.

The teaser shows the title, description, and image of the target, and follows later changes to it.

Parameters:
  • target (str) – Site path or URL of the item, or a URL outside the site.

  • title (str) – Title to store with the link.

  • data (Any) – More data, such as overwrite and description.

Returns:

A teaser block.

Return type:

dict[str, Any]

plone_client.blocks.convert(source, source_format='markdown', *, before=())[source]#

Blocks for Markdown or HTML, converted by collective.html2blocks.

Paragraphs, headings, lists and quotes become text (slate) blocks; images, videos and tables get blocks of their own.

Needs the markdown extra (Python 3.12 or later):

pip install 'plone-client[markdown]'
Parameters:
Returns:

blocks and blocks_layout, as build() returns them.

Raises:
Return type:

dict[str, Any]

plone_client.blocks.iter_blocks(blocks, layout=None)[source]#

Every block, nested ones included, depth first.

Blocks are visited in layout order. Container blocks (grids, columns, accordions…) keep their children either in their own blocks and blocks_layout or inside data; both are followed. Blocks missing from the layout come last.

Parameters:
  • blocks (Mapping[str, Any] | None) – The blocks of an item or of a container block.

  • layout (Mapping[str, Any] | None) – The matching blocks_layout.

Returns:

Pairs of block id and block data.

Return type:

Iterator[tuple[str, dict[str, Any]]]

Every link inside a block, or inside any value.

Finds string values of url, href, link and preview_image_link keys, and the @id of the objects that object browser widgets store in lists ("href": [{"@id": …}]).

Parameters:

node (Any) – A block, a mapping of blocks, or any JSON value.

Returns:

Each link, in document order.

Return type:

Iterator[str]

Profiles#

Named connection profiles, so one machine can talk to many sites.

A profile names a site, a user and where that user’s secret is kept. The profiles live in a TOML file, by default ~/.config/plone-client/config.toml ($XDG_CONFIG_HOME and $PLONE_CLIENT_CONFIG are honored):

current = "blog"

[defaults]
timeout = 60
retries = 5

[profiles.blog]
url = "https://example.org"
username = "editor"

[profiles.local]
url = "http://localhost:8080/Plone"
username = "admin"
auth = "jwt"

[profiles.production]
url = "https://www.example.com"
username = "editor"
read_only = true
secret = "command"
secret_command = "op read op://Private/example/password"
verify = "/etc/ssl/certs/example-ca.pem"

[groups]
sites = ["blog", "production"]

The defaults table holds the connection settings shared by every profile (see DEFAULT_KEYS); a profile’s own value wins. The groups table names lists of profiles, which the MCP server can serve together (plone-client mcp --group sites).

Secrets never go in the file. By default they are kept in the operating system’s keyring (macOS Keychain, Windows Credential Locker, Secret Service on Linux); see plone_client.credentials for the other sources.

Which profile is used, from the strongest choice to the weakest: the name passed explicitly, $PLONE_CLIENT_PROFILE, a .plone-client.toml file in the working directory or one of its parents (profile = "blog"), and the current profile of the configuration file.

plone_client.profiles.DEFAULT_KEYS: tuple[str, ...] = ('timeout', 'verify', 'retries', 'backoff', 'api_prefix', 'read_only')#

Settings allowed in the defaults table of the configuration file.

plone_client.profiles.parse_verify(value)[source]#

Read a verify setting written as text.

Parameters:

value (str) – true or false (also 1/0, yes/no, on/off), or the path of a CA bundle.

Returns:

A boolean, or the path.

Raises:

PloneConfigurationError – If the value is empty.

Return type:

bool | str

plone_client.profiles.default_config_path(environ=None)[source]#

Path of the user’s configuration file.

Parameters:

environ (Mapping[str, str] | None) – Environment; os.environ by default.

Returns:

$PLONE_CLIENT_CONFIG, or config.toml inside $XDG_CONFIG_HOME/plone-client (~/.config/plone-client).

Return type:

Path

plone_client.profiles.find_project_profile(start=None)[source]#

Profile named by a .plone-client.toml file.

The file is looked for in start and in each of its parents, so a repository can say which site it works with. It holds no secrets and can be committed.

Parameters:

start (Path | None) – Directory to start from; the working directory by default.

Returns:

The profile name, or an empty string when there is no file.

Return type:

str

class plone_client.profiles.Profile(name, url, username='', auth='basic', secret='keyring', secret_env='PLONE_CLIENT_PASSWORD', secret_command='', read_only=False, timeout=30.0, verify=True, retries=3, backoff=0.5, api_prefix='++api++', frontend_url='', description='')[source]#

Bases: object

Connection settings of one site.

Parameters:
  • name (str) – Profile name.

  • url (str) – URL of the site root.

  • username (str) – Login name; empty for anonymous access.

  • auth (Literal['basic', 'jwt', 'token']) – basic or jwt with a username and password, or token to send the secret as a JWT.

  • secret (Literal['keyring', 'env', 'command', 'none']) – Where the secret is kept: keyring, env, command or none.

  • secret_env (str) – Variable holding the secret, with secret = "env".

  • secret_command (str) – Command printing the secret, with secret = "command"; run without a shell.

  • read_only (bool) – Refuse every request that could change the site.

  • timeout (float) – Seconds to wait for the site.

  • verify (bool | str) – Verify TLS certificates; a path verifies them against that CA bundle (a file or a directory) instead of the default one.

  • retries (int) – Times a request is repeated after a network error or an overloaded site; see PloneClient.

  • backoff (float) – Base delay in seconds between retries.

  • api_prefix (str) – Traversal prefix of the REST API.

  • frontend_url (str) – URL of the Volto frontend, when url is the backend; used for services that Volto serves (@blocks-schema).

  • description (str) – Free text, shown by plone-client profile list.

property anonymous: bool#

Whether requests go out without credentials.

classmethod from_mapping(name, data)[source]#

Build a profile from a table of the configuration file.

Parameters:
Returns:

The profile.

Raises:

PloneConfigurationError – If a key is unknown or a value invalid.

Return type:

Profile

to_mapping(defaults=None)[source]#

Table for the configuration file, without default values.

Parameters:

defaults (Mapping[str, Any] | None) – The defaults table; values equal to it are left out, so the profile keeps following it.

Returns:

The settings that differ from the defaults, url first.

Return type:

dict[str, Any]

get_secret()[source]#

The profile’s password or token.

Returns:

The secret, or an empty string for anonymous profiles.

Raises:

PloneConfigurationError – If the secret cannot be found.

Return type:

str

client_settings()[source]#

Keyword arguments for PloneClient.

Returns:

URL, credentials and options; the secret is looked up now.

Return type:

dict[str, Any]

summary()[source]#

Description of the profile, safe to print.

Returns:

Settings without any secret.

Return type:

dict[str, Any]

class plone_client.profiles.Config(path, data=None)[source]#

Bases: object

The profiles of a configuration file.

Parameters:
  • path (Path) – Path of the file.

  • data (Mapping[str, Any] | None) – Parsed contents.

groups: dict[str, list[str]]#

Named lists of profiles, such as the sites of one customer.

set_group(name, members)[source]#

Create or replace a group of profiles.

Parameters:
  • name (str) – Group name.

  • members (Iterable[str]) – Names of the profiles in the group; duplicates are dropped and the order kept.

Returns:

The members.

Raises:

PloneConfigurationError – If the name is invalid, the group is empty, or a profile does not exist.

Return type:

list[str]

group(name)[source]#

The profiles of a group.

Parameters:

name (str) – Group name.

Returns:

The profiles, in the group’s order.

Raises:

PloneConfigurationError – If there is no such group.

Return type:

list[Profile]

remove_group(name)[source]#

Remove a group; its profiles are kept.

Parameters:

name (str) – Group name.

Returns:

The members it had.

Raises:

PloneConfigurationError – If there is no such group.

Return type:

list[str]

set_defaults(values)[source]#

Change the settings shared by every profile.

Profiles that took a setting from the old defaults take it from the new ones; settings of their own are kept.

Parameters:

values (Mapping[str, Any]) – Settings to set; None removes a setting.

Raises:

PloneConfigurationError – If a key is not one of DEFAULT_KEYS or a value is invalid.

Return type:

None

get(name)[source]#

A profile by name.

Parameters:

name (str) – Profile name.

Returns:

The profile.

Raises:

PloneConfigurationError – If there is no such profile.

Return type:

Profile

current_name(environ=None, cwd=None)[source]#

Name of the profile to use when none is given explicitly.

Parameters:
  • environ (Mapping[str, str] | None) – Environment; os.environ by default.

  • cwd (Path | None) – Directory where .plone-client.toml is looked for.

Returns:

The name, or an empty string.

Return type:

str

add(profile, *, replace=False)[source]#

Add a profile.

Parameters:
  • profile (Profile) – The profile.

  • replace (bool) – Replace a profile with the same name.

Raises:

PloneConfigurationError – If the name is taken.

Return type:

None

remove(name)[source]#

Remove a profile, also from the groups; a group left empty goes too.

Parameters:

name (str) – Profile name.

Returns:

The removed profile.

Return type:

Profile

to_mapping()[source]#

Contents of the configuration file.

Returns:

current and the defaults, profiles and groups tables.

Return type:

dict[str, Any]

save()[source]#

Write the configuration file, readable only by its owner.

Raises:

PloneConfigurationError – If tomlkit is not installed.

Return type:

None

plone_client.profiles.load_config(path=None)[source]#

Read a configuration file.

Parameters:

path (Path | None) – Path of the file; the user’s by default. A missing file gives an empty configuration.

Returns:

The configuration.

Raises:

PloneConfigurationError – If the file is not valid.

Return type:

Config

plone_client.profiles.settings_from_env(environ, *, prefix='PLONE_CLIENT_')[source]#

Client settings from environment variables.

Reads URL, USERNAME (or USER), PASSWORD, TOKEN, AUTH_METHOD, API_PREFIX, TIMEOUT, VERIFY (true, false or a CA bundle path), RETRIES, BACKOFF, READ_ONLY and FRONTEND_URL, each after the prefix. With prefix="REMOTE_", this reads the REMOTE_URL, REMOTE_USER and REMOTE_PASSWORD variables used by older scripts.

Parameters:
  • environ (Mapping[str, str]) – The environment.

  • prefix (str) – Prefix of the variable names.

Returns:

Keyword arguments for PloneClient.

Raises:

PloneConfigurationError – If the URL is not set.

Return type:

dict[str, Any]

Credentials#

Where the password or token of a profile is kept.

keyring (default)

The operating system’s secret store, through the keyring package: macOS Keychain, Windows Credential Locker, or the Secret Service on Linux. Entries are stored under the service plone-client:<profile>.

env

An environment variable, named by the profile’s secret_env (PLONE_CLIENT_PASSWORD by default). Handy in CI.

command

The output of a command, named by the profile’s secret_command, such as op read op://Private/site/password or pass show plone/site. The command runs without a shell.

none

No secret: the profile is anonymous.

plone_client.credentials.keyring_service(profile)[source]#

Keyring service name of a profile.

Parameters:

profile (Profile) – The profile.

Returns:

plone-client:<profile name>.

Return type:

str

plone_client.credentials.keyring_account(profile)[source]#

Keyring account name of a profile.

Parameters:

profile (Profile) – The profile.

Returns:

The username, or token for token profiles without one.

Return type:

str

plone_client.credentials.get_secret(profile)[source]#

Look up the secret of a profile.

Parameters:

profile (Profile) – The profile.

Returns:

The password or token.

Raises:

PloneConfigurationError – If the secret is missing.

Return type:

str

plone_client.credentials.set_secret(profile, value)[source]#

Store the secret of a profile in the keyring.

Parameters:
  • profile (Profile) – The profile.

  • value (str) – The password or token.

Raises:

PloneConfigurationError – If the profile keeps its secret elsewhere.

Return type:

None

plone_client.credentials.delete_secret(profile)[source]#

Remove the secret of a profile from the keyring.

Parameters:

profile (Profile) – The profile.

Returns:

True if there was a secret to remove.

Return type:

bool

Utilities#

Small helpers shared by the library and the command line.

plone_client.utils.UID_RE = re.compile('^[0-9a-f]{32}$')#

A Plone UID: 32 lowercase hexadecimal characters.

plone_client.utils.uid_from_ref(ref)[source]#

UID named by a reference, if the reference names one.

Two forms name a UID: uid:<UID> and a resolveuid link, the way Volto stores internal links (../resolveuid/<UID>, https://example.org/resolveuid/<UID>/@@download/file).

Parameters:

ref (str) – A path, URL or UID reference.

Returns:

The UID, or an empty string when ref is a plain path or URL.

Return type:

str

plone_client.utils.resolveuid_url(uid, suffix='')[source]#

Link to an item by UID, in the form Volto stores in blocks.

Parameters:
  • uid (str) – UID of the item.

  • suffix (str) – Text appended to the link, such as #section or /@@download/file.

Returns:

../resolveuid/<UID><suffix>.

Return type:

str