SQLObject 开发人员指南

以下是一些关于开发 SQLObject 的说明。

开发安装

首先安装 FormEncode

$ git clone git://github.com/formencode/formencode.git
$ cd formencode
$ sudo python setup.py develop

然后对 SQLObject 执行相同操作

$ git clone git clone git://github.com/sqlobject/sqlobject.git
$ cd sqlobject
$ sudo python setup.py develop

或者更确切地说,fork 它并克隆你的 fork。要开发一个功能或 bug 修复,请创建一个单独的分支,将其推送到你的 fork 并向原始仓库创建一个 pull 请求。这样,CI 将被触发以测试你的代码。

瞧!这些包已全局安装,但检出中的文件并未复制到 site-packages 中。有关更多信息,请参阅 setuptools

架构

SQLObject 中有三种主要类型的对象:表、列和连接。

与表相关联的对象位于 sqlobject/main.py 模块中。有两个主要类:SQLObjectsqlmeta;后者不是元类,而是每个类中 sqlmeta 属性的父类 - 作者尝试将所有与列无关的属性和方法移动到那里,以避免表命名空间混乱。

连接是 DBConnection 类(来自 sqlobject/dbconnection.py)及其具体子类的实例。 DBConnection 包含用于生成 SQL、处理事务等的通用代码。具体连接类(如 PostgresConnectionSQLiteConnection)提供后端特定的功能。

列、验证器和转换器

列是 sqlobject/col.py 中类的实例。每列有两个类:一个供用户包含在 SQLObject 实例中,另一个实例由 SQLObject 元类自动创建。这两个类通常命名为 ColSOCol;例如,BoolColSOBoolCol。用户可见类(Col 的子类)很少包含任何代码;列的主要代码在 SOCol 子类和验证器中。

每列都有一个验证器列表。验证器验证输入数据并将输入数据转换为 python 数据,然后再转换回来。每个验证器都必须有 from_pythonto_python 方法。前者将数据从 python 转换为内部表示,该表示将由转换器转换为 SQL 字符串。后者将数据从 SQL 数据转换为 python。另外请记住,验证器可以接收 None(对于 SQL NULL)和 SQLExpression(表示 SQLObject 表达式的对象);验证器必须原样传递这两个对象。

用户看不到 sqlobject/converters.py 中的转换器。它们在后台用于将验证器返回的对象转换为特定于后端的 SQL 字符串。最详细的转换器是 StringLikeConverter。是的,它将字符串转换为字符串。它使用特定于后端的引用规则将 python 字符串转换为 SQL 字符串。

我们以 BoolCol 为例进行探讨。真正的 BoolCol 没有任何代码。SOBoolCol 有一个创建 BoolValidator 的方法和创建特定于后端的列类型的方法。BoolValidator 有相同的方法 from_pythonto_python;该方法原样传递 NoneSQLExpression 和布尔值;int 和具有 __nonzero__ 方法(Python 3 中为 __bool__)的对象转换为布尔值;其他对象触发验证错误。由调用 from_python 返回的布尔值将由 BoolConverter 转换为 SQL 字符串;来自 to_python 的布尔值(假设它们通过 DB API 驱动程序源自后端)传递给应用程序。

from_python 返回的对象必须使用转换器进行注册。另一种 from_python 方法是返回具有 __sqlrepr__ 方法的对象。此类对象本身转换为 SQL 字符串,不使用转换器。

分支工作流

最初,SQLObject 使用 Subversion 进行开发。即使切换到 git,开发流程也仍然在一定程度上保留了旧的工作流。

在 git 中称为 mastertrunk 是最先进、最不稳定的分支。这是应用新功能的地方。错误修复应用于 oldstablestable 分支,并向上合并——从 oldstablestable,从 stablemaster

风格指南

一般来说,你应该遵循 PEP 8(Python 风格指南)中的建议。一些需要特别注意的事项

  • 除了少数例外,源代码必须是纯 ASCII。包括字符串文字和注释。
  • 除了少数例外,源代码必须是 flake8-clean(因此也是 pep8-clean)。请考虑使用通过运行 flake8 --install-hook 安装的预提交钩子。
  • 没有制表符。任何地方都没有。始终使用 4 个空格缩进。

  • 我们不会过分强调行长。但尽量通过使用括号而不是反斜杠(如果可以的话)对行进行分组来换行。像这样断言

    assert some_condition(a, b), (
        "Some condition failed, %r isn't right!" % a)
    
  • 但如果你在行长方面遇到问题,也许你应该将表达式拆分为多个语句。

  • 方法之间留空行,除非它们非常小且紧密相连。

  • 永远不要使用 condition and trueValue or falseValue 形式。将其拆分并使用变量。

  • 小心命名空间污染。SQLObject 允许 from sqlobject import *,因此名称应该相当独特,或者它们不应该在 sqlobject.__init__ 中导出。

  • 我们对空格非常挑剔。只有一种正确的方法。好的例子

    short = 3
    longerVar = 4
    
    if x == 4:
        do stuff
    
    func(arg1='a', arg2='b')
    func((a + b)*10)
    

    糟糕的例子

    short    =3
    longerVar=4
    
    if x==4: do stuff
    
    func(arg1 = 'a', arg2 = 'b')
    func(a,b)
    func( a, b )
    [ 1, 2, 3 ]
    

    对我们来说,空格使用不当似乎很懒惰。出于这个非常微不足道的理由,我们会降低你代码的评价(无论是否合理)。如果你自己不这样做,我们会为你修复所有代码,因为我们无法忍受杂乱的空格。

  • 使用 @@ 标记不理想的内容,或你担心不正确的内容。尝试同时注明日期并在此处放置你的用户名。

  • 文档字符串很好。它们应该看起来像

    class AClass(object):
        """
        doc string...
        """
    

    不要使用单引号 (‘’’)。不要费心尝试使字符串在垂直方向上更紧凑。

    虽然不是严格要求,但强烈建议使用 reStructuredText 格式的文档字符串。

  • 注释应紧挨在它们注释的内容之前。

  • 方法绝不要以大写字母开头。通常只有类才大写。但方法绝对不能大写。

  • 首选混合大小写。

  • 使用 cls 指代类。使用 meta 指代元类(它也是一个类,但将元类称为 cls 会令人困惑)。

  • 使用 isinstance 而不是比较类型。例如:

    if isinstance(var, str): ...
    # Bad:
    if type(var) is StringType: ...
    
  • 切勿使用两个前导下划线。这很烦人。如果名称冲突是一个问题,请改用名称混淆(例如,_SO_blahblah)。这与双下划线本质上是同一回事,只是双下划线模糊了透明度。

  • 模块名称在包中应唯一。子包不应与同级包或父包共享模块名称。遗憾的是,__init__ 无法做到这一点,但其他情况很容易做到。

  • 模块名称应全部小写,并且可能没有下划线(smushedwords)。

测试

测试很重要。测试可以防止一切崩溃。所有新添加的内容都应进行测试。

测试使用 pytest,它是 unittest 的替代方案。它可在 https://pytest.cn/https://pypi.ac.cn/project/pytest/ 获得。阅读其 入门 文档以了解更多信息。

要实际运行测试,你必须为其提供一个要连接的数据库。你可以使用选项 -D 来执行此操作。你可以提供一个完整的 URI 或几个快捷方式之一,例如 mysql(这些快捷方式在 tests/dbtest.py 的顶部定义)。

所有测试都是 sqlobject/tests 中的模块。每个模块或多或少地测试一种功能。如果你要测试一个模块,请将测试模块称为 tests/test_modulename.py - 只有以 test_ 开头的模块才会被 pytest 选中。

测试“框架”位于 tests/dbtest 中。有几个重要的函数

setupClass(soClass) 为该类创建表。它会尝试避免在不必要时重新创建表。

supports(featureName) 检查数据库后端是否支持命名的功能。哪些后端支持什么在 dbtest 的顶部定义。

如果您import *,您还将获得 pytest 版本的 raises,一个可以为您创建实例的 inserts 函数,以及一些其他函数。

如果您提交补丁或在没有测试的情况下实现功能,我们将被迫编写测试。对我们来说,仅仅编写测试并不好玩。所以请编写测试;即使测试非常完整,也至少需要对所有内容进行练习。

我们现在使用 Github Actions 来运行测试。

https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml/badge.svg?branch=github-actions

文档

请编写文档。文档应以 reStructuredText 格式保存在 docs/ 目录中。我们使用 Sphinx 将文档转换为 HTML。

贡献

Get SQLObject at SourceForge.net. Fast, secure and Free Open Source software downloads