跳转到主要内容

一个用于在Python环境中构建与Node.js生态系统交互的工具链和实用程序的Python框架。

项目描述

calmjs

一个用于在Python环境中构建与Node.js生态系统交互的工具链和实用程序的Python框架。

https://github.com/calmjs/calmjs/actions/workflows/build.yml/badge.svg?branch=3.4.4 https://ci.appveyor.com/api/projects/status/45054tm9cfk7ryam/branch/3.4.4?svg=true https://coveralls.io/repos/github/calmjs/calmjs/badge.svg?branch=3.4.4

简介

Calmjs定义了一个可扩展的框架,用于Python和Node.js运行时之间的互操作性,为Python包的开发者提供一个定义良好的接口,以便在Node.js/JavaScript开发工具和Python包内部的JavaScript代码之间进行双向访问,从而可以从Python环境促进与Node.js/JavaScript环境的适当、正式集成。Calmjs框架的目标是帮助开发、测试和部署包含和/或集成外部JavaScript代码的Python包。

方法

首先,这是通过提供Python包声明对Node.js/JavaScript包或源文件依赖的能力来实现的,这些包或源文件是完成其功能所必需的。这个通用框架将确保这些元数据在通用协议下可访问,以避免不兼容的声明,这些声明在不同项目和环境中不可移植,或者被分散在不同的工具或位置,或者在同一个工作环境中被不同工具集重复。如果没有通用框架,结果就是Python包之间无法正确地沟通它们的非Python需求状态,导致软件堆栈构建、开发和部署困难,或者成为这些过程的错误来源。

其次,通过提供一套基于此可扩展框架的工具,以处理这些声明以生成所需Node.js工具的配置文件,从而构建所需的功能构建和/或运行时环境。

最终,这允许更好的Node.js与特定Python环境集成,降低在可重复方式下与Node.js/JavaScript包一起实现Python包持续集成和/或交付所需的努力。

实现

为了实现这一点,Calmjs框架提供了一组扩展,用于辅助跟踪和管理给定Python包的基于JavaScript或Node.js的包(如通过npm)的依赖项。它还提供了一些基类,可用于构建自定义工具链,以实现将所需JavaScript代码和相关资产编译到应用服务器可能使用的部署工件的不同策略,或者生成测试工具,以确保在开发和生产环境下的正确性。这些额外功能将由其他Python包在calmjs命名空间下提供,以实现这种模块化架构。

Calmjs这个名字最初来源于工具链第一迭代中的步骤,这些步骤涉及使用宿主Python包的命名空间将编译、汇编和链接步骤编译成一个JavaScript模块。标志中的“m”是兔子的耳朵。选择这种动物作为项目的吉祥物是因为它们的饮食习惯,这与JavaScript代码通常通过其他工具和框架转换为最少可用级别类似。

功能概述

与基于Node.js的包管理器集成的框架

通过setuptools命令钩子,calmjs为Python包提供了声明和管理基于Node.js的包管理系统的清单定义文件(例如,如用于npmpackage.json)。在典型使用情况下,这意味着可以跟踪所需Python包需要的JavaScript包的dependenciesdevDependencies的声明,所有这些都在setuptools框架内通过calmjs提供的扩展来实现。

该基础设施的另一部分是,这些声明遵循Python包依赖图。开发者和用户可以使用calmjs控制台命令入口点,或通过setuptools,生成一个清单文件,以促进在完成的应用堆栈中安装由Python包需要的Node.js包,为所有现有包量身定制。

calmjs默认包含对npmyarn的集成支持。

使用相同的命名空间从Python包导出JavaScript代码

一个包含相关JavaScript源代码的Python包,这些源代码位于同一Python模块和命名空间结构中,并且与源树中的Python源代码并行,能够通过setuptools入口点将这些命名空间声明为同一Python包命名空间下JavaScript模块的根。

这些声明将通过calmjs模块注册系统公开的注册表提供,其他包可以通过框架提供的API将声明转换为遵循相同声明模块和命名空间结构的可执行JavaScript代码。默认模块注册表将使用/字符(而不是Python中的.字符)作为名称的分隔符,这是由于JavaScript(以及未来的ES6)中确立的命名约定。

其他与Calmjs框架一起工作的工具可以使用这些原始JavaScript源文件,结合本地Node.js环境,或生成用于网络部署的工件。这导致...

JavaScript工具链与Python环境的更好集成

这是通过提供一个构建用于在Node.js/JavaScript环境中使用JavaScript编写的工具的工具链的框架来实现的,该工具链可以与现有的Python包和环境正确集成。

对于工具或源文件可以如何使用或做什么,没有限制,因为这被留作实现细节。例如,请参考calmjs.rjs Python包,它允许从Python包内嵌入的JavaScript包生成AMD(异步模块定义)工件,或者calmjs.webpack,它用于与webpack集成,以生成另一种常用的打包工件格式。

通常,可以构建工具链来查找和加载所有具有JavaScript源文件的Python包(通过calmjs注册系统),这些包将被提取,并经过适当的转换器(如果有)以构建可部署的工件。测试框架可以设置以帮助运行单元测试、功能测试,以及当然是为成功部署所需的最终集成测试。

定义良好的模块化架构,确保代码重用和可扩展性

到目前为止描述的功能是建立在通用类和模块的基础上的,因此,支持额外的JavaScript工具或自定义转换处理过程可以简单到为几个类创建一个新模块,并带有相关的setuptools入口点。

实际上,calmjs默认仅包含核心框架以及npm/yarn接口部分,对Bowerr.js的支持作为完全独立的包(分别是calmjs.bowercalmjs.rjs),因此,不需要那些包提供的功能的项目、环境或站点可以简单地选择不安装它们。

安装

由于calmjs的目标是将Node.js和npm(或yarn)集成到Python环境中,它们需要在环境中可用;如果尚未安装,请按照针对目标操作系统/环境/平台适当的Node.js安装步骤进行安装。

要将calmjs安装到特定的Python环境中,可以使用以下命令直接从PyPI进行安装:

$ pip install calmjs

替代安装方法(针对开发者,高级用户)

calmjs的开发仍在进行中,要获取最新功能和错误修复,可以通过git安装开发版本,如下所示:

$ # standard installation mode
$ pip install git+https://github.com/calmjs/calmjs.git#egg=calmjs
$ # for an editable installation mode; note the upgrade flag
$ pip install -U -e git+https://github.com/calmjs/calmjs.git#egg=calmjs

请注意,可编辑安装的-U标志是为了确保setuptools升级到最新版本,以避免处理开发包命名空间时出现的问题,这些问题在下一段中进行了说明。

或者,可以直接克隆git仓库,并在源目录的根目录下执行python setup.py develop。但是,如果使用版本早于v31的任何版本的setuptools进行此开发安装方法,那么在calmjs命名空间下导入模块时将出现不一致的错误。在本文档的故障排除部分记录了命名空间导入失败的症状

测试安装

为确保calmjs安装正常工作,可以通过以下方式执行内置测试套件:

$ python -m unittest calmjs.tests.make_suite

如果出现失败,请在问题跟踪器上提交问题,并提供完整的跟踪信息以及安装方法。请记住,还应该包括平台特定信息,例如Python版本、操作系统环境和版本以及与问题相关的其他信息。

用法和关键功能描述

当安装到特定的Python环境中时,calmjs命令行实用程序将可用。

$ calmjs
usage: calmjs [-h] [-d] [-q] [-v] [-V] <command> ...

positional arguments:
  <command>
    artifact     helpers for the management of artifacts
    npm          npm support for the calmjs framework
    yarn         yarn support for the calmjs framework

optional arguments:
  -h, --help     show this help message and exit

global options:
  -d, --debug    show traceback on error; twice for post_mortem
                 '--debugger' when execution cannot continue
  -q, --quiet    be more quiet
  -v, --verbose  be more verbose
  -V, --version  print version information

如前所述,npm支持是内置的,因此始终可用;要访问其帮助,只需执行calmjs npm -h,这将列出特定子命令的可用选项。如果其他子命令可用(这些子命令将由其他calmjs集成包提供),它们将列出为<command>,并且可以通过相同的方式访问它们的具体帮助信息。

为特定的Python包声明一个package.json

如果希望声明对由npm托管的包的依赖关系,则可以在其setup.py中这样做:

from setuptools import setup

package_json = {
    "dependencies": {
        "jquery": "~3.0.0",
        "underscore": "~1.8.0",
    }
}

setup(
    name='example.package',
    # ...
    setup_requires=[
        'calmjs',
        # plus other setup_requires ...
    ],
    package_json=package_json,
    # ...
)

请注意,必须指定calmjs以启用package_json设置关键字,以便在执行python setup.py egg_info(直接或间接)时为给定的包生成package.json元数据文件,即使calmjs尚未安装到当前的Python环境中,它也将从PyPI获取并包含在setuptools设置过程的一部分,而不成为给定包的直接依赖项。如果提供的数据是有效的JSON字符串或字典(不包含不兼容的数据类型),则将生成package.json。例如:

$ python setup.py egg_info
running egg_info
writing package_json to example.package.egg-info/package.json
...
$ cat example.package.egg-info/package.json
{
    "dependencies": {
        "jquery": "~3.0.0",
        "underscore": "~1.8.0"
    }
}

使用 setup_requires 的关键原因是不强迫特定软件包的依赖项将 calmjs 作为它们依赖的一部分,因为通常这仅是开发者的需求,而不是最终用户的需求。这也意味着,对于想要使用 calmjs 和实用工具的开发者,他们必须单独安装(即 pip install calmjs),或者通过使用 extras_require 标志将 calmjs 声明为开发依赖,例如

setup(
    name='example.package',
    # ...
    setup_requires=[
        'calmjs',
        # ...
    ],
    extras_require={
        'dev': [
            'calmjs',
            # ... plus other development dependencies
        ],
    },
    # ...
)

然后完全安装该软件包作为具有 dev 额外功能的可编辑软件包

$ pip install -e .[dev]
Obtaining file://example/package
...
Installing collected packages: ..., calmjs, ...
  Running setup.py develop for example.package
Successfully installed ...

请注意,现在 calmjs 软件包仍然安装在 Python 环境中,它们提供的实用工具现在可以使用,以下章节将涵盖这些内容。

在 Python 软件包依赖项中跨使用 package.json

当将 package.json 文件写入软件包元数据目录后,实用工具如 calmjs 将会利用它。实现这一点的其中一种方法是通过该软件包的 setup.py。通过从该文件调用 setup.py npm --init,将创建一个新的 package.json,并结合给定软件包的 Python 软件包依赖项中声明的所有 dependenciesdevDependencies,然后将它们写入当前目录。这与运行 npm init 相似,区别在于依赖项也是通过给定 Python 软件包的 Python 软件包依赖树进行解析的。

请注意,这需要给定软件包的 package.json 创建和处理能力(请参考前面的章节了解如何实现这一点),并且所有依赖项都必须正确安装并且可以从当前 Python 环境中导入。

或者,可以使用 calmjs npm 实用工具。在命令行中调用 calmjs npm --init example.package 将实现相同的效果,无论在文件系统的哪个位置,前提是 calmjsexample.package 都已安装并通过当前 Python 环境的导入系统可用。有关此实用工具的更多详细信息,请参阅通过 calmjs npmnpm 集成部分。

处理具有 Python 软件包依赖项的 npm 依赖项

扁平化优于嵌套。因此,任何上游 Python 软件包声明的所有 dependencies(和 devDependencies)都将自动继承所有其下游软件包,但它们可以选择通过上述机制用任何它们想要的来覆盖它。他们可以设置 JavaScript 或 Node.js 软件包的所需版本,甚至可以将该依赖项完全删除,只需将版本设置为 None

每当 calmjs 需要实际的 package.json 时,calmjs npm 实用工具将所有 Python 软件包需要的 Node.js 依赖项扁平化到一个文件中,然后将其传递给相应的 JavaScript 软件包管理器进行处理。此过程也是当 calmjs 工具链或实用工具使用这些声明信息生成所需的工件以完成当前任务时进行的。

当然,如果希望包和依赖的嵌套风格与npm相同,没有人会强制使用这种方式,他们可以自由使用任何工具来解释或使用可用的数据文件和依赖项,也可以将包拆分为Python和JavaScript部分,并分别部署和托管在PyPI(用于pip)和npm上,然后想出如何以连贯的方式将它们组合在一起。不要询问(或与)作者关于后一种方式对所有人(开发者、系统集成人员和最终用户)来说更好或更简单。

node_modules内部声明明确的依赖路径

鉴于对从npm获取的特定版本的包的依赖关系被明确指定,构建工具将再次从对这些包所需文件的确切声明中受益。具体来说,编译后的包可以在JSON字符串的extras_calmjs部分声明,类似于package_json,如下所示

extras_calmjs = {
    'node_modules': {
        'jquery': 'jquery/dist/jquery.js',
        'underscore': 'underscore/underscore.js',
    },
}

setup(
    name='example.package',
    ...
    extras_calmjs=extras_calmjs,
    ...
)

由于node_modules被声明为extras_key,环境内包之间的冲突声明将以与package_json中声明的依赖项冲突相同的方式进行解析和合并。

请注意,必须声明完整的路径名称(注意示例中包括.js文件名后缀);也可以声明目录。然而,由于这些声明是在Python内部进行的,因此需要显式完整路径,因此下游集成包必须正确处理和/或将这些转换为标准Node.js工具可能期望的约定(即省略.js文件名后缀)。

从Python包导出JavaScript代码

在先前的示例中进一步,如果example.package内部文件和目录布局如下

.
├── example
│   ├── __init__.py
│   └── package
│       ├── __init__.py
│       ├── content.py
│       ├── form.py
│       ├── ui.js
│       ├── ui.py
│       └── widget.js
└── setup.py

为了通过calmjs./example/package内的JavaScript源文件声明为JavaScript模块,可以在setup.py文件中声明如下入口点

setup(
    ...
    entry_points="""
    ...
    [calmjs.module]
    example.package = example.package
    """,
    ...
)

请注意,入口点的名称无关紧要;该入口点名称被忽略,因为默认模块注册表的目的是提供一个模块名称,该名称直接映射到与源Python模块相同的导入命名空间,但使用ES5命名空间分隔符/,而不是Python中的.字符。如果需要显式映射,可以定义一个新的模块注册表类,该类使用提供的名称作为JavaScript代码中的CommonJS导入名称。

默认方法将公开以下名称的两个源文件

- 'example/package/ui'
- 'example/package/widget'

对于某些项目,可能不希望允许此自动化方法从给定的Python模块中提取所有可用的JavaScript源文件。

为了解决这个问题,可以通过Calmjs框架声明新的模块注册表。只要正确设置了ModuleRegistry子类以从给定的包生成所需的模块,只需像这样声明为calmjs.registry入口点

setup(
    ...
    entry_points="""
    ...
    [calmjs.registry]
    example.module = example.package.registry:ExampleModuleRegistry
    """,
    ...
)

请注意,尽管对入口点名称的允许范围相当不受限制,但这些注册表名称应采用标准点分隔命名空间格式,以确保最大程度的工具兼容性,因为这些可以通过使用此系统的工具在命令行中指定。

一旦声明了注册表,只需将calmjs.module替换为该名称,并添加一个具有calmjs_module_registry属性的example.module注册表,该属性声明此注册表是该包的默认注册表。

setup(
    ...
    calmjs_module_registry=['example.package'],
    entry_points="""
    ...
    [example.module]
    example.package = example.package
    """,
    ...
)

在Calmjs框架中,可以明确指定工具来捕获框架注册的所有或任何模块注册表中的模块。还定义了另一个注册表。如果入口点是这样声明的

setup(
    ...
    entry_points="""
    ...
    [calmjs.py.module]
    example.package = example.package
    """,
    ...
)

命名空间和模块的分隔符将使用.字符而不是/字符。然而,由于.字符是JavaScript模块的有效名称,这种用法可能与其他JavaScript工具产生问题。虽然基于AMD的模块系统通常可以无问题地处理导入中的.字符,允许在JavaScript环境中使用点命名进行类似Python的导入,但这可能会导致与其他JavaScript库不兼容,因此不建议使用这种命名方案。

默认情况下,还声明了另一个具有.tests后缀的注册表,作为之前引入的注册表的补充,这些注册表可以供软件包使用来声明与已声明的模块一起提供的JavaScript测试代码。例如

setup(
    ...
    entry_points="""
    ...
    [calmjs.module]
    example.package = example.package

    [calmjs.module.tests]
    example.package.tests = example.package.tests
    """,
    ...
)

与第一个例子类似,这声明了example.package作为一个导出JavaScript代码的Python命名空间模块,后续的声明部分是包含与第一个模块一起提供的测试的模块。

向加载器提供伴随的资源文件

某些Node.js构建工具和框架支持通过相同的导入/导入系统为JavaScript模块之外的资源文件提供“加载器”的概念。为了为包创建者提供最基本的支持,以减轻将其他资源文件公开给Node.js工具导入系统所需的努力,可以声明并使用一个子加载器注册表,与父模块注册表一起使用。在先前的例子中,如果定义以下入口点

[calmjs.module]
example.package = example.package

[calmjs.module.loader]
json = json[json]
text = text[txt,json]

calmjs.module.loader注册表将引用其父注册表calmjs.module以获取已公开的特定模块,因此它将根据声明的文件扩展名收集所有相关的文件名到一个特定的加载器中。与基本模块注册表不同,模块加载器注册表将忽略Python模块名称部分,而名称(在左侧)是所需的加载器,额外的(在[ ]内用逗号分隔的标记)是要从包中获取的文件扩展名。因此,使用之前为example.package定义的条目,以下require语句应该可以解析,如果目标资源文件对包存在的话

// resolved through "json = ...[json]"
var manifest_obj = require('json!example/package/manifest.json');
// resolved through "text = ...[txt,json]"
var manifest_txt = require('text!example/package/manifest.json');
var index_txt = require('text!example/package/index.txt');

由于注册表生成的值遵循标准工具链规范编译入口语法,这应该满足最基本的使用案例,可以直接作为包的calmjs_module_registry包含。然而,在提供的JavaScript代码与实际集成的工具链包一起使用时,可能存在需要特殊处理(例如,包含/排除针对最终产品生成的部分,或如何将源代码别名或提供给系统,或是否注册本身需要手动集成)的交互;请参阅特定集成包的文档,以了解此特定注册表类型。

最后一点:由于Python入口点系统的限制,假设文件扩展名都是小写。

通过calmjs npmnpm集成

如前所述,可以在setuptools之外使用package.json生成功能。用户可以通过内置的calmjs npm工具轻松完成同样的操作。

$ calmjs npm --help
usage: calmjs npm [-h] [-d] [-q] [-v] [-V] [--view] [--init] [--install]
                  [-i] [-m] [-w] [-E] [-P] [-D]
                  <package> [<package> ...]

npm support for the calmjs framework

positional arguments:
  <package>          python packages to be used for the generation of
                     'package.json'

optional arguments:
  -D, --development  explicitly specify development mode for npm install
  -E, --explicit     explicit mode disables resolution for dependencies;
                     only the specified Python package(s) will be used.
  -h, --help         show this help message and exit
  -i, --interactive  enable interactive prompt; if an action requires an
                     explicit response but none were specified through
                     flags (i.e. overwrite), prompt for response;
                     disabled by default
  -m, --merge        merge generated 'package.json' with the one in
                     current directory; if interactive mode is not
                     enabled, implies overwrite, else the difference will
                     be displayed
  -P, --production   explicitly specify production mode for npm install
  -w, --overwrite    automatically overwrite any file changes to current
                     directory without prompting

当然,上面展示的与 setuptools 框架一起的相同 --init 功能是可用的,但是可以提供包名称,从文件系统的任何位置生成目标 package.json 文件,前提是 Python 环境已经安装了所有必需的包。例如,如果需要安装 example.package 的 Node.js 包,可以调用此命令以查看将要生成的 package.json 文件。

$ calmjs -v npm --view example.package
2016-09-01 16:37:18,398 INFO calmjs.cli generating a flattened
'package.json' for 'example.package'
{
    "dependencies": {
        "jquery": "~3.0.0",
        "underscore": "~1.8.0",
    },
    "devDependencies": {},
    "name": "example.package"
}

如果当前目录中已存在 package.json 文件,使用 -i 标志与 --init--install 将显示生成的版本和现有版本之间可能存在的差异,并提示执行操作。

工具链

如何扩展工具链类以支持用例的文档目前尚不完整。这通常与 calmjs.runtime.DriverRuntime 结合使用,以挂钩到 calmjs 运行时。

遗憾的是,目前还没有完成如何创建完整实现的详细指南(然而,类内的文档是有的)。有关如何实现此功能的示例,请参阅 calmjs.rjscalmjs.webpack 提供的实现。

工具链建议

对于需要向工具链执行提供额外指令的包开发者(例如,为了在 RequireJS 和 webpack 之间实现特定用例的兼容性),工具链系统也将使用建议系统,以便为依赖项创建和注册额外的指令以供使用和重用。与工具链类似,这个功能目前的文档也只限于测试用例。

通过 setuptools 预定义工件生成

可以为特定包定义要生成的工件以及生成它们的规则。只需定义一个函数,它返回一个与所需工具集成的 calmjs.toolchain.Toolchain 子类实例,以及一个包含所需规则的 calmjs.toolchain.Spec 对象。这些特定函数通常由提供它们的包提供,请参阅上一节中列出的工具链包及其链接,以了解如何使用这些函数的更多详细信息。

因为这些也是通过注册系统实现的,所以入口点通常如下所示

setup(
    ...
    build_calmjs_artifacts=True,
    entry_points="""
    ...
    [calmjs.artifacts]
    complete.bundle.js = example.toolchain:builder
    """,
    ...
)

在示例中,模块 example.toolchain 中的 builder 函数用于生成 complete.bundle.js 文件。生成的工件文件将位于包元数据目录(以 .dist-info.egg-info 结尾)中的 calmjs_artifacts 目录内。还将生成一个伴随的 calmjs_artifacts.json 文件,列出在构建该工件时涉及的各个 Python 包的版本以及用于任务的二进制版本。

当将 build_calmjs_artifacts 设置为 True 时,将通过 setup.py build 步骤自动生成这些工件的自定义钩子将被启用。这对于与发行版(如 Python 轮子)自动捆绑工件文件非常有用(例如,运行 setup.py bdist_wheel 也将构建声明的工件。否则,可以使用 setup.py build_calmjs_artifacts 或通过 calmjs artifact build 工具手动调用此步骤。

故障排除

以下是一些在使用 calmjs 时可能遇到的问题。

CRITICAL calmjs.runtime 因严重错误而终止

如果 calmjs 遇到任何意外情况,它可能会像这样中止

$ calmjs npm --install calmjs.dev
CRITICAL calmjs.runtime terminating due to a critical error

如果之前没有列出有用的 ERROR 信息,请尝试使用调试标志(无论是 -d 还是 --debug)再次运行。

$ calmjs -d npm --install calmjs.dev
CRITICAL calmjs.runtime terminating due to exception
Traceback (most recent call last):
...

指定调试标志两次将启用 post_mortem 模式,其中将在失败点启动调试器。实现向 calmjs 命令提供子命令的运行时类的包的作者可能会在他们的开发周期中发现这很有用。请注意,默认调试器只有在顶层运行时类启用使用(这是实现 calmjs 命令的运行时类所做的)并且失败发生在调用运行时类期间时才会被触发。在 calmjs 运行的设置阶段发生的任何其他错误或异常将仅以较低优先级记录(例如,要使设置阶段生成的警告可见,必须提供附加的详细标志)。

ERROR bad ‘calmjs.runtime’ entry point

ImportError

这通常是由于不当地删除了已注册入口点的本地安装的包、指向错误导入位置的 calmjs 的附加包注册的入口点,或使用了与文档中安装部分所述的当前环境冲突的安装方法所导致的。重新使用环境的正确安装方法安装损坏的包,或完全卸载或删除触发不希望的错误消息的包或源文件。

bad entry point

这是由于定义了格式不正确的入口点。触发此错误的包的名称将在日志中注明;可以将错误报告给其开发者。

尝试从 calmjs 命名空间导入时出现随机 ImportError

由于 calmjs 同时被声明为命名空间和包,因此在工作 Python 环境中必须进行某些低级设置,以确保可以正确定位所有模块。然而,早于 v31.0.0setuptools 版本在将包使用 开发安装方法(例如,使用 python setup.py develop)安装到 Python 环境中,并且与在同一命名空间内通过 pip 安装的另一个包一起安装时,不会创建所需的包命名空间声明。失败可能表现为 calmjs 命名空间下任何模块的不一致导入失败。例如

>>> from calmjs import tests
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name tests
>>> from calmjs import parse  # calmjs.parse was installed via pip
>>> from calmjs import tests
>>> # no failure, but it was failing just earlier?

它也可能以不同的方式表现出来,例如 AttributeError,这可能是通过执行 calmjs 的 unittest 触发的

$ coverage run --include=src/* -m unittest calmjs.tests.make_suite
Traceback (most recent call last):
  ...
    parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'tests'
$ python -m calmjs.tests.make_suite
/usr/bin/python: No module named 'calmjs.tests'

为了解决这个问题,请确保将setuptools升级到v31或更高版本,可以通过以下方式通过pip安装/升级:

$ pip install --upgrade setuptools

然后重新安装所有在calmjs命名空间下的所需包,以解决这个导入问题。

环境变量被忽略/未传递给底层工具

一般来说,Calmjs框架默认过滤掉所有环境变量,除了最基本的变量外,并且只将有限的环境变量传递给底层工具。这些变量是PATHNODE_PATH变量,以及平台特定的变量,以启用脚本和二进制文件的执行。

运行时报告在声明的参数上显示‘未识别的参数:’

对于 calmjs>=3.1.0,此问题应该已完全解决。

在ArgumentParser的默认行为中,对于由其子解析器引起的任何未识别的参数,都会无用地责备根解析器。在calmjs-3.1.0之前的原始解决方案中,由于子解析器解析器实现不完整,失败如下所述。这两种误导行为都会阻碍最终用户快速定位错误的参数标志。

例如,如果像这样执行calmjs命令,则错误消息可能如下所示

$ calmjs subcmd1 subcmd2 --flag item
usage: calmjs subcmd1 ... [--flag FLAG]
calmjs subcmd1: error: unrecognized arguments: --flag

这意味着--flag在第二个子命令(即calmjs subcmd1 subcmd2命令)中未被识别,因为该标志放在了subcmd2之后,但subcmd1的子解析器将其标记为错误。不幸的是,argparse模块中存在一些问题,使得完全解决这个问题变得困难,因此请确保在正确的子命令级别提供标志(在此例中,calmjs subcmd1 --flag item subcmd2),否则通过在每个有效子命令后附加-h来在正确的级别上查阅帮助。

模块注册未定位到命名空间包中的文件

Python中的命名空间包存在许多边缘情况,尤其是如果它们通过不同的方法提供到系统上(即zip egg、wheel和开发包的混合)。尽管提供了处理给定包的命名空间模块的解决方案,但存在一些限制。其中一个原因是处理zip egg的复杂性;如果这是一个问题,请确保受影响的包将zip_safe声明为false,或者另外生成一个Python wheel然后安装该wheel,如果目标Python环境将此作为标准安装格式。

UserWarning:未知发行选项:'package_json'

这也适用于其他相关选项,因为它是由在calmjssetuptools不可用的情况下执行setup.py引起的,因此这些关键词的处理方法仍然是未定义的。可以通过在setup_requires部分提供calmjs来纠正此问题。有关此问题的更多信息,请参阅本文件的使用package_json部分。

贡献

变更日志

3.4.4 (2023-03-07)

  • 升级到setuptools-65.6.0及以上版本会导致一个新的distutils版本,该版本“修复”了日志记录的方式,但现在钩子和预期的解决方案不再有效。鉴于distutils的弃用正在进行中,直到setuptools在Python 3.12发布后完全取代它,作者不再信任Python能够提供一个稳定的软件开发平台,因此不会进行任何修复。因此,未来的任何“修复”都将以更加被动的(而不是主动的)方式提供。[ #66 ]

3.4.3 (2023-03-02)

  • 这是Python 3.11的维护版本。

  • 现在将阻止注册同名子解析器,而不是级联到导致无法恢复的ArgumentError。 [ #64 ]

3.4.2 (2021-10-09)

  • 这是Python 3.10的维护版本;没有进行重大更改。

  • 提供了一种检查,用于通过设置CALMJS_SKIP_INTEGRATION环境变量来禁用集成测试,当设置为非空字符串时,将跳过test_dist中找到的集成测试。[ #60 ]

3.4.1 (2019-05-23)

  • 如果工具链执行引发了中止或取消异常,如果启用调试模式,现在将会有适当的调试日志条目。

  • 避免破坏相关项目中现有的advice_packages分配方式 - 确保提供的None值被视为空列表。[ #57 ]

3.4.0 (2019-05-22)

  • 清理由于在比较测试结果和预期答案时未能使用normcase来规范化路径而在Windows上失败的测试用例。[ #53 #54 ]

  • 提供了一种方法来在类级别启用/禁用调用post_mortem调试器,这样这个功能就不会强制适用于Runtime的所有子类。[ #55 ]

  • 为包提供注册,指定要从哪个要求(包)获取工具链建议并默认应用于相关工具链。这也要求对应用可选建议的位置进行一些更改,从先前的在标准工具链运行时作为设置级别建议应用的位置,更改为默认工具链内的默认序列。[ #56 ]

    • 由于这个特性,任何触发工具链中止或取消的设置建议都不会留下未处理的清理建议。

    • 这个特性以允许手动调用工具链并以手动提供的advice_package列表的方式实现,能够始终覆盖默认指定的那些。

3.3.1 (2018-08-20)

  • 纠正辅助函数which的实现,以便接受并返回有效可执行文件的路径参数。[ #52 ]

3.3.0 (2018-07-23)

  • 实现简化Python包提供的辅助资源文件暴露给Node.js构建工具的过程所需的功能。[ #46 #48 #50 ]

    • 提供标准化的基础子模块注册表及其使用的一些辅助函数。

    • 提供具有限制性命名方案的加载模块注册表,该方案直接引用单个父模块注册表。

    • 这也需要以可重用的方式公开父注册表的映射器,以便默认映射器也接受globber和文件扩展名参数。[ #51 ]

    • 重构了多个注册表类,以便它们可以更容易地进行扩展。

    • 根注册表的自我引用属性现在得到了正确实现。

  • 对于在 package.json 中没有定义 mainbrowser 部分的 Node.js 包,如果存在默认入口文件 index.js,则使用它。[ #49 ]

3.2.1 (2018-05-16)

  • 将针对特定包元数据文件集的相关辅助工具打包到返回它们的函数中。自然存在的函数已提供,参数化的键/文件名以便依赖项重用。[ #43 ]

  • 使用 ast 模块解析 es5 字符串节点值,而不是使用 unicode-escape 方法,因为它包含更多情况,包括可能出现的行续行转义序列。[ #44 ]

3.1.0 (2018-04-30)

  • 通过实际不使用默认标记为已弃用的索引函数,而是在 calmjs.indexer 中使用最初打算的 pkg_resources 版本来修复 modgen 函数。[ #30 #33 ]

  • 确保在 pkg_resources 内部规范化后的包名称的查找仍然可以通过其原始名称解析。[ #31 ]

  • 在运行 calmjs artifact build 命令和 distutils 的 build_calmjs_artifacts 命令时,正确返回各种部分成功的未成功退出代码。[ #27 #38 ]

  • 正确定位无法识别的参数的子解析器;包括清理运行时和 argparser 类之间的交互,以及 Python 3.7 兼容性修复。[ #41 ]

  • 修复处理工作目录标志的方法,因为验证应该在开始时而不是之后进行。此外,清理与该标志相关的各种日志/错误消息,以及工具链测试用例隔离的修复。请注意,未将导出目标设置为绝对部分的下游包将导致警告。[ #42 ]

3.0.0 (2018-01-10)

  • 现在提供 yarn 子命令作为 npm 的替代方案。

  • 还在引导运行时阶段降低了日志详细程度,因此对于没有提供所需二进制文件的系统,默认的 calmjs 命令不会显示那些堆叠的警告(使用 -v 增加详细程度将恢复这些警告)。

  • 一些在工具链和规范系统中使用但混淆的内部(但公共)标识符已被重命名,以更好地反映其预期用途和目的。应用弃用代码以帮助过渡,这些将在 4.0.0 中删除。

    • 对于 Spec

      • *_source_map -> *_sourcepath(除了真正引起混淆的键 generate_source_map

      • *_targets -> *_targetpaths(与文件系统上的路径保持一致)。

    • 在工具链上,出于与上述类似的原因

      • sourcemap_suffix -> sourcepath_suffix

      • target_suffix -> targetpath_suffix

  • 修改了具有配置的 NODE_PATH 和当前工作目录的驱动实例的二进制解析顺序,以与 Node.js 内部注入的方式一致(在 module.paths 中,当前工作目录的优先级高于 NODE_PATH),针对 BaseDriver.find_node_modules_basedir 方法。

  • 通过 calmjs.artifacts 注册表为包生成预定义的工件框架。

  • 还将上述方法中的目录解析分离出来,到 BaseDriver.which_with_node_modules

  • 弃用了现有的 toolchain.transpiler 函数作为标准可调用函数。新版本必须是 calmjs.parse 包提供的 BaseUnparser 实例。NullToolchain 将继续使用旧版本的 transpiler。

  • 将完整的转译目标路径进行规范化。请注意,目标路径仍然是工具链特定的。

  • 由于现在功能由 calmjs.parse.vlqcalmjs.parse.sourcemap 提供,因此移除了大部分 vlqsm 模块。只有旧版本的 SourceWriter 类保留,已被弃用。

  • 为加载器插件提供了一级通用支持,因此下游包不再需要显式声明 extras_calmjs 来指定不同工具链的加载器位置(这不可避免地会冲突和引起冲突)。下游的工具链需要实现对此的支持。

  • 工件生产支持,包括与 setuptools 的集成。

2.1.0 (2016-11-29)

  • 如果提供了有效的入口点,则应能够查找具有显式提供模块的命名空间包;当然,如果模块没有正确声明,则行为保持不变(github issue #5)

  • package.json 中的名称字段应包含 Node.js 的标准项目名称,即如果指定了额外内容,则应将其删除。这样做是为了防止 npm 因为警告而崩溃并退出。(github issue #4)

2.0.0 (2016-11-16)

  • 公开了索引器模块的函数映射器和 modgen。

  • 完全重构了 Toolchain 类,以具有更多一致的方法命名约定和参数列表。

  • 编译方法现在从特定实例的方法列表中读取,这允许非常定制的编译步骤。

  • 为工具链提供了跳过特定名称的特定方式。

  • 修复了将捆绑源复制到子目录中嵌套的目标的问题。

  • 现在将 Spec 回调系统重命名为建议系统,并进行了更全面的实现;工具链中的每个步骤都会在注册的每个步骤之前和之后执行匹配标识符下的建议。建议的标识符被正式化为可以从 calmjs.toolchain 模块导入的常量。

  • 建议系统有专门的异常可以抛出,以表示中断或干净地停止运行。

  • 正式化了几个 spec 键,即 BUILD_DIR 和 CONFIG_JS_FILES,分别用于构建目录和标记配置 JavaScript 文件。

  • 在成功调用工具链后,现在将调用在键 calmjs.toolchain.SUCCESS 下注册到 spec 的所有建议。

  • Toolchain 子类提供了专门的运行时支持,加入了少数其他 BaseDriver 子类的行列。这作为 calmjs.runtime.ToolchainRuntime 实现。

  • 现在可以子类化 calmjs.runtime.Runtime 并嵌套,因为它现在会嵌套所有 BaseRuntime。此外,已删除 init 方法,只需使用 __init__ 和标准的子类化 super 使用规则。

  • 每个 Runtime 的默认 ArgumentParser 实例将不再在访问之前创建,因为它现在是一个属性。

  • 提供一种方式,通过新的设置关键字 calmjs_module_registry,让包声明其主要模块注册表或为声明包所声明的注册表。

  • 默认模块注册表名称集合已更改。注册表 calmjs.pythonic 已重命名为 calmjs.py.module;相关的测试相关注册表已重命名为包含其隐含目标的全名。

  • 为 calmjs 框架保留了一小部分核心(已定义)注册表,由注册表本身正式定义和强制执行。

  • 修正了交互模式检测。

  • 为简单转换提供源映射生成辅助工具。

1.0.3 (2016-09-07)

  • 修复了在 Windows 下 Python 2.7 的 subprocess.Popen 中的坏环境变量问题。

  • 在 CI 平台上进行了其他一些小的测试修复。

1.0.2 (2016-09-04)

  • 修复了 Windows 平台上的二进制文件调用问题。

  • 纠正了一些轻微的文字错误。

1.0.0 (2016-09-02)

  • 发布 calmjs 框架基础的第一个版本。

  • 提供了一个名为 calmjs 的 cli 运行时入口点。

  • 通过 setuptools 框架提供与 npm 的核心集成以及通过 setuptools 生成 package.json;这可以通过 setuptool 命令或通过 calmjs 运行时访问。

  • 为 calmjs 内部使用提供注册框架。

  • 为 calmjs 通过预定义的 setuptools 入口点和组注册包提供核心注册表。

  • 为与 node 和其他基于 Node.js 的或其他命令行工具交互提供 cli 工具驱动框架。

  • 在工具驱动框架之上提供基础工具链框架。

  • 为在 calmjs 框架之上构建的模块提供集成测试模块。

项目详情


下载文件

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

源分布

calmjs-3.4.4.zip (296.0 kB 查看散列)

上传时间

构建分布

calmjs-3.4.4-py2.py3-none-any.whl (218.4 kB 查看散列)

上传时间 Python 2 Python 3