# PyPerms (Python Permissions)
PyPerms is a library for convenient access control. The inspiration was the JS library - [CASL](https://casl.js.org/).
## Simple Usage
```python
from pyperms import PermissionsBuilder
from .models import User
def define_perms_for(user):
builder = PermissionsBuilder()
builder.can("read", "Post")
if "admin" in user.roles:
builder.can("*", "*")
return builder.build()
admin = User(id=1, roles=["admin"])
user = User(id=2, roles=["user"])
admin_perms = define_perms_for(admin)
user_perms = define_perms_for(user)
admin_perms = define_perms_for(admin)
user_perms = define_perms_for(user)
admin_perms.can("read", "Post") # True
admin_perms.can("create", "Post") # True
admin_perms.can("read", "Article") # True
user_perms.can("read", "Post") # True
user_perms.can("create", "Post") # False
```
## Typing
For typing `Actions` and `Subjects`, you can use `Literal` from the standard module `typing`.
```python
from typing import Literal
from pyperms import PermissionsBuilder
Actions = Literal["*", "read"]
Subjects = Literal["*", "Post"]
def define_perms():
builder = PermissionsBuilder[Actions, Subjects]()
builder.can("read", "Post") # OK
builder.can("*", "*") # OK
builder.can("create", "Post") # Error
return builder.build()
```
## Fields
For more flexible permission settings, you can use the `fields` parameter.
```python
from pyperms import PermissionsBuilder
def define_perms():
builder = PermissionsBuilder()
builder.can("read", "Post", fields=["title", "author"])
return builder.build()
perms = define_perms()
perms.can("read", "Post", field="title") # True
perms.can("read", "Post", field="created_at") # False
```
## Conditions
Sometimes permission checks may require conditions, such as whether the user is the author of the post. For such cases, there is a `condiotion` parameter in the builder `can` and `cannot` methods. For it to work, it is necessary to pass an instance of the class with the same name in the `subject`.
```python
from pyperms import PermissionsBuilder
from pyperms import operators as _
from .models import Post, User
def define_perms_for(user):
builder = PermissionsBuilder()
builder.can("update", "Post", condition=_.Eq("author", user.id))
return builder.build()
post = Post(id=1, author=1)
user1 = User(id=1)
user2 = User(id=2)
user1_perms = define_perms_for(user1)
user2_perms = define_perms_for(user2)
user1_perms.can("update", post) # True
user2_perms.can("update", post) # False
```
`Operator` is a callable object that returns a boolean value. When it is initialized, the first parameter is the path to the attribute (can be separated by dot for recursive access), the second parameter is the value to be checked.
Here is a list of default operators:
- Logical:
- And
- Or
- Not
- Other:
- Eq
- Ne
- Lt
- Le
- Gt
- Ge
- In
- NIn
- All
- Size
- Regex
## Attributes
Each operator, when called, tries to get the attribute using `getattr`. To reduce the number of `getattr` calls, you can use the `Attribute` class or the `attr` function. An instance of this class stores the received attribute value for each object (comparison by id).
```python
from pyperms import PermissionsBuilder, attr
from pyperms import operators as _
def define_perms_for(user):
builder = PermissionsBuilder()
author = attr("author")
builder.can("read", "Post", condition=_.Eq(author, user.id))
builder.can("update", "Post", condition=_.Eq(author, user.id))
return builder.build()
```
## Custom operators
All operators are subclasses of one of three base classes: `BaseLogicOperator1`, `BaseLogicOperator2`, `BaseOperator`.
An example of your own operator:
```python
from pyperms.conditions.base import BaseOperator
def my_func(__a: int, __b: int) -> bool:
return __a + __b == 2
class MyOperator(BaseOperator, func=my_func):
"Docstring for MyOperator"
...
```
Raw data
{
"_id": null,
"home_page": "https://github.com/X-AROK/pyperms",
"name": "pyperms",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "pyperms,permissions,casl,ability",
"author": "X-AROK",
"author_email": "an_xarok@mail.ru",
"download_url": "https://files.pythonhosted.org/packages/2b/8b/f755ea5298563ee20ebbd23cbe45af04182cf1a6aa4aa789299afb739671/pyperms-0.1.0.tar.gz",
"platform": null,
"description": "# PyPerms (Python Permissions)\n\nPyPerms is a library for convenient access control. The inspiration was the JS library - [CASL](https://casl.js.org/).\n\n## Simple Usage\n\n```python\nfrom pyperms import PermissionsBuilder\n\nfrom .models import User\n\n\ndef define_perms_for(user):\n builder = PermissionsBuilder()\n\n builder.can(\"read\", \"Post\")\n if \"admin\" in user.roles:\n builder.can(\"*\", \"*\")\n\n return builder.build()\n\n\nadmin = User(id=1, roles=[\"admin\"])\nuser = User(id=2, roles=[\"user\"])\n\nadmin_perms = define_perms_for(admin)\nuser_perms = define_perms_for(user)\n\nadmin_perms = define_perms_for(admin)\nuser_perms = define_perms_for(user)\n\nadmin_perms.can(\"read\", \"Post\") # True\nadmin_perms.can(\"create\", \"Post\") # True\nadmin_perms.can(\"read\", \"Article\") # True\n\nuser_perms.can(\"read\", \"Post\") # True\nuser_perms.can(\"create\", \"Post\") # False\n```\n\n## Typing\n\nFor typing `Actions` and `Subjects`, you can use `Literal` from the standard module `typing`.\n\n```python\nfrom typing import Literal\n\nfrom pyperms import PermissionsBuilder\n\nActions = Literal[\"*\", \"read\"]\nSubjects = Literal[\"*\", \"Post\"]\n\n\ndef define_perms():\n builder = PermissionsBuilder[Actions, Subjects]()\n\n builder.can(\"read\", \"Post\") # OK\n builder.can(\"*\", \"*\") # OK\n\n builder.can(\"create\", \"Post\") # Error\n\n return builder.build()\n```\n\n## Fields\n\nFor more flexible permission settings, you can use the `fields` parameter.\n\n```python\nfrom pyperms import PermissionsBuilder\n\n\ndef define_perms():\n builder = PermissionsBuilder()\n builder.can(\"read\", \"Post\", fields=[\"title\", \"author\"])\n return builder.build()\n\n\nperms = define_perms()\nperms.can(\"read\", \"Post\", field=\"title\") # True\nperms.can(\"read\", \"Post\", field=\"created_at\") # False\n```\n\n## Conditions\n\nSometimes permission checks may require conditions, such as whether the user is the author of the post. For such cases, there is a `condiotion` parameter in the builder `can` and `cannot` methods. For it to work, it is necessary to pass an instance of the class with the same name in the `subject`.\n\n```python\nfrom pyperms import PermissionsBuilder\nfrom pyperms import operators as _\n\nfrom .models import Post, User\n\n\ndef define_perms_for(user):\n builder = PermissionsBuilder()\n builder.can(\"update\", \"Post\", condition=_.Eq(\"author\", user.id))\n return builder.build()\n\n\npost = Post(id=1, author=1)\n\nuser1 = User(id=1)\nuser2 = User(id=2)\n\nuser1_perms = define_perms_for(user1)\nuser2_perms = define_perms_for(user2)\n\nuser1_perms.can(\"update\", post) # True\nuser2_perms.can(\"update\", post) # False\n```\n\n`Operator` is a callable object that returns a boolean value. When it is initialized, the first parameter is the path to the attribute (can be separated by dot for recursive access), the second parameter is the value to be checked.\n\nHere is a list of default operators:\n\n- Logical:\n - And\n - Or\n - Not\n- Other:\n - Eq\n - Ne\n - Lt\n - Le\n - Gt\n - Ge\n - In\n - NIn\n - All\n - Size\n - Regex\n\n## Attributes\n\nEach operator, when called, tries to get the attribute using `getattr`. To reduce the number of `getattr` calls, you can use the `Attribute` class or the `attr` function. An instance of this class stores the received attribute value for each object (comparison by id).\n\n```python\nfrom pyperms import PermissionsBuilder, attr\nfrom pyperms import operators as _\n\n\ndef define_perms_for(user):\n builder = PermissionsBuilder()\n\n author = attr(\"author\")\n builder.can(\"read\", \"Post\", condition=_.Eq(author, user.id))\n builder.can(\"update\", \"Post\", condition=_.Eq(author, user.id))\n\n return builder.build()\n```\n\n## Custom operators\n\nAll operators are subclasses of one of three base classes: `BaseLogicOperator1`, `BaseLogicOperator2`, `BaseOperator`.\n\nAn example of your own operator:\n\n```python\nfrom pyperms.conditions.base import BaseOperator\n\n\ndef my_func(__a: int, __b: int) -> bool:\n return __a + __b == 2\n\n\nclass MyOperator(BaseOperator, func=my_func):\n \"Docstring for MyOperator\"\n ...\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Library for convenient access control",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/X-AROK/pyperms",
"Repository": "https://github.com/X-AROK/pyperms"
},
"split_keywords": [
"pyperms",
"permissions",
"casl",
"ability"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d43f017cc7f7d314d49d0c9566648e834ef6ff56944b233b8581efc98d99c7b7",
"md5": "19f79df5f2c78c8320a842662f41b862",
"sha256": "f35f8ac7925d09678a04b3577a951cdefd610fed1fcf22ad64ba53530b5902a8"
},
"downloads": -1,
"filename": "pyperms-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "19f79df5f2c78c8320a842662f41b862",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<4.0",
"size": 8077,
"upload_time": "2023-05-30T13:41:31",
"upload_time_iso_8601": "2023-05-30T13:41:31.477439Z",
"url": "https://files.pythonhosted.org/packages/d4/3f/017cc7f7d314d49d0c9566648e834ef6ff56944b233b8581efc98d99c7b7/pyperms-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2b8bf755ea5298563ee20ebbd23cbe45af04182cf1a6aa4aa789299afb739671",
"md5": "00090311ac896cfdc74a5f5355a14f55",
"sha256": "73ea160c638f3551211dd8d949c73bf0ccc2469f65755c5b8fffdce67bbcb0a9"
},
"downloads": -1,
"filename": "pyperms-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "00090311ac896cfdc74a5f5355a14f55",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 6511,
"upload_time": "2023-05-30T13:41:33",
"upload_time_iso_8601": "2023-05-30T13:41:33.596849Z",
"url": "https://files.pythonhosted.org/packages/2b/8b/f755ea5298563ee20ebbd23cbe45af04182cf1a6aa4aa789299afb739671/pyperms-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-05-30 13:41:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "X-AROK",
"github_project": "pyperms",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pyperms"
}