
    \j[                        d Z ddlmZ ddlmZ ddlZddlZddlZddlm	Z	m
Z
mZmZ  ej                  d      Zh dZddZdd	Z G d
 d      Z G d d      Z G d d      Zg dZy)z?
This submodule implements the SDK's evaluation context model.
    )annotations)IterableN)AnyDictOptionalUnionz[^-a-zA-Z0-9._]>   ipnameemailavatarcountrylastName	firstNamec                F    | j                  dd      j                  dd      S )N%z%25:z%3A)replacekeys    :/root/env/lib/python3.12/site-packages/ldclient/context.py#_escape_key_for_fully_qualified_keyr      s"     ;;sE"**366    c                T    | dk(  ry| dk(  ry| dk(  ryt         j                  |       ryy )N zcontext kind must not be emptykindz""kind" is not a valid context kindmultizJcontext of kind "multi" must be created with create_multi or multi_builderz+context kind contains disallowed characters)_INVALID_KIND_REGEXsearchr   s    r   _validate_kindr       s4    rz/v~3w[!!$'<r   c                  F   e Zd ZdZdZ	 dZ	 	 	 	 	 	 	 	 d'	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d(dZed)d*d       Zed+d       Z	ed,d       Z
ed-d	       Zed.d
       Zed/d       Zed0d       Zed1d       Zed0d       Zed2d       Zed2d       Zed1d       Zed0d       Zd3dZed4d       Zd5dZed6d       Zed7d       Zed6d       Zed8d       Zed2d       Zd9dZd2dZd:dZ ed;d       Z!ed,d       Z"d<d Z#d2d!Z$d0d"Z%d0d#Z&d=d$Z'ed>d%       Z(ed?d&       Z)y)@Contexta}  
    A collection of attributes that can be referenced in flag evaluations and analytics events.
    This entity is also called an "evaluation context."

    To create a Context of a single kind, such as a user, you may use :func:`create()` when only the
    key and the kind are relevant; or, to specify other attributes, use :func:`builder()`.

    To create a Context with multiple kinds (a multi-context), use :func:`create_multi()` or
    :func:`multi_builder()`.

    A Context can be in an error state if it was built with invalid attributes. See :attr:`valid`
    and :attr:`error`.

    A Context is immutable once created.
    userr   Nc
                   |	| j                  |	       y|*t        |      dk(  r| j                  d       yt        |d       }d}
d}d}|D ]  }|j                   |g }|j	                  |j                         /|j
                  |
k(  r| j                  d        y|j
                  }
|dk7  r|dz  }||j
                  dz   t        |j                        z   z  } |r!| j                  d	j                  |             yd
| _	        || _
        d| _        d| _        d| _        d| _        d| _        || _        d| _        y|t$        j&                  }t)        |      }|r| j                  |       y|dk(  r|s| j                  d       y|| _        || _	        || _        || _        || _        || _        d| _
        |t$        j&                  k(  r|n|dt        |      | _        d| _        y)aK  
        Constructs an instance, setting all properties. Avoid using this constructor directly.

        Applications should not normally use this constructor; the intended pattern is to use
        factory methods or builders. Calling this constructor directly may result in some context
        validation being skipped.
        Nr   z,multi-context must contain at least one kindc                    | j                   S Nr   )cs    r   <lambda>z"Context.__init__.<locals>.<lambda>T   s
    !&& r   r   r   z7multi-kind context cannot have same kind more than oncer   z, r   Fz%context key must not be None or empty)_Context__make_invalidlensortederrorappendr   r   r   join_Context__kind_Context__multi_Context__key_Context__name_Context__anonymous_Context__attributes_Context__private_Context__full_key_Context__errorr"   DEFAULT_KINDr    )selfr   r   r
   	anonymous
attributesprivate_attributesmulti_contextsallow_empty_keyr,   	last_kinderrorsfull_keyr'   
kind_errors                  r   __init__zContext.__init__8   s   & &%>"a'##$RS $N8HINIFH# V77&~!#MM!''*66Y&''(abFF	r>OHAFFSL+Nquu+UUUV ##DIIf$56!DK)DLDJDK$D $D!DN&DODL<''D#D)

+"9_ GH
$&+!%)=)=!=#@EF 	r   c           
     &    t        ||dddddd      S )a  
        Creates a single-kind Context with only the key and the kind specified.

        If you omit the kind, it defaults to "user" (:const:`DEFAULT_KIND`).

        :param key: the context key
        :param kind: the context kind; if omitted, it is :const:`DEFAULT_KIND` ("user")
        :return: a context

        :see: :func:`builder()`
        :see: :func:`create_multi()`
        NFr"   )clsr   r   s      r   createzContext.create   s     tS$tT4GGr   c                f    t               }|D ]  }|j                  |        |j                         S )a  
        Creates a multi-context out of the specified single-kind Contexts.

        To create a Context for a single context kind, use :func:`create()` or
        :func:`builder()`.

        You may use :func:`multi_builder()` instead if you want to add contexts one at a time
        using a builder pattern.

        For the returned Context to be valid, the contexts list must not be empty, and all of its
        elements must be valid Contexts. Otherwise, the returned Context will be invalid as
        reported by :func:`error()`.

        If only one context parameter is given, the method returns that same context.

        If a nested context is a multi-context, this is exactly equivalent to adding each of the
        individual kinds from it separately. See :func:`ldclient.ContextMultiBuilder.add()`.

        :param contexts: the individual contexts
        :return: a multi-context

        :see: :func:`create()`
        :see: :func:`multi_builder()`
        )ContextMultiBuilderaddbuild)rF   contextsbuilderr'   s       r   create_multizContext.create_multi   s2    6 &' 	AKKN	}}r   c                   |t         j                  d      S d|vrt         j                  |      S |d   }t        |t              st         j                  d      S |dk(  rt               }|j                         D ]Y  \  }}|dk7  st        |t              st         j                  |      c S t         j                  ||      }|j                  |       [ |j                         S t         j                  ||d         S )a  
        Creates a Context from properties in a dictionary, corresponding to the JSON
        representation of a context or a user.

        If the dictionary has a "kind" property, then it is interpreted as a context using
        the LaunchDarkly JSON schema for contexts. If it does not have a "kind" property, it
        is interpreted as a context with "user" kind using the somewhat different LaunchDarkly
        JSON schema for users in older LaunchDarkly SDKs.

        DEPRECATED: The legacy user format is deprecated and will be removed in 9.0.0

        :param props: the context/user properties
        :return: a context
        zCannot use None as a contextr   r   )r"   _Context__create_with_error_Context__from_dict_old_user
isinstancestr'_Context__create_with_schema_type_errorrI   itemsdict_Context__from_dict_singlerJ   rK   )rF   propsr   bkvr'   s          r   	from_dictzContext.from_dict   s      =../MNN//66V}$$::6BB7?#%A 1;%a.&FFqII221a8AEE!H 779))%v??r   c                    t        |      S )a:  
        Creates a builder for building a Context.
        
        You may use :class:`ldclient.ContextBuilder` methods to set additional attributes and/or
        change the context kind before calling :func:`ldclient.ContextBuilder.build()`. If you
        do not change any values, the defaults for the Context are that its ``kind`` is :const:`DEFAULT_KIND`,
        its :attr:`key` is set to the key parameter specified here, :attr:`anonymous` is False, and it has no values for
        any other attributes.

        This method is for building a Context that has only a single kind. To define a multi-context,
        use :func:`create_multi()` or :func:`multi_builder()`.

        :param key: the context key
        :return: a new builder

        :see: :func:`create()`
        :see: :func:`create_multi()`

        )ContextBuilder)rF   r   s     r   rM   zContext.builder   s    * c""r   c                .    t        |j                  |      S )aX  
        Creates a builder whose properties are the same as an existing single-kind Context.
        
        You may then change the builder's state in any way and call :func:`ldclient.ContextBuilder.build()`
        to create a new independent Context.

        :param context: the context to copy from
        :return: a new builder
        )r^   r   )rF   contexts     r   builder_from_contextzContext.builder_from_context   s     gkk733r   c                    t               S )a0  
        Creates a builder for building a multi-context.

        This method is for building a Context that contains multiple contexts, each for a different
        context kind. To define a single context, use :func:`create()` or :func:`builder()` instead.

        The difference between this method and :func:`create_multi()` is simply that the builder
        allows you to add contexts one at a time, if that is more convenient for your logic.

        :return: a new builder

        :see: :func:`builder()`
        :see: :func:`create_multi()`
        )rI   )rF   s    r   multi_builderzContext.multi_builder   s      #$$r   c                    | j                   du S )aj  
        True for a valid Context, or False for an invalid one.
        
        A valid context is one that can be used in SDK operations. An invalid context is one that
        is missing necessary attributes or has invalid attributes, indicating an incorrect usage
        of the SDK API. The only ways for a context to be invalid are:

        * The :attr:`kind` property had a disallowed value. See :func:`ldclient.ContextBuilder.kind()`.
        * For a single context, the :attr:`key` property was None or empty.
        * You tried to create a multi-context without specifying any contexts.
        * You tried to create a multi-context using the same context kind more than once.
        * You tried to create a multi-context where at least one of the individual Contexts was invalid.

        In any of these cases, :attr:`valid` will be False, and :attr:`error` will return a
        description of the error.

        Since in normal usage it is easy for applications to be sure they are using context kinds
        correctly, and because throwing an exception is undesirable in application code that uses
        LaunchDarkly, the SDK stores the error state in the Context itself and checks for such
        errors at the time the Context is used, such as in a flag evaluation. At that point, if
        the context is invalid, the operation will fail in some well-defined way as described in
        the documentation for that method, and the SDK will generally log a warning as well. But
        in any situation where you are not sure if you have a valid Context, you can check
        :attr:`valid` or :attr:`error`.
        Nr7   r9   s    r   validzContext.valid  s    6 ||t##r   c                    | j                   S )z
        Returns None for a valid Context, or an error message for an invalid one.
        
        If this is None, then :attr:`valid` is True. If it is not None, then :attr:`valid` is
        False.
        re   rf   s    r   r,   zContext.error+  s     ||r   c                    | j                   duS )a  
        True if this is a multi-context.
        
        If this value is True, then :attr:`kind` is guaranteed to be :const:`MULTI_KIND`, and
        you can inspect the individual context for each kind with :func:`get_individual_context()`.

        If this value is False, then :attr:`kind` is guaranteed to return a value that is not
        :const:`MULTI_KIND`.

        :see: :func:`create_multi()`
        N)r0   rf   s    r   multiplezContext.multiple5  s     ||4''r   c                    | j                   S )aj  
        Returns the context's ``kind`` attribute.
        
        Every valid context has a non-empty kind. For multi-contexts, this value is
        :const:`MULTI_KIND` and the kinds within the context can be inspected with
        :func:`get_individual_context()`.

        :see: :func:`ldclient.ContextBuilder.kind()`
        :see: :func:`create()`
        )r/   rf   s    r   r   zContext.kindD  s     {{r   c                    | j                   S )a  
        Returns the context's ``key`` attribute.
        
        For a single context, this value is set by :func:`create`, or :func:`ldclient.ContextBuilder.key()`.

        For a multi-context, there is no single value and :attr:`key` returns an empty string. Use
        :func:`get_individual_context()` to get the Context for a particular kind, then get the
        :attr:`key` of that Context.

        :see: :func:`ldclient.ContextBuilder.key()`
        :see: :func:`create()`
        )r1   rf   s    r   r   zContext.keyR  s     zzr   c                    | j                   S )a  
        Returns the context's ``name`` attribute.
        
        For a single context, this value is set by :func:`ldclient.ContextBuilder.name()`. It is
        None if no value was set.

        For a multi-context, there is no single value and :attr:`name` returns None. Use
        :func:`get_individual_context()` to get the Context for a particular kind, then get the
        :attr:`name` of that Context.

        :see: :func:`ldclient.ContextBuilder.name()`
        )r2   rf   s    r   r
   zContext.nameb  s     {{r   c                    | j                   S )a+  
        Returns True if this context is only intended for flag evaluations and will not be
        indexed by LaunchDarkly.

        The default value is False. False means that this Context represents an entity such as a
        user that you want to be able to see on the LaunchDarkly dashboard.

        Setting ``anonymous`` to True excludes this context from the database that is
        used by the dashboard. It does not exclude it from analytics event data, so it is
        not the same as making attributes private; all non-private attributes will still be
        included in events and data export. There is no limitation on what other attributes
        may be included (so, for instance, ``anonymous`` does not mean there is no :attr:`name`),
        and the context will still have whatever :attr:`key` you have given it.

        This value is also addressable in evaluations as the attribute name "anonymous". It
        is always treated as a boolean true or false in evaluations.

        :see: :func:`ldclient.ContextBuilder.anonymous()`
        )r3   rf   s    r   r:   zContext.anonymousr  s    * r   c                    |dk(  r| j                   S |dk(  r| j                  S |dk(  r| j                  S |dk(  r| j                  S | j                  y| j                  j                  |      S )a  
        Looks up the value of any attribute of the context by name.

        For a single-kind context, the attribute name can be any custom attribute that was set
        by :func:`ldclient.ContextBuilder.set()`. It can also be one of the built-in ones
        like "kind", "key", or "name"; in such cases, it is equivalent to :attr:`kind`,
        :attr:`key`, or :attr:`name`.
        
        For a multi-context, the only supported attribute name is "kind". Use
        :func:`get_individual_context()` to get the context for a particular kind and then get
        its attributes.
        
        If the value is found, the return value is the attribute value. If there is no such
        attribute, the return value is None. An attribute that actually exists cannot have a
        value of None.

        Context has a ``__getitem__`` magic method equivalent to ``get``, so ``context['attr']``
        behaves the same as ``context.get('attr')``.
        
        :param attribute: the desired attribute name
        :return: the attribute value, or None if there is no such attribute

        :see: :func:`ldclient.ContextBuilder.set()`
        r   r   r
   r:   N)r1   r/   r2   r3   r4   getr9   	attributes     r   rp   zContext.get  st    2 ::;;;;####$  $$Y//r   c                `    | j                   y| j                  yt        | j                        S )aK  
        Returns the number of context kinds in this context.

        For a valid individual context, this returns 1. For a multi-context, it returns the number
        of context kinds. For an invalid context, it returns zero.

        :return: the number of context kinds

        :see: :func:`get_individual_context()`
        r      )r7   r0   r*   rf   s    r   individual_context_countz Context.individual_context_count  s-     <<#<<4<<  r   c                H   | j                   yt        |t              rD| j                  || j                  k(  r| S dS | j                  D ]  }|j
                  |k(  s|c S  y| j                  	|dk(  r| S dS |dk  s|t        | j                        k\  ry| j                  |   S )a  
        Returns the single-kind Context corresponding to one of the kinds in this context.

        The ``kind`` parameter can be either a number representing a zero-based index, or a string
        representing a context kind.

        If this method is called on a single-kind Context, then the only allowable value for
        ``kind`` is either zero or the same value as the Context's :attr:`kind`, and the return
        value on success is the same Context.

        If the method is called on a multi-context, and ``kind`` is a number, it must be a
        non-negative index that is less than the number of kinds (that is, less than the value
        of :attr:`individual_context_count`), and the return value on success is one of the
        individual Contexts within. Or, if ``kind`` is a string, it must match the context
        kind of one of the individual contexts.
        
        If there is no context corresponding to ``kind``, the method returns None.

        :param kind: the index or string value of a context kind
        :return: the context corresponding to that index or kind, or None

        :see: :attr:`individual_context_count`
        Nr   )r7   rR   rS   r0   r/   r   r*   )r9   r   r'   s      r   get_individual_contextzContext.get_individual_context  s    0 <<#dC ||##t{{2t<<\\ 66T>H <<194.$.!8ts4<<00||D!!r   c                6    | j                   dS | j                   S )a  
        Gets the names of all non-built-in attributes that have been set in this context.

        For a single-kind context, this includes all the names that were passed to
        :func:`ldclient.ContextBuilder.set()` as long as the values were not None (since a
        value of None in LaunchDarkly is equivalent to the attribute not being set).
    
        For a multi-context, there are no such names.

        :return: an iterable
         r4   rf   s    r   custom_attributeszContext.custom_attributes  s      &&.rED4E4EEr   c                    | j                   S r&   rz   rf   s    r   _attributeszContext._attributes  s        r   c                6    | j                   dS | j                   S )a  
        Gets the list of all attribute references marked as private for this specific Context.

        This includes all attribute names/paths that were specified with
        :func:`ldclient.ContextBuilder.private()`.

        :return: an iterable
        ry   r5   rf   s    r   r<   zContext.private_attributes  s     ^^+r??r   c                    | j                   S r&   r   rf   s    r   _private_attributeszContext._private_attributes  s     ~~r   c                    | j                   S )a.  
        A string that describes the Context uniquely based on ``kind`` and ``key`` values.

        This value is used whenever LaunchDarkly needs a string identifier based on all of the
        :attr:`kind` and :attr:`key` values in the context. Applications typically do not need to use it.
        )r6   rf   s    r   fully_qualified_keyzContext.fully_qualified_key  s     r   c                    | j                   si S | j                  5ddi}| j                  D ]   }|j                  d      ||j                  <   " |S | j                  d      S )a  
        Returns a dictionary of properties corresponding to the JSON representation of the
        context (as an associative array), in the standard format used by LaunchDarkly SDKs.
        
        Use this method if you are passing context data to the front end for use with the
        LaunchDarkly JavaScript SDK.

        :return: a dictionary corresponding to the JSON representation
        r   r   FT)rg   r0   _Context__to_dict_singler   )r9   retr'   s      r   to_dictzContext.to_dict  se     zzI<<#7#C\\ 8007AFF8J$$T**r   c                L    t        j                  | j                         d      S )a  
        Returns the JSON representation of the context as a string, in the standard format
        used by LaunchDarkly SDKs.
        
        This is equivalent to calling :func:`to_dict()` and then ``json.dumps()``.

        :return: the JSON representation as a string
        ),r   )
separators)jsondumpsr   rf   s    r   to_json_stringzContext.to_json_string+  s     zz$,,.Z@@r   c                <   d| j                   i}|r| j                  |d<   | j                  | j                  |d<   | j                  rd|d<   | j                  '| j                  j                         D ]
  \  }}|||<    | j                  d| j                  i|d<   |S )Nr   r   r
   Tr:   privateAttributes_meta)r1   r/   r2   r3   r4   rU   r5   )r9   	with_kindr   rZ   r[   s        r   __to_dict_singlezContext.__to_dict_single6  s    djj!++CK;;"++CK#C())//1 1A>>%/@CL
r   c                8   t        d      }||j                  |       |j                         D ]  \  }}|dk(  r|t        |t              st
        j                  |      c S |j                  d      }|It        |t              st
        j                  d      c S |D ]<  }t        |t              st
        j                  d      c c S |j                  |       > |j                  ||      rt
        j                  |      c S  |j                         S )Nr   r   r   )r^   r   rU   rR   rV   r"   rT   rp   listrS   privatetry_setrK   )r9   rX   r   rY   rZ   r[   ppas           r   __from_dict_singlezContext.__from_dict_singleE  s    2FF4LKKM 	FDAqG|9!!T*"BB1EEEE-.=%a.&FFGZ[[ &)"c2#*#J#JK^#__		"&
 yyA"BB1EE!	F" wwyr   c                |   t        j                  dt               t        d      j	                  d      }d}|j                         D ]R  \  }}|dk(  rU|t        |t              st        j                  |      c S |j                         D ]  \  }}|j                  ||        a|dk(  rl|it        |t              st        j                  |      c S |D ]<  }t        |t              st        j                  |      c c S |j                  |       > |t        v r>|t        |t              st        j                  |      c S |j                  ||       |dk(  r|d}|j                  ||      st        j                  |      c S |dk(  sQd	}U |j!                  |       |j#                         S )
Nz+legacy user format will be removed in 9.0.0r   r#   FcustomprivateAttributeNamesr:   r   T)warningswarnDeprecationWarningr^   r   rU   rR   rV   r"   rT   setr   rS   r   _USER_STRING_ATTRSr   _allow_empty_keyrK   )	r9   rX   rY   has_keyrZ   r[   k1v1r   s	            r   __from_dict_old_userzContext.__from_dict_old_user]  s   CEWX2##F+KKM 	#DAqH}9!!T*"BB1EEggi "FBEE"bM"--9!!T*"BB1EE "B%b#.&FFqIIIIbM" ((9!!S)"BB1EEa#	AyyA"BB1EE:"G;	#< 	
7#wwyr   c                H    t        |t              r| j                  |      S d S r&   )rR   rS   rp   rq   s     r   __getitem__zContext.__getitem__  s    &0C&@txx	"JdJr   c                X    | j                   sd| j                  z  S | j                         S )aC  
        Returns a standard string representation of a context.

        For a valid Context, this is currently defined as being the same as the JSON representation,
        since that is the simplest way to represent all of the Context properties. However, application
        code should not rely on ``__repr__`` always being the same as the JSON representation. If you
        specifically want the latter, use :func:`to_json_string()`. For an invalid Context, ``__repr__``
        returns a description of why it is invalid.

        :return: a string representation
        z[invalid context: %s])rg   r7   r   rf   s    r   __repr__zContext.__repr__  s)     zz*T\\99""$$r   c                   t        |t              sy| j                  |j                  k7  s| j                  |j                  k7  s}| j                  |j                  k7  sd| j
                  |j
                  k7  sK| j                  |j                  k7  s2| j                  |j                  k7  s| j                  |j                  k7  ry| j                  y|j                  +t        |j                        t        | j                        k7  ryt        t        | j                              D ]#  }|j                  |   | j                  |   k7  s# y y)z{
        Compares contexts for deep equality of their attributes.

        :return: true if the Contexts are equal
        FT)rR   r"   r/   r1   r2   r3   r4   r5   r7   r0   r*   range)r9   otheris      r   __eq__zContext.__eq__  s     %);;%,,&$***Ct{{V[VbVbGb 1 11T5F5F%J\J\5\NNeoo-1N <<== C$6#dll:K$Ks4<<() 	A}}Q4<<?2	 r   c                &    | j                  |       S r&   )r   )r9   r   s     r   __ne__zContext.__ne__  s    ;;u%%%r   c                    || _         d| _        d| _        d | _        d| _        d | _        d | _        d | _        d| _        y Nr   F)	r7   r/   r1   r2   r3   r4   r5   r0   r6   )r9   r,   s     r   __make_invalidzContext.__make_invalid  sC    
  r   c                (    t        ddd dd d d d|	      S r   rE   )rF   r,   s     r   __create_with_errorzContext.__create_with_error  s    r2tUD$eUKKr   c                2    t         j                  d|z        S )Nzinvalid data type for "%s")r"   rP   )rF   propnames     r   __create_with_schema_type_errorz'Context.__create_with_schema_type_error  s    **+G(+RSSr   )NFNNNFN)r   Optional[str]r   rS   r
   r   r:   boolr;   zOptional[dict]r<   Optional[list[str]]r=   zOptional[list[Context]]r>   r   r,   r   r&   )r   rS   r   r   returnr"   )rL   r"   r   r"   )rX   rV   r   r"   r   rS   r   r^   )r`   r"   r   r^   )r   rI   )r   r   )r   r   )r   rS   )rr   rS   r   r   )r   int)r   zUnion[int, str]r   Optional[Context])r   zIterable[str])r   zOptional[dict[str, Any]])r   r   )r   dict[str, Any])r   r   r   r   )rX   rV   r   r   r   r"   )r   r   )r,   rS   )r,   rS   r   r"   )r   rS   r   r"   )*__name__
__module____qualname____doc__r8   
MULTI_KINDrC   classmethodrG   rN   r\   rM   ra   rc   propertyrg   r,   rj   r   r   r
   r:   rp   ru   rw   r{   r}   r<   r   r   r   r   r   rW   rQ   r   r   r   r   r)   rP   rT   ry   r   r   r"   r"   !   s     L<J? #%)2626 %#LL L 	L
 L #L 0L 0L L L\ H H  > @ @B # #, 
4 
4 % %" $ $8   ( (          ,#0J ! !"%"N F F ! !
 	@ 	@  
  +&	A  . # #JK% .&	 L L T Tr   r"   c                  b    e Zd ZdZdddZddZddZddZddZddZ	dd	Z
dd
ZddZddZy)r^   a8  
    A mutable object that uses the builder pattern to specify properties for :class:`ldclient.Context`.

    Use this type if you need to construct a context that has only a single kind. To define a
    multi-context, use :func:`ldclient.Context.create_multi()` or :func:`ldclient.Context.multi_builder()`.

    Obtain an instance of ContextBuilder by calling :func:`ldclient.Context.builder()`. Then, call
    setter methods such as :func:`name()` or :func:`set()` to specify any additional attributes. Then,
    call :func:`build()` to create the context. ContextBuilder setters return a reference to the same
    builder, so calls can be chained:
    ::

        context = Context.builder('user-key')             .name('my-name')             .set('country', 'us')             .build

    :param key: the context key
    Nc                   || _         |Gt        j                  | _        d | _        d| _        d | _        d | _        d| _        d| _	        d| _        y |j                  | _        |j                  | _        |j                  | _        |j                  | _        |j                  | _        | j                  d u| _        | j                  d u| _	        d| _        y NF)_ContextBuilder__keyr"   r8   _ContextBuilder__kind_ContextBuilder__name_ContextBuilder__anonymous_ContextBuilder__attributes_ContextBuilder__private$_ContextBuilder__copy_on_write_attrs&_ContextBuilder__copy_on_write_privater   r
   r:   r}   r    _ContextBuilder__allow_empty_key)r9   r   	copy_froms      r   rC   zContextBuilder.__init__  s    
!..DKDK$D $D!DN).D&+0D( "' $..DK#..DK(22D ) 5 5D&::DN)-):):$)FD&+/>>+ED(!&r   c           
         | j                   du| _        | j                  du| _        t	        | j
                  | j                  | j                  | j                  | j                   | j                  d| j                        S )a  
        Creates a Context from the current builder properties.

        The Context is immutable and will not be affected by any subsequent actions on the builder.
    
        It is possible to specify invalid attributes for a ContextBuilder, such as an empty key.
        Instead of throwing an exception, the ContextBuilder always returns an Context and you can
        check :attr:`ldclient.Context.valid` or :attr:`ldclient.Context.error` to see if it has
        an error. See :attr:`ldclient.Context.valid` for more information about invalid conditions.
        If you pass an invalid Context to an SDK method, the SDK will detect this and will log a
        description of the error.

        :return: a new :class:`ldclient.Context`
        N)
r   r   r   r   r"   r   r   r   r   r   rf   s    r   rK   zContextBuilder.build  sk     '+&7&7t&C"(,d(B$t{{DJJT=M=MtO`O`bfbpbp$((* 	*r   c                    || _         | S )an  
        Sets the context's key attribute.
        
        Every context has a key, which is always a string. It cannot be an empty string, but
        there are no other restrictions on its value.

        The key attribute can be referenced by flag rules, flag target lists, and segments.

        :param key: the context key
        :return: the builder
        )r   )r9   r   s     r   r   zContextBuilder.key   s     
r   c                    || _         | S )aw  
        Sets the context's kind attribute.

        Every context has a kind. Setting it to an empty string or None is equivalent to
        :const:`ldclient.Context.DEFAULT_KIND` ("user"). This value is case-sensitive.

        The meaning of the context kind is completely up to the application. Validation rules are
        as follows:
    
        * It may only contain letters, numbers, and the characters ``.``, ``_``, and ``-``.
        * It cannot equal the literal string "kind".
        * For a single context, it cannot equal "multi".
        
        :param kind: the context kind
        :return: the builder
        )r   )r9   r   s     r   r   zContextBuilder.kind  s    " r   c                    || _         | S )a  
        Sets the context's name attribute.

        This attribute is optional. It has the following special rules:

        * Unlike most other attributes, it is always a string if it is specified.
        * The LaunchDarkly dashboard treats this attribute as the preferred display name for
          contexts.
        
        :param name: the context name (None to unset the attribute)
        :return: the builder
        )r   )r9   r
   s     r   r
   zContextBuilder.name#  s     r   c                    || _         | S )a  
        Sets whether the context is only intended for flag evaluations and should not be
        indexed by LaunchDarkly.

        The default value is False. False means that this Context represents an entity
        such as a user that you want to be able to see on the LaunchDarkly dashboard.

        Setting ``anonymous`` to True excludes this context from the database that is
        used by the dashboard. It does not exclude it from analytics event data, so it is
        not the same as making attributes private; all non-private attributes will still be
        included in events and data export. There is no limitation on what other attributes
        may be included (so, for instance, ``anonymous`` does not mean there is no ``name``),
        and the context will still have whatever ``key`` you have given it.

        This value is also addressable in evaluations as the attribute name "anonymous". It
        is always treated as a boolean true or false in evaluations.

        :param anonymous: true if the context should be excluded from the LaunchDarkly database
        :return: the builder

        :see: :attr:`ldclient.Context.anonymous`
        )r   )r9   r:   s     r   r:   zContextBuilder.anonymous3  s    . %r   c                *    | j                  ||       | S )a  
        Sets the value of any attribute for the context.

        This includes only attributes that are addressable in evaluations-- not metadata such
        as :func:`private()`. If ``attributeName`` is ``"private"``, you will be setting an attribute
        with that name which you can use in evaluations or to record data for your own purposes,
        but it will be unrelated to :func:`private()`.
        
        The allowable types for context attributes are equivalent to JSON types: boolean, number,
        string, array (list), or object (dictionary). For all attribute names that do not have
        special meaning to LaunchDarkly, you may use any of those types. Values of different JSON
        types are always treated as different values: for instance, the number 1 is not the same
        as the string "1".

        The following attribute names have special restrictions on their value types, and
        any value of an unsupported type will be ignored (leaving the attribute unchanged):

        * ``"kind"``, ``"key"``: Must be a string. See :func:`kind()` and :func:`key()`.
        * ``"name"``: Must be a string or None. See :func:`name()`.
        * ``"anonymous"``: Must be a boolean. See :func:`anonymous()`.
        
        The attribute name ``"_meta"`` is not allowed, because it has special meaning in the
        JSON schema for contexts; any attempt to set an attribute with this name has no
        effect.

        Values that are JSON arrays or objects have special behavior when referenced in
        flag/segment rules.

        A value of None is equivalent to removing any current non-default value of the
        attribute. Null/None is not a valid attribute value in the LaunchDarkly model; any
        expressions in feature flags that reference an attribute with a null value will
        behave as if the attribute did not exist.

        :param attribute: the attribute name to set
        :param value: the value to set
        :return: the builder
        )r   r9   rr   values      r   r   zContextBuilder.setM  s    L 	Y&r   c                   |dk(  s|dk(  ry|dk(  rt        |t              r|| _        yy|dk(  rt        |t              r|| _        yy|dk(  r|t        |t              r|| _        yy|d	k(  rt        |t
              r|| _        yy| j                  r4d| _        | j                  xr | j                  j                         | _        | j                  i | _        || j                  j                  |d       y|| j                  |<   y)
af  
        Same as :func:`set()`, but returns a boolean indicating whether the attribute was
        successfully set.

        :param attribute: the attribute name to set
        :param value: the value to set
        :return: True if successful; False if the name was invalid or the value was not an
          allowed type for that attribute        
        r   r   Fr   Tr   r
   Nr:   )rR   rS   r   r   r   r   r   r   r   copypopr   s      r   r   zContextBuilder.try_setv  s    ?i72%%"
%%#}
5# 6##%&#( %%).D& $ 1 1 Nd6G6G6L6L6ND$ "D=!!)T2  ,1Di(r   c                    t        |      dk7  rn| j                  r4d| _        | j                  xr | j                  j                         | _        | j                  g | _        | j                  j	                  |       | S )a  
        Designates any number of Context attributes, or properties within them, as private: that is,
        their values will not be sent to LaunchDarkly.

        Each parameter can be either a simple attribute name, or a slash-delimited path referring to
        a JSON object property within an attribute.

        :param attributes: attribute names or references to mark as private
        :return: the builder
        r   F)r*   r   r   r   extend)r9   r;   s     r   r   zContextBuilder.private  sf     z?a++/4,!%!IDNN4G4G4I~~%!#NN!!*-r   c                    || _         y r&   )r   )r9   allows     r   r   zContextBuilder._allow_empty_key  s     "'r   r&   )r   rS   r   r   r   r"   r   )r   rS   r   r^   )r
   r   r   r^   )r:   r   r   r^   )rr   rS   r   r   r   r^   )rr   rS   r   r   r   r   )r;   rS   r   r^   )r   r   )r   r   r   r   rC   rK   r   r   r
   r:   r   r   r   r   ry   r   r   r^   r^     s;    &'(*(( 4'R)V('r   r^   c                  &    e Zd ZdZd ZddZddZy)rI   a+  
    A mutable object that uses the builder pattern to specify properties for a multi-context.

    Use this builder if you need to construct a :class:`ldclient.Context` that contains multiple contexts,
    each for a different context kind. To define a regular context for a single kind, use
    :func:`ldclient.Context.create()` or :func:`ldclient.Context.builder()`.
    
    Obtain an instance of ContextMultiBuilder by calling :func:`ldclient.Context.multi_builder()`;
    then, call :func:`add()` to specify the individual context for each kind. The method returns a
    reference to the same builder, so calls can be chained:
    ::

        context = Context.multi_builder()             .add(Context.new("my-user-key"))             .add(Context.new("my-org-key", "organization"))             .build
    c                     g | _         d| _        y r   )_ContextMultiBuilder__contexts#_ContextMultiBuilder__copy_on_writerf   s    r   rC   zContextMultiBuilder.__init__  s    $r   c           	         t        | j                        dk(  r| j                  d   S d| _        t        dddddd| j                        S )aZ  
        Creates a Context from the current builder properties.

        The Context is immutable and will not be affected by any subsequent actions on the builder.
        
        It is possible for a ContextMultiBuilder to represent an invalid state. Instead of throwing
        an exception, the ContextMultiBuilder always returns a Context, and you can check
        :attr:`ldclient.Context.valid` or :attr:`ldclient.Context.error` to see if it has an
        error. See :attr:`ldclient.Context.valid` for more information about invalid context
        conditions. If you pass an invalid context to an SDK method, the SDK will detect this and
        will log a description of the error.

        If only one context was added to the builder, this method returns that context rather
        than a multi-context.

        :return: a new Context
        rt   r   TNr   F)r*   r   r   r"   rf   s    r   rK   zContextMultiBuilder.build  sG    $ t1$??1%%#tRudD$//JJr   c                :   |j                   rAt        |j                        D ]'  }|j                  |      }|| j	                  |       ) | S | j
                  r&d| _        | j                  j                         | _        | j                  j                  |       | S )a  
        Adds an individual Context for a specific kind to the builer.

        It is invalid to add more than one Context for the same kind, or to add an LContext
        that is itself invalid. This error is detected when you call :func:`build()`.

        If the nested context is a multi-context, this is exactly equivalent to adding each of the
        individual contexts from it separately. For instance, in the following example, ``multi1`` and
        ``multi2`` end up being exactly the same:
        ::

            c1 = Context.new("key1", "kind1")
            c2 = Context.new("key2", "kind2")
            c3 = Context.new("key3", "kind3")

            multi1 = Context.multi_builder().add(c1).add(c2).add(c3).build()

            c1plus2 = Context.multi_builder.add(c1).add(c2).build()
            multi2 = Context.multi_builder().add(c1plus2).add(c3).build()
        
        :param context: the context to add
        :return: the builder
        F)	rj   r   ru   rw   rJ   r   r   r   r-   )r9   r`   r   r'   s       r   rJ   zContextMultiBuilder.add  s    0 7;;<  2215=HHQK  	 ##',$"&//"6"6"8OO""7+r   Nr   )r`   r"   r   rI   )r   r   r   r   rC   rK   rJ   ry   r   r   rI   rI     s    "%K0"r   rI   )r"   r^   rI   )r   rS   r   rS   )r   rS   r   r   )r   
__future__r   collections.abcr   r   rer   typingr   r   r   r   compiler   r   r   r    r"   r^   rI   __all__ry   r   r   <module>r      su    # $  	  - - !bjj!23 Z 7
	`
T `
TFt' t'nP Pf ?r   