docs(docs): in-code fixes for documentation

This commit is contained in:
Scott Lyons 2024-09-05 13:43:08 -07:00
commit 3611849c00
11 changed files with 1523 additions and 193 deletions

View file

@ -128,10 +128,10 @@ impl SzurubooruClient {
/// Construct a new request using the existing client auth and base URL
/// All requests start with the [SzurubooruClient] struct.
/// The (request)[SzurubooruClient::request],
/// (with_fields)[SzurubooruClient::fields],
/// (limit)[SzurubooruClient::limit] and
/// (offset)[SzurubooruClient::offset] methods all return a [SzurubooruRequest] struct that will
/// The [request](crate::SzurubooruClient::request),
/// [with_fields](crate::SzurubooruClient::with_fields),
/// [with_limit](crate::SzurubooruClient::with_limit) and
/// [with_offset](crate::SzurubooruClient::with_offset) methods all return a [SzurubooruRequest] struct that will
/// enable you to actually make the requests.
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
@ -149,19 +149,19 @@ impl SzurubooruClient {
/// Construct a new request while selecting only the given fields
/// The Szurubooru API supports selecting a subset of fields for a given resource.
/// Most resource (models)[szurubooru_client::models] have [Option] fields because of that.
/// Most resource [models](crate::models) have [Option] fields because of that.
/// The default is to return all fields for a given resource.
/// See [here](https://github.com/rr-/szurubooru/blob/master/doc/API.md#field-selecting) for
/// more details
///
/// For example, to select only the `version`, `id` and `content_url` fields of a
/// (PostResource)[szurubooru_client::models::PostResource]
/// [PostResource]
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # #[allow(unused)]
/// # async {
/// let client = SzurubooruClient::new_with_token("http://localhost:5001", "myuser", "sz-123456", true).unwrap();
/// let new_request = client.request().with_fields(vec!["version", "id", "content_url"]);
/// let new_request = client.request().with_fields(vec!["version".to_string(), "id".to_string(), "content_url".to_string()]);
/// # };
/// # ()
/// ```
@ -169,7 +169,7 @@ impl SzurubooruClient {
self.request().with_fields(fields)
}
/// The same as (with_fields)[SzurubooruClient::with_fields], but accepts an Option type instead
/// The same as [with_fields](SzurubooruClient::with_fields), but accepts an Option type instead
pub fn with_optional_fields(&self, fields: Option<Vec<String>>) -> SzurubooruRequest {
self.request().with_optional_fields(fields)
}
@ -178,7 +178,7 @@ impl SzurubooruClient {
/// The Szurubooru API supports limiting the number of resources returned for Paginated
/// API endpoints.
///
/// For example, to limit the number of pools returned by (list_pools)[SzurubooruRequest::list_pools]
/// For example, to limit the number of pools returned by [list_pools](SzurubooruRequest::list_pools)
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # #[allow(unused)]
@ -195,7 +195,7 @@ impl SzurubooruClient {
self.request().with_limit(limit)
}
/// The same as (with_limit)[SzurubooruClient::with_limit], but accepts an Option type instead
/// The same as [with_limit](SzurubooruClient::with_limit), but accepts an Option type instead
pub fn with_optional_limit(&self, limit: Option<u32>) -> SzurubooruRequest {
self.request().with_optional_limit(limit)
}
@ -205,7 +205,7 @@ impl SzurubooruClient {
/// endpoints. Use this offset in combination with the limit to page through
/// large result sets.
///
/// For example, to offset the list of pools returned by (list_pools)[SzurubooruRequest::list_pools]
/// For example, to offset the list of pools returned by [list_pools](SzurubooruRequest::list_pools)
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # #[allow(unused)]
@ -222,7 +222,7 @@ impl SzurubooruClient {
self.request().with_offset(offset)
}
/// The same as (with_offset)[SzurubooruClient::with_offset], but accepts an Option type instead
/// The same as [with_offset](SzurubooruClient::with_offset), but accepts an Option type instead
pub fn with_optional_offset(&self, offset: Option<u32>) -> SzurubooruRequest {
self.request().with_optional_offset(offset)
}
@ -231,9 +231,13 @@ impl SzurubooruClient {
#[derive(Debug)]
/// A type that represents a single Szurubooru request.
pub struct SzurubooruRequest<'a> {
fields: Option<Vec<String>>,
limit: Option<u32>,
offset: Option<u32>,
/// The currently selected fields to return (if applicable)
pub fields: Option<Vec<String>>,
/// The maximum number of resources to return (if supported by the API endpoint)
pub limit: Option<u32>,
/// The number of resource to skip before returning any results
/// (if supported by the API endpoint)
pub offset: Option<u32>,
client: &'a SzurubooruClient,
}
@ -249,19 +253,19 @@ impl<'a> SzurubooruRequest<'a> {
/// Select which fields to return from the query.
/// The Szurubooru API supports selecting a subset of fields for a given resource.
/// Most resource (models)[szurubooru_client::models] have [Option] fields because of that.
/// Most resource [models](crate::models) have [Option] fields because of that.
/// The default is to return all fields for a given resource.
/// See [here](https://github.com/rr-/szurubooru/blob/master/doc/API.md#field-selecting) for
/// more details
///
/// For example, to select only the `version`, `id` and `content_url` fields of a
/// (PostResource)[szurubooru_client::models::PostResource]
/// [PostResource]
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # #[allow(unused)]
/// # async {
/// let client = SzurubooruClient::new_with_token("http://localhost:5001", "myuser", "sz-123456", true).unwrap();
/// let new_request = client.request().with_fields(vec!["version", "id", "content_url"]);
/// let new_request = client.request().with_fields(vec!["version".to_string(), "id".to_string(), "content_url".to_string()]);
/// # };
/// # ()
/// ```
@ -270,8 +274,8 @@ impl<'a> SzurubooruRequest<'a> {
self
}
/// The same as (with_fields)[SzurubooruRequest::with_fields], but accepts an Option type instead
pub fn with_optional_fields(mut self, val: Option<Vec<String>>) -> Self {
/// The same as [with_fields](SzurubooruRequest::with_fields), but accepts an Option type instead
pub fn with_optional_fields(self, val: Option<Vec<String>>) -> Self {
match val {
Some(f) => self.with_fields(f),
None => self,
@ -282,7 +286,7 @@ impl<'a> SzurubooruRequest<'a> {
/// The Szurubooru API supports limiting the number of resources returned for Paginated
/// API endpoints.
///
/// For example, to limit the number of pools returned by (list_pools)[SzurubooruRequest::list_pools]
/// For example, to limit the number of pools returned by [list_pools](SzurubooruRequest::list_pools)
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # #[allow(unused)]
@ -300,8 +304,8 @@ impl<'a> SzurubooruRequest<'a> {
self
}
/// The same as (with_limit)[SzurubooruRequest::with_limit], but accepts an Option type instead
pub fn with_optional_limit(mut self, val: Option<u32>) -> Self {
/// The same as [with_limit](SzurubooruRequest::with_limit), but accepts an Option type instead
pub fn with_optional_limit(self, val: Option<u32>) -> Self {
match val {
Some(f) => self.with_limit(f),
None => self,
@ -313,7 +317,7 @@ impl<'a> SzurubooruRequest<'a> {
/// endpoints. Use this offset in combination with the limit to page through
/// large result sets.
///
/// For example, to offset the list of pools returned by (list_pools)[SzurubooruRequest::list_pools]
/// For example, to offset the list of pools returned by [list_pools](SzurubooruRequest::list_pools)
/// ```no_run
/// # use szurubooru_client::SzurubooruClient;
/// # #[allow(unused)]
@ -331,7 +335,7 @@ impl<'a> SzurubooruRequest<'a> {
self
}
/// The same as (with_offset)[SzurubooruRequest::with_offset], but accepts an Option type instead
/// The same as [with_offset](SzurubooruRequest::with_offset), but accepts an Option type instead
pub fn with_optional_offset(self, val: Option<u32>) -> Self {
match val {
Some(f) => self.with_offset(f),
@ -427,7 +431,7 @@ impl<'a> SzurubooruRequest<'a> {
.map_err(SzurubooruClientError::RequestError)?;
let server_error = serde_json::from_str::<SzurubooruServerError>(&resp_json)
.map_err(|e| SzurubooruClientError::ResponseError(status, resp_json))?;
.map_err(|_e| SzurubooruClientError::ResponseError(status, resp_json))?;
Err(SzurubooruClientError::SzurubooruServerError(server_error))
} else {
Ok(response)
@ -438,7 +442,7 @@ impl<'a> SzurubooruRequest<'a> {
&self,
request: RequestBuilder,
) -> SzurubooruResult<T> {
let mut request = request
let request = request
.build()
.map_err(SzurubooruClientError::RequestBuilderError)?;
@ -487,7 +491,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Updates an existing tag category using specified parameters. Name must match
/// `tag_category_name_regex` from server's configuration. All fields except
/// [version](models::TagCategoryResource::version) are optional - update concerns only provided fields.
/// [version](crate::models::TagCategoryResource::version) are optional - update concerns only provided fields.
pub async fn update_tag_category<T>(
&self,
name: T,
@ -535,8 +539,9 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Searches for tags.
/// See the (named tokens)[tokens::TagNamedToken] and (sort tokens)[tokens::TagSortToken] for
/// all possible query tokens, or use (QueryToken)[tokens::QueryToken] for a custom token
/// See the [named tokens](crate::tokens::TagNamedToken) and
/// [sort tokens](crate::tokens::TagSortToken) for all possible query tokens, or use
/// [QueryToken] for a custom token
pub async fn list_tags(
&self,
query: Option<&Vec<QueryToken>>,
@ -547,7 +552,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Creates a new tag using specified parameters. Names, suggestions and implications must
/// match `tag_name_regex` from server's configuration. Category must exist and is the same
/// as the `name` field within (TagCategoryResource)[models::TagCategoryResource] resource.
/// as the `name` field within [TagCategoryResource] resource.
/// Suggestions and implications are optional. If specified implied tags or suggested tags do
/// not exist yet, they will be automatically created. Tags created automatically have no
/// implications, no suggestions, one name and their category is set to the first tag category
@ -559,7 +564,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Updates an existing tag using specified parameters. Names, suggestions and implications must
/// match `tag_name_regex` from server's configuration. Category must exist and is the same
/// as the `name` field within (TagCategoryResource)[models::TagCategoryResource] resource.
/// as the `name` field within [TagCategoryResource] resource.
/// Suggestions and implications are optional. If specified implied tags or suggested tags do
/// not exist yet, they will be automatically created. Tags created automatically have no
/// implications, no suggestions, one name and their category is set to the first tag category
@ -608,7 +613,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Lists siblings of given tag, e.g. tags that were used in the same posts as the given tag.
/// The (occurrences)[models::TagSibling::occurrences] field signifies how many times a given
/// The [occurrences](crate::models::TagSibling::occurrences) field signifies how many times a given
/// sibling appears with given tag. Results are sorted by occurrences count and the list is
/// truncated to the first 50 elements. Doesn't use paging.
pub async fn get_tag_siblings<T>(
@ -624,9 +629,8 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Searches for posts.
/// See (PostNamedToken)[tokens::PostNamedToken], (PostSortToken)[tokens::PostSortToken] and
/// (PostSpecialToken)[tokens::PostSpecialToken] for valid tokens to use with this method, or
/// use (QueryToken)[tokens::QueryToken] to construct a custom token
/// See [PostNamedToken], [PostSortToken] and [PostSpecialToken] for valid tokens to use with
/// this method, or use [QueryToken] to construct a custom token
pub async fn list_posts(
&self,
query: Option<&Vec<QueryToken>>,
@ -654,7 +658,7 @@ impl<'a> SzurubooruRequest<'a> {
/// the image.
/// If specified tags do not exist yet, they will be automatically created. Tags created
/// automatically have no implications, no suggestions, one name and their category is set to
/// the first tag category found. (safety)[models::CreateUpdatePost::safety] must be any of
/// the first tag category found. [safety](crate::models::CreateUpdatePost::safety) must be any of
/// `safe`, `sketchy` or `unsafe`.
/// Relations must contain valid post IDs. If `flag` is omitted, they will be defined by
/// default (`"loop"` will be set for all video posts, and `"sound"` will be auto-detected).
@ -672,7 +676,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Update an existing post
/// See [SzurubooruRequest::create_post_from_url] for more details about the fields in
/// (CreateUpdatePost)[models::CreateUpdatePost]
/// [CreateUpdatePost]
pub async fn update_post(
&self,
post_id: u32,
@ -686,7 +690,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Update an existing post from a given URL
/// See [SzurubooruRequest::create_post_from_url] for more details about the fields in
/// (CreateUpdatePost)[models::CreateUpdatePost]
/// [CreateUpdatePost]
pub async fn update_post_from_url(
&self,
post_id: u32,
@ -748,7 +752,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Create a new post from a file handle
/// See [SzurubooruRequest::create_post_from_url] for more details about the fields in
/// (CreateUpdatePost)[models::CreateUpdatePost]
/// [CreateUpdatePost]
pub async fn create_post_from_file<T>(
&self,
file: &mut File,
@ -773,7 +777,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Create a new post from a file path
/// See [SzurubooruRequest::create_post_from_url] for more details about the fields in
/// (CreateUpdatePost)[models::CreateUpdatePost]
/// [CreateUpdatePost]
pub async fn create_post_from_file_path(
&self,
file_path: impl AsRef<Path>,
@ -793,7 +797,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Create a post from a token previously generated by
/// (upload_temporary_file_from_path)[SzurubooruRequest::upload_temporary_file_from_path]
/// [upload_temporary_file_from_path](SzurubooruRequest::upload_temporary_file_from_path)
pub async fn create_post_from_token(
&self,
new_post: &CreateUpdatePost,
@ -814,7 +818,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Update an existing post from an open File handle
/// See [SzurubooruRequest::create_post_from_url] for more details about the fields in
/// (CreateUpdatePost)[models::CreateUpdatePost]
/// [CreateUpdatePost]
pub async fn update_post_from_file(
&self,
post_id: u32,
@ -838,7 +842,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Update an existing post from a file path
/// See [SzurubooruRequest::create_post_from_url] for more details about the fields in
/// (CreateUpdatePost)[models::CreateUpdatePost]
/// [CreateUpdatePost]
pub async fn update_post_from_file_path(
&self,
post_id: u32,
@ -888,7 +892,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Update a post from a token previously generated by
/// (upload_temporary_file_from_path)[SzurubooruRequest::upload_temporary_file_from_path]
/// [upload_temporary_file_from_path](SzurubooruRequest::upload_temporary_file_from_path)
pub async fn update_post_from_token(
&self,
post_id: u32,
@ -957,7 +961,7 @@ impl<'a> SzurubooruRequest<'a> {
.map(|cr| cr.bytes_stream())
}
///Fetches the given post ID's image as a (Bytes)[bytes::Bytes] struct
///Fetches the given post ID's image as a [Bytes](bytes::Bytes) struct
pub async fn get_image_bytes(&self, post_id: u32) -> SzurubooruResult<bytes::Bytes> {
let content_response = self.get_post_content(post_id, false).await?;
@ -967,7 +971,7 @@ impl<'a> SzurubooruRequest<'a> {
.map_err(SzurubooruClientError::RequestError)
}
///Fetches the given post ID's thumbnail as a (Bytes)[bytes::Bytes] struct
///Fetches the given post ID's thumbnail as a [Bytes](bytes::Bytes) struct
pub async fn get_thumbnail_bytes(&self, post_id: u32) -> SzurubooruResult<bytes::Bytes> {
let content_response = self.get_post_content(post_id, true).await?;
@ -1090,11 +1094,11 @@ impl<'a> SzurubooruRequest<'a> {
let hex_string = hex::encode(hash);
let qt = QueryToken::token(PostNamedToken::ContentChecksum, hex_string);
let mut psr = self
let psr = self
.list_posts(Some(&vec![qt]))
.await
.map(|psr| self.propagate_urls(psr))?;
Ok(psr.results.first().map(|pr| pr.clone()))
Ok(psr.results.first().cloned())
}
/// Searches for an exact match of a file path based on the SHA1 checksum
@ -1133,7 +1137,7 @@ impl<'a> SzurubooruRequest<'a> {
///
/// Removes source post and merges all of its tags, relations, scores, favorites and comments to
/// the target post. If [MergePost::replace_content] is set to `true`, content of the target post
/// the target post. If [MergePost::replace_post_content] is set to `true`, content of the target post
/// is replaced using the content of the source post; otherwise it remains unchanged. Source
/// post properties such as its safety, source, whether to loop the video and other scalar
/// values do not get transferred and are discarded.
@ -1146,7 +1150,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Updates score of authenticated user for given post. Valid scores are -1, 0 and 1.
pub async fn rate_post(&self, post_id: u32, score: i8) -> SzurubooruResult<PostResource> {
if score < -1 || score > 1 {
if !(-1..=1).contains(&score) {
return Err(SzurubooruClientError::ValidationError(
"Score must be -1, 0 or 1".to_string(),
));
@ -1175,9 +1179,9 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Retrieves the post that is currently featured on the main page in web client. If no post is
/// featured, <post> is [Option::None]. Note that this method exists mostly for compatibility
/// with setting featured post - most of the time, you'd want to use query global info which
/// contains more information.
/// featured, the result will be [Option::None]. Note that this method exists mostly for
/// compatibility with setting featured post - most of the time, you'd want to use query global
/// info which contains more information.
pub async fn get_featured_post(&self) -> SzurubooruResult<Option<PostResource>> {
self.do_request(Method::GET, "/api/featured-post", None, None::<&String>)
.await
@ -1213,7 +1217,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Updates an existing tag category using specified parameters. Name must match
/// `tag_category_name_regex` from server's configuration. All fields except the
/// [version](models::CreateUpdatePoolCategory::version) field are optional - update concerns
/// [version](crate::models::CreateUpdatePoolCategory::version) field are optional - update concerns
/// only the provided fields.
pub async fn update_pool_category<T>(
&self,
@ -1272,7 +1276,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Searches for pools.
/// Anonymous tokens are the same as the [name](tokens::PoolNamedToken::Name) token
/// Anonymous tokens are the same as the [name](crate::tokens::PoolNamedToken::Name) token
pub async fn list_pools(
&self,
query: Option<&Vec<QueryToken>>,
@ -1284,8 +1288,8 @@ impl<'a> SzurubooruRequest<'a> {
/// Creates a new pool using specified parameters. Names, suggestions and implications must
/// match `pool_name_regex` from server's configuration. Category must exist and is the same as
/// [name](models::PoolCategoryResource::name) field.
/// [posts](models::CreateUpdatePool::posts) is an optional list of integer post IDs. If the
/// [name](crate::models::PoolCategoryResource::name) field.
/// [posts](crate::models::CreateUpdatePool::posts) is an optional list of integer post IDs. If the
/// specified posts do not exist, an error will be thrown.
pub async fn create_pool(
&self,
@ -1296,14 +1300,14 @@ impl<'a> SzurubooruRequest<'a> {
.map(|r| self.propagate_urls(r))
}
/// Updates an existing pool using specified parameters. [name](models::CreateUpdatePool::name),
/// Updates an existing pool using specified parameters. [names](crate::models::CreateUpdatePool::names),
/// must match `pool_name_regex` from server's configuration.
/// [category](models::CreateUpdatePool::category) must exist and is the same as
/// [name](models::PoolCategoryResource::name) field. [posts](models::CreateUpdatePool::posts)
/// [category](crate::models::CreateUpdatePool::category) must exist and is the same as
/// [name](crate::models::PoolCategoryResource::name) field. [posts](crate::models::CreateUpdatePool::posts)
/// is an optional list of integer post IDs. If the specified posts do not exist yet, an error
/// will be thrown. The full list of post IDs must be provided if they are being updated, and
/// the previous list of posts will be replaced with the new one. All fields except
/// [version](models::CreateUpdatePool::version) are optional - update concerns only provided
/// [version](crate::models::CreateUpdatePool::version) are optional - update concerns only provided
/// fields.
pub async fn update_pool(
&self,
@ -1343,7 +1347,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Searches for comments.
/// Anonymous tokens are the same as the [text](tokens::CommentNamedToken::text) token
/// Anonymous tokens are the same as the [text](crate::tokens::CommentNamedToken::Text) token
pub async fn list_comments(
&self,
query: Option<&Vec<QueryToken>>,
@ -1394,7 +1398,7 @@ impl<'a> SzurubooruRequest<'a> {
comment_id: u32,
score: i8,
) -> SzurubooruResult<CommentResource> {
if score < -1 || score > 1 {
if !(-1..=1).contains(&score) {
return Err(SzurubooruClientError::ValidationError(
"Score must be -1, 0 or 1".to_string(),
));
@ -1406,9 +1410,8 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Searches for users
/// Anonymous tokens are the same as the [name](tokens::UserNamedToken)
/// See [UserNamedToken](tokens::UserNamedToken) and [UserSortToken](tokens::UserSortToken)
/// for type-safe tokens
/// Anonymous tokens are the same as the [name](crate::tokens::UserNamedToken::Name) token
/// See [UserNamedToken] and [UserSortToken] for type-safe tokens
pub async fn list_users(
&self,
query: Option<&Vec<QueryToken>>,
@ -1451,7 +1454,7 @@ impl<'a> SzurubooruRequest<'a> {
/// Creates a new user using specified parameters. Names and passwords must match
/// `user_name_regex` and `password_regex` from server's configuration, respectively.
/// Email address, rank and avatar fields are optional. Avatar style can be either
/// [gravatar](models::UserAvatarStyle::Gravatar) or [manual](models::UserAvatarStyle::Manual).
/// [gravatar](crate::models::UserAvatarStyle::Gravatar) or [manual](crate::models::UserAvatarStyle::Manual).
/// `manual` avatar style requires client to pass also the `avatar` file.
/// If the rank is empty and the user happens to be the first user ever created,
/// become an administrator, whereas subsequent users will be given the rank indicated by
@ -1462,7 +1465,7 @@ impl<'a> SzurubooruRequest<'a> {
.map(|r| self.propagate_urls(r))
}
/// Create a [UserResource](models::UserResource) with the included Avatar file
/// Create a [UserResource] with the included Avatar file
/// See [create_user](SzurubooruRequest::create_user) for other applicable fields and
/// restrictions
pub async fn create_user_with_avatar_file(
@ -1482,7 +1485,7 @@ impl<'a> SzurubooruRequest<'a> {
.map(|r| self.propagate_urls(r))
}
/// Create a [UserResource](models::UserResource) with the included Avatar file path
/// Create a [UserResource] with the included Avatar file path
/// See [create_user](SzurubooruRequest::create_user) for other applicable fields and
/// restrictions
pub async fn create_user_with_avatar_path(
@ -1506,9 +1509,9 @@ impl<'a> SzurubooruRequest<'a> {
/// Updates user using specified parameters. Names and passwords must match
/// `user_name_regex` and `password_regex` from server's configuration, respectively.
/// Email address, rank and avatar fields are optional. Avatar style can be either
/// [gravatar](models::UserAvatarStyle::Gravatar) or [manual](models::UserAvatarStyle::Manual).
/// [gravatar](crate::models::UserAvatarStyle::Gravatar) or [manual](crate::models::UserAvatarStyle::Manual).
/// `manual` avatar style requires client to pass also the `avatar` file.
/// All fields except the [version](models::CreateUpdateUser::version) are optional
/// All fields except the [version](crate::models::CreateUpdateUser::version) are optional
/// - update concerns only provided fields.
pub async fn update_user<T>(
&self,
@ -1524,7 +1527,7 @@ impl<'a> SzurubooruRequest<'a> {
.map(|r| self.propagate_urls(r))
}
/// Update a [UserResource](models::UserResource) with the included Avatar file
/// Update a [UserResource] with the included Avatar file
/// See [update_user](SzurubooruRequest::update_user) for other applicable fields and
/// restrictions
pub async fn update_user_with_avatar_file<T>(
@ -1549,7 +1552,7 @@ impl<'a> SzurubooruRequest<'a> {
.map(|r| self.propagate_urls(r))
}
/// Update a [UserResource](models::UserResource) with the included Avatar file path
/// Update a [UserResource] with the included Avatar file path
/// See [update_user](SzurubooruRequest::update_user) for other applicable fields and
/// restrictions
pub async fn update_user_with_avatar_path<T>(
@ -1629,7 +1632,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Updates an existing user token using specified parameters. All fields except the
/// [version](models::CreateUpdateUserAuthToken::version) are optional - update concerns only
/// [version](crate::models::CreateUpdateUserAuthToken::version) are optional - update concerns only
/// provided fields.
pub async fn update_user_token<T>(
&self,
@ -1647,7 +1650,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Deletes an existing user token using specified parameters. All fields except the
/// [version](models::CreateUpdateUserAuthToken::version) are optional - update concerns only
/// [version](crate::models::CreateUpdateUserAuthToken::version) are optional - update concerns only
/// provided fields.
pub async fn delete_user_token<T>(
&self,
@ -1700,7 +1703,7 @@ impl<'a> SzurubooruRequest<'a> {
}
/// Lists recent resource snapshots.
/// See [SnapshotNamedToken](tokens::SnapshotNamedToken) for query tokens.
/// See [SnapshotNamedToken] for query tokens.
/// There are no sort tokens. The snapshots are always sorted by creation time.
pub async fn list_snapshots(
&self,
@ -1711,11 +1714,11 @@ impl<'a> SzurubooruRequest<'a> {
.map(|r| self.propagate_urls(r))
}
/// Retrieves simple statistics. [featured_post](models::GlobalInfo::featured_post) is
/// [None](Option::None) if there is no featured post yet.
/// [server_time](models::GlobalInfo::server_time) is pretty much the same as the Date HTTP
/// Retrieves simple statistics. [featured_post](crate::models::GlobalInfo::featured_post) is
/// [None] if there is no featured post yet.
/// [server_time](crate::models::GlobalInfo::server_time) is pretty much the same as the Date HTTP
/// field, only formatted in a manner consistent with other dates. Values in config key are
/// taken directly from the server config, with the exception of privilege array keys being
/// taken directly from the server config, except for the privilege array keys being
/// converted to lower camel case to match the API convention.
pub async fn get_global_info(&self) -> SzurubooruResult<GlobalInfo> {
self.do_request(Method::GET, "/api/info", None, None::<&String>)

View file

@ -57,7 +57,7 @@ pub enum SzurubooruClientError {
#[error("JSON Serialization error: {0}")]
JSONSerializationError(#[source] serde_json::Error),
/// Error when validation fails for one of the Builder types
#[error("Vlidation error: {0}")]
#[error("Validation error: {0}")]
ValidationError(String),
/// Error occurred when reading a file
#[error("IO Error: {0}")]
@ -80,12 +80,17 @@ impl From<UninitializedFieldError> for SzurubooruClientError {
}
#[cfg(feature = "python")]
create_exception!(szurubooru_client, SzuruPyClientError, PyException);
create_exception!(
szurubooru_client,
SzuruClientError,
PyException,
"An exception that contains two pieces of information: The error kind and error details"
);
#[cfg(feature = "python")]
impl std::convert::From<SzurubooruClientError> for PyErr {
fn from(value: SzurubooruClientError) -> Self {
SzuruPyClientError::new_err((value.as_ref().to_string(), value.to_string()))
SzuruClientError::new_err((value.as_ref().to_string(), value.to_string()))
}
}

View file

@ -36,6 +36,7 @@ pub mod models;
pub mod tokens;
#[cfg(feature = "python")]
#[doc(hidden)]
pub mod py;
#[cfg(feature = "python")]
@ -49,7 +50,7 @@ mod szurubooru_client {
#[pymodule_export]
pub use crate::{
errors::SzuruPyClientError,
errors::SzuruClientError,
/*models::{
AroundPostResult, CommentResource, GlobalInfo, ImageSearchResult,
ImageSearchSimilarPost, MicroPoolResource, MicroPostResource, MicroTagResource,
@ -66,6 +67,7 @@ mod szurubooru_client {
UserNamedToken, UserSortToken,
},*/
py::asynchronous::PythonAsyncClient, py::synchronous::PythonSyncClient,
py::PyPagedSearchResult,
};
#[pymodule(name = "_tokens")]
@ -77,7 +79,6 @@ mod szurubooru_client {
PostSpecialToken, QueryToken, SnapshotNamedToken, TagNamedToken, TagSortToken,
UserNamedToken, UserSortToken,
};
use pyo3::prelude::*;
}
#[pymodule(name = "_models")]

View file

@ -13,7 +13,7 @@ use std::collections::HashMap;
use strum_macros::AsRefStr;
#[cfg(feature = "python")]
use pyo3::{exceptions::PyValueError, prelude::*, types::*};
use pyo3::prelude::*;
#[cfg(feature = "python")]
use serde_pyobject::to_pyobject;
@ -45,16 +45,16 @@ impl<T: WithBaseURL> WithBaseURL for UnpagedSearchResult<T> {
#[derive(Debug, Serialize, Deserialize)]
/// A result of search operation that involves paging
///
/// Use (offset)[crate::SzurubooruRequest::offset] and (limit)[crate::SzurubooruRequest::limit]
/// Use [offset](crate::SzurubooruRequest::with_offset) and [limit](crate::SzurubooruRequest::with_limit)
/// to fetch the next page
pub struct PagedSearchResult<T> {
/// The original query for the request
pub query: String,
/// The number of [T] to skip forward
/// The number of `T` to skip forward
pub offset: u32,
/// The maximum number of [T] to return
/// The maximum number of `T` to return
pub limit: u32,
/// The total number of [T] that match the [query](PagedSearchResult::query)
/// The total number of `T` that match the [query](PagedSearchResult::query)
pub total: u32,
/// The results themselves
pub results: Vec<T>,
@ -88,7 +88,10 @@ impl<T: WithBaseURL> WithBaseURL for Vec<T> {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all, eq))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, eq, module = "szurubooru_client.models")
)]
/// A [tag resource](TagResource) stripped down to `names`, `category` and `usages` fields.
pub struct MicroTagResource {
/// The tag names and aliases
@ -101,7 +104,9 @@ pub struct MicroTagResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl MicroTagResource {
/// Function that generates the representation string for this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -133,7 +138,10 @@ pub struct ResourceVersion {
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
/// A single tag. Tags are used to let users search for posts.
pub struct TagResource {
/// resource version. See [versioning](ResourceVersion)
@ -162,7 +170,9 @@ pub struct TagResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl TagResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -170,7 +180,7 @@ impl TagResource {
/// Creates or updates a tag using specified parameters. Names, suggestions and implications must
/// match `tag_name_regex` from server's configuration. Category must exist and is the same as name
/// field within <tag-category> resource. Suggestions and implications are optional. If specified
/// field within [TagCategoryResource] resource. Suggestions and implications are optional. If specified
/// implied tags or suggested tags do not exist yet, they will be automatically created. Tags
/// created automatically have no implications, no suggestions, one name and their category is set
/// to the first tag category found. If there are no tag categories established yet, an error
@ -215,7 +225,10 @@ pub struct CreateUpdateTag {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
/// A single tag category. The primary purpose of tag categories is to distinguish certain tag
/// types (such as characters, media type etc.), which improves user experience.
pub struct TagCategoryResource {
@ -235,7 +248,9 @@ pub struct TagCategoryResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl TagCategoryResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -284,7 +299,10 @@ pub struct MergeTags {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
/// Lists siblings of given tag, e.g. tags that were used in the same posts as the given tag
pub struct TagSibling {
/// The related tag
@ -295,14 +313,19 @@ pub struct TagSibling {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl TagSibling {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, AsRefStr, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// The type of post
pub enum PostType {
@ -325,7 +348,10 @@ pub enum PostType {
}
#[derive(Debug, Clone, Serialize, Deserialize, AsRefStr, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// How SFW/NSFW the post is
pub enum PostSafety {
@ -333,14 +359,17 @@ pub enum PostSafety {
Safe,
/// Post is possibly NSFW
Sketchy,
/// Alias of (Sketchy)[PostSafety::Sketchy]
/// Alias of [Sketchy](PostSafety::Sketchy)
Questionable,
/// Post is NSFW
Unsafe,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A post resource stripped down to `id` and `thumbnailUrl` fields.
pub struct MicroPostResource {
@ -352,7 +381,9 @@ pub struct MicroPostResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl MicroPostResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -378,7 +409,10 @@ pub(crate) struct PostId {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A post resource
pub struct PostResource {
@ -455,7 +489,9 @@ pub struct PostResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl PostResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -586,7 +622,10 @@ pub struct RateResource {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A text annotation rendered on top of the post
pub struct NoteResource {
@ -601,14 +640,19 @@ pub struct NoteResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl NoteResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// The Rank of a given User
pub enum UserRank {
@ -625,7 +669,10 @@ pub enum UserRank {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// The kind of User Avatar
pub enum UserAvatarStyle {
@ -635,8 +682,9 @@ pub enum UserAvatarStyle {
Manual,
}
// Because pyo3 get_all doesn't let you exclude fields we have to define the fields twice
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass)]
#[cfg_attr(all(feature = "python"), pyclass(module = "szurubooru_client.models"))]
#[serde(rename_all = "camelCase")]
/// A single user
pub struct UserResource {
@ -751,13 +799,16 @@ pub struct UserResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl UserResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
#[getter]
#[pyo3(name = "email")]
/// Returns this resource's email field, if the current user has permission to see it
pub fn email_py(&self) -> PyResult<Option<String>> {
match &self.email {
None => Ok(None),
@ -768,6 +819,7 @@ impl UserResource {
#[getter]
#[pyo3(name = "liked_post_count")]
/// Returns this resource's liked_post_count, if the current user has permission to see it
pub fn liked_post_count_py(&self) -> PyResult<Option<u32>> {
match &self.liked_post_count {
None => Ok(None),
@ -778,6 +830,7 @@ impl UserResource {
#[getter]
#[pyo3(name = "disliked_post_count")]
/// Returns this resource's disliked_post_count, if the current user has permission to see it
pub fn disliked_post_count_py(&self) -> PyResult<Option<u32>> {
match &self.disliked_post_count {
None => Ok(None),
@ -788,6 +841,7 @@ impl UserResource {
#[getter]
#[pyo3(name = "favorite_post_count")]
/// Returns this resource's favorite_post_count, if the current user has permission to see it
pub fn favorite_post_count_py(&self) -> PyResult<Option<u32>> {
match &self.favorite_post_count {
None => Ok(None),
@ -843,7 +897,10 @@ pub struct CreateUpdateUser {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A user resource stripped down to `name` and `avatarUrl` fields
pub struct MicroUserResource {
@ -855,7 +912,9 @@ pub struct MicroUserResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl MicroUserResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -875,7 +934,10 @@ impl WithBaseURL for MicroUserResource {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "kebab-case")]
/// A single user token
pub struct UserAuthTokenResource {
@ -901,7 +963,9 @@ pub struct UserAuthTokenResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl UserAuthTokenResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -957,7 +1021,10 @@ pub struct TemporaryPassword {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// Simple server configuration
pub struct GlobalInfoConfig {
@ -982,7 +1049,10 @@ pub struct GlobalInfoConfig {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// Simple server statistics
pub struct GlobalInfo {
@ -1004,14 +1074,19 @@ pub struct GlobalInfo {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl GlobalInfo {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A single pool category. The primary purpose of pool categories is to distinguish certain pool
/// types (such as series, relations etc.), which improves user experience.
@ -1030,7 +1105,9 @@ pub struct PoolCategoryResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl PoolCategoryResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1066,7 +1143,10 @@ pub struct CreateUpdatePoolCategory {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// Type that represents a Pool resource
pub struct PoolResource {
@ -1093,7 +1173,9 @@ pub struct PoolResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl PoolResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1158,9 +1240,9 @@ pub struct CreateUpdatePool {
/// // Merge pool ID 1 at version 1 to pool ID 3 at version 5
/// let merge_pool = MergePoolBuilder::default()
/// .remove_pool_version(1)
/// .remove(1)
/// .remove_pool(1)
/// .merge_to_version(5)
/// .merge_to(3)
/// .merge_to_pool(3)
/// .build()
/// .unwrap();
/// ```
@ -1179,7 +1261,10 @@ pub struct MergePool {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A micro resource representing a Pool. A subset of the fields of a [PoolResource].
pub struct MicroPoolResource {
@ -1197,14 +1282,19 @@ pub struct MicroPoolResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl MicroPoolResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A type representing a Comment on a post
pub struct CommentResource {
@ -1230,7 +1320,9 @@ pub struct CommentResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl CommentResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1267,7 +1359,10 @@ pub struct CreateUpdateComment {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// The kind of snapshot that has been recorded
pub enum SnapshotOperationType {
@ -1282,7 +1377,10 @@ pub enum SnapshotOperationType {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// The kind of resource described by this snapshot
pub enum SnapshotResourceType {
@ -1301,7 +1399,10 @@ pub enum SnapshotResourceType {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase", untagged)]
/// Data for a resource that was created
#[allow(clippy::large_enum_variant)]
@ -1320,7 +1421,9 @@ pub enum SnapshotCreationDeletionData {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl SnapshotCreationDeletionData {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1341,7 +1444,10 @@ impl WithBaseURL for SnapshotCreationDeletionData {
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass)]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// Data for a modified resource
pub struct SnapshotModificationData {
@ -1366,20 +1472,26 @@ pub struct SnapshotModificationData {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl SnapshotModificationData {
#[getter]
/// Get the value associated with this snapshot
pub fn get_value(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
let obj = to_pyobject(py, &self.value).unwrap().unbind();
Ok(obj)
}
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(all(feature = "python"), pyclass(eq))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, module = "szurubooru_client.models")
)]
#[serde(untagged)]
/// Type representing the data as part of a snapshot
#[allow(clippy::large_enum_variant)]
@ -1404,7 +1516,10 @@ impl WithBaseURL for SnapshotData {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// Overall type representing some sort of change to a resource
pub struct SnapshotResource {
@ -1425,7 +1540,9 @@ pub struct SnapshotResource {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl SnapshotResource {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1442,7 +1559,10 @@ impl WithBaseURL for SnapshotResource {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A result when searching for similar posts to a given image
pub struct ImageSearchSimilarPost {
@ -1454,7 +1574,9 @@ pub struct ImageSearchSimilarPost {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl ImageSearchSimilarPost {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1470,7 +1592,10 @@ impl WithBaseURL for ImageSearchSimilarPost {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
#[serde(rename_all = "camelCase")]
/// A type to represent the result from an Image search request
pub struct ImageSearchResult {
@ -1484,7 +1609,9 @@ pub struct ImageSearchResult {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl ImageSearchResult {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}
@ -1500,7 +1627,10 @@ impl WithBaseURL for ImageSearchResult {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(all(feature = "python"), pyclass(get_all))]
#[cfg_attr(
all(feature = "python"),
pyclass(get_all, module = "szurubooru_client.models")
)]
/// A type that represents posts that are before or after an existing post
pub struct AroundPostResult {
/// A previous post, if it exists
@ -1511,7 +1641,9 @@ pub struct AroundPostResult {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pymethods)]
#[doc(hidden)]
impl AroundPostResult {
/// Generates a representative string of this resource
fn __repr__(&self) -> String {
format!("{:?}", self)
}

View file

@ -7,7 +7,10 @@ use pyo3::exceptions::{PyRuntimeError, PyValueError};
use pyo3::prelude::*;
use std::path::PathBuf;
#[pyclass(name = "SzurubooruAsyncClient")]
#[pyclass(name = "SzurubooruAsyncClient", module = "szurubooru_client")]
/// An asynchronous client for Szurubooru
///
/// :see: :class:`~szurubooru_client.SzurubooruSyncClient` for supported parameters
pub struct PythonAsyncClient {
client: SzurubooruClient,
}
@ -16,8 +19,9 @@ pub struct PythonAsyncClient {
impl PythonAsyncClient {
#[new]
#[pyo3(signature = (host, username=None, token=None, password=None, allow_insecure=None))]
/// Creates a new instance of the Asynchornous client
///
///
/// :see: :class:`~szurubooru_client.SzurubooruSyncClient` for supported parameters
pub fn new(
host: String,
username: Option<String>,
@ -47,6 +51,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (fields=None))]
/// List the available tag categories (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_tag_categories` for parameters and return type
pub async fn list_tag_categories(
&self,
fields: Option<Vec<String>>,
@ -60,6 +67,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, color=None, order=None, fields=None))]
/// Creates a new tag category using the specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_tag_category` for parameters and return type
pub async fn create_tag_category(
&self,
name: String,
@ -83,11 +93,15 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (name, version, color=None, order=None, fields=None))]
#[pyo3(signature = (name, version, new_name=None, color=None, order=None, fields=None))]
/// Updates an existing tag category (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_tag_category` for parameters and return type
pub async fn update_tag_category(
&self,
name: String,
version: u32,
new_name: Option<String>,
color: Option<String>,
order: Option<u32>,
fields: Option<Vec<String>>,
@ -95,6 +109,9 @@ impl PythonAsyncClient {
let mut cutag = CreateUpdateTagCategoryBuilder::default();
let mut cutag = cutag.version(version);
if let Some(name) = new_name {
cutag = cutag.name(name);
}
if let Some(color) = color {
cutag = cutag.color(color);
}
@ -111,6 +128,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, fields=None))]
/// Fetches a tag category by name (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_tag_category` for parameters and return type
pub async fn get_tag_category(
&self,
name: String,
@ -123,6 +143,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (name, version))]
/// Deletes a tag category (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_tag_category` for parameters and return type
pub async fn delete_tag_category(&self, name: String, version: u32) -> PyResult<()> {
self.client
.request()
@ -131,6 +155,8 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (name))]
/// Sets the default tag category for the site (async version)
pub async fn set_default_tag_category(&self, name: String) -> PyResult<()> {
self.client
.request()
@ -140,6 +166,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (query=None, fields=None, limit=None, offset=None))]
/// List the tags currently available on the site (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_tags` for parameters and return type
pub async fn list_tags(
&self,
query: Option<Vec<QueryToken>>,
@ -158,9 +187,11 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (names, category=None, description=None, implications=None, suggestions=None, fields=None))]
/// Creating a new tag (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_tag` for parameters and return type
pub async fn create_tag(
&self,
//names: Vec<String>,
names: Py<PyAny>,
category: Option<String>,
description: Option<String>,
@ -203,11 +234,15 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, version, names=None, category=None, description=None, implications=None, suggestions=None, fields=None))]
#[allow(clippy::too_many_arguments)]
/// Updates an existing tag (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_tag` for parameters and return type
pub async fn update_tag(
&self,
name: String,
version: u32,
names: Option<Vec<String>>,
names: Option<Py<PyAny>>,
category: Option<String>,
description: Option<String>,
implications: Option<Vec<String>>,
@ -217,7 +252,18 @@ impl PythonAsyncClient {
let mut cubuild = CreateUpdateTagBuilder::default();
cubuild.version(version);
if let Some(names) = names {
cubuild.names(names);
Python::with_gil(|py| {
if let Ok(name) = names.extract::<String>(py) {
Ok(cubuild.names(vec![name]))
} else {
let list_res = names.extract::<Vec<String>>(py);
if let Ok(names) = list_res {
Ok(cubuild.names(names))
} else {
Err(list_res.err().unwrap())
}
}
})?;
}
if let Some(cat) = category {
cubuild.category(cat);
@ -240,6 +286,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, fields=None))]
/// Fetches an existing tag (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_tag` for parameters and return type
pub async fn get_tag(
&self,
name: String,
@ -252,6 +301,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (name, version))]
/// Deletes an existing tag (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_tag` for parameters and return type
pub async fn delete_tag(&self, name: String, version: u32) -> PyResult<()> {
self.client
.request()
@ -261,6 +314,10 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (remove_tag, remove_tag_version, merge_to_tag, merge_to_version, fields=None))]
/// Removes source tag and merges all of its usages, suggestions and implications to the
/// target tag. (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.merge_tags` for parameters and return type
pub async fn merge_tags(
&self,
remove_tag: String,
@ -282,6 +339,11 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (name))]
/// Lists siblings of given tag, e.g. tags that were used in the same posts as the given tag.
/// (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_tag_siblings` for parameters and return type
pub async fn get_tag_siblings(&self, name: String) -> PyResult<Vec<TagSibling>> {
self.client
.request()
@ -292,6 +354,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (query=None, fields=None, limit=None, offset=None))]
/// Lists the posts currently available on the site (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_posts` for parameters and return type
pub async fn list_posts(
&self,
query: Option<Vec<QueryToken>>,
@ -309,12 +374,16 @@ impl PythonAsyncClient {
.map(Into::into)
}
#[pyo3(signature = (url=None, token=None, file_path=None, thumbnail_path=None, tags=None, safety=None, source=None,
#[pyo3(signature = (url=None, upload_token=None, file_path=None, thumbnail_path=None, tags=None, safety=None, source=None,
relations=None, notes=None, flags=None, anonymous=None, fields=None))]
#[allow(clippy::too_many_arguments)]
/// Create a new post using one of three image sources (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_post` for parameters and return type
pub async fn create_post(
&self,
url: Option<String>,
token: Option<String>,
upload_token: Option<String>,
file_path: Option<PathBuf>,
thumbnail_path: Option<PathBuf>,
tags: Option<Vec<String>>,
@ -349,7 +418,7 @@ impl PythonAsyncClient {
cupost.anonymous(anonymous);
}
if let Some(token) = token {
if let Some(token) = upload_token {
cupost.content_token(token);
let cupost = cupost.build()?;
self.client
@ -382,6 +451,10 @@ impl PythonAsyncClient {
#[pyo3(signature = (post_id, post_version, url=None, token=None, file_path=None,
thumbnail_path=None, tags=None, safety=None, source=None, relations=None, notes=None,
flags=None, fields=None))]
#[allow(clippy::too_many_arguments)]
/// Updates an existing post (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_post` for parameters and return type
pub async fn update_post(
&self,
post_id: u32,
@ -452,6 +525,10 @@ impl PythonAsyncClient {
}
}
#[pyo3(signature = (post_id))]
/// Downloads the given post's image as a byte array (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_image_bytes` for parameters and return type
pub async fn get_image_bytes(&self, post_id: u32) -> PyResult<Vec<u8>> {
let bytes = self
.client
@ -462,6 +539,10 @@ impl PythonAsyncClient {
Ok(bytes)
}
#[pyo3(signature = (post_id, file_path))]
/// Downloads the given post's image to a path on the filesystem
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.download_image_to_path` for parameters and return type
pub async fn download_image_to_path(&self, post_id: u32, file_path: PathBuf) -> PyResult<()> {
self.client
.request()
@ -470,6 +551,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (post_id))]
/// Downloads the given post's thumbnail as a byte array
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_thumbnail_bytes` for parameters and return type
pub async fn get_thumbnail_bytes<'py>(&self, post_id: u32) -> PyResult<Vec<u8>> {
let bytes = self
.client
@ -480,6 +565,10 @@ impl PythonAsyncClient {
Ok(bytes)
}
#[pyo3(signature = (post_id, file_path))]
/// Downloads the given post's thumbnail to a path on the filesystem
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.` for parameters and return type
pub async fn download_thumbnail_to_path(
&self,
post_id: u32,
@ -492,6 +581,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (image_path))]
/// Reverse image searches for an image from the filesystem (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.reverse_image_search` for parameters and return type
pub async fn reverse_image_search(&self, image_path: PathBuf) -> PyResult<ImageSearchResult> {
self.client
.request()
@ -500,6 +593,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (image_path))]
/// Searches for an *exact* image match of an image from the filesystem (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.post_for_image` for parameters and return type
pub async fn post_for_image(&self, image_path: PathBuf) -> PyResult<Option<PostResource>> {
self.client
.request()
@ -509,6 +606,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (post_id, fields=None))]
/// Fetches an individual post by its post ID (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_post` for parameters and return type
pub async fn get_post(
&self,
post_id: u32,
@ -521,6 +621,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Fetches posts from *around* the given post ID. That means the post before and after,
// if they exist. (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_around_post` for parameters and return type
pub async fn get_around_post(&self, post_id: u32) -> PyResult<AroundPostResult> {
self.client
.request()
@ -529,6 +633,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Deletes a post by its ID (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_post` for parameters and return type
pub async fn delete_post(&self, post_id: u32, version: u32) -> PyResult<()> {
self.client
.request()
@ -539,6 +646,10 @@ impl PythonAsyncClient {
#[pyo3(signature = (remove_post, remove_post_version, merge_to_post,
merge_to_version, replace_post_content=false, fields=None))]
/// Removes source post and merges all of its tags, relations, scores, favorites and comments to
/// the target post (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.merge_post` for parameters and return type
pub async fn merge_post(
&self,
remove_post: u32,
@ -563,13 +674,17 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (post_id, rating, fields=None))]
/// Updates score of authenticated user for given post. Valid scores are -1, 0 and 1.
/// (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.rate_post` for parameters and return type
pub async fn rate_post(
&self,
post_id: u32,
rating: i8,
fields: Option<Vec<String>>,
) -> PyResult<PostResource> {
if rating < -1 || rating > 1 {
if !(-1..=1).contains(&rating) {
Err(PyValueError::new_err("Rating must be -1, 0, or 1"))
} else {
self.client
@ -581,6 +696,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (post_id, fields=None))]
/// Marks the post as favorite for the current user (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.favorite_post` for parameters and return type
pub async fn favorite_post(
&self,
post_id: u32,
@ -594,6 +712,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (post_id, fields=None))]
/// Unmarks the post as favorite for the current user (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.unfavorite_post` for parameters and return type
pub async fn unfavorite_post(
&self,
post_id: u32,
@ -607,6 +728,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (fields=None))]
/// Retrieves the post that is currently featured on the main page (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_featured_post` for parameters and return type
pub async fn get_featured_post(
&self,
fields: Option<Vec<String>>,
@ -619,6 +743,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (post_id, fields=None))]
/// Features a post on the main page (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.set_featured_post` for parameters and return type
pub async fn set_featured_post(
&self,
post_id: u32,
@ -632,6 +759,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (fields=None))]
/// Lists all pool categories (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_pool_categories` for parameters and return type
pub async fn list_pool_categories(
&self,
fields: Option<Vec<String>>,
@ -645,6 +775,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, color=None, fields=None))]
/// Creates a new pool category using specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_pool_category` for parameters and return type
pub async fn create_pool_category(
&self,
name: String,
@ -665,6 +798,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, version, new_name=None, color=None, fields=None))]
/// Updates an existing tag category using specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_pool_category` for parameters and return type
pub async fn update_pool_category(
&self,
name: String,
@ -690,6 +826,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, fields=None))]
/// Fetches an existing pool category (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_pool_category` for parameters and return type
pub async fn get_pool_category(
&self,
name: String,
@ -702,6 +841,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Deletes existing pool category (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_pool_category` for parameters and return type
pub async fn delete_pool_category(&self, name: String, version: u32) -> PyResult<()> {
self.client
.request()
@ -711,6 +853,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, fields=None))]
/// Sets given pool category as default (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.set_default_pool_category` for parameters and return type
pub async fn set_default_pool_category(
&self,
name: String,
@ -724,6 +869,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (query=None, fields=None, limit=None, offset=None))]
/// List the post pools currently available on the site (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_pools` for parameters and return type
pub async fn list_pools(
&self,
query: Option<Vec<QueryToken>>,
@ -742,6 +890,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (names, category=None, description=None, posts=None, fields=None))]
/// Creates a new pool using specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_pool` for parameters and return type
pub async fn create_pool<'py>(
&self,
names: Py<PyAny>,
@ -781,13 +932,17 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
#[pyo3(signature = (pool_id, version, names=None, category=None, description=None,
#[pyo3(signature = (pool_id, version, new_names=None, category=None, description=None,
posts=None, fields=None))]
#[allow(clippy::too_many_arguments)]
/// Updates an existing pool using specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_pool` for parameters and return type
pub async fn update_pool(
&self,
pool_id: u32,
version: u32,
names: Option<Vec<String>>,
new_names: Option<Vec<String>>,
category: Option<String>,
description: Option<String>,
posts: Option<Vec<u32>>,
@ -795,7 +950,7 @@ impl PythonAsyncClient {
) -> PyResult<PoolResource> {
let mut cupool = CreateUpdatePoolBuilder::default();
cupool.version(version);
if let Some(names) = names {
if let Some(names) = new_names {
cupool.names(names);
}
@ -817,6 +972,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (pool_id, fields=None))]
/// Retrieves information about an existing pool (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_pool` for parameters and return type
pub async fn get_pool(
&self,
pool_id: u32,
@ -829,6 +987,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Deletes existing pool (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_pool` for parameters and return type
pub async fn delete_pool(&self, pool_id: u32, version: u32) -> PyResult<()> {
self.client
.request()
@ -838,6 +999,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (remove_pool, remove_pool_version, merge_to_pool, merge_to_version, fields=None))]
/// Removes source pool and merges all of its posts with the target pool. (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.merge_pools` for parameters and return type
pub async fn merge_pools(
&self,
remove_pool: u32,
@ -860,6 +1024,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (query=None, fields=None, limit=None, offset=None))]
/// List the comments currently available on the site (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_comments` for parameters and return type
pub async fn list_comments(
&self,
query: Option<Vec<QueryToken>>,
@ -878,6 +1045,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (text, post_id, fields=None))]
/// Creates a new comment under a given post (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_comment` for parameters and return type
pub async fn create_comment(
&self,
text: String,
@ -897,6 +1067,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (comment_id, version, text, fields=None))]
/// Updates an existing comment with new text (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_comment` for parameters and return type
pub async fn update_comment(
&self,
comment_id: u32,
@ -917,6 +1090,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (comment_id, fields=None))]
/// Fetches an existing comment (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_comment` for parameters and return type
pub async fn get_comment(
&self,
comment_id: u32,
@ -929,6 +1105,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Deletes an existing comment (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_comment` for parameters and return type
pub async fn delete_comment(&self, comment_id: u32, version: u32) -> PyResult<()> {
self.client
.request()
@ -938,6 +1117,10 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (comment_id, rating, fields=None))]
/// Updates score of authenticated user for given comment. Valid scores are -1, 0 and 1.
/// (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.rate_comment` for parameters and return type
pub async fn rate_comment(
&self,
comment_id: u32,
@ -952,6 +1135,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (query=None, fields=None, limit=None, offset=None))]
/// List the users currently registered on the site (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_users` for parameters and return type
pub async fn list_users(
&self,
query: Option<Vec<QueryToken>>,
@ -970,6 +1156,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, password, rank=None, avatar_path=None, fields=None))]
/// Creates a new user using specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_user` for parameters and return type
pub async fn create_user(
&self,
name: String,
@ -1004,6 +1193,10 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (name, version, new_name=None, password=None, rank=None, avatar_path=None, fields=None))]
#[allow(clippy::too_many_arguments)]
/// Updates an existing user using specified parameters (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update` for parameters and return type
pub async fn update_user(
&self,
name: String,
@ -1045,6 +1238,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (user_name, fields=None))]
/// Retrieves information about an existing user (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.get_user` for parameters and return type
pub async fn get_user(
&self,
user_name: String,
@ -1057,6 +1253,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Deletes an existing user (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_user` for parameters and return type
pub async fn delete_user(&self, user_name: String, version: u32) -> PyResult<()> {
self.client
.request()
@ -1066,6 +1265,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (user_name, fields=None))]
/// Fetches a list of the given user's auth tokens (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_user_tokens` for parameters and return type
pub async fn list_user_tokens(
&self,
user_name: String,
@ -1080,6 +1282,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (user_name, note=None, enabled=None, expiration_time=None, fields=None))]
/// Creates an auth token for the given user (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.create_user_token` for parameters and return type
pub async fn create_user_token(
&self,
user_name: String,
@ -1107,6 +1312,10 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (user_name, token, version, enabled=None, note=None, expiration_time=None, fields=None))]
#[allow(clippy::too_many_arguments)]
/// Update a user's existing auth token (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.update_user_token` for parameters and return type
pub async fn update_user_token(
&self,
user_name: String,
@ -1136,6 +1345,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Deletes an existing user auth token (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.delete_user_token` for parameters and return type
pub async fn delete_user_token(
&self,
user_name: String,
@ -1149,6 +1361,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Start a password reset request (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.password_reset_request` for parameters and return type
pub async fn password_reset_request(&self, email_or_name: String) -> PyResult<()> {
self.client
.request()
@ -1157,6 +1372,9 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Confirm a password reset request (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.password_reset_confirm` for parameters and return type
pub async fn password_reset_confirm(
&self,
email_or_name: String,
@ -1171,6 +1389,9 @@ impl PythonAsyncClient {
}
#[pyo3(signature = (query=None, fields=None, limit=None, offset=None))]
/// List the snapshots currently available on the site (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.list_snapshots` for parameters and return type
pub async fn list_snapshots(
&self,
query: Option<Vec<QueryToken>>,
@ -1188,6 +1409,15 @@ impl PythonAsyncClient {
.map(Into::into)
}
/// Retrieves simple statistics. ``featured_post`` is ``None`` if there is no featured post yet.
/// ``server_time`` is pretty much the same as the Date HTTP
/// field, only formatted in a manner consistent with other dates. Values in config key are
/// taken directly from the server config, with the exception of privilege array keys being
/// converted to lower camel case to match the API convention.
///
/// (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.global_info` for parameters and return type
pub async fn global_info(&self) -> PyResult<GlobalInfo> {
self.client
.request()
@ -1196,6 +1426,10 @@ impl PythonAsyncClient {
.map_err(Into::into)
}
/// Puts a file from a given file path in temporary storage and assigns it a token that can be
/// used in other requests. (async version)
///
/// :see: :func:`~szurubooru_client.SzurubooruSyncClient.upload_temporary_file` for parameters and return type
pub async fn upload_temporary_file(&self, file_path: PathBuf) -> PyResult<String> {
self.client
.request()

View file

@ -1,19 +1,26 @@
use crate::models::PagedSearchResult;
use pyo3::exceptions::PyException;
use pyo3::prelude::*;
use pyo3::types::PyList;
use pyo3::types::PyListMethods;
// rustfmt likes to break the Python docstrings
#[rustfmt::skip]
pub mod asynchronous;
#[rustfmt::skip]
pub mod synchronous;
#[derive(Debug)]
#[pyclass(name = "PagedSearchResult", get_all)]
#[pyclass(name = "PagedResult", get_all, module = "szurubooru_client")]
/// A paged result generated by most of the ``list`` methods of the Szurubooru clients
pub struct PyPagedSearchResult {
/// The query string that was used to generate these results
pub query: String,
/// The offset for the request, how many resource to skip before returning the results
pub offset: u32,
/// The maximum number of results to return
pub limit: u32,
/// The total number of results generated by the query
pub total: u32,
/// The results themselves
pub results: Py<PyList>,
}

File diff suppressed because it is too large Load diff

View file

@ -3,9 +3,8 @@
//! not guarantee that a given API endpoint will support the given tag.
#[cfg(feature = "python")]
use pyo3::{exceptions::PyValueError, prelude::*, types::*};
use pyo3::{exceptions::PyValueError, prelude::*};
use std::fmt::Display;
use std::str::FromStr;
use strum_macros::AsRefStr;
/// A named token such as `foo:bar`
@ -26,7 +25,7 @@ pub trait ToQueryString {
/// A query token using for searching posts, tags and pools
#[derive(Debug, Clone)]
#[cfg_attr(all(feature = "python"), pyclass)]
#[cfg_attr(all(feature = "python"), pyclass(module = "szurubooru_client.tokens"))]
pub struct QueryToken {
/// The key for this token. For `foo:bar` this would be `foo`
pub key: String,
@ -145,24 +144,106 @@ impl QueryToken {
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Generates a named token. Named tokens are used to filter resources returned by the API.
/// An example of this would be returning posts with a certain safety value.
///
/// This function will accept any string, but if you want to be more sure about your code you
/// can use any of the :ref:`Named token <named-tokens-enums>` types listed below.
/// See the example below.
///
/// :param key: String or Named field
/// :param value: The string or int value to use to filter by
/// :returns: The named query token
/// :rtype: QueryToken
///
/// -----
/// Usage
/// -----
/// This lists all posts that are marked as 'safe'.
///
/// ```python
/// client.list_posts(query=[named_token(PostNamedToken.Safety, 'safe')])
/// ```
///
/// Which is equivalent to the possibly more error-prone:
///
/// ```python
/// client.list_posts(query=[named_token("safety", 'safe')])
/// ```
pub fn named_token(key: &Bound<'_, PyAny>, value: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::token_py(key, value)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Generates a sorting token. Sorting tokens are used to sort resources returned by the API.
/// An example of this would be returning posts by score descending.
///
/// This function will accept any string, but if you want to be more sure about your code you
/// can use any of the :ref:`Sort token <sort-tokens-enums>` types listed below. See the example below.
///
/// :param key: String or Sort field name
/// :returns: The sort query token
/// :rtype: QueryToken
///
/// -----
/// Usage
/// -----
/// This lists posts by score descending:
///
/// ```python
/// client.list_posts(query=[-sort_token(PostSortToken.Score)])
/// ```
///
/// Which is equivalent to the possibly more error-prone:
///
/// ```python
/// client.list_posts(query=[-sort_token("score")])
/// ```
pub fn sort_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::sort_py(key)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Generates an anonymous token. Anonymous tokens are tokens that don't require some
/// sort of prefix to be used in a search. What the anonymous tag corresponds to depends
/// on the type of resource you're listing. For example, when listing posts the anonymous
/// tags correspond to post tags
///
///
/// :param str key: The anonymous token to create
/// :returns: The anonymous query token
/// :rtype: QueryToken
///
/// -----
/// Usage
/// -----
///
/// ```python
/// client.list_posts(fields=[anonymous_token("cat")])
/// ```
pub fn anonymous_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::anonymous_py(key)
}
#[cfg(feature = "python")]
#[cfg_attr(all(feature = "python"), pyfunction)]
/// Special tokens are a very limited set of tokens supported by the ``list_posts`` API.
/// They include being able to filter by posts that the current user has upvoted, or favorited.
/// See :class:`PostSpecialToken` for all the supported token names.
///
/// :param key: The special token name, string or ``PostSpecialToken``
///
/// -----
/// Usage
/// -----
///
/// Selects posts with score of 0, without comments and without favorites
///
/// ```python
/// client.list_post(fields=[special_token(PostSpecialToken.Tumbleweed)])
/// ```
pub fn special_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
QueryToken::special_py(key)
}
@ -171,17 +252,20 @@ pub fn special_token(key: &Bound<'_, PyAny>) -> PyResult<QueryToken> {
#[cfg_attr(all(feature = "python"), pymethods)]
impl QueryToken {
#[pyo3(name = "__str__")]
/// Generates a string representation of this QueryToken
pub fn to_python_string(&self) -> PyResult<String> {
Ok(format!("QueryToken(\"{}\", \"{}\")", self.key, self.value))
}
#[pyo3(name = "__repr__")]
/// Generates a string representation of this QueryToken
pub fn to_python_repr(&self) -> PyResult<String> {
self.to_python_string()
}
#[pyo3(name = "token")]
#[staticmethod]
#[doc(hidden)]
pub fn token_py(key: &Bound<'_, PyAny>, value: &Bound<'_, PyAny>) -> PyResult<Self> {
let value = if let Ok(value) = value.extract::<u32>() {
value.to_string()
@ -210,6 +294,7 @@ impl QueryToken {
#[pyo3(name = "sort")]
#[staticmethod]
#[doc(hidden)]
pub fn sort_py(key: &Bound<'_, PyAny>) -> PyResult<Self> {
if let Ok(tnt) = key.extract::<TagSortToken>() {
Ok(QueryToken::sort(tnt))
@ -230,6 +315,7 @@ impl QueryToken {
#[pyo3(name = "anonymous")]
#[staticmethod]
#[doc(hidden)]
pub fn anonymous_py(key: &Bound<'_, PyAny>) -> PyResult<Self> {
let key = key.extract::<String>()?;
Ok(QueryToken::anonymous(key))
@ -237,6 +323,7 @@ impl QueryToken {
#[pyo3(name = "special")]
#[staticmethod]
#[doc(hidden)]
pub fn special_py(key: &Bound<'_, PyAny>) -> PyResult<Self> {
if let Ok(special) = key.extract::<PostSpecialToken>() {
Ok(QueryToken::special(special))
@ -248,9 +335,15 @@ impl QueryToken {
}
#[pyo3(name = "negate")]
#[doc(hidden)]
pub fn negate_py(&self) -> PyResult<Self> {
Ok(self.negate())
}
/// Negates the query token. Would turn ``konosuba`` into ``-konosuba``
pub fn __neg__(&self) -> PyResult<Self> {
Ok(self.negate())
}
}
impl Display for QueryToken {
@ -273,7 +366,10 @@ impl ToQueryString for Vec<QueryToken> {
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_tags](crate::SzurubooruRequest::list_tags)
pub enum TagNamedToken {
/// having given name (accepts wildcards)
@ -321,7 +417,10 @@ impl<'py> FromPyObject<'py> for TagNamedToken {
#[derive(Debug, AsRefStr, Eq, PartialEq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_tags](crate::SzurubooruRequest::list_tags)
pub enum TagSortToken {
/// as random as it can get
@ -357,7 +456,10 @@ impl SortableToken for TagSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_posts](crate::SzurubooruRequest::list_posts)
pub enum PostNamedToken {
/// having given post number
@ -392,8 +494,9 @@ pub enum PostNamedToken {
RelationCount,
/// having been featured given number of times
FeatureCount,
/// given type of posts. `value` can be either `image`, `animation` (or `animated` or `anim`),
/// `flash` (or `swf`) or `video` (or `webm`). Use [models::PostType] for type-safe values
/// given type of posts. The value can be either `image`, `animation` (or `animated` or `anim`),
/// `flash` (or `swf`) or `video` (or `webm`). Use [PostType](crate::models::PostType)
/// for type-safe values
Type,
/// having given SHA1 checksum
ContentChecksum,
@ -445,8 +548,8 @@ pub enum PostNamedToken {
FeatureDate,
/// alias of [PostNamedToken::FeatureDate]
FeatureTime,
/// having given safety. <value> can be either `safe`, `sketchy` (or `questionable`) or `unsafe`
/// Use [models::PostSafety] for the type-safe version
/// Post safety. Can be either `safe`, `sketchy` (or `questionable`) or `unsafe`
/// Use [PostSafety](crate::models::PostSafety) for the type-safe version
Safety,
/// alias of [PostNamedToken::Safety]
Rating,
@ -455,7 +558,10 @@ impl NamedToken for PostNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_posts](crate::SzurubooruRequest::list_posts)
pub enum PostSortToken {
/// as random as it can get
@ -498,7 +604,7 @@ pub enum PostSortToken {
Date,
/// alias of [PostSortToken::CreationDate]
Time,
/// like [PostSortToken::CreationDate], only looks at last edit time
/// like [PostSortToken::CreationDate], only looks at last edit time instead
LastEditDate,
/// alias of [PostSortToken::LastEditDate]
LastEditTime,
@ -523,7 +629,10 @@ impl SortableToken for PostSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe special query tokens for use with [list_posts](crate::SzurubooruRequest::list_posts)
pub enum PostSpecialToken {
/// posts liked by currently logged-in user
@ -539,7 +648,10 @@ impl SpecialToken for PostSpecialToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_pools](crate::SzurubooruRequest::list_pools)
pub enum PoolNamedToken {
/// having given name (accepts wildcards)
@ -565,7 +677,10 @@ impl NamedToken for PoolNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_pools](crate::SzurubooruRequest::list_pools)
pub enum PoolSortToken {
/// as random as it can get
@ -593,7 +708,10 @@ impl SortableToken for PoolSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with
/// [list_comments](crate::SzurubooruRequest::list_comments)
pub enum CommentNamedToken {
@ -624,7 +742,10 @@ impl NamedToken for CommentNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with
/// [list_comments](crate::SzurubooruRequest::list_comments)
pub enum CommentSortToken {
@ -653,7 +774,10 @@ impl SortableToken for CommentSortToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with [list_users](crate::SzurubooruRequest::list_users)
pub enum UserNamedToken {
/// having given name (accepts wildcards)
@ -675,7 +799,10 @@ impl NamedToken for UserNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe sort query tokens for use with [list_users](crate::SzurubooruRequest::list_users)
pub enum UserSortToken {
/// as random as it can get
@ -699,7 +826,10 @@ impl SortableToken for UserNamedToken {}
#[derive(Debug, AsRefStr, PartialEq, Eq, Clone)]
#[strum(serialize_all = "kebab-case")]
#[cfg_attr(all(feature = "python"), pyclass(eq, eq_int))]
#[cfg_attr(
all(feature = "python"),
pyclass(eq, eq_int, module = "szurubooru_client.tokens")
)]
/// Type-safe named query tokens for use with
/// [list_snapshots](crate::SzurubooruRequest::list_snapshots)
pub enum SnapshotNamedToken {