from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Iterable, Sequence, Tuple, Protocol, IO, Union
if TYPE_CHECKING:
from ...client_SYNC import Client
from ...models.flair import FlairTemplate, FlairTemplateChoices, UserFlairAssociation
from ...models.upload_lease import UploadLease
import csv
from io import StringIO
from functools import cached_property
import os.path as op
from ...util.base_conversion import to_base36
from ...iterators.chunking import chunked
from ...iterators.call_chunk_chaining_iterator import CallChunkChainingIterator
from ...iterators.call_chunk import CallChunk
from ...pagination.paginator_chaining_iterator import ImpartedPaginatorChainingIterator
from ...pagination.paginators.flair_sync1 import UserFlairAssociationPaginator
from ...model_loaders.flair import (
load_variant2_flair_template,
load_variant1_flair_template,
load_flair_template_choices,
load_user_flair_association,
)
from ...http.util.guess_filename_mimetype import guess_filename_mimetype
from ...model_loaders.upload_lease import load_upload_lease
[docs]class FlairProcedures:
def __init__(self, client: Client) -> None:
self._client = client
[docs] def set_user_flair(self,
sr: str,
user: str,
text: Optional[str],
css_class: Optional[str] = None,
) -> None:
"""Set the flair information on a user.
Any previously set flair information will be discarded.
A null argument means the field will not be sent in the request.
The API treats this as the same as supplying an empty string.
To revoke a flair, specify null or an empty string for the `text`
and `css_class` parameters.
.. .PARAMETERS
:param `str` sr:
Subreddit name.
:param `str` user:
User name.
:param `Optional[str]` text:
Flair text.
Specify a string no longer than 64 characters.
If longer than 64 characters then the parameter is ignored and an empty string is used.
:param `Optional[str]` css_class:
Flair CSS class.
Specify a string no longer than 100 characters.
If longer than 100 characters then a `BAD_CSS_NAME` API error is returned.
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `BAD_FLAIR_TARGET`:
The specified user doesn't exist.
+ `BAD_CSS_NAME`:
- The specified CSS class was longer than 100 characters.
- The specified CSS class contained invalid characters.
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- There is no user context.
- You do not have permission to set flairs in the specified subreddit.
+ `404`:
The specified subreddit does not exist.
"""
def g() -> Iterable[tuple[str, str]]:
yield ('name', user)
if text is not None: yield ('text', text)
if css_class is not None: yield ('css_class', css_class)
self._client.request('POST', f'/r/{sr}/api/flair', data=dict(g()))
[docs] def set_post_flair(self,
sr: str,
subm: Union[int, str],
text: Optional[str],
css_class: Optional[str] = None,
) -> None:
"""Set the flair information on a post.
Any previously set flair information will be discarded.
A null argument means the field will not be sent in the request.
The API treats this as the same as supplying an empty string.
To revoke a flair, specify null or an empty string for the `text`
and `css_class` parameters.
.. .PARAMETERS
:param `str` sr:
Subreddit name.
:param `Union[int, str]` subm:
Submission ID.
:param `Optional[str]` text:
Flair text.
Specify a string no longer than 64 characters.
If longer than 64 characters then the parameter is ignored and an empty string is used.
:param `Optional[str]` css_class:
Flair CSS class.
Specify a string no longer than 100 characters.
If longer than 100 characters then a `BAD_CSS_NAME` API error is returned.
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `BAD_FLAIR_TARGET`:
The specified submission doesn't exist.
+ `BAD_CSS_NAME`:
- The specified CSS class was longer than 100 characters.
- The specified CSS class contained invalid characters.
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- There is no user context.
- You do not have permission to set flairs in the specified subreddit.
- The target submission does not belong to the specified subreddit.
+ `404`:
The specified subreddit does not exist.
"""
id36 = x if isinstance((x := subm), str) else to_base36(x)
def g() -> Iterable[tuple[str, str]]:
yield ('link', 't3_' + id36)
if text is not None: yield ('text', text)
if css_class is not None: yield ('css_class', css_class)
self._client.request('POST', f'/r/{sr}/api/flair', data=dict(g()))
[docs] def bulk_set_user_flairs(self,
sr: str,
items: Iterable[Tuple[str, str, str]],
) -> CallChunkChainingIterator[bool]:
"""Bulk set flair information for users.
The second parameter is an iterable of 3-element tuples:
`(user, text, css_class)`: the target user name, the flair text,
and CSS class to assign.
.. .PARAMETERS
:param `str` sr:
:param `Iterable[tuple[str, str, str]]` items:
An iterable of tuples consisting of `(user, text, css_class)`.
.. .RETURNS
:returns:
For each input item, a boolean appears in the output indicating whether
the flair assignment succeeded.
:rtype: :class:`~.iterators.call_chunk_chaining_iterator.CallChunkChainingIterator`\\[`bool`]
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- There is no user context.
- You do not have permission to set flairs in the specified subreddit.
+ `404`:
The specified subreddit does not exist.
"""
def mass_update_user_flairs(items: Sequence[Tuple[str, str, str]]) -> Sequence[bool]:
sio = StringIO()
csv.writer(sio).writerows(items)
s = sio.getvalue()
root = self._client.request('POST', f'/r/{sr}/api/flaircsv', files={'flair_csv': s})
return [d['ok'] for d in root]
itr = map(
lambda xs: CallChunk(mass_update_user_flairs, xs),
chunked(items, 100),
)
return CallChunkChainingIterator(itr)
def _create_or_update_flair_template(self,
sr: str,
flair_type: str,
*,
uuid: Optional[str] = None,
text: Optional[str] = None,
css_class: Optional[str] = None,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
mod_only: Optional[bool] = None,
text_editable: Optional[bool] = None,
allowable_content: Optional[str] = None,
max_emojis: Optional[int] = None,
) -> FlairTemplate:
d = {'flair_type': flair_type}
for k, v in (
('flair_template_id', uuid),
('text', text),
('css_class', css_class),
('background_color', bg_color),
('text_color', fg_color_scheme),
('mod_only', None if mod_only is None else '01'[mod_only]),
('text_editable', None if text_editable is None else '01'[text_editable]),
('allowable_content', allowable_content),
('max_emojis', str(max_emojis)),
):
if v is not None:
d[k] = v
root = self._client.request('POST', f'/r/{sr}/api/flairtemplate_v2', data=d)
return load_variant2_flair_template(root)
[docs] def create_user_flair_template(self,
sr: str,
*,
text: Optional[str] = None,
css_class: Optional[str] = None,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
mod_only: Optional[bool] = None,
text_editable: Optional[bool] = None,
allowable_content: Optional[str] = None,
max_emojis: Optional[int] = None,
) -> FlairTemplate:
"""Create a user flair template.
Any previously set flair information will be discarded.
A null argument means the field will not be sent in the request.
The API treats this as the same as supplying an empty string.
.. .PARAMETERS
:param `str` sr:
:param `Optional[str]` text:
:param `Optional[str]` css_class:
:param `Optional[str]` bg_color:
A 6-digit rgb hex color with an optional hash at the start. E.g. `#fb8559`.
For user flair templates, the background color can be unset, making it transparent.
(Post flairs cannot be transparent.)
Effective default: empty string. It will be transparent.
:param `Optional[str]` fg_color_scheme:
Either `dark` or `light`.
Effective default: `dark`.
:param `Optional[bool]` mod_only:
Whether flair is only available for mods to select.
Effective default: false.
:param `Optional[bool]` text_editable:
Whether users will be able to edit their flair text.
Effective default: false.
:param `Optional[str]` allowable_content:
Either: `all`, `emoji`, `text`.
Effective default: `all`.
:param `Optional[int]` max_emojis:
An integer from 1 to 10.
Effective default: `10`.
.. .RETURNS
:returns: The newly created flair template.
:rtype: :class:`~.models.flair.FlairTemplate`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- There is no user context.
- You do not have permission to set flairs in the specified subreddit.
+ `404`:
The specified subreddit does not exist.
"""
return self._create_or_update_flair_template(
sr,
flair_type='USER_FLAIR',
text=text,
css_class=css_class,
bg_color=bg_color,
fg_color_scheme=fg_color_scheme,
mod_only=mod_only,
text_editable=text_editable,
allowable_content=allowable_content,
max_emojis=max_emojis,
)
[docs] def create_post_flair_template(self,
sr: str,
*,
text: Optional[str] = None,
css_class: Optional[str] = None,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
mod_only: Optional[bool] = None,
text_editable: Optional[bool] = None,
allowable_content: Optional[str] = None,
max_emojis: Optional[int] = None,
) -> FlairTemplate:
"""Create a post flair template.
Behaves similarly to :meth:`.create_user_flair_template`.
.. .PARAMETERS
:(parameters):
Same as :meth:`.create_user_flair_template`,
but `bg_color` effective default is different.
:param `Optional[str]` bg_color:
Effective default: `#d3d6da`.
.. .RETURNS
:(returns): Same as :meth:`.create_user_flair_template`.
.. .RAISES
:(raises): Same as :meth:`.create_user_flair_template`.
"""
return self._create_or_update_flair_template(
sr,
flair_type='LINK_FLAIR',
text=text,
css_class=css_class,
bg_color=bg_color,
fg_color_scheme=fg_color_scheme,
mod_only=mod_only,
text_editable=text_editable,
allowable_content=allowable_content,
max_emojis=max_emojis,
)
[docs] def update_user_flair_template(self,
sr: str,
uuid: str,
*,
text: Optional[str] = None,
css_class: Optional[str] = None,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
mod_only: Optional[bool] = None,
text_editable: Optional[bool] = None,
allowable_content: Optional[str] = None,
max_emojis: Optional[int] = None,
) -> FlairTemplate:
"""Update a user flair template.
Behaves similarly to :meth:`.create_user_flair_template`.
.. .PARAMETERS
:(parameters):
Similar to :meth:`.create_user_flair_template`.
:param `str` uuid:
The flair template UUID.
"""
return self._create_or_update_flair_template(
sr,
flair_type='USER_FLAIR',
uuid=uuid,
text=text,
css_class=css_class,
bg_color=bg_color,
fg_color_scheme=fg_color_scheme,
mod_only=mod_only,
text_editable=text_editable,
allowable_content=allowable_content,
max_emojis=max_emojis,
)
[docs] def update_post_flair_template(self,
sr: str,
uuid: str,
*,
text: Optional[str] = None,
css_class: Optional[str] = None,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
mod_only: Optional[bool] = None,
text_editable: Optional[bool] = None,
allowable_content: Optional[str] = None,
max_emojis: Optional[int] = None,
) -> FlairTemplate:
"""Update a post flair template.
Behaves similarly to :meth:`.update_user_flair_template`.
"""
return self._create_or_update_flair_template(
sr,
flair_type='LINK_FLAIR',
uuid=uuid,
text=text,
css_class=css_class,
bg_color=bg_color,
fg_color_scheme=fg_color_scheme,
mod_only=mod_only,
text_editable=text_editable,
allowable_content=allowable_content,
max_emojis=max_emojis,
)
[docs] def delete_flair_template(self, sr: str, uuid: str) -> None:
"""Delete a user or post flair template.
.. .PARAMETERS
:param `str` sr:
:param `str` uuid:
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- There is no user context.
- You do not have permission.
+ `404`:
- The specified subreddit does not exist.
- The specified flair UUID does not exist.
"""
self._client.request('POST', f'/r/{sr}/api/deleteflairtemplate', data={'flair_template_id': uuid})
[docs] def delete_all_user_flair_templates(self, sr: str) -> None:
"""Delete all user flair templates in a subreddit.
.. .PARAMETERS
:param `str` sr:
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- There is no user context.
- You do not have permission.
+ `404`:
The specified subreddit does not exist.
"""
self._client.request('POST', f'/r/{sr}/api/clearflairtemplates', data={'flair_type': 'USER_FLAIR'})
[docs] def delete_all_post_flair_templates(self, sr: str) -> None:
"""Delete all post flair templates in a subreddit."""
self._client.request('POST', f'/r/{sr}/api/clearflairtemplates', data={'flair_type': 'LINK_FLAIR'})
[docs] def retrieve_user_flair_templates(self, sr: str) -> Sequence[FlairTemplate]:
"""Return a list of available user flair templates in a subreddit.
Current user must be a moderator of the subreddit
(otherwise a 403 HTTP error is returned).
For non-mods, there is :meth:`.get_post_flair_choices`.
.. .PARAMETERS
:param `str` sr:
.. .RETURNS
:rtype: `Sequence`\\[:class:`~.models.flair.FlairTemplate`]
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `USER_REQUIRED`:
There is no user context.
:raises redditwarp.http.exceptions.StatusCodeException:
+ `302`:
The specified subreddit does not exist.
+ `403`:
You do not have permission.
"""
root = self._client.request('GET', f'/r/{sr}/api/user_flair_v2')
return [load_variant1_flair_template(d) for d in root]
[docs] def retrieve_post_flair_templates(self, sr: str) -> Sequence[FlairTemplate]:
"""Return a list of available post flair templates in a subreddit.
Behaves similarly to :meth:`.retrieve_user_flair_templates`.
"""
root = self._client.request('GET', f'/r/{sr}/api/link_flair_v2')
return [load_variant1_flair_template(d) for d in root]
[docs] def reorder_user_flair_templates(self, sr: str, order: Sequence[str]) -> None:
"""Reorder user flair templates.
Reorders the flair templates as shown in the UI.
The list must contain every flair UUID, otherwise a 400 HTTP error is returned.
If you duplicate an ID the flair will have multiple references in the UI.
.. .PARAMETERS
:param `str` sr:
:param `Sequence[str]` order:
A list of all flair UUIDs.
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
A flair template ID is missing from the provided list.
+ `500`:
The specified subreddit does not exist.
"""
params = {'subreddit': sr, 'flair_type': 'USER_FLAIR'}
self._client.request('PATCH', '/api/flair_template_order', params=params, json=order)
[docs] def reorder_post_flair_templates(self, sr: str, order: Sequence[str]) -> None:
"""Reorder post flair templates.
Behaves similarly to :meth:`.reorder_user_flair_templates`.
"""
params = {'subreddit': sr, 'flair_type': 'LINK_FLAIR'}
self._client.request('PATCH', '/api/flair_template_order', params=params, json=order)
[docs] def assign_user_flair_template(self,
sr: str,
user: str,
uuid: str,
*,
text: Optional[str] = None,
) -> None:
"""Assign a user flair template.
.. .PARAMETERS
:param `str` sr:
:param `str` user:
:param `str` uuid:
:param `Optional[str]` text:
Custom text to override the template's text.
Supply `None` or empty string to use the template's text.
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- The specified flair UUID does not exist.
- You do not have permission.
+ `404`:
- The specified subreddit does not exist.
- The specified user does not exist.
"""
d = {
'name': user,
'flair_template_id': uuid,
}
if text is not None:
d['text'] = text
self._client.request('POST', f'/r/{sr}/api/selectflair', data=d)
[docs] def assign_post_flair_template(self,
sr: str,
subm: Union[int, str],
uuid: str,
*,
text: Optional[str] = None,
) -> None:
"""Assign a post flair template.
.. .PARAMETERS
:param `str` sr:
:param `str` user:
:param `str` uuid:
:param `Optional[str]` text:
Custom text to override the template's text.
Supply `None` or empty string to use the template's text.
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
- The specified flair UUID does not exist.
- You do not have permission.
+ `404`:
- The specified subreddit does not exist.
- The specified submission does not exist.
"""
id36 = x if isinstance((x := subm), str) else to_base36(x)
d = {
'link': 't3_' + id36,
'flair_template_id': uuid,
}
if text is not None:
d['text'] = text
self._client.request('POST', f'/r/{sr}/api/selectflair', data=d)
[docs] def assign_user_flair(self,
sr: str,
user: str,
text: Optional[str],
css_class: Optional[str] = None,
*,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
) -> None:
"""Assign a custom user flair.
This is a newer version of :meth:`.set_user_flair`.
.. .PARAMETERS
:param `str` sr:
:param `str` user:
:param `Optional[str]` text:
:param `Optional[str]` css_class:
:param `Optional[str]` bg_color:
:param `Optional[str]` fg_color_scheme:
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `BAD_CSS_NAME`:
- The specified CSS class was longer than 100 characters.
- The specified CSS class contained invalid characters.
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
You do not have permission.
+ `404`:
- The specified subreddit does not exist.
- The specified user does not exist.
"""
d = {'name': user}
for k, v in (
('text', text),
('css_class', css_class),
('background_color', bg_color),
('text_color', fg_color_scheme),
):
if v is not None:
d[k] = v
self._client.request('POST', f'/r/{sr}/api/selectflair', data=d)
[docs] def assign_post_flair(self,
sr: str,
subm: Union[int, str],
text: Optional[str],
css_class: Optional[str] = None,
*,
bg_color: Optional[str] = None,
fg_color_scheme: Optional[str] = None,
) -> None:
"""Assign a custom post flair.
This is a newer version of :meth:`.set_user_flair`.
.. .PARAMETERS
:param `str` sr:
:param `Union[int, str]` subm:
:param `Optional[str]` text:
:param `Optional[str]` css_class:
:param `Optional[str]` bg_color:
:param `Optional[str]` fg_color_scheme:
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `BAD_CSS_NAME`:
- The specified CSS class was longer than 100 characters.
- The specified CSS class contained invalid characters.
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
You do not have permission.
+ `404`:
- The specified subreddit does not exist.
- The specified submission does not exist.
"""
id36 = x if isinstance((x := subm), str) else to_base36(x)
d = {'link': 't3_' + id36}
for k, v in (
('text', text),
('css_class', css_class),
('background_color', bg_color),
('text_color', fg_color_scheme),
):
if v is not None:
d[k] = v
self._client.request('POST', f'/r/{sr}/api/selectflair', data=d)
[docs] def get_user_flair_template_choices(self, sr: str) -> FlairTemplateChoices:
"""Get user flair template choices.
.. .PARAMETERS
:param `str` sr:
.. .RETURNS
:returns: :class:`~.models.flair.FlairTemplateChoices`, a `Sequence`\\[:class:`~.models.flair.FlairTemplateChoice`]
:rtype: :class:`~.models.flair.FlairTemplateChoices`
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `302`:
There is no user context.
+ `404`:
The specified subreddit does not exist.
"""
root = self._client.request('POST', f'/r/{sr}/api/flairselector')
return load_flair_template_choices(root)
[docs] def get_post_flair_template_choices(self, sr: str) -> FlairTemplateChoices:
"""Get user flair template choices.
Behaves similarly to :meth:`.get_user_flair_template_choices`.
"""
root = self._client.request('POST', f'/r/{sr}/api/flairselector', data={'is_newlink': '1'})
return load_flair_template_choices(root)
[docs] def get_user_flair_association(self, sr: str, user: str) -> Optional[UserFlairAssociation]:
"""Get a user flair association in a subreddit.
.. .PARAMETERS
:param `str` sr:
:param `str` user:
.. .RETURNS
:rtype: `Optional`\\[:class:`~.models.flair.UserFlairAssociation`]
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `302`:
The specified subreddit does not exist.
+ `403`:
- There is no user context.
- You are not a moderator of the subreddit.
"""
params = {'name': user, 'limit': '1'}
root = self._client.request('GET', f'/r/{sr}/api/flairlist', params=params)
users_data = root['users']
if not users_data:
return None
user_data = users_data[0]
if user_data['user'].lower() != user.lower():
return None
return load_user_flair_association(user_data)
[docs] def get_user_flair_associations(self,
sr: str,
amount: Optional[int] = None,
) -> ImpartedPaginatorChainingIterator[UserFlairAssociationPaginator, UserFlairAssociation]:
"""Get a user flair associations in a subreddit.
.. .PARAMETERS
:param `str` sr:
:param `str` user:
.. .RETURNS
:rtype: :class:`~.pagination.paginator_chaining_iterator.ImpartedPaginatorChainingIterator`\\[:class:`~.pagination.paginators.flair_sync1.UserFlairAssociationPaginator`, :class:`~.models.flair.UserFlairAssociation`]
.. .RAISES
:raises redditwarp.http.exceptions.StatusCodeException:
+ `302`:
The specified subreddit does not exist.
+ `403`:
- There is no user context.
- You are not a moderator of the subreddit.
"""
p = UserFlairAssociationPaginator(self._client, f'/r/{sr}/api/flairlist')
return ImpartedPaginatorChainingIterator(p, amount)
[docs] def show_my_flair(self, sr: str) -> None:
"""Show the current user's flair in the subreddit.
To tell if the current user's flair is shown::
subr = client.p.subreddit.fetch_by_name('Python')
print(subr.me.flair.shown)
.. .PARAMETERS
:param `str` sr:
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `USER_REQUIRED`:
There is no user context.
:raises redditwarp.http.exceptions.StatusCodeException:
+ `403`:
You do not have permission.
+ `404`:
The specified subreddit does not exist.
"""
self._client.request('POST', f'/r/{sr}/api/setflairenabled', params={'flair_enabled': '1'})
[docs] def hide_my_flair(self, sr: str) -> None:
"""Hide the current user's flair in the subreddit."""
self._client.request('POST', f'/r/{sr}/api/setflairenabled', params={'flair_enabled': '0'})
[docs] class PostAppearance:
def __init__(self, outer: FlairProcedures) -> None:
self._client = outer._client
def _obtain_upload_lease_helper(self,
*,
sr: str,
uuid: str,
imagetype: str,
filepath: str,
mimetype: Optional[str] = None,
) -> UploadLease:
if mimetype is None:
mimetype = guess_filename_mimetype(filepath)
result = self._client.request('POST', f'/api/v1/{sr}/flair_style_asset_upload_s3/{uuid}',
data={'imagetype': imagetype, 'filepath': filepath, 'mimetype': mimetype})
return load_upload_lease(result)
[docs] def obtain_thumbnail_upload_lease(self,
*,
sr: str,
uuid: str,
filepath: str,
mimetype: Optional[str] = None,
) -> UploadLease:
return self._obtain_upload_lease_helper(
sr=sr,
uuid=uuid,
imagetype='postPlaceholderImage',
filepath=filepath,
mimetype=mimetype,
)
[docs] def obtain_background_upload_lease(self,
*,
sr: str,
uuid: str,
filepath: str,
mimetype: Optional[str] = None,
) -> UploadLease:
return self._obtain_upload_lease_helper(
sr=sr,
uuid=uuid,
imagetype='postBackgroundImage',
filepath=filepath,
mimetype=mimetype,
)
[docs] def deposit_file(self,
file: IO[bytes],
upload_lease: UploadLease,
*,
timeout: float = 1000,
) -> None:
resp = self._client.http.request('POST', upload_lease.endpoint,
data=upload_lease.fields, files={'file': file}, timeout=timeout)
resp.ensure_successful_status()
[docs] class ObtainUploadLeaseFunction(Protocol):
def __call__(self,
*,
sr: str,
uuid: str,
filepath: str,
mimetype: Optional[str] = None,
) -> UploadLease: ...
def _upload_helper(self,
file: IO[bytes],
*,
sr: str,
uuid: str,
filepath: Optional[str] = None,
timeout: float = 1000,
obtain_upload_lease: ObtainUploadLeaseFunction,
) -> UploadLease:
if filepath is None:
filepath = op.basename(getattr(file, 'name', ''))
if not filepath:
raise ValueError("the `filepath` parameter must be explicitly specified if the file object has no `name` attribute.")
upload_lease = obtain_upload_lease(sr=sr, uuid=uuid, filepath=filepath)
self.deposit_file(file, upload_lease, timeout=timeout)
return upload_lease
[docs] def upload_thumbnail(self,
file: IO[bytes],
*,
sr: str,
uuid: str,
filepath: Optional[str] = None,
timeout: float = 1000,
) -> UploadLease:
return self._upload_helper(file=file, sr=sr, uuid=uuid, filepath=filepath, timeout=timeout, obtain_upload_lease=self.obtain_thumbnail_upload_lease)
[docs] def upload_background(self,
file: IO[bytes],
*,
sr: str,
uuid: str,
filepath: Optional[str] = None,
timeout: float = 1000,
) -> UploadLease:
return self._upload_helper(file=file, sr=sr, uuid=uuid, filepath=filepath, timeout=timeout, obtain_upload_lease=self.obtain_background_upload_lease)
[docs] def config(self,
sr: str,
uuid: str,
*,
title_color: Optional[str] = '',
background_color: Optional[str] = '',
thumbnail_image_url: Optional[str] = '',
background_image_url: Optional[str] = '',
) -> None:
"""Configure a post flair's post appearance settings.
All parameters should be specified. If a parameter is not specified or is
an invalid value, its default will be used.
.. .PARAMETERS
:param `Optional[str]` title_color:
A hex color.
The default value will be used if an empty string or any other invalid value is specified.
Default: `#222222`.
:param `Optional[str]` background_color:
A hex color.
The default value will be used if an empty string or any other invalid value is specified.
Default: `#FFFFFF`.
:param `Optional[str]` thumbnail_image_url:
The URL location of a thumbnail image.
Specify an empty string to remove the image.
:param `Optional[str]` background_image_url:
The URL location of a background image.
Specify an empty string to remove the image.
.. .RETURNS
:rtype: `None`
.. .RAISES
:raises redditwarp.exceptions.RedditError:
+ `USER_REQUIRED`:
There is no user context.
"""
def g() -> Iterable[tuple[str, str]]:
if title_color is not None: yield ('postTitleColor', title_color)
if background_color is not None: yield ('postBackgroundColor', background_color)
if thumbnail_image_url is not None: yield ('postPlaceholderImage', thumbnail_image_url)
if background_image_url is not None: yield ('postBackgroundImage', background_image_url)
self._client.request('PUT', f'/api/v1/{sr}/flair_styles/{uuid}', data=dict(g()))
post_appearance: cached_property[PostAppearance] = cached_property(PostAppearance)
("""
When you edit a post flair template (through the new Reddit UI), there is a toggle at
the bottom of the menu that says "Edit post appearance". The methods on this object
relate to these settings.
The important method is :meth:`~PostAppearance.config`.
""")