1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
U
¬ý°dçlã@s(dZddlmZddlmZddlmZmZddlZddlm    Z    ddl
Z ddl m Z mZmZddlmZmZddlZdd    lmZmZdd
lmZdd lmZmZmZmZmZdd lm Z m!Z!ddl"m#m$m%Z&dd l'm(Z(dddœdd„Z)ddddœdd„Z*Gdd„dƒZ+Gdd„de(ej,ƒZ-dS)a
Read SAS7BDAT files
 
Based on code written by Jared Hobbs:
  https://bitbucket.org/jaredhobbs/sas7bdat
 
See also:
  https://github.com/BioStatMatt/sas7bdat
 
Partial documentation of the file format:
  https://cran.r-project.org/package=sas7bdat/vignettes/sas7bdat.pdf
 
Reference for binary data compression:
  http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/1992/9210/ross/ross.htm
é)Ú annotations)Úabc)ÚdatetimeÚ    timedeltaN)Úcast)ÚCompressionOptionsÚFilePathÚ
ReadBuffer)ÚEmptyDataErrorÚOutOfBoundsDatetime)Ú    DataFrameÚisna)Ú
get_handle)Úread_double_with_byteswapÚread_float_with_byteswapÚread_uint16_with_byteswapÚread_uint32_with_byteswapÚread_uint64_with_byteswap)ÚParserÚget_subheader_index)Ú
ReaderBaseÚfloatÚstr©Z sas_datetimeÚunitcCsVt|ƒrtjS|dkr,tdddƒt|dS|dkrJtdddƒt|dStdƒ‚dS)NÚsé¨é)ÚsecondsÚd)Údayszunit must be 'd' or 's')r ÚpdZNaTrrÚ
ValueErrorr©r#úMd:\z\workplace\vscode\pyvenv\venv\Lib\site-packages\pandas/io/sas/sas7bdat.pyÚ_parse_datetime<sr%z    pd.Series)Ú sas_datetimesrÚreturncCsJztj||ddWStk
rD|jt|d}ttj|ƒ}|YSXdS)aÉ
    Convert to Timestamp if possible, otherwise to datetime.datetime.
    SAS float64 lacks precision for more than ms resolution so the fit
    to datetime.datetime is ok.
 
    Parameters
    ----------
    sas_datetimes : {Series, Sequence[float]}
       Dates or datetimes in SAS
    unit : {str}
       "d" if the floats represent dates, "s" for datetimes
 
    Returns
    -------
    Series
       Series of datetime64 dtype or datetime.datetime.
    z
1960-01-01)rÚorigin©rN)r!Ú to_datetimer Úapplyr%rÚSeries)r&rZs_seriesr#r#r$Ú_convert_datetimesJs  r-c@sXeZdZUded<ded<ded<ded<ded<ded    <ddddddd
d œd d „ZdS)Ú_ColumnÚintÚcol_idú str | bytesÚnameÚlabelÚformatÚbytesÚctypeÚlengthÚNone)r0r2r3r4r6r7r'cCs(||_||_||_||_||_||_dS©N)r0r2r3r4r6r7)Úselfr0r2r3r4r6r7r#r#r$Ú__init__ls
z_Column.__init__N)Ú__name__Ú
__module__Ú __qualname__Ú__annotations__r;r#r#r#r$r.ds
r.c @sâeZdZUdZded<ded<dSd    d
d
d d d
d
d ddœ    dd„Zddœdd„Zddœdd„Zddœdd„Zddœdd„Z    ddœdd„Z
ddœdd „Z ddd!œd"d#„Z dddd$œd%d&„Z ddd'œd(d)„Zddd*d+œd,d-„Zddœd.d/„Zd
dœd0d1„Zddœd2d3„Zddœd4d5„Zdddd+œd6d7„Zdddd+œd8d9„Zdddd+œd:d;„Zdddd+œd<d=„Zdddd+œd>d?„Zdddd+œd@dA„Zdddd+œdBdC„Zdddd+œdDdE„ZdTd ddFœdGdH„ZdIdJ„ZddœdKdL„ZdMdN„ZdOd*dPœdQdR„Z dS)UÚSAS7BDATReaderaË
    Read SAS files in SAS7BDAT format.
 
    Parameters
    ----------
    path_or_buf : path name or buffer
        Name of SAS file or file-like object pointing to SAS file
        contents.
    index : column identifier, defaults to None
        Column to use as index.
    convert_dates : bool, defaults to True
        Attempt to convert dates to Pandas datetime values.  Note that
        some rarely used SAS date formats may be unsupported.
    blank_missing : bool, defaults to True
        Convert empty strings to missing values (SAS uses blanks to
        indicate missing character variables).
    chunksize : int, defaults to None
        Return SAS7BDATReader object for iterations, returns chunks
        with given number of lines.
    encoding : str, 'infer', defaults to None
        String encoding acc. to Python standard encodings,
        encoding='infer' tries to detect the encoding from the file header,
        encoding=None will leave the data in binary format.
    convert_text : bool, defaults to True
        If False, text variables are left as raw bytes.
    convert_header_text : bool, defaults to True
        If False, header text, including column names, are left as raw
        bytes.
    r/Ú _int_lengthz bytes | NoneÚ _cached_pageNTÚinferzFilePath | ReadBuffer[bytes]Úboolz
int | Nonez
str | Nonerr8)    Ú path_or_bufÚ convert_datesÚ blank_missingÚ    chunksizeÚencodingÚ convert_textÚconvert_header_textÚ compressionr'c
 
    Csú||_||_||_||_||_||_||_d|_d|_g|_    g|_
g|_ g|_ g|_ d|_g|_g|_g|_d|_d|_d|_t|dd|    d|_|jj|_|j|j|j|j|j|j|j|jdg    |_ z| !¡| "¡Wnt#k
rô| $¡‚YnXdS)Nzlatin-1órÚrbF)Zis_textrL)%ÚindexrFrGrHrIrJrKÚdefault_encodingrLÚcolumn_names_rawÚ column_namesÚcolumn_formatsÚcolumnsÚ%_current_page_data_subheader_pointersrBÚ_column_data_lengthsÚ_column_data_offsetsÚ _column_typesÚ_current_row_in_file_indexZ_current_row_on_page_indexrÚhandlesÚhandleÚ _path_or_bufÚ_process_rowsize_subheaderÚ_process_columnsize_subheaderÚ_process_subheader_countsÚ_process_columntext_subheaderÚ_process_columnname_subheaderÚ#_process_columnattributes_subheaderÚ_process_format_subheaderÚ_process_columnlist_subheaderÚ_subheader_processorsÚ_get_propertiesÚ_parse_metadataÚ    ExceptionÚclose)
r:rErOrFrGrHrIrJrKrLr#r#r$r;¡sX ÿ
÷  zSAS7BDATReader.__init__z
np.ndarray)r'cCstj|jtjdS)z5Return a numpy int64 array of the column data lengths©Údtype)ÚnpÚasarrayrVÚint64©r:r#r#r$Úcolumn_data_lengthsàsz"SAS7BDATReader.column_data_lengthscCstj|jtjdS)z0Return a numpy int64 array of the column offsetsrj)rlrmrWrnror#r#r$Úcolumn_data_offsetsäsz"SAS7BDATReader.column_data_offsetscCstj|jt d¡dS)zj
        Returns a numpy character array of the column types:
           s (string) or d (double)
        ZS1rj)rlrmrXrkror#r#r$Ú column_typesèszSAS7BDATReader.column_typescCs|j ¡dSr9)rZriror#r#r$riïszSAS7BDATReader.closecCs
|j d¡|j d¡|_|jdttjƒ…tjkr<tdƒ‚| tj    tj
¡}|tj krtd|_ d|_ tj|_tj|_nd|_ tj|_tj|_d|_ | tjtj¡}|tjkr²tj}nd}| tjtj¡}|dkrâd    |_tjd
k|_nd |_tjd k|_| tjtj¡d}|tj kr6tj ||_!|j"d krD|j!|_"nd|›d|_!t#dddƒ}| $tj%|tj&¡}|t'j(|dd|_)| $tj*|tj+¡}|t'j(|dd|_,| -tj.|tj/¡|_0|j |j0d¡}|j|7_t|jƒ|j0krðtdƒ‚| -tj1|tj2¡|_3dS)Nri z'magic number mismatch (not a SAS file?)TéFéóú<Úbigú>ÚlittlerCzunknown (code=ú)rrrr)z*The SAS7BDAT file appears to be truncated.)4r\ÚseekÚreadrBÚlenÚconstÚmagicr"Ú _read_bytesZalign_1_offsetZalign_1_lengthZu64_byte_checker_valueÚU64rAZpage_bit_offset_x64Ú_page_bit_offsetZsubheader_pointer_length_x64Ú_subheader_pointer_lengthZpage_bit_offset_x86Zsubheader_pointer_length_x86Zalign_2_offsetZalign_2_lengthZalign_1_checker_valueZ align_2_valueZendianness_offsetZendianness_lengthÚ
byte_orderÚsysÚ    byteorderÚ need_byteswapZencoding_offsetZencoding_lengthZencoding_namesZinferred_encodingrIrÚ _read_floatZdate_created_offsetZdate_created_lengthr!Z to_timedeltaZ date_createdZdate_modified_offsetZdate_modified_lengthZ date_modifiedÚ
_read_uintZheader_size_offsetZheader_size_lengthÚ header_lengthZpage_size_offsetZpage_size_lengthÚ _page_length)r:ÚbufZalign1ÚepochÚxr#r#r$rfòsj 
 
 
 
 ÿÿÿÿzSAS7BDATReader._get_propertiesr cCs(|j|jp dd}|jr$| ¡t‚|S)Nr)Únrows)r|rHÚemptyriÚ StopIteration)r:Údar#r#r$Ú__next__8s
zSAS7BDATReader.__next__)ÚoffsetÚwidthcCsR|jdk    st‚|dkr&t|j||jƒS|dkr>t|j||jƒS| ¡tdƒ‚dS)Nrtrszinvalid float width)rBÚAssertionErrorrr‡rrir"©r:r”r•r#r#r$rˆ@sÿÿzSAS7BDATReader._read_float)r”r•r'cCs‚|jdk    st‚|dkr&| |d¡dS|dkr>t|j||jƒS|dkrVt|j||jƒS|dkrnt|j||jƒS| ¡tdƒ‚dS)Nrrértrszinvalid int width)    rBr–r€rr‡rrrir"r—r#r#r$r‰Os.ÿÿÿzSAS7BDATReader._read_uint)r”r7cCsB|jdk    st‚||t|jƒkr0| ¡tdƒ‚|j|||…S)NzThe cached page is too small.)rBr–r}rir"©r:r”r7r#r#r$r€cs
zSAS7BDATReader._read_bytesr1)r”r7r'cCs| | ||¡ d¡¡S)Nó )Ú_convert_header_textr€Úrstripr™r#r#r$Ú_read_and_convert_header_textjsÿz,SAS7BDATReader._read_and_convert_header_textcCsNd}|sJ|j |j¡|_t|jƒdkr(qJt|jƒ|jkr@tdƒ‚| ¡}qdS)NFrz2Failed to read a meta data page from the SAS file.)r\r|r‹rBr}r"Ú_process_page_meta)r:Údoner#r#r$rgoszSAS7BDATReader._parse_metadatacCsZ| ¡tjtjtjg}|j|kr,| ¡|jtjk}|jtjk}t|pV|pV|j    gkƒSr9)
Ú_read_page_headerr~Úpage_meta_typesZ page_amd_typeÚ page_mix_typeÚ_current_page_typeÚ_process_page_metadataÚpage_data_typerDrU)r:ÚptZ is_data_pageZ is_mix_pager#r#r$ržys
  ÿýz!SAS7BDATReader._process_page_metacCs^|j}tj|}| |tj¡tj@|_tj|}| |tj¡|_    tj
|}| |tj ¡|_ dSr9) r‚r~Zpage_type_offsetr‰Zpage_type_lengthZpage_type_mask2r£Zblock_count_offsetZblock_count_lengthZ_current_page_block_countZsubheader_count_offsetZsubheader_count_lengthÚ_current_page_subheaders_count)r:Ú
bit_offsetZtxr#r#r$r †s
ÿ
 
ÿz SAS7BDATReader._read_page_headercCs|j}t|jƒD]}tj|}||j|}| ||j¡}||j7}| ||j¡}||j7}| |d¡}|d7}| |d¡}|dks|tjkr’q|     ||j¡}    t
|    ƒ}
|j |
} | dkr |tj dfk} |tj k} |jrô| rô| rô|j ||f¡n| ¡td|    ›ƒ‚q| ||ƒqdS)NrrzUnknown subheader signature )r‚Úranger§r~Zsubheader_pointers_offsetrƒr‰rAZtruncated_subheader_idr€rreZcompressed_subheader_idZcompressed_subheader_typerLrUÚappendrir")r:r¨Úir”Z total_offsetZsubheader_offsetZsubheader_lengthZsubheader_compressionZsubheader_typeZsubheader_signatureZsubheader_indexZsubheader_processorÚf1Úf2r#r#r$r¤“s>
 
 
  ÿþ
 
 
ÿÿz%SAS7BDATReader._process_page_metadatacCsÒ|j}|}|}|jr&|d7}|d7}n|d7}|d7}| |tj||¡|_| |tj||¡|_| |tj||¡|_    | |tj
||¡|_ tj |}| |||¡|_ | |d¡|_| |d¡|_dS)NiªiÂibizr˜)rArr‰r~Zrow_length_offset_multiplierZ
row_lengthZrow_count_offset_multiplierÚ    row_countZcol_count_p1_multiplierÚ col_count_p1Zcol_count_p2_multiplierÚ col_count_p2Z'row_count_on_mix_page_offset_multiplierZ_mix_page_row_countÚ_lcsÚ_lcp)r:r”r7Úint_lenZ
lcs_offsetZ
lcp_offsetZmxr#r#r$r]¾s8
 þ þ ÿ ÿ
z)SAS7BDATReader._process_rowsize_subheadercCsT|j}||7}| ||¡|_|j|j|jkrPtd|j›d|j›d|j›dƒdS)Nz Warning: column count mismatch (z + z != z)
)rAr‰Ú column_countr¯r°Úprint)r:r”r7r³r#r#r$r^Üsÿz,SAS7BDATReader._process_columnsize_subheadercCsdSr9r#r™r#r#r$r_çsz(SAS7BDATReader._process_subheader_countsc    Csš||j7}| |tj¡}| ||¡}|d|… d¡}|j |¡t|jƒdkr–d}tj    D]}||kr\|}q\||_
||j8}|d}|j r”|d7}| ||j ¡}| d¡}|dkrðd|_ |d}|j rÐ|d7}| ||j ¡}|d|j …|_nŒ|tjkr4|d    }|j r|d7}| ||j ¡}|d|j …|_nH|j dkr|d|_ |d}|j r^|d7}| ||j ¡}|d|j …|_t|d
ƒr–| |j¡|_dS) NrršrrMértóé é(Ú creator_proc)rAr‰r~Ztext_block_size_lengthr€rœrQrªr}Zcompression_literalsrLrr²r±rºZrle_compressionÚhasattrr›)    r:r”r7Ztext_block_sizerŒZ    cname_rawZcompression_literalZclZoffset1r#r#r$r`êsN
 
 
 
   z,SAS7BDATReader._process_columntext_subheadercCsÒ|j}||7}|d|dd}t|ƒD]¢}|tj|dtj}|tj|dtj}|tj|dtj}| |tj¡}    | |tj    ¡}
| |tj
¡} |j |    } | |
|
| …} |j   | | ¡¡q*dS)Nr˜é rsr)rAr©r~Zcolumn_name_pointer_lengthZ!column_name_text_subheader_offsetZcolumn_name_offset_offsetZcolumn_name_length_offsetr‰Z!column_name_text_subheader_lengthZcolumn_name_offset_lengthZcolumn_name_length_lengthrQrRrªr›)r:r”r7r³Zcolumn_name_pointers_countr«Ztext_subheaderZcol_name_offsetZcol_name_lengthÚidxÚ
col_offsetZcol_lenZname_rawÚcnamer#r#r$rasD  ÿþÿ ÿþÿ ÿþÿÿÿ
z,SAS7BDATReader._process_columnname_subheaderc
CsÞ|j}|d|d|d}t|ƒD]²}||tj||d}|d|tj||d}|d|tj||d}| ||¡}    |j |    ¡| |tj    ¡}    |j
 |    ¡| |tj ¡}    |j  |    dkrÒdnd¡q&dS)Nr˜r¼rsródós) rAr©r~Zcolumn_data_offset_offsetZcolumn_data_length_offsetZcolumn_type_offsetr‰rWrªZcolumn_data_length_lengthrVZcolumn_type_lengthrX)
r:r”r7r³Zcolumn_attributes_vectors_countr«Zcol_data_offsetZ col_data_lenZ    col_typesrŽr#r#r$rb8s* ÿÿþ
ýÿÿ   z2SAS7BDATReader._process_columnattributes_subheadercCsdSr9r#r™r#r#r$rdRsz,SAS7BDATReader._process_columnlist_subheadercCsx|j}|tjd|}|tjd|}|tjd|}|tjd|}|tjd|}|tjd|}    | |tj    ¡}
t
|
t |j ƒdƒ} | |tj ¡} | |tj¡} | |tj¡}t
|t |j ƒdƒ}| |tj¡}| |    tj¡}|j |}| ||||…¡}|j | }| || | | …¡}t |jƒ}t||j||||j||j|ƒ}|j |¡|j |¡dS)Nér)rAr~Z)column_format_text_subheader_index_offsetZcolumn_format_offset_offsetZcolumn_format_length_offsetZ(column_label_text_subheader_index_offsetZcolumn_label_offset_offsetZcolumn_label_length_offsetr‰Z)column_format_text_subheader_index_lengthÚminr}rQZcolumn_format_offset_lengthZcolumn_format_length_lengthZ(column_label_text_subheader_index_lengthZcolumn_label_offset_lengthZcolumn_label_length_lengthr›rTr.rRrXrVrSrª)r:r”r7r³Ztext_subheader_formatZcol_format_offsetZcol_format_lenZtext_subheader_labelZcol_label_offsetZ col_label_lenrŽZ
format_idxZ format_startZ
format_lenZ    label_idxZ label_startZ    label_lenZ label_namesZ column_labelZ format_namesZ column_formatZcurrent_column_numberÚcolr#r#r$rcVs`ÿÿÿÿÿÿ
ÿ
ÿ
ú     z(SAS7BDATReader._process_format_subheader)rr'cCsò|dkr|jdk    r|j}n|dkr(|j}t|jƒdkrF| ¡tdƒ‚|dkr`|j|jkr`tƒSt||j|jƒ}|j     d¡}|j     d¡}t
j ||ft d|_ t
j|d|ft
jd|_d|_t|ƒ}| |¡| ¡}|jdk    rî| |j¡}|S)NrzNo columns to parse from filerÀrÁrjrs)rHr®r}rXrir
rYr rÃÚcountrlrÚobjectÚ _string_chunkÚzerosZuint8Ú _byte_chunkÚ_current_row_in_chunk_indexrr|Ú_chunk_to_dataframerOZ    set_index)r:rZndÚnsÚpÚrsltr#r#r$r|s*  
 
 zSAS7BDATReader.readcCs¦g|_|j |j¡|_t|jƒdkr(dSt|jƒ|jkrf| ¡dt|jƒd›d|jd›d}t|ƒ‚| ¡|j    t
j kr‚|  ¡|j    t
j t
j t
jgkr¢| ¡SdS)NrTz-failed to read complete page from file (read rz of z bytes)F)rUr\r|r‹rBr}rir"r r£r~r¡r¤r¥r¢Ú_read_next_page)r:Úmsgr#r#r$rϬs$ÿ þzSAS7BDATReader._read_next_pagec Cst|j}|j}t|||ƒ}i}d\}}t|jƒD]*}|j|}|j|dkrÚ|j|dd…fj|jdd}    t    j
|    t j |d||<|j rÐ|j|tjkr®t||dƒ||<n"|j|tjkrÐt||dƒ||<|d7}q0|j|dkr<t    j
|j|dd…f|d    ||<|jr2|jdk    r2| ||j¡||<|d7}q0| ¡td
t|j|ƒ›ƒ‚q0t||j|d d }
|
S) N)rrrÀrrj)rkrOrrrÁ)rOzunknown column type F)rTrOÚcopy)rÊrYr©r´rRrXrÉÚviewr„r!r,rlÚfloat64rFrSr~Zsas_date_formatsr-Zsas_datetime_formatsrÇrJrIÚ_decode_stringrrir"Úreprr ) r:ÚnÚmÚixrÎZjsZjbÚjr2Zcol_arrZdfr#r#r$rËÅs2
 
 
z"SAS7BDATReader._chunk_to_dataframecCs| |jp|j¡Sr9)ÚdecoderIrP©r:Úbr#r#r$rÔäszSAS7BDATReader._decode_stringr5)rÜr'cCs|jr| |¡S|SdSr9)rKrÔrÛr#r#r$r›çs
z#SAS7BDATReader._convert_header_text)NTTNNTTrC)N)!r<r=r>Ú__doc__r?r;rprqrrrirfr“rˆr‰r€rrgržr r¤r]r^r_r`rarbrdrcr|rÏrËrÔr›r#r#r#r$r@sN
ö ?F
  + -!7r@).rÝÚ
__future__rÚ collectionsrrrr…ÚtypingrÚnumpyrlZpandas._typingrrr    Z pandas.errorsr
r Zpandasr!r r Zpandas.io.commonrZpandas.io.sas._byteswaprrrrrZpandas.io.sas._sasrrZpandas.io.sas.sas_constantsÚioZsasZ sas_constantsr~Zpandas.io.sas.sasreaderrr%r-r.ÚIteratorr@r#r#r#r$Ú<module>s&