
    5i'                     \    d dl mZ d dlZddlmZ ddlmZmZmZ ddl	m
Z
 	  G d de      Zy)	    )defaultdictN   )merge)err_exitDXError
DXCLIError)
basestringc                   j    e Zd ZdZd Zedd       Zedd       Zedd       Zd Z	d Z
d Zd	 Zd
 Zy)SystemRequirementsDictz
    A class representing system requirements that can be passed as
    "systemRequirements" or an entry of the "systemRequirementsByExecutable"
    to the class-xxxx/run or job/new API call (after converting
    it to a dictionary with as_dict()).
    c                 r    |t        |t              st        d      t        j                  |      | _        y)aS  
        Example of the entrypoints input:
        {"main":
            {"instanceType": "mem2_hdd2_x2"},
         "other_function":
            {"instanceType": "mem2_hdd2_x1",
             "clusterSpec": {"type": "spark",
                             "version": "2.4.0",
                             "initialInstanceCount": 2}}}
        Nz)Expected entrypoints to be a dict or None)
isinstancedictr   copydeepcopyentrypoints)selfr   s     z/home/marpiech/ifpan-abm-pgxpred/analysis/marpiech-gwas-test/venv/lib/python3.12/site-packages/dxpy/system_requirements.py__init__zSystemRequirementsDict.__init__   s0     ":k4+HEFF==5    c                 `   	 | | d      S t        |t              st        |t              r | |ddt        |      iii      S t        |t              r7 | |j	                         D ci c]  \  }}|ddt        |      ii c}}      S t
        c c}}w # t
        $ r t        d       Y yw xY w)ab  
        Returns a SystemRequirementsDict that can be passed as a
        "systemRequirements" input or an entry of the "systemRequirementsByExecutable" mapping
        to job/new or run/ API calls.
        The instance_count_arg should be either a:
        * string or int eg. "6" or 8
        * dictionary, eg. {"main": 4, "other_function": 2}
        NclusterSpecinitialInstanceCountzCExpected instance_count field to be either an int, string or a dict)r   r	   intr   items
ValueErrorr   )clsinstance_count_arg
entrypointkvs        r   from_instance_countz*SystemRequirementsDict.from_instance_count(   s    		[!)4y ,j9ZHZ\_=`J9OQTUgQh8i(jkll,d3]o]u]u]wxUYUVXYA0FA/OPPxyy y 	[YZ	[s.   	B 6B %B (B
B 
B B-,B-c           	          | | d      S t        |t              r | |d|ii      S t        |t              r, | |j                         D ci c]
  \  }}|d|i c}}      S t	        d      c c}}w )aw  
        Returns SystemRequirementsDict that can be passed as a
        "systemRequirements" input or an entry of the "systemRequirementsByExecutable" mapping
        to job/new or run/ API calls.
        The instance_type_arg should be either a:
        * string, eg. mem1_ssd1_x2
        * dictionary, eg. {"main": "mem2_hdd2_x2", "other_function": "mem2_hdd2_x1"}
        NinstanceTypez<Expected instance_type field to be either a string or a dict)r   r	   r   r   r   )r   instance_type_argr   fnfn_insts        r   from_instance_typez)SystemRequirementsDict.from_instance_type=   s     $t9'4
^5F$GHII'.IZI`I`Ibc+"g^W55cddTUU ds   A.
c                     g d}||vrt        dj                  |            |dk(  r | |      S t        t              }|j	                         D ]  \  }}||v s||   ||   |<     | t        |            S )z
        Returns SystemRequirementsDict encapsulating system requirements.
        It can extract only entrypoints with specific fields ('clusterSpec',
        'instanceType', 'instanceTypeSelector', etc), depending on the value of _type.
        )allr   r#   instanceTypeSelector
fpgaDrivernvidiaDriverz/Expected '_type' to be one of the following: {}r)   )r   formatr   r   r   )r   system_requirements_typeallowed_types	extractedr   reqs          r   from_sys_requirementsz,SystemRequirementsDict.from_sys_requirementsQ   s     u'KRRS`abbE>*++%	288: 	:OJ|/25z	*%e,	: 4	?##r   c           	      d   t        j                  | j                        }t        |j	                         D cg c]  \  }}|j                  d      ||f c}}      }t        |j	                         D cg c]%  \  }}||j                  v sd|j                  v r||f' c}}      }|j	                         D ]R  \  }}||   d   j                  |j                  j                  ||j                  j                  d            d          T |j                  j	                         D ]o  \  }}||vsd| j                  v sd| j                  d   v s,dt        j                  | j                  d   d         i||<   ||   d   j                  |d          q t        |      S c c}}w c c}}w )a  
        Returns SystemRequirementsDict can be passed in a "systemRequirements"
        input or as an entry of the "systemRequirementsByExecutable" mapping
        to app-xxx/run, e.g. {'fn': {'clusterSpec': {initialInstanceCount: 3, version: "2.4.0", ..}}}
        Since full clusterSpec must be passed to the API server, we need to retrieve the cluster
        spec defined in app doc's systemRequirements and overwrite the field initialInstanceCount
        with the value the user passed to dx run for each entrypoint.
        initialInstanceCount is currently the only clusterSpec's field the user is allowed to change
        at runtime.
        A few scenarios when requesting instance count for different entrypoints with dx run 
        and the resulting merged systemRequirements (merged_cluster_spec). The bootstapScript
        field here is only one of many (version, ports, etc) that should be copied from app
        spec to merged_cluster_spec:

        Requested: {"*": 5}
        App doc: {"main": "clusterSpec": {"initialInstanceCount": 7, bootstrapScript: "x.sh"},
                "other": "clusterSpec": {"initialInstanceCount": 9, bootstrapScript: "y.sh"}}
        Merged: {"main": "clusterSpec": {"initialInstanceCount": 5, bootstrapScript: "x.sh"},
                "other": "clusterSpec": {"initialInstanceCount": 5, bootstrapScript: "y.sh"}}
        
        Requested: {"*": 15}
        App doc: {"main": "clusterSpec": {"initialInstanceCount": 7, bootstrapScript: "x.sh"},
                  "other": "clusterSpec": {"initialInstanceCount": 9, bootstrapScript: "y.sh"},
                  "*": "clusterSpec": {"initialInstanceCount": 11, bootstrapScript: "y.sh"}}
        Merged: {"main": "clusterSpec": {"initialInstanceCount": 15, bootstrapScript: "x.sh"},
                 "other": "clusterSpec": {"initialInstanceCount": 15, bootstrapScript: "y.sh"},
                 "*": "clusterSpec": {"initialInstanceCount": 15, bootstrapScript: "y.sh"}}

        Requested: {"main": 12}
        App doc: {"main": "clusterSpec": {"initialInstanceCount": 7, bootstrapScript: "x.sh"},
                  "other": "clusterSpec": {"initialInstanceCount": 9, bootstrapScript: "y.sh"}}
        Merged: {"main": "clusterSpec": {"initialInstanceCount": 12, bootstrapScript: "x.sh"}}

        Requested: {"main": 33}
        App doc: {"*": "clusterSpec": {"initialInstanceCount": 2, bootstrapScript: "z.sh"}}
        Merged: {"main": "clusterSpec": {"initialInstanceCount": 33, bootstrapScript: "z.sh"}}

        Requested: {"main": 22, "*": 11}
        App doc: {"*": "clusterSpec": {"initialInstanceCount": 2, bootstrapScript: "t.sh"}}
        Merged: {"main": "clusterSpec": {"initialInstanceCount": 22, bootstrapScript: "t.sh"},
                 "*": "clusterSpec": {"initialInstanceCount": 11, bootstrapScript: "t.sh"}}
        r   *)r   r   r   r   r   getupdater   )r   srdmerged_cluster_specr   r    entry_ptr2   s          r   override_cluster_specz,SystemRequirementsDict.override_cluster_spece   s   X #mmD,<,<= #7J7P7P7R#wtq!VWV[V[\iVjVvQF#wx #7J7P7P7R $<tq! C3??$: &'F $< =
 1668 	XMHc)-8??##Hcoo.A.A#.FGVX	X !__224 	XMHc22sd>N>N7NS`dhdtdtuxdySy1>dN^N^_bNcdqNr@s0t#H-#H-m<CCCDVW	X
 &&9::) $x$<s   F&
F&
8*F,
c                    d|j                         v r|S | j                  j                         |j                  j                         z  }t        j	                  |      }|D ]w  }|j                  j                  |      xsU |j                  j                  d      xs8 | j                  j                  |      xs | j                  j                  d      ||<   y t        |      S )Nr5   )as_dictr   keysr   fromkeysr6   r   )r   requested_specr   merged_speces        r   override_specz$SystemRequirementsDict.override_spec   s    .((**!!&&++-0J0J0O0O0QQmmK0 	^A+77;;A>  ^.B\B\B`B`adBe  ^imiyiyi}i}~  jA  ^  EI  EU  EU  EY  EY  Z]  E^KN	^%k22r   c           	         ||y|xs i }|xs i }i }t        t        |j                               t        |j                               z         D ]1  }t        |j	                  |i       fi |j	                  |i       ||<   3 |S )a=  
        Merges the values of two dictionaries, which are expected to be dictionaries, e.g
        d1 = {'a': {'x': pqr}}
        d2 = {'a': {'y': lmn}, 'b': {'y': rst}}
        will return: {'a': {'x': pqr, 'y': lmn}, 'b': {'y': rst}}.
        Collisions of the keys of the sub-dictionaries are not checked.
        N)setlistr>   r   r6   )r   d1d2addedkeys        r   _add_dict_valuesz'SystemRequirementsDict._add_dict_values   s     :"*X2X2tBGGIbggi89 	DCbffS"oC"&&b/CE#J	Dr   c                     t        |t              st        d      | j                  | j                  |j                        }t        |      S )Nz0Developer error: SystemRequirementsDict expected)r   r   r   rK   r   )r   otheradded_entrypointss      r   __add__zSystemRequirementsDict.__add__   sD    %!78LMM 11$2B2BEDUDUV%&788r   c                     | j                   S )N)r   )r   s    r   r=   zSystemRequirementsDict.as_dict   s    r   N)r5   )r)   )__name__
__module____qualname____doc__r   classmethodr!   r'   r3   r;   rC   rK   rO   r=    r   r   r   r      sg    6 [ [( V V& $ $&C;J3(9 r   r   )collectionsr   r   utilsr   
exceptionsr   r   r   compatr	   objectr   rV   r   r   <module>r\      s*    #   7 7 ~ V ~ r   