Python:如何最好地处理同时开发库和应用程序的开发?

时间:2018-07-17 23:03:59

标签: python import module

当前项目的示例目录结构:

#define nowInSeconds CFAbsoluteTimeGetCurrent()//since Jan 1 2001 00:00:00 GMT
#define secondsSinceDeviceRestart ((int)round([[NSProcessInfo processInfo] systemUptime]))
#define storage [NSUserDefaults standardUserDefaults]
#define DISTANCE(__valueOne, __valueTwo) ((((__valueOne)-(__valueTwo))>=0)?((__valueOne)-(__valueTwo)):((__valueTwo)-(__valueOne)))

+(BOOL)didDeviceReset {
    static BOOL didDeviceReset;
    static dispatch_once_t onceToken;
    int currentRestartDate = nowInSeconds-secondsSinceDeviceRestart;
    int previousRestartDate = (int)[((NSNumber *)[storage objectForKey:@"previousRestartDate"]) integerValue];
    int dateVarianceThreshold = 10;
    dispatch_once(&onceToken, ^{
        if (!previousRestartDate || DISTANCE(currentRestartDate, previousRestartDate) > dateVarianceThreshold) {
            didDeviceReset = YES;
        } else {
            didDeviceReset = NO;
        }
    });
    [storage setObject:@(currentRestartDate) forKey:@"previousRestartDate"];
    [storage synchronize];
    return didDeviceReset;
}

我是唯一的开发人员,并且正在并行开发上述所有应用程序。

我的问题:

  • 如何最好地处理在三个项目(myproject/ | +-- mylibrary/ | | | +-- __init__.py | | | +-- (code files) | +-- webapi/ | | | +-- __init__.py <-- contains Flask API code and blueprints, using the mylibrary code | | | +-- object/ | | | +-- __init__.py <-- Flask API code for "object"s, imported via blueprints | +-- cli/ | | | +-- __init__.py <-- argparse, code to use the mylibrary code from the CLI, etc. | +-- gui_app/ | +-- __init__.py <-- the start of a GUI application, using the mylibrary code importwebapi)中编写cli语句以从gui_app模块导入代码?我看到三个选择:
    • 使用PYTHONPATH或mylibrarysys.path添加到使用该库的每个应用程序的路径。这适用于..文件,但是我不确定如何从__init__.py开始,而基本上没有向webapi/object/__init__.py添加../..。另外,这使得应用程序以后很难分发。
    • 重组应用程序,使库的每个“用户”都是库的子模块;然后我可以做sys.path。这是一个坏主意,因为它基本上使整个from .. import mylibrary模块都是“整体的”。
    • 每次我有机会mylibrary安装到我的mylibrary中。然后只需使用site-packages开发其他三个应用程序。但是,这很痛苦,因为我正在并行开发应用程序的全部四个部分。
  • 我打算自己分发import mylibrary,因此可以通过例如点子然后,可以分别安装mylibrarywebapi。 (也许gui_app可以合并到cli中,因此,如果将其作为模块运行,它将显示CLI,但仍然不能解决其他两个应用程序的问题)

这是我与多个使用该库的应用程序同时编写代码库的第一次经验。什么是实现此目的的最“ Pythonic”或更准确,最安全且最不容易出错的方式?

1 个答案:

答案 0 :(得分:1)

我认为您太复杂了。

您的最终目标是将库和应用程序都分别分发,并由pip安装。要使其正常工作,它们只需要是具有各自单独的setup.py的单独程序包,并且该应用程序的“ requirements.txt”中就会包含该库。

而且,一旦这样做,它也可以解决您的开发问题。创建一个虚拟环境,然后在处理该应用程序时将库pip install放入该环境中。

无需手动符号链接或在任何地方复制任何内容。或者以一种可以同时使用已安装的库和相对路径的库的方式编写测试。或其他。并且不会弄乱sys.path;该库位于venv的站点包中,该站点包已在sys.path中。使所有这些工作正常进行是虚拟环境的重点。

您甚至不需要自述文件中的任何复杂内容。只需使用pip安装该应用程序的人(无论是系统范围的还是venv的)都会自动获得该库。应用程序中的工作人员可以像对待任何其他依赖项一样对待库。 (他们应该已经知道如何创建venv并在其中安装requirements.txt。)唯一的真正问题是在库上工作的人对应用程序不感兴趣,但正在将其用作库的测试代码,但是您只需在库本身中包含足够的测试代码(您可能仍要这样做)就可以使它变得不必要。

如果有某种原因无法解决您的问题,您可以考虑从独立库包中构建版本化的子包,requestsurllib3bs4的方式相同与unicodedamnit一起使用。但是从您的描述中,我看不到您有任何需要的迹象。


我认为您的问题可能是您认为pip只能从PyPI或另一个pip回购中安装分布式软件包。实际上,它比这灵活得多。正如the User Guide所说:

  

pip支持从PyPI,版本控制,本地项目以及直接从分发文件进行安装。

如果您查看pip install的参考,它可以采用以下任何一种形式:

pip [options] <requirement specifier> [package-index-options] ...
pip [options] -r <requirements file> [package-index-options] ...
pip [options] [-e] <vcs project url> ...
pip [options] [-e] <local project path> ...
pip [options] <archive url/path> ...

如果您想知道这是如何工作的,请稍微简化一下,所有变化(除非您处理的是预制轮,在这里无关紧要)都归结为(只是略微简化了)下载源代码/签出/打开包装/等。在某个地方做pip install .cd进入那个地方,然后在那里做pip install .

因此,如果要安装库的当前工作树,则可以执行以下操作:

pip install /path/to/lib

或者,更常见的情况是,您已经在/path/to/lib中了,所以:

pip install .

对于开发模式安装,您可能希望插入-e标志,或者覆盖版本检查(或仅覆盖--force-reinstall),或者使用{{ 1}},或忽略要求或约束等,但是所有这些选项对于从本地路径(或#egg回购,分支或变更列表)进行安装的效果都与从PyPI进行安装一样。

即使是非常复杂的内容,git也可以很好地处理。是否要切换回pip上的内容以比较您当前的更改如何影响事物? master。是否想给某个人一个自定义分支,以便他可以对此进行测试?推分支,他可以做pip install git+file:/path/to/lib@master。您可能永远不需要这些东西,但是pip install git+https://github.com/fdmillion/liblibrary@someguytest已经拥有了几乎可以想象的任何东西。