软件开发目录设计
对于提高项目可读性、可维护性的要求就很高了。”项目目录结构”其实也是属于”可读性和可维护性”的范畴,我们设计一个层次清晰的目录结构,就是为了达到以下两点:
可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
1、bin/: 存放项目的一些可执行文件,当然你可以起名 script/之类得也行
2、foo/: 存放项目的所有源代码。
(1)源代码中的所有模块、包都应该放在此目录。不要置于顶层目录
(2)其子目录tests/存放单元测试代码;
(3)程序的入口最好命名为main.py
3、docs/:存放一些文档
setup.py:安装、部署、打包的脚本
4、requirements.txt:存放软件依赖的外部python包列表
README:项目的说明文件。
除此之外,有一些方案给出了更加多的内容。比如LICENSE.txt,ChangeLog.txt 文件等,这些东西主要是项目开源的时候需要用到的。
关于README[自述文件]的内容
这个文件的目的是能够简要的描述项目的信息,让读者快速了解这个项目。
它需要说明一下几个事项:
1、软件的定位,软件的基本功能
2、运行代码的方法:安装环境,启动命令等
3、简要的使用说明
4、代码目录结构说明,更详细点可以说明软件的基本原理
5、常见问题说明。
关于requirements.txt[要求]和setup.py
setup.py
一般来说用setup来管理代码的打包、安装、部署问题。业界标准的写法是用python刘雪的打包工具Setuptools来管理这些事情。这种方式普遍应用于开源项目中。不过这里的核销思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署的工具,能快速便捷的在一台新机器上讲环境安装好,代码部署好喝将程序运行起来 。
如果手动完成 软件的 安装环境,部署代码,运行程序,经常会出现以下问题。
1、安装环境时经常忘记最近添加了一个新的python 包,结果一到线上运行,程序就出错了。
2、python包的版本依赖问题,有时候程序中使用的是一个版本的python包,但是官网的意见是最新的包了,通过手动安装可能会出错。
3、如果依赖的包很多的话,一个一个安装这些依赖是很费事
4、新手再开始写项目的时候,将程序跑起来非常麻烦,因为可能经常忘记这么安装各种依赖
setup.py可以将这些事情自动化起来,提供效率,减少出错的概率“复杂的东西自动化,能自动化的东西一定要自动化”是一个非常好的习惯
setuptools的文档比较庞大,刚接触的话,可能不好找到切入点,学习技术的方式就是看他人是怎么用得,可以参考python的一个web框架,flask是如何写得:setup.py
当然,简单点自己写个安装脚本(deploy.sh【配置,展开】)替代setup.py也是可以的
requirements.txt
这个文件存在的目的是:
1‘方便开发者维护软件的包一辆。将开发过程中新增的包添加进这个列表中,避免在Setup.py安装一辆时漏掉软件包。
2、方便读者明确项目使用了哪些python包
这个文件的格式是每一行包含一个包的依赖说明,通常是flask> = 0.10这种格式,要求是这个格式能被pip识别,这样可以简单的通过pip install -r requirements.txt 把所有python包依赖都装好了,具体格式说明:
需求文件¶
在安装软件,特别是Python软件包时,通常会安装很多库。你刚刚做了easy_install MyPackage ,你得到了十几个包。每个软件包都有自己的版本。
也许你运行该安装,它的工作原理。大!它会继续工作吗?您是否必须提供特殊选项才能找到所有内容?你必须安装一堆其他可选件吗?最重要的是,你能再次做到吗?需求文件为您提供了创建环境的方法:一组协同工作的包。
如果您曾尝试在新系统上设置应用程序,或者稍微更新一些应用程序,并且使其失败,那么pip要求就适合您。如果你没有遇到这个问题那么你最终会这样,所以pip要求也适合你 - 要求明确,可重复地安装包。
那么什么是需求文件?它们非常简单:要安装的软件包列表。您可以创建一个需求文件,而不是运行像pip install MyApp这样的东西并获取任何库。
MyApp的
框架== 0.9.4
库> = 0.2
如果将其保存在requirements.txt中,则可以pip install -r requirements.txt。无论MyApp在setup.py中列出什么,您都将获得特定版本的Framework(0.9.4)和至少0.2版本的Library。(您可能认为可以在MyApp的setup.py中列出这些特定版本 - 但如果您这样做,则必须编辑MyApp,如果您想尝试新版本的Framework,或者如果您确定该版本,则需要发布新版本的MyApp库0.3不适用于您的应用程序。)您还可以添加MyApp不严格要求的可选库和支持工具,为人们提供一组推荐的库。
您还可以包含“可编辑”包 - 从Subversion,Git,Mercurial和Bazaar签出的包。这些就像使用-e 选项来进行pip一样。他们看着像是:
-e svn + http:// myrepo / svn / MyApp#egg = MyApp
您必须使用svn +(git +,hg +或bzr +)启动URL ,并且必须包含#egg = Package,因此pip知道该URL的内容。您还可以在URL中包含@rev,例如@ 275以查看修订版275。
需求文件大多是扁平的。也许MyApp需要 Framework,而Framework需要Library。我鼓励您仍然将所有这些列在一个需求文件中; Python程序的本质是 MyApp和Library之间直接存在隐式绑定。例如,Framework可能会暴露一个Library的对象,因此如果更新了Library,它可能会直接破坏MyApp。如果发生这种情况,您可以更新需求文件以强制使用早期版本的库,并且您可以执行此操作而无需重新发布MyApp。
阅读需求文件格式以了解其他功能。
冻结要求
所以你有一套可用的软件包,你希望能够在其他地方安装它们。 需求文件允许您安装确切的版本,但它不会告诉您所有确切版本是什么。
要从已知的工作环境创建新的需求文件,请使用:
$ pip freeze> stable-req.txt
这将为stable-req.txt编写所有已安装库的列表,其中 包含每个库的确切版本。您可能希望在生成后编辑文件(例如,消除不必要的库),但它将为构建需求文件提供稳定的起点。
您还可以为其提供现有的需求文件,并将其用作新文件的一种模板。所以,如果你这样做:
$ pip freeze -r devel-req.txt> stable-req.txt
它将按顺序保留devel-req.txt中列出的包并保留注释。
该要求的文件格式
需求文件是一种获取pip以安装特定包以构成环境的方法。本文档描述了该格式。要了解何时应使用需求文件,请参阅需求文件。
需求文件的每一行都表示要安装的内容。例如:
MyPackage == 3.0
告诉pip安装3.0版本的MyPackage。
您还可以在需求文件中请求额外内容:
MyPackage == 3.0 [ PDF ]
包也可以以“可编辑”的形式安装。这将源代码放入src / distname(使名称小写)并在包上运行python setup.py develop。要表示可编辑,请使用-e,如:
-e svn + http://svn.myproject.org/svn/MyProject/trunk#egg=MyProject
该#蛋= MyProject的部分是很重要的,因为虽然你可以给出的SVN位置只需安装,项目名称是在其他地方有用。
您还可以为不可编辑的网址指定鸡蛋名称。这对于指向本地文件系统上的HEAD位置很有用:
文件:///路径/要/你的/ lib目录/项目#蛋= MyProject的
或相对路径:
文件:../../ LIB /项目#蛋= MyProject的
如果你需要给pip(和关联easy_install)提示有关在哪里找到包,你可以使用-f (-- find-links)选项,如:
$ pip -f http://someserver.org/index-of-packages MyPackage == 3.0
然后皮普将寻找在链路http://someserver.org/index-of-packages 匹配版本3.0的MyPackage的 -链接应该像MyPackage的-3.0.tar.gz。
如果你想从带有直接链接的tarball或zip文件安装,你不需要-f选项,你只需要传递绝对URL,如:
$ pip install http://someserver.org/packages/MyPackage-3.0.tar.gz
版本控制
现在pip知道以下主要版本控制系统:
颠覆
Pip支持URL方案svn,svn + svn,svn + http,svn + https,svn + ssh。您还可以对SVN URL进行特定修订,例如:
-e svn + svn://svn.myproject.org/svn/MyProject#egg=MyProject
-e svn + http://svn.myproject.org/svn/MyProject/trunk@2019#egg=MyProject
这将检查修订版 2019. @ {20080101}还将查看2008-01-01的修订版。您只能使用-e svn + ...查看特定的修订版本。
Git的
Pip目前支持通过git,git + http和git + ssh进行克隆:
-e git://git.myproject.org/MyProject.git#egg=MyProject
-e git + http://git.myproject.org/MyProject/#egg=MyProject
-e git + ssh://git@myproject.org/MyProject/#egg=MyProject
传递分支名称,提交哈希或标记名称也是可能的:
-e git://git.myproject.org/MyProject.git@master#egg=MyProject
-e git://git.myproject.org/MyProject.git@v1.0#egg=MyProject
-e git:/ / / / / / / / / / / / / / / /
水银
支持的方案是:hg + http,hg + https, hg + static-http和hg + ssh:
-e hg + http://hg.myproject.org/MyProject/#egg=MyProject
-e hg + https://hg.myproject.org/MyProject/#egg=MyProject
-e hg + ssh://hg@myproject.org/MyProject/#egg=MyProject
您还可以指定修订号,修订哈希,标记名称或本地分支名称:
-e hg + http://hg.myproject.org/MyProject/@da39a3ee5e6b#egg=MyProject
-e hg + http://hg.myproject.org/MyProject/@2019#egg=MyProject
-e hg + http://hg.myproject.org/MyProject/@v1.0#egg=MyProject
-e hg + http://hg.myproject.org/MyProject/@special_feature#egg=MyProject
义卖
Pip使用bzr + http,bzr + https,bzr + ssh, bzr + sftp,bzr + ftp和bzr + lp方案支持Bazaar :
-e bzr + http://bzr.myproject.org/MyProject/trunk/#egg=MyProject
-e bzr + sftp://user@myproject.org/MyProject/trunk/#egg=MyProject
-e bzr + ssh://user@myproject.org/MyProject/trunk/#egg=MyProject
-e bzr + ftp://user@myproject.org/MyProject/trunk/#egg=MyProject
-e bzr + lp:MyProject#egg = MyProject
可以像这样安装标签或修订版:
-e bzr + https://bzr.myproject.org/MyProject/trunk/@2019#egg=MyProject
-e bzr + http://bzr.myproject.org/MyProject/trunk/@v1.0#egg=MyProject
递归要求
如果您愿意,还可以参考其他需求文件,例如:
-r Pylons-requirements.txt
这为您提供了一种抽象出各种要求的方法。但是,对于冻结的要求,这并不是非常友好,因为Pylons-requirements.txt中的所有内容都 将显示在冻结文件中。
索引,查找链接
您还可以 在需求文件中为--index-url和--find-links选项提供值,例如:
--index-url http://example.com/private-pypi/
请注意,使用--index-url会删除PyPI的使用,而使用--extra-index-url将添加其他索引。
--find-links更加临时; 而不是一个完整的“索引”,你只需要一个指向可用包的链接的HTML页面。只需将所有私有软件包放在一个目录中并使用Apache自动索引,就可以发布软件包,以便pip可以找到它们。 --find-links总是添加剂; pip看着它能找到的一切。使用它像:
--find-links http://example.com/private-packages/
请注意,所有这些选项必须在他们自己的行上。
关于配置文件的使用方法
注意,再上面的目录结构中,没有将conf.py放在源码目录下,而是放在.docs/目录下。
很多项目对配文件的使用做法是:
1、配置文件写在一个或多个python文件中,比如此处的conf.py。
2、项目中哪个模块用到这个配置文件就通过import conf 这种形式在代码中使用配置。
这种做法不是很赞成:
1、这让单元测试变得困难(因为模块内部依赖了外部配置)
2、另外一方面配置文件作为用户控制程序的接口,应当可以由用户自由一指定文件的路径。
3、程序组件可复用性太差,因为这种贯穿所有模块的代码硬编码方式,使得大部分模块都依赖conf.py这个文件。
所有,配置的使用,更好的方式是:
1、模块的配置都是可以灵活配置的,不受外部配置文件的影响。
2、程序的配置也可以灵活控制。
能够佐证这个思想的是,用过nginx和mysql的人都知道,nginx,mysql这些程序都可以自由的指定用户配置。
所以,不应当再代码中直接import conf 来配置文件。上面的目录结构中conf.py是给出的一个配置样例,不是在写死程序直接引用的配置文件,可以通过 给main.py启动参数指定配置路径的方式来让程序读取配置内容。当然,这里的conf.py你可以换个类似的名字,或者你也可以使用其他格式的内容来编写配置文件,比如settings.yaml之类。