ó i'dWc@sÝdZddlmZddlZddlmZmZmZddl Z ddl m Z ddl m Z mZmZmZmZmZmZddlmZmZmZddlmZd „Zd efd „ƒYZdS( s9 Python package with ctypes wrapper for libnvpair(3LIB). An nvlist_t is often returned from other C libraries. This package, and classes nvlistp and NVList in particular, provide access to nvlist_t. An NVList behaves according to its flags (which are set at creation time and can not be altered). In general keys for all the flavours of NVList are a tuple of (name, datatype) where name is a str and datatype is taken from libnvpair.const.DATA_TYPE_MAP.keys(), e.g. "INT64". When retrieving or deleting values, often the name is sufficient and the key is not required to be a tuple. But Python can't infer when setting values, so full keys are required. In general it is best to use full keys. Behaviour differences: flags == 0: This is the least dictionary like NVList. Duplicate keys are allowed. nvl[(name, datatype)] = value # adds *without* replacement. del nvl[name] # deletes all keys/value pairs ignoring datatype del nvl[(name, datatype)] # Deletes all key/value pairs where # the key matches both name and datatype. x = nvl[name] # Return all values whose key matched name, ignoring # the datatype. If more than one value, a tuple of # values is returned. x = nvl[(name, datatype)] # Return all values that have a key # matching both name and datatype. # If more than one value, a tuple of # values is returned. flags == libnvpair.const.NV_UNIQUE_NAME: This is closer to a python dictionary. Duplicate keys are not allowed, but neither are keys with the same name. So if the key ("name", "UINT16") is part of this NVList, adding ("name", "STRING") destroys the previous value. Even though those are different keys for a python dictionary. nvl[(name, datatype)] = value # Replaces any previous # nvl[(name, *)]. del nvl[name] # Deletes the only value that can have this name. del nvl[(name, datatype)] # Deletes the only value that has this # key. x = nvl[name] # Retrieve any key matching (name, *). x = nvl[(name, datatype)] # Name and datatype must match. # If you search for ("name", "INT8") # you will not get back ("name", "INT16"). flags == libnvpair.const.NV_UNIQUE_NAME_TYPE: This is nearly identical to a python dictionary whose keys are always (name, datatype). It deviates with `del` and getitem, which allow referencing items by just name. nvl[(name, datatype)] = value # Replaces any previous # nvl[(name, datatype)]. del nvl[name] # Deletes all keys/value pairs ignoring datatype. del nvl[(name, datatype)] # deletes the only value that has this # key x = nvl[name] # Retrieve all values for keys matching (name, *). # If more than one value, a tuple of values is # returned. x = nvl[(name, datatype)] # Retrieves only possible value. Regardless of flags accessing a key, via del or get that doesn't exist at all raises a KeyError. If you are implementing another C library which returns a pointer to an nvlist_t, you will need to import just nvlistp and NVList: from libnvpair.cstruct import nvlistp from libnvpair import NVList You then need to make the restype of the C function an nvlistp and wrap that function to turn its result into an NVList: _foo = _SOMELIB.foo _foo.argtypes = (arg0, arg1, ... argN) _foo.restype = nvlistp def foo(arg0, arg1, ... argN): nvl = _foo(arg0, arg1, ... argN) # error check return NVList(nvl) An NVList sets _as_parameter_ to the hidden nvlistp so it is safe to use it in a function that requires an nvlistp. Some libraries, e.g. libzfs return a cached NVList that you must not delete. In that case you would change foo above to do this. def foo(arg0, arg1, ... argN): nvl = _foo(arg0, arg1, ... argN) # error check return NVList(nvl, False) # Python won't free this ever. iÿÿÿÿ(tMutableMappingN(tENOMEMtEINVALtENOENT(tnvlistp(tNV_UNIQUE_NAMEtNV_UNIQUE_NAME_TYPEtNV_ENCODE_NATIVEt NV_ENCODE_XDRt DATA_TYPE_MAPtDATA_TYPE_NVLISTtDATA_TYPE_NVLIST_ARRAY(tcfunctstatetutil(tNVPairIteratorcCsOtj|ƒ}ttB}itjd6tjt6tjt6tj|6||ƒS(s)_alocate_state(nvlistp) -> .private.Statei(R t nvlist_nvflagRRR t NVLIteratort NVLDictionarytNVLTupleDictionary(tnvlptflagstbuggy((s../__init__.pyt_allocate_state£s     tNVListcBs"eZdZded„Zed„ƒZed„ƒZed„ƒZ e j d„ƒZ ed„ƒZ e d„ƒZ d„Zd „Zd „Zd „Zd „Zd „Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zdd„Zd„Zd„Zdd„Zd„ZRS(s8An NVList is a MutableMapping using a C nvlist_t pointercCsø|r0t|tƒrÜ|tkrÜd|_qÜn¬|dttfkrTtdƒ‚ntƒ}tj t j |ƒ|dƒ}|dkrÜ|t kr¢t dƒ‚n|tkr½tdƒ‚nt|dtj|ƒƒ‚nt|ƒ|_t|_dS(Nsdon't track thisis9flags must be in (0, NV_UNIQUE_NAME, NV_UNIQUE_NAME_TYPE)s nvlist_alloc(): invalid arguments#nvlist_alloc(): insufficient memorysnvlist_alloc(): %s(t isinstancetbooltFalset_refRRt ValueErrorRR t nvlist_alloctCtbyrefRt TypeErrorRt MemoryErrortOSErrortoststrerrorRt_statetTruet_native(tselfRRterr((s../__init__.pyt__init__·s      cCs|jS(N(R&(R)((s../__init__.pyR ÍscCs |jjS(N(R R(R)((s../__init__.pyRÑscCs|jS(ss determines encoding used to pickle. True uses NV_ENCODE_NATIVE, False uses NV_ENCODE_XDR. (R((R)((s../__init__.pytnativeÕscCs+t|tƒstdƒ‚n||_dS(Nsnative must be a bool(RRR!R((R)tval((s../__init__.pyR,ÝscCs |jjS(N(R t_as_parameter_(R)((s../__init__.pyR.ãscCsI|tkrt|ƒS|tkrEtg|D]}t|ƒ^q,ƒS|S(s?patch nvlistp and (nvlistp, ...) to be NVList and (NVList, ...)(R RR ttuple(tdatatypetvaluetelem((s../__init__.pytfixitemçs    #cCséitt6tt6|j}tjƒ}tj|tj |ƒ|ƒ}tj |j ƒ}tj |tj tj |tjtjƒƒƒtj |ƒ|dƒ}|dkrâ|tkrÃtdƒ‚qât|dtj|ƒƒ‚n|jS(Nis"nvlist_pack(): insufficient memorysnvlist_pack(): %s(RR'RRR,Rtc_size_tR t nvlist_sizeR tcreate_string_bufferR1t nvlist_packtcasttPOINTERtc_charRR"R#R$R%traw(R)tencodingtbufszR*tdata((s../__init__.pyt __getstate__õs  $  cCs‰tƒ}tj|t|ƒtj|ƒdƒ}|dkrv|tkrWtdƒ‚qvt|dt j |ƒƒ‚nt |ƒ|_ dS(Nis$nvlist_unpack(): insufficient memorysnvlist_unpack(): %s( RR t nvlist_unpacktlenRR RR"R#R$R%RR&(R)R>RR*((s../__init__.pyt __setstate__s '  cCs)tj|ƒdkrdSt|jƒƒS(Nii(R t nvlist_emptyRAtvalues(R)((s../__init__.pyt__len__scCs)dtfd„ƒY}||jdtƒS(sx.__iter__() <==> iter(x)tNVKeysIteratorcBseZdZd„ZRS(s5class to manage iterating over the keys in an NVList.cSstj|ƒ}|j|jfS(s2x.next() -> the next value, or raise StopIteration(t_NVPairIteratortnexttnameR0(R)tpair((s../__init__.pyRHs(t__name__t __module__t__doc__RH(((s../__init__.pyRFstforward(RGR R'(R)RF((s../__init__.pyt__iter__scCskt|tƒr%tj||ƒdkStj|ƒ\}}x*t|ƒD]}|||fkrGtSqGWtS(Ni( RtstrR t nvlist_existsRtnormalize_tuple_keytiterR'R(R)tkeyRIR0((s../__init__.pyt __contains__$scCsa|jj|ƒ}g|D]\}}|j||ƒ^q}t|ƒdkrW|dSt|ƒS(sx.__getitem__(y) <==> x[y]ii(R t__getitem_helper__R3RAR/(R)RTtresultR0R1tacc((s../__init__.pyt __getitem__/s +cCs#dtfd„ƒY}||jƒS(s2D.itervalues() -> an iterator over the values of DtNVListValuesIteratorcBseZdZd„ZRS(s7class to manage iterating over the values in an NVList.cSstj|ƒ}|jS(s2x.next() -> the next value, or raise StopIteration(RGRHR1(R)RJ((s../__init__.pyRH?s(RKRLRMRH(((s../__init__.pyRZ=s(RGR (R)RZ((s../__init__.pyt itervalues;scCs#dtfd„ƒY}||jƒS(s=D.iteritems() -> an iterator over the (key, value) items of DtNVKeysValuesIteratorcBseZdZd„ZRS(sOclass to manage iterating over the (key, value) pairs in an NVList.cSs(tj|ƒ}|j|jf|jfS(s2x.next() -> the next value, or raise StopIteration(RGRHRIR0R1(R)RJ((s../__init__.pyRHJs(RKRLRMRH(((s../__init__.pyR\Gs(RGR (R)R\((s../__init__.pyt iteritemsEscCsGtƒt|jƒ}}x'|D]}|j|j|jfƒq W|S(sD.keys() -> list of D's keys(tlistRGR tappendRIR0(R)RXtitrRJ((s../__init__.pytkeysPs cCsPtƒt|jƒ}}x0|D](}|j|j|jf|jfƒq W|S(s8D.items() -> list of D's (key, value) pairs, as 2-tuples(R^RGR R_RIR0R1(R)RXR`RJ((s../__init__.pytitemsXs &cCs>tƒt|jƒ}}x|D]}|j|jƒq W|S(s D.values() -> list of D's values(R^RGR R_R1(R)RXR`RJ((s../__init__.pyRD`s cCs|jj||ƒdS(N(R t __setitem__(R)RTR1((s../__init__.pyRciscCsnt|tƒs"|jj|ƒnHtj||ƒ}|tkrOt|ƒ‚n|tkrjt dƒ‚ndS(Ns%nvlist_remove_all(): invalid argument( RRPR t __delitem__R tnvlist_remove_allRtKeyErrorRR!(R)RTR*((s../__init__.pyRdls  cCs|r|jj||ƒ}n|jj|ƒ}g|D]\}}|j||ƒ^q7}t|ƒdkru|dSt|ƒS(s· D.pop(k[,d]) -> v, remove specified key and return the corresponding value. If key is not found, d is returned if given, otherwise KeyError is raised ii(R t__pop_helper__R3RAR/(R)RTtdefaultRWR0R1RX((s../__init__.pytpopys+cCseytt|jƒƒ}Wntk r8tdƒ‚nX|j|jf|jf}|j|ƒ|S(s‰ D.popitem() -> (k, v), remove and return some (key, value) pair as a 2-tuple; but raise KeyError if D is empty. spopitem(): NVList is empty( RHRGR t StopIterationRfRIR0R1tremove(R)RJRW((s../__init__.pytpopitemŠs  cCstj|ƒdS(s,D.clear() -> None. Remove all items from D.N(R t nvlist_clear(R)((s../__init__.pytclear˜scKsÒt|ƒr'tt|jƒƒƒ‚nt|ttfƒrµtj||dƒ}|dkrÎ|t krxt dƒ‚n|t kr“t dƒ‚nt |dtj|ƒƒ‚qÎntt|ƒj||ƒdS(s‹ D.update(E, **F) -> None. Update D from dict/iterable E and F. if E isinstance(nvlistp) -> nvlist_merge() called. If E has a .keys() method, does: for k in E: D[k] = E[k] If E lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, if **F is present it definitionally has bad keys of type str, not a tuple of (str, DATA_TYPE). So first, before merging we check that **kwds is None. Be advised that although other does NOT have to be an nvlistp, it does have to have keys which are (str, DATA_TYPE) tuples or a key error will be thrown. is nvlist_merge(): invalid arguments#nvlist_merge(): insufficient memorysnvlist_merge(): %sN(RARfRPRaRRRR t nvlist_mergeRR!RR"R#R$R%tsupertupdate(R)tothertkwdsR*((s../__init__.pyRqs    "c Cs”idd6dt6dt6|j}d|t|ƒfg}tdƒ}tdƒ}tƒ}x´|jƒD]¦\\}}}t|t|ƒƒ}t|} t|t| ƒƒ}|t krÔ|j || dfƒqi|t krù|j || d fƒqi|j || |fƒqiWd ||f} |j | dƒ|j d ||d ƒx7|D]/\}}}|j | ||t |ƒfƒqTWdj |ƒS(sx.__repr__() <==> repr(x)t0iRRsNVList [%s] (%d): tNAMEtTYPERs NVList Arrays%%-%ds %%-%ds %%stVALUEt-is (RuRvRw(RRRtidRAR^R]tmaxR R R_R RPtjoin( R)tsflagsRWtnmlentdtlentvalsRIR0R1tdtnametfmt((s../__init__.pyt__repr__¾s,       $N(( RKRLRMtNoneRR+tpropertyR RR,tsetterR.t staticmethodR3R?RBRERORURYR[R]RaRbRDRcRdRiRlRnRqR‚(((s../__init__.pyR´s4         !(RMt collectionsRtctypesRterrnoRRRR$tlibnvpair.cstructRtlibnvpair.constRRRRR R R t libnvpairR R Rtlibnvpair.privateRRGRR(((s../__init__.pyt€s  4