跳转到主要内容

pyflyby - Python开发生产工具,特别是自动导入管理

项目描述

https://badge.fury.io/py/pyflyby.svg https://travis-ci.org/deshaw/pyflyby.png?branch=master

Pyflyby 是一套适用于 Python 3.8+ 的 Python 编程生产力工具。

用于命令行交互
  • py:命令行多工具

用于 IPython 交互
  • autoimporter:在需要时自动导入符号。

用于编辑 Python 源代码
  • tidy-imports:添加缺失的‘导入’,删除未使用的‘导入’,并重新格式化导入块。

  • find-import:打印如何导入特定符号到 stdout。

  • reformat-imports:重新格式化 import

  • collect-imports:打印出给定文件集中所有的导入。

  • collect-exports:打印出给定模块集中的定义,形式为导入语句。

  • transform-imports:重命名导入的模块/函数。

安装

$ pip install pyflyby
这将在您的 ipython 中创建一个名为 py 的别名,该别名运行内部 pyflyby 插件。

pyflyby 依赖于 ipython,如果尚未安装,请使用以下命令进行安装

$ pip install ipython

快速入门:Autoimporter + IPython

$ py
In [1]: re.search("[a-z]+", "....hello...").group(0)
[PYFLYBY] import re
Out[1]: 'hello'

In [2]: chisqprob(arange(5), 2)
[PYFLYBY] from numpy import arange
[PYFLYBY] from scipy.stats import chisqprob
Out[2]: [ 1.      0.6065  0.3679  0.2231  0.1353]

要将 pyflyby 作为一次性加载到现有的 IPython 会话中

$ ipython
In [1]: %load_ext pyflyby

要配置 IPython/Jupyter Notebook 以自动加载 pyflyby

$ py pyflyby.install_in_ipython_config_file

或者

$ echo 'c.InteractiveShellApp.extensions.append("pyflyby")' \
  >> ~/.ipython/profile_default/ipython_config.py

$ ipython
In [1]: b64decode('aGVsbG8=')
[PYFLYBY] from base64 import b64decode
Out[1]: 'hello'

自动导入延迟变量

可以使用自动导入器来延迟定义变量。

要使用,请将以下内容放入您的 IPython 启动文件(~/.ipython/profile_default/startup/autoimp.py)中,或者在您的 IPython 配置文件中

from pyflyby import add_import

add_import("foo", "foo = 1")

add_import(
    "df, data as dd",
    '''
    import pandas as pd
    data = [1,2,3]
    df =  pd.DataFrame(data)
''')

您可以将关键字 strict=False 添加到不失败,如果不在 IPython 中或 pyflyby 扩展没有加载。

快速入门:py 命令行多工具

$ py b64decode aGVsbG8=
[PYFLYBY] from base64 import b64decode
[PYFLYBY] b64decode('aGVsbG8=', altchars=None)
'hello'

$ py log2 sys.maxint
[PYFLYBY] from numpy import log2
[PYFLYBY] import sys
[PYFLYBY] log2(9223372036854775807)
63.0

$ py 'plot(cos(arange(30)))'
[PYFLYBY] from numpy import arange
[PYFLYBY] from numpy import cos
[PYFLYBY] from matplotlib.pyplot import plot
[PYFLYBY] plot(cos(arange(30)))
<plot>

$ py 38497631 / 13951446
2.7594007818257693

$ py foo.py

快速入门:tidy-imports

要使用 tidy-imports,只需指定要整理的文件名即可。

例如

$ echo 're.search("[a-z]+", "....hello..."), chisqprob(arange(5), 2)' > foo.py

$ tidy-imports foo.py
--- /tmp/foo.py
+++ /tmp/foo.py
@@ -1 +1,9 @@
+from __future__ import absolute_import, division, with_statement
+
+from   numpy                    import arange
+from   scipy.stats              import chisqprob
+import re
+
 re.search("[a-z]+", "....hello..."), chisqprob(arange(5), 2)

Replace /tmp/foo.py? [y/N]

快速入门:导入库

创建一个名为 .pyflyby 的文件,其中包含类似以下内容的行

from mypackage.mymodule import MyClass, my_function
import anotherpackage.anothermodule

您可以将此文件放在您的家目录中或与您的 *.py 文件相同的目录中。

详细信息:自动导入

自动导入 - 永远不再输入“导入”!

该模块允许您的“已知导入”在 IPython 交互会话中自动工作,无需输入导入语句(并且无需因偶尔使用的导入而减慢您的 Python 启动速度)。

示例

In [1]: re.search("[a-z]+", "....hello...").group(0)
[PYFLYBY] import re
Out[1]: 'hello'

In [2]: chisqprob(arange(5), 2)
[PYFLYBY] from numpy import arange
[PYFLYBY] from scipy.stats import chisqprob
Out[2]: [ 1.      0.6065  0.3679  0.2231  0.1353]

In [3]: np.sin(arandom(5))
[PYFLYBY] from numpy.random import random as arandom
[PYFLYBY] import numpy as np
Out[3]: [ 0.0282  0.0603  0.4653  0.8371  0.3347]

In [4]: isinstance(42, Number)
[PYFLYBY] from numbers import Number
Out[4]: True

它只需这样就可以工作

Tab 完成工作,即使在尚未导入的模块上也一样。在以下示例中,请注意,当我们需要了解其成员时,才会导入 numpy,并且仅在此之后

$ ipython
In [1]: nump<TAB>
In [1]: numpy
In [1]: numpy.arang<TAB>
[PYFLYBY] import numpy
In [1]: numpy.arange

IPython的“?”魔法帮助(pinfo/pinfo2)在需要时将自动导入符号

$ ipython
In [1]: arange?
[PYFLYBY] from numpy import arange
... Docstring: arange([start,] stop[, step,], dtype=None) ...

其他IPython魔法命令也正常工作

$ ipython
In [1]: %timeit np.cos(pi)
[PYFLYBY] import numpy as np
[PYFLYBY] from numpy import pi
100000 loops, best of 3: 2.51 us per loop

$ echo 'print arange(4)' > foo.py
$ ipython
In [1]: %run foo.py
[PYFLYBY] from numpy import arange
[0 1 2 3]

实现细节

自动导入发生在解析时间,在代码执行之前。命名空间永远不会包含尚未导入的名称条目。

这种方法在解析时间导入与之前使用代理对象的自动导入实现形成对比。那些使用代理对象的实现效果不佳,因为无法使代理对象的行为完美。例如,如果x或T是代理对象,则instance(x, T)将返回错误答案。

兼容性

测试了以下版本
  • Python 3.8, 3.9, 3.10

  • IPython 0.10, 0.11, 0.12, 0.13, 1.0, 1.2, 2.0, 2.1, 2.2, 2.3, 2.4, 3.0, 3.1, 3.2, 4.0., 7.11(最新版)

  • IPython(文本控制台),IPython笔记本,Spyder

详情:导入库

Pyflyby使用“导入库”来指定如何导入给定的符号。

导入库文件只是一个包含‘import’(或‘from … import …’)行的Python源文件。这些可以使用 collect-importscollect-exports 自动生成。

已知导入

find-imports,tidy-imports 和 autoimport 会查询已知导入的数据库以确定导入的位置。例如,如果导入数据库包含

from numpy import arange, NaN

那么当你在IPython中输入以下内容时

print(arange(10))

自动导入器将自动执行 from numpy import arange

该数据库可以是一个文件或多个文件。这使得项目特定的 known_imports 能够与全局和用户默认值一起使用。

PYFLYBY_PATH 环境变量指定了要读取的文件。这是一个以冒号分隔的文件名或目录名列表。默认值为

PYFLYBY_PATH=/etc/pyflyby:~/.pyflyby:.../.pyflyby

如果你设置

PYFLYBY_PATH=/foo1/bar1:/foo2/bar2

则这会替换默认值。

您可以使用短横线来在路径中包含默认值。如果您设置

PYFLYBY_PATH=/foo1/bar1:-:/foo2/bar2

则这会读取 /foo1/bar1,然后是默认位置,然后是 /foo2/bar2

$PYFLYBY_PATH 中,.../.pyflyby(用三个点表示)意味着将搜索所有祖先目录以查找名为“ .pyflyby”的成员。

例如,假设存在以下文件

/etc/pyflyby/stuff.py
/u/quarl/.pyflyby/blah1.py
/u/quarl/.pyflyby/more/blah2.py
/proj/share/mypythonstuff/.pyflyby
/proj/share/mypythonstuff/foo/bar/.pyflyby/baz.py
/.pyflyby

进一步假设

  • /proj 是与 / 在不同文件系统上的。

  • $HOME=/u/quarl

那么默认情况下,tidy-imports /proj/share/mypythonstuff/foo/bar/quux/zot.py 将使用以下

/etc/pyflyby/stuff.py
/u/quarl/.pyflyby/blah1.py
/u/quarl/.pyflyby/more/blah2.py
/proj/share/mypythonstuff/foo/bar/.pyflyby/baz.py
/proj/share/mypythonstuff/.pyflyby (a file)

忘记导入

有时您可能需要让 pyflyby “忘记”已知导入数据库中的条目。

您可以在 $PYFLYBY_PATH 可达的任何文件中放置以下内容

__forget_imports__ = ["from numpy import NaN"]

这很有用,如果你想要使用一组由其他人维护的导入,除了几个特定的导入。

$PYFLYBY_PATH 中的条目将按照指定的顺序从左到右处理,因此请将包含这些文件的目录放在你的 $PYFLYBY_PATH 的末尾。默认情况下,tidy-imports 和其他工具会处理 /etc/pyflyby,然后是 ~/.pyflyby,最后是每个目录下的 .pyflyby

强制导入

在某个项目中,你可能有一个策略,始终包含某些导入。例如,你可能希望在所有文件中都执行 from __future__ import division

您可以在 $PYFLYBY_PATH 可达的任何文件中放置以下内容

__mandatory_imports__ = ["from __future__ import division"]

要撤销从其他 .pyflyby 文件继承的强制导入,请使用 __forget_imports__(见上文)。

标准化导入

有时你希望每次运行 tidy-imports 时都自动将导入重命名为新名称。

您可以在 $PYFLYBY_PATH 可达的任何文件中放置以下内容

__canonical_imports__ = {"oldmodule.oldfunction": "newmodule.newfunction"}

这相当于运行

tidy-imports --transform=oldmodule.oldfunction=newmodule.newfunction

肥皂箱:避免使用“星号”导入

在 Python 中编程时,避免在生产代码中使用 from foopackage import * 是一种良好的软件工程实践。

这种风格是维护噩梦

  • 很难弄清楚各种符号(函数、类等)来自哪里。

  • 很难判断什么被什么覆盖了。

  • 当包以微不足道的方式发生变化时,你的代码将受到影响。考虑以下示例:假设 foopackage.py 包含 import sys,而 myprogram.py 包含 from foopackage import *; if some_condition: sys.exit(0)。如果 foopackage.py 中的 import sys 被删除,则 myprogram.py 现在已损坏,因为它缺少 import sys

要修复此类代码,你可以运行 tidy-imports --replace-star-imports 以自动将星号导入替换为特定需要的导入。

tidy-imports 的项目配置

你可以通过使用 pyproject.toml 文件的 [tool.pyflyby] 部分来基于存储库配置 Pyflyby。Pyflyby 将在当前工作目录及其所有父目录中查找,直到找到 pyproject.toml 文件,然后从中加载默认值。

大多数长命令行标志的默认值都可以在这个部分中配置。只需使用长选项名称,用下划线 _ 替换破折号 -。对于形式为 –xxx–no-xxx 的长选项,你可以将布尔值分配给 xxx。例如

[tool.pyflyby]
add_missing=true
from_spaces=7
remove_unused=false

Emacs 支持

  • 要在 GNU Emacs 中获取 M-x tidy-imports 命令,请将其添加到你的 ~/.emacs 中。

    (load "/path/to/pyflyby/lib/emacs/pyflyby.el")
  • Pyflyby.el 还不支持 XEmacs;欢迎提供补丁。

著作权

此插件由 D. E. Shaw group 贡献给社区。

https://www.deshaw.com/assets/logos/blue_logo_417x125.png

Pyflyby 由 Karl Chen 编写 <quarl@8166.clguba.z.quarl.org>

我们热爱贡献!在你能够贡献之前,请签署并提交此 贡献者许可协议 (CLA)。此 CLA 的目的是保护本项目的所有用户。

许可证

Pyflyby 在非常宽松的许可下发布,即 MIT/X11 许可证;请参阅 LICENSE.txt。

发布

  1. lib/python/pyflyby/_version.py 中检查版本号,可能需要增加它。

  2. 如有必要,进行提交和标记,然后推送标签/提交。

  3. 可选:设置 SOURCE_DATE_EPOCH 以实现可重复构建

    export SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)
  4. 构建 SDIST

    python setup.py sdist
  5. 可选:使用 IPython 工具重新打包 SDIST 以确保 ZIP 只包含 SOURCE_DATE_EPOCH 日期

    python ~/dev/ipython/tools/retar.py dist/pyflyby-1.7.8.tar.gz
    shasum -a 256 dist/*
  6. 可选,重复 4 & 5 以验证校验和未更改。

  7. 使用 twine 上传

    twine upload dist/*
  8. 检查/更新 https://github.com/conda-forge/pyflyby-feedstock 以获取 conda-forge 上的新 pyflyby 版本

项目详情


下载文件

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

源分发

pyflyby-1.9.6.tar.gz (443.8 kB 查看哈希值)

上传时间

支持者