本程序用于从 .sas
文件中提取需要递交至监管机构的代码,并另存为 .txt
格式的文件。
然后使用 pip
命令安装指定版本,例如:
pip install git+https://github.com/smjc-org/[email protected]
或者从特定 commit 安装:
pip install git+https://github.com/smjc-org/py-submit.git@03c8953663c8d9f6cb71a925df4fa1da7ca34cc3
上述命令会将本程序安装到环境变量中指定的目录下,后续可直接通过 submit
命令调用。
Note
对于 Windows 用户,你可以在 %LOCALAPPDATA%/Programs/Python/Python313/Scripts
中看到 submit.exe
,你在终端执行 submit
命令实际上调用的是这个程序。
submit
命令会识别 .sas
文件中的特殊注释,根据这些注释,删除多余的代码片段,保留需要递交的代码片段。
submit
命令可以识别的特殊注释如下:
/*
symbols
SUBMIT BEGIN
symbols
*/
: 指定需要提交的代码的起始位置/*
symbols
SUBMIT END
symbols
*/
: 指定需要提交的代码的终止位置/*
symbols
NOT SUBMIT BEGIN
symbols
*/
: 指定无需提交的代码的起始位置/*
symbols
NOT SUBMIT END
symbols
*/
: 指定无需提交的代码的终止位置
Note
symbols
可以是符号*
,-
,=
,- 注释不区分大小写
举例:
/*
Top-Level Comment
*/
proc datasets library = work memtype = data kill noprint;
quit;
dm ' log; clear; output; clear; odsresult; clear; ';
/*SUBMIT BEGIN*/
proc sql noprint;
create table work.adsl as select * from rawdata.adsl;
quit;
proc sql noprint;
create table work.t_6_1_1 as select * from adsl;
quit;
/*SUBMIT END*/
%LOG;
%ERROR;
经 submit
命令处理之后将会变成:
proc sql noprint;
create table work.adsl as select * from rawdata.adsl;
quit;
proc sql noprint;
create table work.t_6_1_1 as select * from adsl;
quit;
子命令 copyfile
用于处理单个 .sas
文件。
submit copyfile "adae.sas" "adae.txt"
submit cpf "adae.sas" "adae.txt"
其中,adae.sas
是需要处理的 .sas
文件路径,adae.txt
是处理后保存的 .txt
文件路径。
Tip
cpf
是copyfile
的别名(alias),大多数选项都具有别名,可通过--help
命令查看。- 可以使用相对路径和绝对路径,使用相对路径时,以
submit
命令执行所在目录为根。 例如:在/code
目录下处理子目录/code/adam
中的adae.sas
文件,应该执行submit copyfile "adam/adae.sas" "submit/adae.txt"
,此时adae.txt
文件将保存在/code/submit
目录下。
--convert-mode
选项用于指定处理模式,可选值为:positive
, negative
, both
,默认为 both
。
positive
: 仅处理/* SUBMIT BEGIN */
,/* SUBMIT END */
negative
: 仅处理/* NOT SUBMIT BEGIN*/
,/* NOT SUBMIT END */
both
: 同时处理所有四个特殊注释
Important
/* NOT SUBMIT BEGIN*/
, /* NOT SUBMIT END */
的处理优先级高于 /* SUBMIT BEGIN */
, /* SUBMIT END */
。
submit copyfile --convert-mode negative
上述命令将会把:
%macro BAplot(indata, var, outdata);
data _tmp1;
set &indata;
run;
proc sql noprint;
create table _tmp2 as select * from _tmp1;
quit;
data &outdata;
set _tmp2;
run;
/*NOT SUBMIT BEGIN*/
proc template;
define statgraph BAplot;
begingraph;
entrytitle "BA Plot";
layout overlay;
scatterplot x=Period y=BA / group=Subject;
endlayout;
endgraph;
end;
run;
proc sgrender data=&outdata template=BAplot;
run;
/*NOT SUBMIT END*/
%mend BAplot;
处理为:
%macro BAplot(indata, var, outdata);
data _tmp1;
set &indata;
run;
proc sql noprint;
create table _tmp2 as select * from _tmp1;
quit;
data &outdata;
set _tmp2;
run;
%mend BAplot;
--macro-subs
选项用于替换 .sas
文件中宏变量,它应当是一个字典,形式为 {key=value,...}
,其键 key
为宏变量名称,值 value
为替换字符串。
例如,如果想将下面的代码块中的宏变量 &id
替换为 01
:
/*submit begin*/
data adeff;
set adeff.adeff&id;
run;
/*submit end*/
你需要指定 --macro-subs "{id=01}"
。
Tip
value
可以为空,例如 --macro-subs "{id=}"
,此时程序将会删除宏变量 &id
。
Warning
--macro-subs
不支持嵌套的宏变量,例如:&&id
,&&&id
等。
--encoding
选项指定 .sas
文件的编码格式。若未指定该选项,将尝试猜测最有可能的编码格式,并用于后续处理。
submit copyfile --convert-mode negative --encoding gbk
Note
本程序使用 chardet 进行编码格式的自动识别,但 chardet
会将 gbk
编码的文件错误地识别为 gb2312
编码。chardet/chardet#168
如果出现类似 UnicodeDecodeError:'gb2312'codec can't decode byte xfb in position 6436: illegal multibyte sequence
的错误提示,请尝试手动指定 --encoding gbk
。
子命令 copydir
用于处理包含 .sas
文件的目录,该命令将以递归的方式自动查找扩展名为 .sas
的文件并进行处理,非 .sas
文件将被忽略。
submit copydir "/source" "/dest"
--merge
选项指定将所有 .sas
文件进行转换后合并到单个 .txt
文件。
例如:
submit copydir "/source" "/dest" --merge "code.txt"
上述代码会将 /source
目录中的所有 .sas
文件转换成 .txt
文件,并将转换后的 .txt
文件合并到 /dest/code.txt
中。
Note
合并后的 .txt
文件包含源目录中所有需要递交的 sas 代码,使用注释 /*======
filename
.txt======*/
分隔来自不同 .sas
文件的代码。
其中 filename
是源目录中 .sas
文件名称(不含扩展名)。
Important
某些地方医疗器械监督管理局不接收压缩包作为递交文件,且递交文件数量存在限制,因此必须将所有 .sas
文件合并成一个单独的 .txt
文件。
--exclude-dirs
选项指定排除的目录列表,这些目录中的文件将会被跳过处理。该选项支持 glob
模式,详见 glob 模式介绍。
submit copydir "/source" "/dest" --exclude-dirs macro
可同时指定多个目录:
submit copydir "/source" "/dest" --exclude-dirs macro qc initial
上述命令将在目录名称匹配 macro
, qc
或 initial
时跳过处理其中的文件。
--exclude-files
选项指定排除的文件列表,这些文件将会被跳过处理。该选项支持 glob
模式,详见 glob 模式介绍。
submit copydir "/source" "/dest" --exclude-dirs macro --exclude-files fcmp.sas format.sas
上述命令将在目录名称匹配 macro
时跳过处理其中的文件,并在文件名称匹配 fcmp.sas
或 format.sas
(无论是否在 macro
目录中)时跳过处理。
glob
是一种使用通配符指定文件(目录)名称集合的模式,查看 wiki。
你可以在路径中使用以下特殊字符作为通配符:
*
: 匹配任意数量的非分隔符型字符,包括零个。例如,f*.sas
匹配f1.sas
、f2.sas
、f3.sas
等等。**
: 匹配任意数量的文件或目录分段,包括零个。例如,**/f*.sas
匹配figure/f1.sas
、figure/f2.sas
、figure/draft/f1.sas
等等。?
: 匹配一个不是分隔符的字符。例如,t1?.sas
匹配t1.sas
、t10.sas
、t11.sas
等等。[seq]
: 匹配在 seq 中的一个字符。例如,[tfl]1.sas
匹配t1.sas
、f1.sas
、l1.sas
。
更多语法请查看 模式语言。
假设有这样一个文件目录结构:
D:.
├─source
│ ├─f1.sas
│ ├─f2.sas
│ ├─f2-deprecated.sas
│ ├─f3.sas
│ ├─f3-deprecated.sas
│ ├─t1.sas
│ ├─t2.sas
│ ├─t2-deprecated.sas
│ ├─t2-deprecated-20241221.sas
│ ├─t3.sas
│ ├─t4.sas
│ ├─t5.sas
│ ├─t5-deprecated.sas
│ ├─t6.sas
│ ├─t7.sas
│ └─t7-deprecated.sas
└─dest
现在需要将 source
目录中的 .sas
文件转换为 .txt
文件,但忽略名称包含 deprecated
的文件。
如果不使用 glob
模式,命令应该是这样的:
submit copydir source dest --exclude-files "f2-deprecated.sas" "f3-deprecated.sas" "t2-deprecated.sas" "t2-deprecated-20241221.sas" "t5-deprecated.sas" "t7-deprecated.sas"
使用 glob
模式,命令得到简化:
submit copydir source dest --exclude-files "*deprecated*.sas"
usage: submit [options] copyfile [-h] [-c {positive,negative,both}] [--macro-subs MACRO_SUBS] [--encoding ENCODING] sas_file txt_file
positional arguments:
sas_file SAS 文件路径
txt_file TXT 文件路径
options:
-h, --help show this help message and exit
-c, --convert-mode {positive,negative,both}
转换模式(默认 both)
--macro-subs MACRO_SUBS
宏变量替换,格式为 {key=value,...}(默认无)
--encoding ENCODING 编码格式(默认自动检测)
usage: submit [options] copydir [-h] [-c {positive,negative,both}] [--macro-subs MACRO_SUBS] [--encoding ENCODING] [-mrg MERGE] [-exf [EXCLUDE_FILES ...]] [-exd [EXCLUDE_DIRS ...]] sas_dir txt_dir
positional arguments:
sas_dir SAS 文件目录
txt_dir TXT 文件目录
options:
-h, --help show this help message and exit
-c, --convert-mode {positive,negative,both}
转换模式(默认 both)
--macro-subs MACRO_SUBS
宏变量替换,格式为 {key=value,...}(默认无)
--encoding ENCODING 编码格式(默认自动检测)
-mrg, --merge MERGE 合并到一个文件(默认无)
-exf, --exclude-files [EXCLUDE_FILES ...]
排除文件列表(默认无)
-exd, --exclude-dirs [EXCLUDE_DIRS ...]
排除目录列表(默认无)
.bat
文件是一种批处理文件,你可以将多条 submit
命令保存在单个 .bat
文件中,这样只需双击这个文件即可批量处理 .sas
文件。
例如:
submit copydir "D:/project/code/adam" "D:/project/submit/adam"
submit copydir "D:/project/code/tfl" "D:/project/submit/tfl" --exclude-files merge.sas
submit copydir "D:/project/code/macro" "D:/project/submit/macro" --convert-mode negative
前置条件:
-
克隆仓库代码
git clone https://github.com/smjc-org/py-submit.git
-
安装依赖
uv sync
-
安装 pre-commit
pre-commit install pre-commit install --hook-type commit-msg
-
修改代码
-
测试代码
pytest
Note
执行 pytest
命令前需要先激活虚拟环境。
- 发起 pull request
Note
- 推荐使用 VSCode 编辑代码
- 需要使用 Conventional Commits 1.0.0 规范的提交信息