Skip to main content

SARIF 工具

项目描述

萨里夫工具

一组用于处理 SARIF 文件的命令行工具和 Python 库。

在此处阅读有关 SARIF 格式的更多信息:https ://sarifweb.azurewebsites.net/

安装

先决条件

您需要安装 Python 3.8 或更高版本。从python.org获取。本文档假定该python命令运行该版本。

在 Windows 上安装

打开管理员命令提示符(开始 > 命令提示符 > 以管理员身份运行)并输入:

pip install sarif-tools

在 Linux 或 Mac 上安装

sudo pip install sarif-tools

测试安装

使用安装后pip,您应该能够运行:

sarif --version

安装故障排除

本节有一些建议,以防sarif安装后命令不可用。

在 Python 安装目录中创建一个名为sarifor的启动器。该目录需要位于 环境变量中,您才能在命令提示符下键入;如果在安装时以超级用户身份运行(例如 Windows 上的管理员命令提示符,或在 Linux 上使用) ,则很可能出现这种情况。sarif.exeScriptsScriptsPATHsarifpipsudo

如果该Scripts目录不在 中PATH,那么您需要键入python -m sarif而不是sarif运行该工具。

python当和pip上的命令PATH来自不同的安装,或者python超级用户上的安装与普通用户路径上的命令PATH不同时,可能会出现混淆。python在 Windows 上,您可以在普通 CMD 和 Admin CMD 中使用where pythonandwhere pip来查看正在使用的安装;在 Linux 上,它是which pythonwhich pip有和没有sudo.

命令行用法

usage: sarif [-h] [--version] [--debug] [--check {error,warning,note}] {blame,copy,csv,diff,html,info,ls,summary,trend,usage,word} ...

Process sets of SARIF files

positional arguments:
  {blame,copy,csv,diff,html,info,ls,summary,trend,usage,word}
                        command

optional arguments:
  -h, --help            show this help message and exit
  --version, -v         show program's version number and exit
  --debug               Print information useful for debugging
  --check {error,warning,note}, -x {error,warning,note}
                        Exit with error code if there are any issues of the specified level (or for diff, an increase in issues at that level).

commands:
blame    Enhance SARIF file with information from `git blame`
copy     Write a new SARIF file containing optionally-filtered data from other SARIF file(s)
csv      Write a CSV file listing the issues from the SARIF files(s) specified
diff     Find the difference between two [sets of] SARIF files
html     Write an HTML representation of SARIF file(s) for viewing in a web browser
info     Print information about SARIF file(s) structure
ls       List all SARIF files in the directories specified
summary  Write a text summary with the counts of issues from the SARIF files(s) specified
trend    Write a CSV file with time series data from SARIF files with "yyyymmddThhmmssZ" timestamps in their filenames
usage    (Command optional) - print usage and exit
word     Produce MS Word .docx summaries of the SARIF files specified
Run `sarif <COMMAND> --help` for command-specific help.

命令

假设输入文件位于以下位置,则命令如下所示:

  • C:\temp\sarif_files= 具有任意文件名的 SARIF 文件目录。
  • C:\temp\sarif_with_date= 包含时间戳的文件名的 SARIF 文件目录,例如C:\temp\sarif_with_date\myapp_devskim_output_20211001T012000Z.sarif.
  • C:\temp\old_sarif_files= 旧版本中具有任意文件名的 SARIF 文件目录。
  • C:\code\my_source_repo= 从中获得 SARIF 结果的源代码文件的检出目录。

责备

usage: sarif blame [-h] [--output PATH] [--code PATH] [file_or_dir [file_or_dir ...]]

Enhance SARIF file with information from `git blame`

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output PATH, -o PATH
                        Output file or directory
  --code PATH, -c PATH  Path to git repository; if not specified, the current working directory is used

使用信息扩充 SARIF 文件git blame,并将扩充后的文件写入指定位置。

sarif blame -o "C:\temp\sarif_files_with_blame_info" -c "C:\code\my_source_repo" "C:\temp\sarif_files"

如果当前工作目录是 git 仓库,则该-c参数可以省略。

有关添加到 SARIF 文件的责任信息的格式,请参阅下面的责任过滤。

复制

usage: sarif copy [-h] [--output FILE] [--blame-filter FILE] [--timestamp] [file_or_dir [file_or_dir ...]]

Write a new SARIF file containing optionally-filtered data from other SARIF file(s)

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file
  --blame-filter FILE, -b FILE
                        Specify the blame filter file to apply. See README for format.
  --timestamp, -t       Append current timestamp to output filename in the "yyyymmddThhmmssZ" format used by the `sarif trend` command

编写一个新的 SARIF 文件,其中包含来自现有 SARIF 文件或多个 SARIF 文件的可选过滤数据。生成的文件包含从原始 SARIF 文件连续运行的每次运行。可以过滤结果(请参阅下面的Blame 过滤),在这种情况下,仅包含原始 SARIF 文件中满足过滤器的结果;输出文件不包含有关排除记录的信息。如果原始文件中的一次运行为空,或者其所有结果都被过滤掉,则仍包括空运行。

如果未提供输出文件名,out.sarif则写入在当前目录中调用的文件。如果输出文件已经存在并且也在输入文件列表中,则不包含在输入中,以避免结果重复。输出文件在没有警告的情况下被覆盖。

说明file_or_dir符可以包括通配符,例如c:\temp\**\devskim*.sarif(即“glob”)。这适用于所有命令,但对于copy.

这样做的一个用途是将在构建过程中运行的多个静态分析工具中的一组 SARIF 文件组合成一个文件,该文件可以更容易地作为构建资产进行存储和处理。

CSV

usage: sarif csv [-h] [--output PATH] [--blame-filter FILE] [--autotrim] [--trim PREFIX] [file_or_dir [file_or_dir ...]]

Write a CSV file listing the issues from the SARIF files(s) specified

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output PATH, -o PATH
                        Output file or directory
  --blame-filter FILE, -b FILE
                        Specify the blame filter file to apply. See README for format.
  --autotrim, -a        Strip off the common prefix of paths in the CSV output
  --trim PREFIX         Prefix to strip from issue paths, e.g. the checkout directory on the build agent

从 [一组] SARIF 文件中写出一个简单的问题列表。然后可以对其进行分析,例如通过 Excel 中的数据透视表。

使用该--trim选项从路径中去除特定前缀,以使 CSV 不那么冗长。或者,用于--autotrim剥离最长的公共前缀。

生成单个 SARIF 文件的 CSV 摘要,并抑制公共文件路径前缀:

sarif csv "C:\temp\sarif_files\devskim_myapp.sarif"

生成包含路径前缀的 SARIF 文件目录的 CSV 摘要C:\code\my_source_repo

sarif csv --trim c:\code\my_source_repo "C:\temp\sarif_files"

有关如何使用该选项的信息,请参阅下面的责备过滤。--blame-filter

差异

usage: sarif diff [-h] [--output FILE] [--blame-filter FILE] old_file_or_dir new_file_or_dir

Find the difference between two [sets of] SARIF files

positional arguments:
  old_file_or_dir       An old SARIF file or a directory containing the old SARIF files
  new_file_or_dir       A new SARIF file or a directory containing the new SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file
  --blame-filter FILE, -b FILE
                        Specify the blame filter file to apply. See README for format.

打印两个 [set of] SARIF 文件之间的差异。

两个 SARIF 文件中的问题之间的区别:

sarif diff "C:\temp\old_sarif_files\devskim_myapp.sarif" "C:\temp\sarif_files\devskim_myapp.sarif"

SARIF文件的两个目录中的问题之间的区别:

sarif diff "C:\temp\old_sarif_files" "C:\temp\sarif_files"

将输出写入 JSON 文件而不是打印到标准输出:

sarif diff -o mydiff.json "C:\temp\old_sarif_files\devskim_myapp.sarif" "C:\temp\sarif_files\devskim_myapp.sarif"

有关如何使用该选项的信息,请参阅下面的责备过滤。--blame-filter

html

usage: sarif html [-h] [--output PATH] [--blame-filter FILE] [--no-autotrim] [--image IMAGE] [--trim PREFIX] [file_or_dir [file_or_dir ...]]

Write an HTML representation of SARIF file(s) for viewing in a web browser

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output PATH, -o PATH
                        Output file or directory
  --blame-filter FILE, -b FILE
                        Specify the blame filter file to apply. See README for format.
  --no-autotrim, -n     Do not strip off the common prefix of paths in the output document
  --image IMAGE         Image to include at top of file - SARIF logo by default
  --trim PREFIX         Prefix to strip from issue paths, e.g. the checkout directory on the build agent

创建一个总结 SARIF 结果的 HTML 文件。

sarif html -o summary.html "C:\temp\sarif_files"

使用--trim从路径中去除特定前缀的选项,以减少生成的 HTML 页面的冗长。--no-autotrim除非指定,否则将修剪路径的最长公共前缀。

使用该--image选项为 HTML 页面的顶部提供标题图像。图像嵌入到 HTML 中,因此 HTML 文档仍然是可移植的独立文件。

有关如何使用该选项的信息,请参阅下面的责备过滤。--blame-filter

信息

usage: sarif info [-h] [--output FILE] [file_or_dir [file_or_dir ...]]

Print information about SARIF file(s) structure

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file

打印有关 SARIF 文件或多个文件的结构的信息。这是关于 JSON 结构,而不是工具产生的结果的任何含义。摘要包括文件的完整路径、文件大小和修改日期、运行次数以及每次运行的生成运行的工具、结果的数量以及结果属性包中的条目。

c:\temp\sarif_files\ios_devskim_output.sarif
  1256241 bytes (1.2 MiB)
  modified: 2021-10-13 21:50:01.251544, accessed: 2022-01-09 18:23:00.060573, ctime: 2021-10-13 20:49:00
  1 run
    Tool: devskim
    1323 results
    All results have properties: tags, DevSkimSeverity

ls

usage: sarif ls [-h] [--output FILE] [file_or_dir [file_or_dir ...]]

List all SARIF files in the directories specified

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file

列出一个或多个目录中的 SARIF 文件。

sarif ls "C:\temp\sarif_files" "C:\temp\sarif_with_date"

概括

usage: sarif ls [-h] [--output FILE] [file_or_dir [file_or_dir ...]]

List all SARIF files in the directories specified

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file

打印一个或多个 SARIF 文件中的问题摘要,按严重性分组,然后按出现次数排序。

当提供目录作为输入和输出时,会为每个输入文件编写摘要,以及包含总计的另一个文件。

sarif summary -o summaries "C:\temp\sarif_files"

如果未指定输出目录或文件,则将整体摘要打印到标准输出。

sarif summary "C:\temp\sarif_files\devskim_myapp.sarif"

有关如何使用该选项的信息,请参阅下面的责备过滤。--blame-filter

趋势

usage: sarif trend [-h] [--output FILE] [--blame-filter FILE] [--dateformat {dmy,mdy,ymd}] [file_or_dir [file_or_dir ...]]

Write a CSV file with time series data from SARIF files with "yyyymmddThhmmssZ" timestamps in their filenames

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file
  --blame-filter FILE, -b FILE
                        Specify the blame filter file to apply. See README for format.
  --dateformat {dmy,mdy,ymd}, -f {dmy,mdy,ymd}
                        Date component order to use in output CSV. Default is `dmy`

生成一个 CSV,显示来自目录中的一组 SARIF 文件的问题时间线。SARIF 文件名必须包含特定格式的时间戳,yyyymmddThhhmmss例如20211012T110000Z.

CSV 可以加载到 Microsoft Excel 中以进行图形和趋势分析。

sarif trend -o timeline.csv "C:\temp\sarif_with_date" --dateformat dmy

有关如何使用该选项的信息,请参阅下面的责备过滤。--blame-filter

用法

usage: sarif usage [-h] [--output FILE]

(Command optional) - print usage and exit

optional arguments:
  -h, --help            show this help message and exit
  --output FILE, -o FILE
                        Output file

打印使用并退出。

单词

usage: sarif word [-h] [--output PATH] [--blame-filter FILE] [--no-autotrim] [--image IMAGE] [--trim PREFIX] [file_or_dir [file_or_dir ...]]

Produce MS Word .docx summaries of the SARIF files specified

positional arguments:
  file_or_dir           A SARIF file or a directory containing SARIF files

optional arguments:
  -h, --help            show this help message and exit
  --output PATH, -o PATH
                        Output file or directory
  --blame-filter FILE, -b FILE
                        Specify the blame filter file to apply. See README for format.
  --no-autotrim, -n     Do not strip off the common prefix of paths in the output document
  --image IMAGE         Image to include at top of file - SARIF logo by default
  --trim PREFIX         Prefix to strip from issue paths, e.g. the checkout directory on the build agent

创建代表一个 SARIF 文件或多个 SARIF 文件的 Word 文档。

如果为-o选项和输入提供目录,则为每个单独的 SARIF 文件和完整的 SARIF 文件集生成一个 Word 文档。否则,将创建一个 Word 文档。

在目录中为每个 SARIF 文件创建一个 Word 文档,并为所有这些文件创建一个 Word 文档reports(如果不存在则创建):

sarif word -o reports "C:\temp\sarif_files"

为单个 SARIF 文件创建 Word 文档:

sarif word -o "reports\devskim_myapp.docx" "C:\temp\sarif_files\devskim_myapp.sarif"

使用--trim从路径中去除特定前缀的选项,以使生成的文档不那么冗长。--no-autotrim除非指定,否则将修剪路径的最长公共前缀。

使用该--image选项为 Word 文档的顶部提供标题图像。

有关如何使用该选项的信息,请参阅下面的责备过滤。--blame-filter

过错过滤

使用该sarif blame命令来增加一个 SARIF 文件或多个带有责备信息的 SARIF 文件。

责任信息被添加到每个result成功获得的对象的属性包中。使用的键和值与git blame瓷器格式相同。例如:

{
  "ruleId": "SM00702",
  ...
  "properties": {
    "blame": {
      "author": "aperson",
      "author-mail": "<aperson@acompany.com>",
      "author-time": "1350899798",
      "author-tz": "+0000",
      "committer": "aperson",
      "committer-mail": "<aperson@acompany.com>",
      "committer-time": "1350899798",
      "committer-tz": "+0000",
      "summary": "blah blah commit comment blah",
      "boundary": true,
      "filename": "src/net/myproject/mypackage/MyClass.java"
    }
  }
}

请注意,裸boundary键被赋予自动值true

--blame-filter然后可以通过可用于各种命令的选项,将这些责备数据用于过滤和汇总。此选项需要过滤器列表文件的路径,其中包含模式和子字符串列表以匹配责备信息作者电子邮件。过滤器列表文件的格式如下:

# Lines beginning with # are interpreted as comments and ignored.
# A line beginning with "description: " is interpreted as an optional description for the filter.  If no title is specified, the filter file name is used.
description: Example filter from README.md
# Lines beginning with "+: " are interpreted as inclusion substrings.  E.g. the following line includes issues whose author-mail field contains "@microsoft.com".
+: @microsoft.com
# The "+: " can be omitted.
@microsoft.com
# Instead of a substring, a regular expression can be used, enclosed in "/" characters.  Issues whose author-mail field includes a string matching the regular expression are included.  Use ^ and $ to match the whole author-mail field.
+: /^<myname.*\.com>$/
# Again, the "+: " can be omitted for a regular expression include pattern.
/^<myname.*\.com>$/
# Lines beginning with "-: " are interpreted as exclusion substrings.  E.g. the following line excludes issues whose author-mail field contains "bot@microsoft.com".
-: bot@microsoft.com
# Instead of a substring, a regular expression can be used, enclosed in "/" characters.  Issues whose author-mail field includes a string matching the regular expression are excluded.  Use ^ and $ to match the whole author-mail field.  E.g. the following pattern excludes all issues whose author-mail field contains a GUID.
-: /[0-9A-F]{8}[-][0-9A-F]{4}[-][0-9A-F]{4}[-][0-9A-F]{4}[-][0-9A-F]{12}/

这是一个过滤器文件示例,其中包含由@microsoft.com电子邮件地址或myname.SOMETHING.com电子邮件地址更改的行上的问题,但如果这些电子邮件地址以 GUID 结尾bot@microsoft.com或包含 GUID,则不包含问题。和上面的例子一样,只是去掉了注释。

description: Example filter from README.md
+: @microsoft.com
+: /^<myname.*\.com>$/
-: bot@microsoft.com
-: /[0-9A-F]{8}[-][0-9A-F]{4}[-][0-9A-F]{4}[-][0-9A-F]{4}[-][0-9A-F]{12}/

所有匹配都不区分大小写,因为电子邮件地址是。行首和行尾的空格被忽略,这也意味着行尾字符无关紧要。blame 过滤器文件必须是 UTF-8 编码的(包括纯 ASCII7)。它可以有或没有字节顺序标记。

如果没有包含模式,则包含所有问题,但匹配排除模式的问题除外。如果存在包含模式,则仅包含与包含模式匹配的问题。如果问题与一种或多种包含模式以及至少一种排除模式匹配,则将其排除。

有时,SARIF 文件中可能存在无法应用过滤器的问题,因为没有可用的责备信息。这可能有两个原因:或者没有为发生问题的文件记录责任信息,或者问题位置缺少行号(或指定行号 1 作为占位符),因此无法将责任信息与问题。默认情况下包含这些问题。要确定这些是哪些问题,请创建一个过滤器文件,其中排除可以应用过滤器的所有内容:

description: Exclude everything filterable
-: /.*/

然后使用此过滤器文件运行sarif命令--blame-filter以查看默认包含的问题。

用作 Python 库

尽管不是其主要目的,但您可以使用 Python 脚本或模块中的 sarif-tools 来加载和汇总 SARIF 结果。

基本使用模式

安装后,使用sarif.loader加载一个或多个 SARIF 文件,然后使用对返回的SarifFileSarifFileSet对象的操作来探索数据。

from sarif import loader

sarif_data = loader.load_sarif_file(path_to_sarif_file)
issue_count_by_severity = sarif_data.get_result_count_by_severity()
error_histogram = sarif_data.get_issue_code_histogram("error")

结果访问接口

sarif_files模块中定义的三个类SarifFileSetSarifFileSarifRun,提供了类似的 API,允许在多个聚合级别上类似地处理 SARIF 结果。本节简要介绍三个聚合级别的一些关键 API。

get_distinct_tool_names()

返回 aSarifFile或 a 中所有文件的不同工具名称列表SarifFileSet。ASarifRun有一个工具名称,因此等效方法是get_tool_name()

获取结果()

返回 SARIF 结果列表。这些是SARIF 标准第 3.27 节中定义的对象 。

获取记录()

将 SARIF 结果列表返回为简化的扁平记录字典。每条记录都有在 中定义的属性sarif_file.RECORD_ATTRIBUTES

  • "Tool"- 包含结果的运行的工具名称。
  • "Severity"- 用于记录的 SARIF 严重性。之一(如果记录未指定,则为默认值)error或.warningnote
  • "Code"- 结果中的问题代码。
  • "Location"- 问题的位置,通常是包含问题的文件。格式因工具而异。
  • "Line"- 出现问题的文件中的行号。值是一个字符串。这默认为"1"如果工具未能识别线。

get_records_grouped_by_severity()

按照get_records(),但结果是从 SARIF 严重级别(errorwarningnote到该严重级别的记录列表的字典。

get_result_count(), get_result_count_by_severity()

获取 SARIF 结果的总数。 get_result_count_by_severity()从 SARIF 严重性级别 ( error,warningnote) 返回一个字典到该严重性的整数个结果。

get_issue_code_histogram(严重性)

对于给定的严重性,以对列表的形式获取直方图。每对中的第一项是问题代码,第二项是匹配记录的数量,列表按频率降序排列(与sarif summary命令输出相同)。

分解和文件名访问

这些字段和方法允许访问有关 SARIF 文件的基础信息。

  • SarifFileSet.subdirs-SarifFileSet对应SarifFileSet于创建目录的子目录的对象列表。
  • SarifFileSet.files-SarifFile对应于包含在从中SarifFileSet创建的目录中的 SARIF 文件的对象列表。
  • SarifFile.get_abs_file_path()- 获取 SARIF 文件的绝对路径。
  • SarifFile.get_file_name()- 获取 SARIF 文件的名称。
  • SarifFile.get_file_name_without_extension()- 获取不带扩展名的 SARIF 文件的名称。用于构造派生文件名。
  • SarifFile.get_filename_timestamp()- 从 SARIF 文件的文件名中提取时间戳,并将其作为字符串返回。时间戳必须采用sarif trend 命令中指定的格式。
  • SarifFile.runs-SarifRun包含在 SARIF 文件中的对象列表。大多数 SARIF 文件只包含一个运行,但可以将多个工具的运行聚合到一个 SARIF 文件中。

路径缩短 API

调用或对象init_path_prefix_stripping(autotrim, path_prefixes)来设置路径过滤,自动删除最长的公共前缀 ( )或删除特定前缀(以及 中的字符串列表)。SarifFileSetSarifFileSarifRunautotrim=Trueautotrim=Falsepath_prefixes

过错过滤API

调用init_blame_filter(filter_description, include_substrings, include_regexes, exclude_substrings, exclude_regexes),SarifFileSetSarifFile对象SarifRun来设置责备过滤。 filter_description是一个字符串,其他参数是字符串列表(/正则表达式周围没有字符)。它们以一种明显的方式对应于上述Blame 过滤中描述的过滤文件内容。

get_filter_stats()从 sarif 文件中读取结果或记录后调用以检索过滤器统计信息。None如果没有过滤器,则返回,否则返回sarif_file.FilterStats具有整数字段filtered_in_result_countfiltered_out_result_countmissing_blame_count的对象unconvincing_line_number_count。调用对象以获得这些统计信息to_string()FilterStats可读表示,其中还包括过滤器文件名或描述(filter_description字段)。

CI 管道中的建议用法

--check如果存在指定级别或更高级别的任何问题,则将选项与命令结合使用会summary导致 sarif-tools 以非零退出代码退出。在违反 SAST 的情况下,这对于使持续集成 (CI) 管道失败很有用。

SARIF 问题级别为error和。这些都是该选项的有效 选项。warningnote--check

例如,如果有任何错误或警告失败:

sarif --check warning summary c:\temp\sarif_files

diff命令可以检查指定级别或更高级别的问题相对于先前或基线构建的任何增加。

例如,如果在错误级别有任何新问题代码,则失败:

sarif --check error diff c:\temp\old_sarif_files c:\temp\sarif_files

您还可以使用 sarif-tools 过滤和合并多个工具的输出。例如

# First run your static analysis tools, configured to write SARIF output.  How to do that depends
# the tool.

# Now run the blame command to augment the output with blame information.
sarif blame -o with_blame/myapp_mytool_with_blame.sarif myapp_mytool.sarif

# Now combine all tools' output into a single file
sarif copy --timestamp -o artifacts/myapp_alltools_with_blame.sarif

下载myapp_alltools_with_blame_TIMESTAMP.sarif生成的文件。然后,您可以使用--blame-filter参数过滤结果,或者使用sarif trend.

学分

sarif-tools 最初由 Simon Abykov、Nick Brabbs、Anthony Hayward、Sivaji Kondapalli、Matt Parkes 和 Kathryn Pentland 在 2021 年微软全球黑客马拉松期间开发。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

sarif-tools-1.0.0.tar.gz (41.4 kB 查看哈希

已上传 source

内置分布

sarif_tools-1.0.0-py3-none-any.whl (39.7 kB 查看哈希

已上传 py3