
    5i&                     &    d dl mZ  G d de      Zy)    )print_functionc                   Z    e Zd ZdZefdZd Zd Zd Zd Z	d Z
d Z	 dd	Zd
 Z	 	 ddZy)JSONValidatora
  
    JSON validator class to validate a JSON against a schema.

    The schema is a dictionary with the following structure:

    {
        "key1": {
            "type": dict,
            "properties": {
                "name": {"type": str, "required": True},
                "attribute": {"type": str}
            }
        },
        "key2": {
            "type": dict,
            "properties": {
                "xyz": {"type": str},
                "abc": {"type": list}
            },
            "conflicting_keys": [["xyz", "abc"]]
        },
        "list_key_example": {
            "type": list,
            "items": {
                "type": dict,
                "properties": {
                    "nested_key1": {"type": str, "required": True},
                    "nested_key2": {"type": str}
                }
            }
        },
        "id": {
            "type": list,
        },
        "conflicting_keys": [["key1", "key2"]],
        "dependent_conditional_keys": {
            "list_key_example": ["key1", "key2"]
        }
    }

    Key types can be defined via the "type" key

    Required keys can be defined via the "required" key

    Conflicting keys can be defined via the "conflicting_keys" key, where the value is a list of lists of keys that are mutually exclusive.
    Conflicting keys can be defined at the level of the schema for the entire JSON or at key-level.
    In the example above, within "key2" the keys "xyz" and "abc" are mutually exclusive and cannot be present together.
    Similarly, at the level of the whole JSON, "key1" and "key2" are mutually exclusive and cannot be present together.

    Conditional key combinations can be defined via the dependent_conditional_keys at the level of the schema. These should be defined as a dict where the value is a list.
    In the example above, dependent_conditional_keys is defined as {"list_key_example": ["key1", "key2"]}, which means whenever list_key_example is present, either "key1"
    or "key2" has to be also present.

    Currently the maximum level of nestedness supported for validation is as deep as shown in the example above via the "list_key_example" key.

    This is an example of a valid JSON that satisfies all the conditions defined in the schema above:

    {
        "key1": {
            "name": "test",
        },
        "list_key_example": [
            {"nested_key1": "1", "nested_key2": "2"},
            {"nested_key1": "3", "nested_key2": "4"},
            {"nested_key1": "5"}
        ],
        "id": ["id_1", "id_2"]
    }

    c                 V    || _         || _        t        |t              r|s	 |d       y y )Nz Schema must be a non-empty dict.)schemaerror_handler
isinstancedict)selfr   r   s      /home/marpiech/ifpan-abm-pgxpred/analysis/marpiech-gwas-test/venv/lib/python3.12/site-packages/dxpy/bindings/apollo/json_validation_by_schema.py__init__zJSONValidator.__init__L   s+    *&$'v<= 06    c                 X   t        |t              r|s| j                  d       | j                  |       | j	                  |       | j
                  j                         D ]  \  }}||v s| j                  |j                  di       ||          |j                  d      t        k(  r&| j                  |j                  di       ||   |       |j                  d      s| j                  ||       | j                  ||   |        | j                  |       | j                  |       y )Nz$Input JSON must be a non-empty dict.
propertiestypeitemsconflicting_keys)r	   r
   r   error_on_invalid_keysvalidate_typesr   r   validate_propertiesgetlistvalidate_list_itemscheck_incompatible_subkeyscheck_incompatible_keys check_dependent_key_combinations)r   
input_jsonkeyvalues       r   validatezJSONValidator.validateS   s	   *d+:EF"":.J'++++- 	JJCj ((<)DjQToV99V$,,,		'2.
3
 99/033JD33JsOSI	J 	$$Z0--j9r   c           
      H   |j                         D ]  \  }}t        || j                  j                  |i       j                  d            r<| j	                  dj                  || j                  j                  |i       j                  d      t        |                    y )Nr   4Key '{}' has an invalid type. Expected {} but got {})r   r	   r   r   r   formatr   )r   
input_dictr   r   s       r   r   zJSONValidator.validate_typesm   s    $**, 	JCeT[[__S"%=%A%A&%IJ""JQQT[[__S"599&A4;	r   c                 `   |j                         D ]  \  }}||vr1|j                  d      r | j                  dj                  |             ||v s@t	        ||   |j                  d            r_| j                  dj                  ||j                  d      t        ||                       y )Nrequiredz2Required key '{}' was not found in the input JSON.r   r"   )r   r   r   r#   r	   r   )r   r   r$   r   r   s        r   r   z!JSONValidator.validate_propertiesv   s    $**, 
	JC*$:)>""HOOPST j JsOUYYvEV)W""JQQUYYv.Z_0E
	r   c           
         |j                  d      }|ra|D ][  }t        ||      s+| j                  dj                  ||t	        |                   | j                  |j                  di       |       ] y t        |t              s*| j                  dj                  t	        |      |             |D ]3  }t        |t              r| j                  dj                  |             5 y )Nr   zDExpected list items within '{}' to be of type {} but got {} instead.r   zExpected list but got {} for {}z0Expected list items to be of type string for {}.)r   r	   r   r#   r   r   r   str)r   item_schema
input_listkey_name	item_typeitems         r   r   z!JSONValidator.validate_list_items   s    OOF+	" R!$	2&&^ee$id
 ((r)JDQR j$/""5<<T*=MxX # !$,&&JQQ$r   c           	          | j                   j                  |i       j                  dg       D ]G  }t        fd|D              s| j                  dj	                  |dj                  |                   I y )Nr   c              3   &   K   | ]  }|v  
 y wN ).0kr   s     r   	<genexpr>z;JSONValidator.check_incompatible_subkeys.<locals>.<genexpr>   s     1q1
?1   zGFor {}, exactly one of {} must be provided in the supplied JSON object. or r   r   allr   r#   join)r   r   current_keykeyss    `  r   r   z(JSONValidator.check_incompatible_subkeys   sg    KKOOK4889KRP 	D1D11""]dd#V[[%6	r   c                     | j                   j                  dg       D ]F  }t        fd|D              s| j                  dj	                  dj                  |                   H y )Nr   c              3   &   K   | ]  }|v  
 y wr0   r1   )r2   r   r   s     r   r4   z8JSONValidator.check_incompatible_keys.<locals>.<genexpr>   s     53*$5r5   z?Exactly one of {} must be provided in the supplied JSON object.r6   r7   )r   r   r;   s    ` r   r   z%JSONValidator.check_incompatible_keys   sX    KKOO$6; 	D555""U\\D)	r   c           	         | j                   j                  di       }|j                         D ]  \  }}||v s|D cg c]	  }||v s| }}t        |      dk(  r0| j	                  dj                  |dj                  |                   t        |      dkD  sl|so| j	                  dj                  dj                  |                    y c c}w )Ndependent_conditional_keysr   zGWhen {} is present, one of the following keys must be also present: {}.z,    zAOnly one of the associated keys {} can be present for main key {})r   r   r   lenr   r#   r9   )r   r   enforce_one_associated_keymandatory_combinationsmain_keyassociated_keysr   present_associated_keyss           r   r   z.JSONValidator.check_dependent_key_combinations   s     "&1Mr!R)?)E)E)G 	%Ho:%#2+cZ6GC+' + ./14&&ahh$dii&@
 ./!38R&&[bb IIo6	+s   	CCc                     g }|D ]"  }|| j                   vs|j                  |       $ |r!| j                  dj                  |             y y )Nz#Found following invalid filters: {})r   appendr   r#   )r   r   invalid_keysr   s       r   r   z#JSONValidator.error_on_invalid_keys   sV     	)C$++%##C(	) 5<<\J r   c           	         ||   D ]u  }t        ||         t        ||         k  r!| j                  dj                  ||             |sD||   ||   z
  |kD  sS| j                  dj                  ||||             w |sy||   D cg c]  }t        ||          }}||   D cg c]  }t        ||          }	}t        |	      t	        |      z
  |kD  r"| j                  dj                  ||             yyyc c}w c c}w )z
        This won't run by default when calling .validate() on a JSONValidator object. Run it separately when necessary
        z){} cannot be less than or equal to the {}z@Range of {} and {} cannot be greater than {} for each item in {}z&Range cannot be greater than {} for {}N)intr   r#   maxmin)
r   r   r   start_subkey
end_subkeywindow_widthcheck_each_separatelyr-   start_values
end_valuess
             r   are_list_items_within_rangez)JSONValidator.are_list_items_within_range   s)    sO 	D4
#$D,>(??""?FF"L %
#d<&88<G&&Zaa(*lC	 % AK3PC\ 23PLP<FsOLD#d:./LJL:\!22\A""<CCLRUV B % QLs   C:%C?N)F)iF)__name__
__module____qualname____doc__printr   r    r   r   r   r   r   r   r   rT   r1   r   r   r   r      sM    EN .3 >:40 6;,	" #%r   r   N)
__future__r   objectr   r1   r   r   <module>r\      s    %oF or   