@@ -19,8 +19,297 @@ project. We then discuss various perspectives on how to build code which
1919can be extended and tested reliably.
2020
2121
22- Structure is Key
23- ----------------
22+
23+ Structure of the Repository
24+ ---------------------------
25+
26+ It's Important.
27+ :::::::::::::::
28+
29+ Just as Code Style, API Design, and Automation are essential for a
30+ healthy development cycle, Repository structure is a crucial part of
31+ your project's
32+ `architecture <http://www.amazon.com/gp/product/1257638017/ref=as_li_ss_tl?ie=UTF8&tag=bookforkind-20&linkCode=as2&camp=1789&creative=39095&creativeASIN=1257638017 >`__.
33+
34+ When a potential user or contributor lands on your repository's page,
35+ they see a few things:
36+
37+ - Project Name
38+ - Project Description
39+ - Bunch O' Files
40+
41+ Only when they scroll below the fold will the user see your project's
42+ README.
43+
44+ If your repo is a massive dump of files or a nested mess of directories,
45+ they might look elsewhere before even reading your beautiful
46+ documentation.
47+
48+ Dress for the job you want, not the job you have.
49+
50+ Of course, first impressions aren't everything. You and your colleagues
51+ will spend countless hours working with this repository, eventually
52+ becoming intimately familiar with every nook and cranny. The layout of
53+ it is important.
54+
55+ Sample Repository
56+ :::::::::::::::::
57+
58+ **tl;dr **: This is what `Kenneth Reitz <http://kennethreitz.org >`_ recommends.
59+
60+ This repository is `available on
61+ GitHub <https://github.com/kennethreitz/samplemod> `__.
62+
63+ ::
64+
65+ README.rst
66+ LICENSE
67+ setup.py
68+ requirements.txt
69+ sample/__init__.py
70+ sample/core.py
71+ sample/helpers.py
72+ docs/conf.py
73+ docs/index.rst
74+ tests/test_basic.py
75+ tests/test_advanced.py
76+
77+ Let's get into some specifics.
78+
79+ The Actual Module
80+ :::::::::::::::::
81+
82+ .. csv-table ::
83+ :widths: 20, 40
84+
85+ "Location", "``./sample/ `` or ``./sample.py ``"
86+ "Purpose", "The code of interest"
87+
88+
89+ Your module package is the core focus of the repository. It should not
90+ be tucked away:
91+
92+ ::
93+
94+ ./sample/
95+
96+ If your module consists of only a single file, you can place it directly
97+ in the root of your repository:
98+
99+ ::
100+
101+ ./sample.py
102+
103+ Your library does not belong in an ambiguous src or python subdirectory.
104+
105+ License
106+ :::::::
107+
108+
109+ .. csv-table ::
110+ :widths: 20, 40
111+
112+ "Location", "``./LICENSE ``"
113+ "Purpose", "Lawyering up."
114+
115+
116+ This is arguably the most important part of your repository, aside from
117+ the source code itself. The full license text and copyright claims
118+ should exist in this file.
119+
120+ If you aren't sure which license you should use for your project, check
121+ out `choosealicense.com <http://choosealicense.com >`_.
122+
123+ Of course, you are also free to publish code without a license, but this
124+ would prevent many people from potentially using your code.
125+
126+ Setup.py
127+ ::::::::
128+
129+ .. csv-table ::
130+ :widths: 20, 40
131+
132+ "Location", "``./setup.py ``"
133+ "Purpose", "Package and distribution management."
134+
135+
136+ If your module package is at the root of your repository, this should
137+ obviously be at the root as well.
138+
139+ Requirements File
140+ :::::::::::::::::
141+
142+ .. csv-table ::
143+ :widths: 20, 40
144+
145+ "Location", "``./requirements.txt ``"
146+ "Purpose", "Development dependencies."
147+
148+
149+ A `pip requirements
150+ file <http://www.pip-installer.org/en/latest/requirements.html> `__
151+ should be placed at the root of the repository. It should specify the
152+ dependencies required to contribute to the project: testing, building,
153+ and generating documentation.
154+
155+ If your project has no development dependencies, or you prefer
156+ development environment setup via ``setup.py ``, this file may be
157+ unnecessary.
158+
159+ Documentation
160+ :::::::::::::
161+
162+
163+ .. csv-table ::
164+ :widths: 20, 40
165+
166+ "Location", "``./docs/ ``"
167+ "Purpose", "Package reference documentation."
168+
169+ There is little reason for this to exist elsewhere.
170+
171+ Test Suite
172+ ::::::::::
173+
174+
175+ .. csv-table ::
176+ :widths: 20, 40
177+
178+ "Location", "``./test_sample.py `` or ``./tests ``"
179+ "Purpose", "Package integration and unit tests."
180+
181+ Starting out, a small test suite will often exist in a single file:
182+
183+ ::
184+
185+ ./test_sample.py
186+
187+ Once a test suite grows, you can move your tests to a directory, like
188+ so:
189+
190+ ::
191+
192+ tests/test_basic.py
193+ tests/test_advanced.py
194+
195+ Obviously, these test modules must import your packaged module to test
196+ it. You can do this a few ways:
197+
198+ - Expect the package to be installed in site-packages.
199+ - Use a simple (but *explicit *) path modification to resolve the
200+ package properly.
201+
202+ I highly recommend the latter. Requiring a developer to run
203+ `setup.py <http://setup.py >`__ develop to test an actively changing
204+ codebase also requires them to have an isolated environment setup for
205+ each instance of the codebase.
206+
207+ To give the individual tests import context, create a tests/context.py
208+ file:
209+
210+ ::
211+
212+ import os
213+ import sys
214+ sys.path.insert(0, os.path.abspath('..'))
215+
216+ import sample
217+
218+ Then, within the individual test modules, import the module like so:
219+
220+ ::
221+
222+ from .context import sample
223+
224+ This will always work as expected, regardless of installation method.
225+
226+ Some people will assert that you should distribute your tests within
227+ your module itself -- I disagree. It often increases complexity for your
228+ users; many test suites often require additional dependencies and
229+ runtime contexts.
230+
231+ Makefile
232+ ::::::::
233+
234+
235+ .. csv-table ::
236+ :widths: 20, 40
237+
238+ "Location", "``./Makefile ``"
239+ "Purpose", "Generic management tasks."
240+
241+
242+ If you look at most of my projects or any Pocoo project, you'll notice a
243+ Makefile laying around. Why? These projects aren't written in C... In
244+ short, make is a incredibly useful tool for defining generic tasks for
245+ your project.
246+
247+ **Sample Makefile: **
248+
249+ ::
250+
251+ init:
252+ pip install -r requirements.txt
253+
254+ test:
255+ py.test tests
256+
257+ Other generic management scripts (e.g. ``manage.py ``
258+ or ``fabfile.py ``) belong at the root of the repository as well.
259+
260+ Regarding Django Applications
261+ :::::::::::::::::::::::::::::
262+
263+ I've noticed a new trend in Django applications since the release of
264+ Django 1.4. Many developers are structuring their repositories poorly
265+ due to the new bundled application templates.
266+
267+ How? Well, they go to their bare and fresh repository and run the
268+ following, as they always have:
269+
270+ ::
271+
272+ $ django-admin.py start-project samplesite
273+
274+ The resulting repository structure looks like this:
275+
276+ ::
277+
278+ README.rst
279+ samplesite/manage.py
280+ samplesite/samplesite/settings.py
281+ samplesite/samplesite/wsgi.py
282+ samplesite/samplesite/sampleapp/models.py
283+
284+ Don't do this.
285+
286+ Repetitive paths are confusing for both your tools and your developers.
287+ Unnecessary nesting doesn't help anybody (unless they're nostalgic for
288+ monolithic SVN repos).
289+
290+ Let's do it properly:
291+
292+ ::
293+
294+ $ django-admin.py start-project samplesite .
295+
296+ Note the "``. ``".
297+
298+ The resulting structure:
299+
300+ ::
301+
302+ README.rst
303+ manage.py
304+ samplesite/settings.py
305+ samplesite/wsgi.py
306+ samplesite/sampleapp/models.py
307+
308+
309+
310+
311+ Structure of Code is Key
312+ ------------------------
24313
25314Thanks to the way imports and modules are handled in Python, it is
26315relatively easy to structure a Python project. Easy, here, means
0 commit comments