
    {io                         S r SSKJr  SSKrSSKrSSKJr  SSKJrJ	r	J
r
  SSKJr  \" SS	5            SS
 j5       r\" SSSSSS5      SSSSSS.               SS jj5       r " S S5      r " S S5      rg)z,Provide helper classes used by other models.    )annotationsN)OrderedDict)AnyCallable	Generator   )_deprecate_argspermissionsknown_permissionsc                    Uc  S/nOJS/n[        U [        U5      -
  5      nUR                  S U 5       5        UR                  S U 5       5        SR                  U5      $ )aW  Return a comma separated string of permission changes.

:param known_permissions: A set of strings representing the available permissions.
:param permissions: A list of strings, or ``None``. These strings can exclusively
    contain ``+`` or ``-`` prefixes, or contain no prefixes at all. When prefixed,
    the resulting string will simply be the joining of these inputs. When not
    prefixed, all permissions are considered to be additions, and all permissions in
    the ``known_permissions`` set that aren't provided are considered to be
    removals. When ``None``, the result is ``"+all"``.

z+allz-allc              3  ,   #    U  H
  nS U 3v   M     g7f)-N .0xs     J/home/james-whalen/.local/lib/python3.13/site-packages/praw/models/util.py	<genexpr>%permissions_string.<locals>.<genexpr>!   s     /w!!gw   c              3  ,   #    U  H
  nS U 3v   M     g7f)+Nr   r   s     r   r   r   "   s     3{!!g{r   ,)sortedsetextendjoin)r   r
   to_setomitteds       r   permissions_stringr       s`     *S-==>/w//3{3388F    functionpause_afterskip_existingattribute_nameexclude_beforecontinue_after_idfullnameF)r%   r'   r&   r#   r$   c          	   +  <  #    Un[        SS9n[        S5      n	Sn
SnUSLn SnSnSnUc  X-  nU
S	-   S
-  n
U(       d  SU0US'   [        [        U " SSU0UD65      5       H9  n[	        UU5      nUU	;   a  M  SnU	R                  U5        UnU(       a  M5  Uv   M;     UnSnU(       a  US:  a  Sv   OfU(       a  UR                  5         SnOLUS	-  nU(       a  X:  a  UR                  5         SnSv   O$[        R                  " UR                  5       5        M  7f)a  Yield new items from ``function`` as they become available.

:param function: A callable that returns a :class:`.ListingGenerator`, e.g.,
    :meth:`.Subreddit.comments` or :meth:`.Subreddit.new`.
:param attribute_name: The field to use as an ID (default: ``"fullname"``).
:param exclude_before: When ``True`` does not pass ``params`` to ``function``
    (default: ``False``).
:param pause_after: An integer representing the number of requests that result in no
    new items before this function yields ``None``, effectively introducing a pause
    into the stream. A negative value yields ``None`` after items from a single
    response have been yielded, regardless of number of new items obtained in that
    response. A value of ``0`` yields ``None`` after every response resulting in no
    new items, and a value of ``None`` never introduces a pause (default: ``None``).
:param skip_existing: When ``True``, this does not yield any results from the first
    request thereby skipping any items that existed in the stream prior to starting
    the stream (default: ``False``).
:param continue_after_id: The initial item ID value to use for ``before`` in
    ``params``. The stream will continue from the item following this one (default:
    ``None``).

Additional keyword arguments will be passed to ``function``.

.. note::

    This function internally uses an exponential delay with jitter between
    subsequent responses that contain no new results, up to a maximum delay of just
    over 16 seconds. In practice, that means that the time before pause for
    ``pause_after=N+1`` is approximately twice the time before pause for
    ``pause_after=N``.

For example, to create a stream of comment replies, try:

.. code-block:: python

    reply_function = reddit.inbox.comment_replies
    for reply in praw.models.util.stream_generator(reply_function):
        print(reply)

To pause a comment stream after six responses with no new comments, try:

.. code-block:: python

    subreddit = reddit.subreddit("test")
    for comment in subreddit.stream.comments(pause_after=6):
        if comment is None:
            break
        print(comment)

To resume fetching comments after a pause, try:

.. code-block:: python

    subreddit = reddit.subreddit("test")
    comment_stream = subreddit.stream.comments(pause_after=5)

    for comment in comment_stream:
        if comment is None:
            break
        print(comment)
    # Do any other processing, then try to fetch more data
    for comment in comment_stream:
        if comment is None:
            break
        print(comment)

To bypass the internal exponential backoff, try the following. This approach is
useful if you are monitoring a subreddit with infrequent activity, and you want to
consistently learn about new items from the stream as soon as possible, rather than
up to a delay of just over sixteen seconds.

.. code-block:: python

    subreddit = reddit.subreddit("test")
    for comment in subreddit.stream.comments(pause_after=0):
        if comment is None:
            continue
        print(comment)

   )max_counteri-  r   NTFd         beforeparamslimitr   )
ExponentialCounter
BoundedSetreversedlistgetattraddresettimesleepcounter)r"   r%   r'   r&   r#   r$   function_kwargsbefore_attributeexponential_counterseen_attributeswithout_before_counterresponses_without_newvalid_pause_afterfoundnewest_attributer1   item	attributes                     r   stream_generatorrG   &   sP    B ),< oO#4/
#+E&<q&@B%F")13C(DOH%T("J"J/"JKLDn5IO+E	*( =
 M ,qJ%%'$%!!Q&! %:%H#))+()%


.6689A s   BDBDc                  @    \ rS rSrSrS	S jrS
S jrSS jrSS jrSr	g)r3      zA set with a maximum size that evicts the oldest items when necessary.

This class does not implement the complete set interface.

c                @    U R                  U5        XR                  ;   $ )z/Test if the :class:`.BoundedSet` contains item.)_access_setselfrE   s     r   __contains__BoundedSet.__contains__   s    Tyy  r!   c                .    Xl         [        5       U l        g)z+Initialize a :class:`.BoundedSet` instance.N)	max_itemsr   rL   )rN   rR   s     r   __init__BoundedSet.__init__   s    "M	r!   c                Z    XR                   ;   a  U R                   R                  U5        g g )N)rL   move_to_endrM   s     r   rK   BoundedSet._access   s#    99II!!$' r!   c                    U R                  U5        SU R                  U'   [        U R                  5      U R                  :  a  U R                  R	                  SS9  gg)z?Add an item to the set discarding the oldest item if necessary.NF)last)rK   rL   lenrR   popitemrM   s     r   r7   BoundedSet.add   sI    T		$tyy>DNN*II5) +r!   )rL   rR   N)rE   r   returnbool)rR   int)rE   r   )
__name__
__module____qualname____firstlineno____doc__rO   rS   rK   r7   __static_attributes__r   r!   r   r3   r3      s    !
"
(*r!   r3   c                  2    \ rS rSrSrSS jrS	S jrS rSrg)
r2      z6A class to provide an exponential counter with jitter.c                    SU l         Xl        g)zInitialize an :class:`.ExponentialCounter` instance.

:param max_counter: The maximum base value.

    .. note::

        The computed value may be 3.125% higher due to jitter.

r-   N_base_max)rN   r+   s     r   rS   ExponentialCounter.__init__   s     
	r!   c                    U R                   S-  nU R                   [        R                  " 5       U-  -   US-  -
  n[        U R                   S-  U R                  5      U l         U$ )z?Increment the counter and return the current value with jitter.g      0@r   )rj   randomminrk   )rN   
max_jittervalues      r   r;   ExponentialCounter.counter   sQ    ZZ$&


V]]_z99JNJa3
r!   c                    SU l         g)zReset the counter to 1.r-   N)rj   )rN   s    r   r8   ExponentialCounter.reset   s	    
r!   ri   N)r+   r_   )r]   zint | float)	r`   ra   rb   rc   rd   rS   r;   r8   re   r   r!   r   r2   r2      s    @ r!   r2   )r   zset[str]r
   zlist[str] | Noner]   str)r"   r   r%   ru   r'   z
str | Noner&   r^   r#   z
int | Noner$   r^   r<   r   r]   zGenerator[Any, None, None])rd   
__future__r   rn   r9   collectionsr   typingr   r   r   utilr	   r    rG   r3   r2   r   r!   r   <module>rz      s    2 "   # + + "  34"1A 50  %$( ":: : "	:
 : : : :  ::D* *: r!   