Skip to content

Latest commit

 

History

History
433 lines (309 loc) · 13.6 KB

README.md

File metadata and controls

433 lines (309 loc) · 13.6 KB

submit.py

requires-python version GitHub License uv Ruff Renovate enabled pytest codecov pre-commit.ci status

本程序用于从 .sas 文件中提取需要递交至监管机构的代码,并另存为 .txt 格式的文件。

安装

首先安装 PythonGit

然后使用 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 命令可以识别的特殊注释如下:

  • /*symbolsSUBMIT BEGINsymbols*/: 指定需要提交的代码的起始位置
  • /*symbolsSUBMIT ENDsymbols*/: 指定需要提交的代码的终止位置
  • /*symbolsNOT SUBMIT BEGINsymbols*/: 指定无需提交的代码的起始位置
  • /*symbolsNOT SUBMIT ENDsymbols*/: 指定无需提交的代码的终止位置

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;

处理单个 SAS 文件

子命令 copyfile 用于处理单个 .sas 文件。

submit copyfile "adae.sas" "adae.txt"
submit cpf "adae.sas" "adae.txt"

其中,adae.sas 是需要处理的 .sas 文件路径,adae.txt 是处理后保存的 .txt 文件路径。

Tip

  • cpfcopyfile 的别名(alias),大多数选项都具有别名,可通过 --help 命令查看。
  • 可以使用相对路径和绝对路径,使用相对路径时,以 submit 命令执行所在目录为根。 例如:在 /code 目录下处理子目录 /code/adam 中的 adae.sas 文件,应该执行 submit copyfile "adam/adae.sas" "submit/adae.txt",此时 adae.txt 文件将保存在 /code/submit 目录下。

--convert-mode

--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

--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

--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

处理多个 SAS 文件

子命令 copydir 用于处理包含 .sas 文件的目录,该命令将以递归的方式自动查找扩展名为 .sas 的文件并进行处理,非 .sas 文件将被忽略。

submit copydir "/source" "/dest"

--convert-mode

--convert-mode

--macro-subs

--macro-subs

--encoding

--encoding

--merge

--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

--exclude-dirs 选项指定排除的目录列表,这些目录中的文件将会被跳过处理。该选项支持 glob 模式,详见 glob 模式介绍

submit copydir "/source" "/dest" --exclude-dirs macro

可同时指定多个目录:

submit copydir "/source" "/dest" --exclude-dirs macro qc initial

上述命令将在目录名称匹配 macro, qcinitial 时跳过处理其中的文件。

--exclude-files

--exclude-files 选项指定排除的文件列表,这些文件将会被跳过处理。该选项支持 glob 模式,详见 glob 模式介绍

submit copydir "/source" "/dest" --exclude-dirs macro --exclude-files fcmp.sas format.sas

上述命令将在目录名称匹配 macro 时跳过处理其中的文件,并在文件名称匹配 fcmp.sasformat.sas (无论是否在 macro 目录中)时跳过处理。

glob 模式介绍

glob 是一种使用通配符指定文件(目录)名称集合的模式,查看 wiki

你可以在路径中使用以下特殊字符作为通配符:

  • *: 匹配任意数量的非分隔符型字符,包括零个。例如,f*.sas 匹配 f1.sasf2.sasf3.sas 等等。
  • **: 匹配任意数量的文件或目录分段,包括零个。例如,**/f*.sas 匹配 figure/f1.sasfigure/f2.sasfigure/draft/f1.sas 等等。
  • ?: 匹配一个不是分隔符的字符。例如,t1?.sas 匹配 t1.sast10.sast11.sas 等等。
  • [seq]: 匹配在 seq 中的一个字符。例如,[tfl]1.sas 匹配 t1.sasf1.sasl1.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"

命令行选项参考

submit copyfile

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   编码格式(默认自动检测)

submit copydir

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 脚本编写示例

.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

如何贡献

前置条件:

  1. 克隆仓库代码

    git clone https://github.com/smjc-org/py-submit.git
  2. 安装依赖

    uv sync
  3. 安装 pre-commit

    pre-commit install
    pre-commit install --hook-type commit-msg
  4. 修改代码

  5. 测试代码

    pytest

Note

执行 pytest 命令前需要先激活虚拟环境。

  1. 发起 pull request

Note

  1. 推荐使用 VSCode 编辑代码
  2. 需要使用 Conventional Commits 1.0.0 规范的提交信息