Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
aiolinkding
is a Python3, async library that interfaces with linkding
instances. It is intended to be a reasonably light wrapper around the linkding API
(meaning that instead of drowning the user in custom objects/etc., it focuses on
returning JSON straight from the API).
pip install aiolinkding
aiolinkding
is currently supported on:
It's easy to create an API client for a linkding instance. All you need are two parameters:
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
asyncio.run(main())
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Get all bookmarks:
bookmarks = await client.bookmarks.async_get_all()
# >>> { "count": 100, "next": null, "previous": null, "results": [...] }
asyncio.run(main())
client.bookmarks.async_get_all()
takes three optional parameters:
query
: a string query to filter the returned bookmarkslimit
: the maximum number of results that should be returnedoffset
: the index from which to return results (e.g., 5
starts at the fifth bookmark)import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Get all archived bookmarks:
bookmarks = await client.bookmarks.async_get_archived()
# >>> { "count": 100, "next": null, "previous": null, "results": [...] }
asyncio.run(main())
client.bookmarks.async_get_archived()
takes three optional parameters:
query
: a string query to filter the returned bookmarkslimit
: the maximum number of results that should be returnedoffset
: the index from which to return results (e.g., 5
starts at the fifth bookmark)import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Get a single bookmark:
bookmark = await client.bookmarks.async_get_single(37)
# >>> { "id": 37, "url": "https://example.com", "title": "Example title", ... }
asyncio.run(main())
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Create a new bookmark:
created_bookmark = await client.bookmarks.async_create(
"https://example.com",
title="Example title",
description="Example description",
tag_names=[
"tag1",
"tag2",
],
)
# >>> { "id": 37, "url": "https://example.com", "title": "Example title", ... }
asyncio.run(main())
client.bookmarks.async_create()
takes four optional parameters:
title
: the bookmark's titledescription
: the bookmark's descriptionnotes
: Markdown notes to add to the bookmarktag_names
: the tags to assign to the bookmark (represented as a list of strings)is_archived
: whether the newly-created bookmark should automatically be archivedunread
: whether the newly-created bookmark should be marked as unreadshared
: whether the newly-created bookmark should be shareable with other linkding usersimport asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Update an existing bookmark:
updated_bookmark = await client.bookmarks.async_update(
37,
url="https://different-example.com",
title="Different example title",
description="Different example description",
tag_names=[
"tag1",
"tag2",
],
)
# >>> { "id": 37, "url": "https://different-example.com", ... }
asyncio.run(main())
client.bookmarks.async_update()
takes four optional parameters (inclusion of any parameter
will change that value for the existing bookmark):
url
: the bookmark's URLtitle
: the bookmark's titledescription
: the bookmark's descriptionnotes
: Markdown notes to add to the bookmarktag_names
: the tags to assign to the bookmark (represented as a list of strings)unread
: whether the bookmark should be marked as unreadshared
: whether the bookmark should be shareable with other linkding usersimport asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Archive a bookmark by ID:
await client.bookmarks.async_archive(37)
# ...and unarchive it:
await client.bookmarks.async_unarchive(37)
asyncio.run(main())
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Delete a bookmark by ID:
await client.bookmarks.async_delete(37)
asyncio.run(main())
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Get all tags:
tags = await client.tags.async_get_all()
# >>> { "count": 100, "next": null, "previous": null, "results": [...] }
asyncio.run(main())
client.tags.async_get_all()
takes two optional parameters:
limit
: the maximum number of results that should be returnedoffset
: the index from which to return results (e.g., 5
starts at the fifth bookmark)import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Get a single tag:
tag = await client.tags.async_get_single(22)
# >>> { "id": 22, "name": "example-tag", ... }
asyncio.run(main())
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Create a new tag:
created_tag = await client.tags.async_create("example-tag")
# >>> { "id": 22, "name": "example-tag", ... }
asyncio.run(main())
import asyncio
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
client = await async_get_client("http://127.0.0.1:8000", "token_abcde12345")
# Get all tags:
tags = await client.user.async_get_profile()
# >>> { "theme": "auto", "bookmark_date_display": "relative", ... }
asyncio.run(main())
By default, the library creates a new connection to linkding with each coroutine. If you
are calling a large number of coroutines (or merely want to squeeze out every second of
runtime savings possible), an aiohttp
ClientSession
can be used for
connection pooling:
import asyncio
from aiohttp import async_get_clientSession
from aiolinkding import async_get_client
async def main() -> None:
"""Use aiolinkding for fun and profit."""
async with ClientSession() as session:
client = await async_get_client(
"http://127.0.0.1:8000", "token_abcde12345", session=session
)
# Get to work...
asyncio.run(main())
Thanks to all of our contributors so far!
python3 -m venv .venv
source ./.venv/bin/activate
script/setup
poetry run pytest --cov aiolinkding tests
README.md
with any new documentation.FAQs
A Python3, async interface to the linkding REST API
We found that aiolinkding demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.