Ë
    ª2ÚiØ:  ã            	      ó  — d Z ddlmZ ddlmZ ddlZddlmZ ddlZddlZ	ddl
mZ ddlZddlmZ ddlmZ erdd	lmZmZmZmZ d
ZdZdZdZg d¢ZdZdZdZdZde› de› de› de› d�	Z de› de› d�Z!dd„Z"dd„Z#d„ Z$d„ Z% G d„ de«      Z&y) a-  
Read a SAS XPort format file into a Pandas DataFrame.

Based on code from Jack Cushman (github.com/jcushman/xport).

The file format is defined here:

https://support.sas.com/content/dam/SAS/support/en/technical-papers/record-layout-of-a-sas-version-5-or-6-data-set-in-sas-transport-xport-format.pdf
é    )Úannotations)ÚdatetimeN)ÚTYPE_CHECKING)Úfind_stack_level)Ú
get_handle)Ú	SASReader)ÚCompressionOptionsÚDatetimeNaTTypeÚFilePathÚ
ReadBufferzPHEADER RECORD*******LIBRARY HEADER RECORD!!!!!!!000000000000000000000000000000  zKHEADER RECORD*******MEMBER  HEADER RECORD!!!!!!!000000000000000001600000000zPHEADER RECORD*******DSCRPTR HEADER RECORD!!!!!!!000000000000000000000000000000  zPHEADER RECORD*******OBS     HEADER RECORD!!!!!!!000000000000000000000000000000  )ÚntypeÚnhfunÚfield_lengthÚnvar0ÚnameÚlabelÚnformÚnflÚnum_decimalsÚnfjÚnfillÚniformÚniflÚnifdÚnposÚ_z‚Parameters
----------
filepath_or_buffer : str or file-like object
    Path to SAS file or object implementing binary read method.zâindex : identifier of index column
    Identifier of column that should be used as index of the DataFrame.
encoding : str
    Encoding for text data.
chunksize : int
    Read file `chunksize` lines at a time, returns iterator.zBformat : str
    File format, only `xport` is currently supported.z\iterator : bool, default False
    Return XportReader object for reading file incrementally.z#Read a SAS file into a DataFrame.

ú
a  

Returns
-------
DataFrame or XportReader

Examples
--------
Read a SAS Xport file:

>>> df = pd.read_sas('filename.XPT')

Read a Xport file in 10,000 line chunks:

>>> itr = pd.read_sas('filename.XPT', chunksize=10000)
>>> for chunk in itr:
>>>     do_something(chunk)

z$Class for reading SAS Xport files.

zš

Attributes
----------
member_info : list
    Contains information about the file
fields : list
    Contains information about the variables in the file
c                ón   — 	 t        j                  | d«      S # t        $ r t        j                  cY S w xY w)z1Given a date in xport format, return Python date.z%d%b%y:%H:%M:%S)r   ÚstrptimeÚ
ValueErrorÚpdÚNaT)Údatestrs    úN/var/www/html/acx/venv/lib/python3.12/site-packages/pandas/io/sas/sas_xport.pyÚ_parse_dater%   �   s3   € ðä× Ñ  Ð*;Ó<Ð<øÜò Ü�v‰vŠðús   ‚ ˜4³4c                ód   — i }d}|D ]#  \  }}| |||z    j                  «       ||<   ||z  }Œ% |d= |S )a  
    Parameters
    ----------
    s: str
        Fixed-length string to split
    parts: list of (name, length) pairs
        Used to break up string, name '_' will be filtered from output.

    Returns
    -------
    Dict of name:contents of string at given location.
    r   r   )Ústrip)ÚsÚpartsÚoutÚstartr   Úlengths         r$   Ú_split_liner-   Š   sU   € ð €CØ€EØò ‰ˆˆfØ�e˜e f™nÐ-×3Ñ3Ó5ˆˆD‰	Ø�‰‰ðð 	ˆCˆØ€Jó    c                óâ   — |dk7  rit        j                  t        | «      t        j                  d«      «      }t        j                  d|› dd|z
  › �«      }|j	                  |¬«      }| |d<   |S | S )Né   ÚS8ÚSz,S©ÚdtypeÚf0)ÚnpÚzerosÚlenr4   Úview)ÚvecÚnbytesÚvec1r4   Úvec2s        r$   Ú_handle_truncated_float_vecr>       si   € ð �‚{Ü�x‰xœ˜C›¤"§(¡(¨4£.Ó1ˆÜ—‘˜1˜V˜H B q¨6¡z lÐ3Ó4ˆØ�y‰y˜uˆyÓ%ˆØˆˆT‰
Øˆà€Jr.   c                óˆ  — t        j                  d«      }| j                  |¬«      }|d   }|d   }|dz  }t        j                  t	        | «      t         j
                  ¬«      }d|t        j                  |dz  «      <   d|t        j                  |d	z  «      <   d
|t        j                  |dz  «      <   ||z  }||z	  |dz  dd
|z
  z   z  z  }|dz  }||dz	  dz  dz
  dz  |z   dz   dz  |dz  z  z  }t        j                  t	        |«      fd¬«      }||d<   ||d<   |j                  d¬«      }|j                  d«      }|S )zf
    Parse a vector of float values representing IBM 8 byte floats into
    native 8 byte floats.
    z>u4,>u4r3   r5   Úf1iÿÿÿ é   i    é   i  @ é   i  € é   é   l   ÿß é   é   éA   iÿ  é   l        z>f8Úf8)	r6   r4   r9   r7   r8   Úuint8ÚwhereÚemptyÚastype)	r:   r4   r<   Úxport1Úxport2Úieee1ÚshiftÚieee2Úieees	            r$   Ú_parse_float_vecrU   ³   sd  € ô
 �H‰H�YÓ€EØ�8‰8˜%ˆ8Ó €DØ�$‰Z€FØ�$‰Z€Fð �ZÑ€Eô �H‰H”S˜“X¤R§X¡XÔ.€EØ+,€EŒ"�(‰(�6˜JÑ&Ó
'Ñ(Ø+,€EŒ"�(‰(�6˜JÑ&Ó
'Ñ(Ø+,€EŒ"�(‰(�6˜JÑ&Ó
'Ñ(ð 
ˆe�O€EØ�u‰_ &¨:Ñ"5¸2ÀÀUÁÑ;KÑ!LÑM€Eð 
ˆZÑ€Eð 
�6˜R‘< 4Ñ'¨2Ñ-°!Ñ3°uÑ<¸tÑCÈÑJØ�Ñññ €Eô �8‰8”S˜“Z�M¨Ô3€DØ€Dˆ�JØ€Dˆ�JØ�9‰9˜5ˆ9Ó!€DØ�;‰;�tÓ€Dà€Kr.   c                  ót   — e Zd ZeZ	 	 	 	 d	 	 	 	 	 	 	 	 	 dd„Zdd„Zd„ Zdd„Zdd„Z	dd„Z
ddd„Zd	„ Zddd
„Zy)ÚXportReaderNc                óú   — || _         d| _        || _        || _        t	        |d|d|¬«      | _        | j
                  j                  | _        	 | j                  «        y # t        $ r | j                  «        ‚ w xY w)Nr   ÚrbF)ÚencodingÚis_textÚcompression)Ú	_encodingÚ_lines_readÚ_indexÚ
_chunksizer   ÚhandlesÚhandleÚfilepath_or_bufferÚ_read_headerÚ	ExceptionÚclose)Úselfrc   ÚindexrZ   Ú	chunksizer\   s         r$   Ú__init__zXportReader.__init__ï   s|   € ð "ˆŒØˆÔØˆŒØ#ˆŒä!ØØØØØ#ô
ˆŒð #'§,¡,×"5Ñ"5ˆÔð	Ø×ÑÕøÜò 	Ø�J‰JŒLØð	ús   ÁA ÁA:c                ó8   — | j                   j                  «        y ©N)ra   rf   ©rg   s    r$   rf   zXportReader.close  s   € Ø�‰×ÑÕr.   c                óT   — | j                   j                  d«      j                  «       S )NéP   )rc   ÚreadÚdecoderm   s    r$   Ú_get_rowzXportReader._get_row  s"   € Ø×&Ñ&×+Ñ+¨BÓ/×6Ñ6Ó8Ð8r.   c           
     óè  — | j                   j                  d«       | j                  «       }|t        k7  rd|v rt	        d«      ‚t	        d«      ‚| j                  «       }ddgddgd	dgd
dgddgg}t        ||«      }|d   dk7  rt	        d«      ‚t        |d   «      |d<   || _        | j                  «       }t        |d d «      |d<   | j                  «       }| j                  «       }|j                  t        «      }|t        k(  }	|r|	st	        d«      ‚t        |dd «      }
ddgddgddgddgd	dgd
dgddgg}t        | j                  «       |«      }ddgd
dgddgddgg}|j                  t        | j                  «       |«      «       t        |d   «      |d<   t        |d   «      |d<   || _        dddœ}t        | j                  «       dd «      }|
|z  }|dz  r|d|dz  z
  z  }| j                   j                  |«      }g }d}t        |«      |
k\  rË|d |
 ||
d  }}|j!                  d«      }t#        j$                  d|«      }t'        t)        t*        |d ¬!«      «      }|d
= ||d"      |d"<   |d#   }|d"   dk(  r|d$k  s|dkD  rd%|› d&�}t-        |«      ‚|j/                  «       D ]  \  }}	 |j1                  «       ||<   Œ ||d#   z  }||gz  }t        |«      |
k\  rŒË| j                  «       }|t4        k(  st	        d'«      ‚|| _        || _        | j                   j;                  «       | _        | j?                  «       | _         | j6                  D �cg c]  }|d(   jC                  «       ‘Œ c}| _"        tG        | j6                  «      D ��cg c]$  \  }}d)tI        |«      z   d*tI        |d#   «      z   f‘Œ& }}}tK        jL                  |«      }|| _'        y # t2        $ r Y �Œ<w xY wc c}w c c}}w )+Nr   z**COMPRESSED**z<Header record indicates a CPORT file, which is not readable.z#Header record is not an XPORT file.ÚprefixrF   Úversionr0   ÚOSr   Úcreatedé   zSAS     SAS     SASLIBz!Header record has invalid prefix.ÚmodifiedzMember header not foundéûÿÿÿéþÿÿÿÚset_nameÚsasdatar   é(   ÚtypeÚnumericÚchar)rA   rB   é6   é:   ro   éŒ   z>hhhh8s40s8shhh2s8shhl52sT)Ústrictr   r   rB   zFloating field width z is not between 2 and 8.zObservation header not found.r   r(   r2   )(rc   Úseekrr   Ú_correct_line1r    r-   r%   Ú	file_infoÚ
startswithÚ_correct_header1Ú_correct_header2ÚintÚupdateÚmember_inforp   r8   ÚljustÚstructÚunpackÚdictÚzipÚ
_fieldkeysÚ	TypeErrorÚitemsr'   ÚAttributeErrorÚ_correct_obs_headerÚfieldsÚrecord_lengthÚtellÚrecord_startÚ_record_countÚnobsrq   ÚcolumnsÚ	enumerateÚstrr6   r4   Ú_dtype)rg   Úline1Úline2Úfifrˆ   Úline3Úheader1Úheader2Ú	headflag1Ú	headflag2ÚfieldnamelengthÚmemrŽ   ÚtypesÚ
fieldcountÚ
datalengthÚ	fielddatar™   Ú
obs_lengthÚ
fieldbytesÚfieldstructÚfieldÚflÚmsgÚkÚvÚheaderÚxÚiÚdtypelr4   s                                  r$   rd   zXportReader._read_header  s]  € Ø×Ñ×$Ñ$ QÔ'ð —‘“ˆØ”NÒ"Ø 5Ñ(ô !ØRóð ô ÐBÓCÐCà—‘“ˆØ˜"ˆ~ 	¨1˜~°°a¨y¸3À¸)ÀiÐQSÀ_ÐUˆÜ  sÓ+ˆ	Ø�XÑÐ":Ò:ÜÐ@ÓAÐAÜ*¨9°YÑ+?Ó@ˆ	�)ÑØ"ˆŒà—‘“ˆÜ +¨E°#°2¨JÓ 7ˆ	�*Ñð —-‘-“/ˆØ—-‘-“/ˆØ×&Ñ&Ô'7Ó8ˆ	ØÔ/Ñ/ˆ	Ù™iÜÐ6Ó7Ð7ä˜g b¨˜nÓ-ˆð �qˆMØ˜ˆOØ˜ˆNØ˜ˆNØ�1ˆIØ�"ˆIØ˜ˆOð
ˆô " $§-¡-£/°3Ó7ˆØ˜BÐ # r ¨W°b¨M¸FÀA¸;ÐGˆØ×Ñœ; t§}¡}£¸Ó<Ô=Ü"-¨k¸*Ñ.EÓ"Fˆ�JÑÜ!,¨[¸Ñ-CÓ!Dˆ�IÑØ&ˆÔð  &Ñ)ˆÜ˜Ÿ™›¨¨BÐ/Ó0ˆ
Ø$ zÑ1ˆ
à˜Š?Ø˜"˜z¨B™Ñ.Ñ.ˆJØ×+Ñ+×0Ñ0°Ó<ˆ	ØˆØˆ
Ü�)‹n Ò/ð Ð*˜?Ð+Ø˜/Ð*Ð+ð "ˆJð $×)Ñ)¨#Ó.ˆJä Ÿ-™-Ð(CÀZÓPˆKÜœœZ¨¸TÔBÓCˆEØ�c�
Ø" 5¨¡>Ñ2ˆE�'‰NØ�~Ñ&ˆBØ�W‰~ Ò*°°a²¸RÀ!ºVØ-¨b¨TÐ1IÐJ�Ü “nÐ$àŸ™›ò ‘��1ðØ Ÿw™w›y�E˜!’Hðð ˜% Ñ/Ñ/ˆJØ�u�gÑˆFô7 �)‹n Ó/ð: —‘“ˆØÔ,Ò,ÜÐ<Ó=Ð=àˆŒØ'ˆÔØ ×3Ñ3×8Ñ8Ó:ˆÔà×&Ñ&Ó(ˆŒ	Ø48·K±KÖ@¨q˜˜&™	×(Ñ(Õ*Ò@ˆŒô
 & d§k¡kÓ2÷
á��5ð ”3�q“6‰\˜3¤ U¨>Ñ%:Ó!;Ñ;Ò<ð
ˆñ 
ô —‘˜Ó ˆØˆ�øô/ &ò Úðüò Aùó
s   Ê0OÍO)Î)O.Ï	O&Ï%O&c                óB   — | j                  | j                  xs d¬«      S )NrA   ©Únrows)rp   r`   rm   s    r$   Ú__next__zXportReader.__next__  s   € Ø�y‰y˜tŸ™Ò3°!ˆyÓ4Ð4r.   c                óð  — | j                   j                  dd«       | j                   j                  «       | j                  z
  }|dz  dk7  rt	        j
                  dt        «       ¬«       | j                  dkD  r4| j                   j                  | j                  «       || j                  z  S | j                   j                  dd«       | j                   j                  d«      }t        j                  |t        j                  ¬«      }t        j                  |dk(  «      }t        |«      dk(  rd}nd	t        |«      z  }| j                   j                  | j                  «       ||z
  | j                  z  S )
zÇ
        Get number of records in file.

        This is maybe suboptimal because we have to seek to the end of
        the file.

        Side effect: returns file position to record_start.
        r   rB   ro   zxport file may be corrupted.)Ú
stackleveli°ÿÿÿr3   l     @@€  r0   )rc   r†   r›   rœ   ÚwarningsÚwarnr   rš   rp   r6   Ú
frombufferÚuint64Úflatnonzeror8   )rg   Útotal_records_lengthÚlast_card_bytesÚ	last_cardÚixÚtail_pads         r$   r�   zXportReader._record_count‚  s:  € ð 	×Ñ×$Ñ$ Q¨Ô*Ø#×6Ñ6×;Ñ;Ó=À×@QÑ@QÑQÐà "Ñ$¨Ò)Ü�M‰MØ.Ü+Ó-õð
 ×Ñ Ò"Ø×#Ñ#×(Ñ(¨×):Ñ):Ô;Ø'¨4×+=Ñ+=Ñ=Ð=à×Ñ×$Ñ$ S¨!Ô,Ø×1Ñ1×6Ñ6°rÓ:ˆÜ—M‘M /¼¿¹ÔCˆ	ô �^‰^˜IÐ)<Ñ<Ó=ˆäˆr‹7�aŠ<Ø‰Hàœ3˜r›7‘{ˆHà×Ñ×$Ñ$ T×%6Ñ%6Ô7à$ xÑ/°D×4FÑ4FÑFÐFr.   c                óB   — |€| j                   }| j                  |¬«      S )a  
        Reads lines from Xport file and returns as dataframe

        Parameters
        ----------
        size : int, defaults to None
            Number of lines to read.  If None, reads whole file.

        Returns
        -------
        DataFrame
        r¾   )r`   rp   )rg   Úsizes     r$   Ú	get_chunkzXportReader.get_chunk¨  s#   € ð ˆ<Ø—?‘?ˆDØ�y‰y˜tˆyÓ$Ð$r.   c                ó®   — |j                  d¬«      }|d   dk(  |d   dk(  z  |d   dk(  z  }|d   dk\  |d   d	k  z  |d   d
k(  z  |d   dk(  z  }||z  }|S )Nzu1,u1,u2,u4r3   r@   r   Úf2Úf3r5   rH   éZ   é_   é.   )r9   )rg   r:   r¸   ÚmissÚmiss1s        r$   Ú_missing_doublezXportReader._missing_double¹  s†   € Ø�H‰H˜=ˆHÓ)ˆØ�$‘˜1‘  4¡¨A¡Ñ.°!°D±'¸Q±,Ñ?ˆà�‰g˜‰o ! D¡'¨T¡/Ñ2Ø�‰w˜$‰ñ à�‰w˜$‰ñ ð 	ð
 	�‰ˆØˆr.   c                ó|  — |€| j                   }t        || j                   | j                  z
  «      }|| j                  z  }|dk  r| j	                  «        t
        ‚| j                  j                  |«      }t        j                  || j                  |¬«      }i }t        | j                  «      D ]ò  \  }}|dt        |«      z      }	| j                  |   d   }
|
dk(  rLt        |	| j                  |   d   «      }	| j!                  |	«      }t#        |	«      }t        j$                  ||<   nf| j                  |   d   dk(  rQ|	D �cg c]  }|j'                  «       ‘Œ }}| j(                  �(|D �cg c]  }|j+                  | j(                  «      ‘Œ }}|j-                  |i«       Œô t/        j0                  |«      }| j2                  €<t/        j4                  t7        | j                  | j                  |z   «      «      |_        n|j;                  | j2                  «      }| xj                  |z  c_        |S c c}w c c}w )a  Read observations from SAS Xport file, returning as data frame.

        Parameters
        ----------
        nrows : int
            Number of rows to read from data file; if None, read whole
            file.

        Returns
        -------
        A DataFrame.
        r   )r4   Úcountr(   r   r€   r   r�   )rž   Úminr^   rš   rf   ÚStopIterationrc   rp   r6   rÅ   r¢   r    rŸ   r¡   r™   r>   rØ   rU   ÚnanÚrstripr]   rq   r�   r!   Ú	DataFramer_   ÚIndexÚrangerh   Ú	set_index)rg   r¿   Ú
read_linesÚread_lenÚrawÚdataÚdf_dataÚjrº   r:   r   rÖ   r¸   ÚyÚdfs                  r$   rp   zXportReader.readÄ  sè  € ð ˆ=Ø—I‘IˆEä˜ §	¡	¨D×,<Ñ,<Ñ <Ó=ˆ
Ø × 2Ñ 2Ñ2ˆØ�qŠ=Ø�J‰JŒLÜÐØ×%Ñ%×*Ñ*¨8Ó4ˆÜ�}‰}˜S¨¯©¸:ÔFˆàˆÜ˜dŸl™lÓ+ò 	#‰DˆAˆqØ�sœS ›V‘|Ñ$ˆCØ—K‘K ‘N 7Ñ+ˆEØ˜	Ò!Ü1°#°t·{±{À1±~ÀnÑ7UÓV�Ø×+Ñ+¨CÓ0�Ü$ SÓ)�ÜŸ&™&��$’Ø—‘˜Q‘ Ñ(¨FÒ2Ø),Ö- A�Q—X‘X•ZÐ-�Ð-à—>‘>Ð-Ø;<Ö=°a˜Ÿ™ $§.¡.Õ1Ð=�AÐ=à�N‰N˜A˜q˜6Õ"ð	#ô �\‰\˜'Ó"ˆà�;‰;ÐÜ—x‘x¤ d×&6Ñ&6¸×8HÑ8HÈ:Ñ8UÓ VÓWˆB�Hà—‘˜dŸk™kÓ*ˆBà×Ò˜JÑ&Õàˆ	ùò .ùò >s   ÅH4Å,"H9)Nz
ISO-8859-1NÚinfer)
rc   zFilePath | ReadBuffer[bytes]rZ   z
str | Noneri   ú
int | Noner\   r	   ÚreturnÚNone)rí   rî   )rí   úpd.DataFrame)rí   rŒ   rl   )rÎ   rì   rí   rï   )r¿   rì   rí   rï   )Ú__name__Ú
__module__Ú__qualname__Ú_xport_reader_docÚ__doc__rj   rf   rr   rd   rÀ   r�   rÏ   rØ   rp   © r.   r$   rW   rW   ì   sv   „ Ø€Gð
 Ø+Ø $Ø*1ðà8ðð ð	ð
 ðð (ðð 
óó8ò9óló\5ó$GôL%ò"	õ1r.   rW   )r#   r¡   rí   r
   )r(   r¡   )'rô   Ú
__future__r   r   r�   Útypingr   rÃ   Únumpyr6   Úpandas.util._exceptionsr   Úpandasr!   Úpandas.io.commonr   Úpandas.io.sas.sasreaderr   Úpandas._typingr	   r
   r   r   r‡   rŠ   r‹   r˜   r”   Ú_base_params_docÚ_params2_docÚ_format_params_docÚ_iterator_docÚ_read_sas_docró   r%   r-   r>   rU   rW   rõ   r.   r$   ú<module>r     s  ðñõ #å Û Ý  Û ã å 4ã å 'Ý -á÷ó ð Wð ð Rð ð Wð ð Wð ò€
ð(CÐ ð@€ð9Ð ðA€ð
àÐ ð ØÐ ð Ø€ð Ø€ð ð€ð2ð Ð ð Ø€ð ð	Ð óóò,ò&6ôrI�)õ Ir.   