No project description provided
Project description
ckanext-flakes
Tools for creating and managing independent chunks of data.
ℹ Whenever you see the word flake below, it means a record, that contains an arbitrary dictionary. A couple of facts:
- Absolutely every flake contains data. At least an empty dictionary. But there is no flake that has no data at all.
- Flake can hold extra details, that are not a part of the data. Its purpose, description, tags, anything. Extra details are just a separate dictionary that can hold any information that is important for the flake but cannot be placed inside the flake's primary data.
- Flakes belong to the user. There is no unowned flake. Whenever owner is removed, all his flakes removed as well.
- Flake can have a name. Not necessary, but if you want to create a very special flake, you can give it a name. You cannot have two flakes with the same name(because every named flake is really special for you). But other users can use the same names for their flakes as you do. In other words, flake's name is unique per user.
- Flake can have a parent. If the parent is removed, all its descendants
removed as well. Parent extends flake's data, providing default
values. The behavior of the flake with a parent is very similar to the
built-in
collections.ChainMap
. Flake can have only one parent, so there are no things like python's method resolution order. - Flake can be validated.
- Flakes can be combined. Check
flakes_flake_combine
andflakes_flake_merge
actions below.
Where you can use it?
-
You want to create a TODO list inside your application. You actually can
- define custom dataset type for this purpose
- Create migration, model, set of actions
Easy, but I've done it too many times and at some point, I even created macros for such tasks. Do I have to do it again? Hmmm.. why not use flakes? They can hold arbitrary data, such as task, deadline, and state. By default, flakes are visible only to the owner(and sysadmin, of course), so they won't leak to other users. And you can use flake's extra in order to set, for example, the task's subject and use it for filtering via
flakes_flake_list
. The only thing you need to do is a UI for the TODO list. But you have to do it anyway because it must be styled using your app's style guidelines and branding colors. -
You need to create resources before the dataset. Don't know why, but you have all the resource details(except for the uploaded file because flakes are about information, not about files). CKAN will not be happy if you try
resource_create
without the dataset's ID.But how about creating a flake? Put all the details into it and forget about the resource. Take a break or even vacation. Get back to work, and create a dataset. Add dataset's ID to the existing flake via
flakes_flake_update
orflakes_flake_override
. And turn it into a resource usingflakes_flake_materialize
. -
You are developing multi-step dataset creation form. Sounds cool. But you have to store different pieces of dataset somewhere. Of course, if you don't have an overprotective validation schema, you can just save all the parts inside the draft dataset. But if you do have such schema.. well, you know what I'll recommend, right? Just create a bunch of flakes, combine them into a dictionary, and send this dictionary to the
package_create
. Or merge them into a new flake and materialize using API action on your choice. Have you said "validation"? Or you meant another "validation"? -
How about a user-request functionality? User has a
state
so you can create a pending user account, that requires approval. But when somebody creates a user request, he can give you extra details, like the reason to join the portal, the organization in which the new user wants to be a member, etc. You already know what to do. -
Actually, anything that requires some sort of approval can use flakes:
- Dataset suggestion? Yes, you don't need a draft dataset here.
- Dataset revision, that must be approved, before an actual dataset is updated? Why not? If you prefer to clone the dataset, modify the clone, and merge it back, it's ok. But if it's overkill for your case and you just need small patches, flake may save you a day or two.
- Request to move a dataset from one organization to another or mark it as obsolete/superseeded? I don't mind.
Requirements
Requires python v3.7 or greater. Python v2 support doesn't require much effort, but it neither worth the time you'll spend on it.
Compatibility with core CKAN versions:
CKAN version | Compatible? |
---|---|
2.9 | yes |
2.10 | yes |
Installation
To install ckanext-flakes:
-
Install it via pip:
pip install ckanext-flakes
-
Add
flakes
to theckan.plugins
setting in your CKAN config file. -
Run DB migrations:
ckan db upgrade -p flakes
Config settings
# Allow logged-in user to create flakes.
# When disabled, only sysadmin can work with flakes.
# (optional, default: true).
ckanext.flakes.creation.allowed = no
# Allow validation. Depending on your validation schemas,
# it can potentially discover some sensitive information.
# For example, there is a validator, which verifies that user ID exists.
# That's why validation is disabled by default.
# (optional, default: false).
ckanext.flakes.validation.allowed = yes
Interfaces
Provides ckanext.flakes.interfaces.IFlakes
interface. Always use
inherit=True
when implementing it, because it may change in the future.
Currently it provides the following hooks:
class IFlakes(Interface):
"""Extend functionality of ckanext-flakes"""
def get_flake_schemas(self) -> dict[str, dict[str, Any]]:
"""Register named validation schemas.
Used by `flakes_flake_validate` and `flakes_data_validate` actions.
Returns:
Mapping of names and corresponding validation schemas.
Example:
def get_flake_schemas(self) -> dict[str, dict[str, Any]]:
return {
"schema-that-requires-name": {"name": [not_missing]}
}
"""
return {}
def get_flake_factories(self) -> dict[str, Callable[[dict[str, Any]], dict[str, Any]]]:
"""Register named example factories.
Used by `flakes_data_example` action.
Returns:
Mapping of names and corresponding example factories.
Example:
def get_flake_factories(self) -> dict[str, dict[str, Any]]:
def factory(payload: dict[str, Any]):
return {"field": "value"}
return {
"test-factory": factory
}
"""
return {}
API
flakes_flake_create
Create flake.
Args:
name (str, optional): name of the flake
data (dict): flake's data
parent_id (str, optional): ID of flake to extend
extras (dict): flake's extra details
flakes_flake_show
Display existing flake
Args:
id (str): ID of flake to display
expand (bool, optional): Extend flake using data from the parent flakes
flakes_flake_list
Display all flakes of the user.
If both extra_path
in form of ["top_level_key", "nested_key", ...]
and
string extra_value
are provided, show only flakes that satisfy given search
criteria. Example:
first_flake = Flake(extras={"xxx": {"yyy": "hello"}})
second_flake = Flake(extras={"xxx": {"yyy": "world"}})
flake_list(context, {"extra_path": ["xxx", "yyy"], "extra_value": "hello"})
>>> first_flake
Args:
expand (bool, optional): Extend flake using data from the parent flakes
extra_path (list, optional): Nested path existing in extras
extra_value (str, optional): Value stored under the specified path
flakes_flake_update
Update existing flake
Args:
id (str): ID of flake to update
data (dict): flake's data
parent_id (str, optional): ID of flake to extend
extras (dict): flake's extra details
flakes_flake_override
Update existing flake by name or create a new one.
Args:
name (str): Name flake to override
data (dict): template itself
parent_id (str, optional): ID of flake to extend
extras (dict): flake's extra details
flakes_flake_delete
Delete existing flake
Args:
id (str): ID of flake to delete
flakes_flake_lookup
Search flake by name.
Args:
name (str): Name of the flake
flakes_flake_validate
Validate existing flake
Schemas must be registered via IFlakes
interface.
Args:
id (str): ID of flake to validate
expand (bool, optional): Extend flake using data from the parent flakes
schema(str): validation schema for the flake's data
flakes_data_validate
Validate arbitrary data against the schema.
Args:
data (dict): data that needs to be validated
schema(str): validation schema for the data
flakes_data_example
Generate an example of the flake's data using named factory.
Factories must be registered via IFlakes
interface.
Args:
factory(str): example factory
data (dict, optional): payload for the example factory
flakes_flake_materialize
Send flake's data to API action.
Args:
id (str): ID of flake to materialize
expand (bool, optional): Extend flake using data from the parent flakes
remove (bool, optional): Remove flake after materialization
action (str): API action to use for materialization
flakes_flake_combine
Combine and show data from multiple flakes
id
argument specifies all the flakes that must be combined. All of the flakes
must exist, otherwise NotFound
error raised. IDs at the start of the list have
higher priority(override matching keys). IDs at the end of the list have lower
priority(can be shadowed by former flakes).
expand
must be a dict[str, bool]
. Keys are IDs of the flakes, values are
expand flags for the corresponding flake.
Args:
id (list): IDs of flakes.
expand (dict, optional): Extend flake using data from the parent flakes
flakes_flake_merge
Combine multiple flakes and save the result.
Args:
id (list): IDs of flakes.
expand (dict, optional): Extend flake using data from the parent flakes
remove (bool, optional): Remove flakes after the operation.
destination (str, optional): Save data into the specified flake instead of a new one
flakes_data_patch
Partially overrides data leaving other fields intact.
Args:
id (str): ID of flake
data (dict): patch for data
flakes_extras_patch
Partially overrides extras leaving other fields intact.
Args:
id (str): ID of flake
extras (dict): patch for extras
Developer installation
To install ckanext-flakes for development, activate your CKAN virtualenv and do:
git clone https://github.com/DataShades/ckanext-flakes.git
cd ckanext-flakes
python setup.py develop
Tests
To run the tests, do:
pytest
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file ckanext-flakes-0.0.7.tar.gz
.
File metadata
- Download URL: ckanext-flakes-0.0.7.tar.gz
- Upload date:
- Size: 36.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.11.3 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0bbf53eb332189d1374ee7e912a44cf64d194150f418485d5ac0410c1f4df0ed |
|
MD5 | fdfbc6ae8bd2d7b2eb7ea9758465ba88 |
|
BLAKE2b-256 | 47120180c0eb337c308356c291c27ffdc4fda4cbac0342b027351c0b75aa9816 |
File details
Details for the file ckanext_flakes-0.0.7-py3-none-any.whl
.
File metadata
- Download URL: ckanext_flakes-0.0.7-py3-none-any.whl
- Upload date:
- Size: 39.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.11.3 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a4026b921a62bdab044bfb364d2d8762fd5ad26e5b9f33c222593053ee3f36bf |
|
MD5 | 76313bf4015acd409493a5e7a26347b2 |
|
BLAKE2b-256 | 56f0e913db0c0e562fd52fdadc2efe16df1fc09cb9e478e45fb950a31549aa90 |