Skip to main content

A Python interface for Plankanban

Project description

plankapy

A Python API for Planka

PyPI - License

PyPI - Version PyPI - Downloads GitHub last commit

Release Docs

Installation

pip install plankapy

Documentation

The full documentation can be found here.

Getting Started

After pip installing, you can connect to a Planka instance using a Planka interface object

from plankapy.v2 import Planka

planka = Planka('https://planka.mydomain.com')

After creating the Planka instance, you can authenticate using the login method:

planka.login(username='username', password='password')
-- OR --
planka.login(api_key='MY_API_KEY')

Logging in for the first time required accepting the instance ToS. Consult with your instance admin on avalable ToS localizations and required ToS types for your user.

planka.login(username=..., password=..., accept_terms=True)

-- With Language --
planka.login(username=..., password=..., accept_terms=True, lang='ja-JP')

-- Specific ToS --
planka.login(username=..., password=..., accept_terms=True, terms_type='extended')

Now that you've authenticated with the server, you have access to everything that you'd be able to access through the web-ui

>>> planka.me
User({...})
>>> planka.projects
[Project({...}), Project({...}), ...]

Features

Fully Typed

Interfaces for all planka objects are fully documented and typed in the source, so if you are using an IDE that supports a python language server you will get full autocompletion. autocomplete

All methods are fully documented using doctrings and contain all info needed to properly form a function call: inline_doc

Since all objects are initialized as a series of endpoints with a local schema cache, it allows you to access any object from any other object in the tree without ever losing track of what you have: circular

All endpoints and schemas are documeted using TypedDict syntax, so you can safely create raw API calls using the PlankaEndpoints object: typed-endpoints

All responses are fully typed as well: 'typed-response-1 'typed-response-2 'typed-response-3

NOTE:

When using plankapy it is reccommended to turn your type checker settings to the strictest mode possible. Since most interfaces forego runtime checks for extensive type hints.

Model Lists

When reading the published docs, all property attributes that are typed as list[<PlankaModel[T]>] will be converted to ModelList at runtime. This list subclass can be used like a regulat list, bu allows indexing and filtering using __getitem__ syntax

int/slice

Since ModelList subclasses list, all regular list interfaces still work:

>>> board.cards[-1]
Card({...})
>>> board.cards[:2]
[Card({...}), Card({})]

str/Id

If a string is used to index a model list, the last model with the matching id is popped. If the id does not exist, the exception raised will be the same as popping from an empty list

>>> my_card_id = '...'
>>> board.cards[my_card_id]
Card({'id': '...'})

SchemaFilter/dict

If you want to define a filter on the model schema, you can pass a dictionary of schema values or expressions to the index:

>>> board.cards[{'name': 'My Card'}]
[Card({'name': 'My Card'})]

>>> board.cards[{'name': lambda name: 'My' in name}]
[Card({'name': 'My Card'}), Card({'name': 'My Other Card'})]

ModelFilter

You can also specify a raw expression to filter the list:

>>> board.cards[lambda card: planka.me in card.members]

Model

You can also direcly pass a Model to the index. The returned result is another ModelList that can be dpop'ed to check for membership

>>> board.users[planka.me].dpop()
None # Not in board

extract

Model lists also allow schema extraction using the extract method. If a single key is passed, a list of values is returned. If multiple keys are passed, a list of tuples of values is returned

>>> board.cards.extract('name')
['My Card', 'My Other Card']
>>> board.card.extract('name', 'dueDate')
[('My Card', None), ('My Other Card', '2026...')]

dpop

A way to safely pop from the model list. Has the same interface as list.pop but accepts a default keyword argument which is det to None when not set by the user:

>>> board.lists[0].pop(0)
IndexError...
>>> board.lists[0].dpop(0, 'Empty')
'Empty'

Live Updates

Every model contains a schema cache attribute that is used for direct attribute access. This means that checking the value of name for a card will not change until sync is called

>>> card = board.cards[{'name': 'My Card'}].dpop()
>>> card.name
'My Card'

# Change Name on server to 'Not My Card'
>>> card.name
'My Card'
>>> card.sync()
>>> card.name
'Not My Card'

If you want your functions to maintain sync with the server, you access the card via other endpoints. All properties that return item lists will re-construct themselves from the response when accessed

>>> card = lambda: board.cards[0]
>>> card().name
'My Card'

# Change Name on server to 'Not My Card'
>>> card().name
'Not My Card'

This example aliases a request chain to a callable lambda function. You can also just use the full desired request path too

>>> board.cards[0].name
'My Card'

# Change Name on server to 'Not My Card'
>>> board.cards[0].name
'Not My Card'

NOTE: This specific structure is written to always get the first card in the board. This could be useful, but you will usually want to apply a specific filter.

Attribute access in Loops

Since extended calls can fire off multiple requests to keep data synced, if you have a tight/hot loop that is accessing a lot of object attributes, it's best to explicitly use the schema cache:

>>> all_cards = ModelList()
>>> for project in planka.projects:
...     for board in project.boards:
...         all_cards.extend(board.cards)

>>> print(all_cards.extract('name'))
['My Card', ...]

Now you have an all_cards model list that contains the endpoints and a cache of all cards in your visible projects.

If you don't need the models at the end of the loop, you can instead just capture values:

>>> card_due_dates = []
>>> for project in planka.projects:
...     for board in project.boards:
...         card_due_dates.extend(board.cards.extract('name', 'dueDate'))

>>> print(card_due_dates)
[('My Card', '2026...'), ('Other Card', None), ...]

License

This project is licensed under the AGPLv3 License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plankapy-2.3.0.tar.gz (111.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plankapy-2.3.0-py3-none-any.whl (135.7 kB view details)

Uploaded Python 3

File details

Details for the file plankapy-2.3.0.tar.gz.

File metadata

  • Download URL: plankapy-2.3.0.tar.gz
  • Upload date:
  • Size: 111.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for plankapy-2.3.0.tar.gz
Algorithm Hash digest
SHA256 2c7bff9ee81db94094f92eab8c8f0b397b301e16a18eae36f816d222f5b98c3c
MD5 1599e0773df4c0ea4b013fe8212921dd
BLAKE2b-256 d937844c6e352aab7694881a0c3cef1b92d5c9bd3ff92147bef9e068e75c6026

See more details on using hashes here.

File details

Details for the file plankapy-2.3.0-py3-none-any.whl.

File metadata

  • Download URL: plankapy-2.3.0-py3-none-any.whl
  • Upload date:
  • Size: 135.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for plankapy-2.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 699532cfff4e5ca7e47409d17ff64c34aff85a41ea14887a87adc1770b3c1066
MD5 5867baa12e6fb6c6ad375fb47dc77c3e
BLAKE2b-256 f657db8f36d86e649ec19e1978a665c6b6cde945f9d72f28f326154d3705562b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page