{
    "componentChunkName": "component---src-templates-post-page-js",
    "path": "/2018/starting-python-project",
    "result": {"data":{"site":{"siteMetadata":{"title":"Solid Abstractions","siteUrl":"https://solidabstractions.com","twitterId":291334023,"author":{"fullName":"Julien Hartmann","profileHtml":"I am an open-source de­vel­op­er, for­mer IT con­sul­tant with a pas­sion for new tech­nol­o­gies. I be­lieve the role of an en­gi­neer is to em­pow­er peo­ple, by as­sem­bling sim­ple, re­fined de­signs.\n","links":[{"url":"https://github.com/spectras/","name":"github","title":"GitHub"},{"url":"https://stackoverflow.com/users/3212865/spectras","name":"stackoverflow","title":"StackOverflow"},{"url":"https://www.linkedin.com/in/julienhartmann/","name":"linkedin","title":"LinkedIn"}],"profilePicNode":{"original":{"src":"/static/profile-pic-301a9cbe7b572c3e7910c9717d2b3bcd.jpg"}},"url":"https://etherdream.org/about"}}},"markdownRemark":{"id":"8450e687-092b-5ca7-a759-9d2f03deb668","excerpt":"We hack together a couple of modules, do quick manual testing. Eventually, the code remains a\nhackish mess rotting away which may be fine but a little unsatisfactory.","html":"<p>We hack together a couple of modules, do quick manual testing. Eventually, the code remains a\nhackish mess rotting away which may be fine but a little unsatisfactory.</p>\n<p>--- excerpt ---</p>\n<p>We have all been there: we need to start a new project. It can be an actual project or,\nat some point in our lives, it could have been a small homework assignment. Now sitting\nin front of an empty directory, we figure we will not bother with the boilerplate yet.</p>\n<p>We hack together a couple of modules, do quick manual testing because, heck, setting up\nan actual testing infrastructure is boring and takes time. And eventually, we either\nresolve to spend the time to do it, or for a short-term project, the code remains a\nhackish mess rotting away which may be fine but a little unsatisfactory.</p>\n<p>This is why starting with a nice project template is a good idea.</p>\n<div class=\"note\"><p>→ Coming back? Here is a direct link to <a href=\"https://github.com/spectras/toys/tree/master/template-python\" class=\"external\" rel=\"external noopener noreferrer\">the template</a>.</p></div>\n<h2 id=\"what-do-we-need\">What do we need?</h2>\n<p>We have a couple of basic tools to support any project. Roughly, we need:</p>\n<ul>\n<li>A proper code layout, that works well with common Python ecosystem.</li>\n<li>A version control system.</li>\n<li>An automated testing suite.</li>\n<li>Test coverage to assess our tests' quality.</li>\n<li>Standard packaging tools.</li>\n</ul>\n<p>And the ability to setup all this quickly and consistently, be it for other contributors\nor ourselves two years from now.</p>\n<p>Lastly, if we are to share and accept contributions, on top of that we need at least:</p>\n<ul>\n<li>Documentation tools to make contributions easier and more in line with our style.</li>\n<li>Continuous integration to check contributions.</li>\n</ul>\n<p>That should cover the most common needs.</p>\n<h2 id=\"a-simple-template\">A simple template</h2>\n<h3 id=\"tools\">Tools</h3>\n<p>Unless we have specific, unusual needs, it is best to stick to industry standards, as\nthey are more likely to stand the test of time.</p>\n<ul>\n<li>Git is the obvious choice for new projects outside of established ecosystems.\nIt is ubiquitous, and <a href=\"https://github.com\" class=\"external\" rel=\"external noopener noreferrer\">github</a> has a neat pull-request workflow\nthat works great for projects following an open-source approach (whether they\nactually are open source or not).</li>\n<li>We will use the <a href=\"https://docs.pytest.org\" class=\"external\" rel=\"external noopener noreferrer\">pytest</a> framework for testing. Although not\npart of python as <a href=\"https://docs.python.org/3/library/unittest.html\" class=\"external\" rel=\"external noopener noreferrer\">unittest</a> is,\nit features better support for many third-party libraries and cleaner setup.</li>\n<li>We will use <a href=\"https://github.com/nedbat/coveragepy\" class=\"external\" rel=\"external noopener noreferrer\">coverage.py</a> to ensure our tests\nare thorough. Integrates well with <code class=\"language-text\">pytest</code>, using <code class=\"language-text\">pytest-cov</code>.</li>\n<li>We will add a <a href=\"https://tox.readthedocs.io\" class=\"external\" rel=\"external noopener noreferrer\">tox</a> configuration to make it easy to\nrun tests on several python versions.</li>\n<li><a href=\"https://www.pylint.org/\" class=\"external\" rel=\"external noopener noreferrer\">Pylint</a> will ensure we follow\n<a href=\"https://www.python.org/dev/peps/pep-0008/\" class=\"external\" rel=\"external noopener noreferrer\">PEP 8</a> style guidelines.</li>\n<li>We will use the <a href=\"http://www.sphinx-doc.org\" class=\"external\" rel=\"external noopener noreferrer\">sphinx</a> documentation generator that\nhas grown standard in the python community.</li>\n<li>We will use the usual <a href=\"https://setuptools.readthedocs.io\" class=\"external\" rel=\"external noopener noreferrer\">setuptools</a> used in\nmost python projects.</li>\n</ul>\n<p>Continuous integration depends a bit more on the environment. If building an open-source\nproject, <a href=\"https://travis-ci.org/\" class=\"external\" rel=\"external noopener noreferrer\">travis-ci</a> has widespread use. Let's use it.</p>\n<p>I will not explain how to use the tools. See the link to the template below.</p>\n<h3 id=\"layout\">Layout</h3>\n<p>I uploaded <a href=\"https://github.com/spectras/toys/tree/master/template-python\" class=\"external\" rel=\"external noopener noreferrer\">the template</a> to github. It assumes a project named <code class=\"language-text\">example</code>. File\nlayout is straightforward:</p>\n<dl><dt>docs /</dt><dd><p>The template uses <a href=\"http://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html\" class=\"external\" rel=\"external noopener noreferrer\">autodoc</a>\nto extract documentation from docstrings. This directory simply describes the structure\nof the documentation, importing extracted docstrings in the correct spots.</p></dd><dt>&#x3C;project name> /</dt><dd><p>The namespace of the project. It should have the same name. All the code lives here,\nand all imports should therefore read like <code class=\"language-python\"> <span class=\"token keyword\">from</span> example<span class=\"token punctuation\">.</span>foo <span class=\"token keyword\">import</span> bar</code>.\nAlways use full-path imports.</p></dd><dt>tests /</dt><dd><p>Unit tests. Every file in <code class=\"language-text\">&lt;project name></code> should have a matching file in <code class=\"language-text\">tests</code>, prefixed\nwith <code class=\"language-text\">test_</code>. This makes pytest recognize them automatically. In them, every test case\nshould be a function with a descriptive name starting with <code class=\"language-text\">test_</code> as well.</p></dd><dt>setup.py</dt><dd><p>Packaging configuration. It defines project dependencies and customizes install.\nIf the project should be runnable, this is where entry points are configured.\nIf you use the template, be sure to update author name and project url there.</p></dd></dl>\n<p>Other files should be obvious by just looking at them in the template.</p>\n<p>This is it. No excuses for not having a decent setup now. The template is <a href=\"https://github.com/spectras/toys/tree/master/template-python\" class=\"external\" rel=\"external noopener noreferrer\">here</a>,\nsetup instructions included. Feel free to copy it, use and reuse it.</p>\n<h2 id=\"more-tips-and-resources\">More tips and resources</h2>\n<p>In no particular order:</p>\n<ul>\n<li>The <a href=\"https://pyscaffold.org\" class=\"external\" rel=\"external noopener noreferrer\">pyscaffold</a> project has a nice generator that creates\nproject templates for specific frameworks.</li>\n<li>\n<p>If building an asynchronous project using\n<a href=\"https://docs.python.org/3/library/asyncio.html\" class=\"external\" rel=\"external noopener noreferrer\">asyncio</a>:</p>\n<ul>\n<li>add <code class=\"language-text\">pytest-asyncio</code> and <code class=\"language-text\">sphinxcontrib-asyncio</code> to <code class=\"language-text\">requirements-dev.txt</code>.</li>\n<li>add <code class=\"language-text\">'pytest-asyncio'</code> into the <code class=\"language-text\">tests_require</code> section of <code class=\"language-text\">setup.py</code>.</li>\n<li>add <code class=\"language-text\">'sphinxcontrib.asyncio'</code> into the <code class=\"language-text\">extensions</code> section of <code class=\"language-text\">docs/conf.py</code>.</li>\n</ul>\n</li>\n<li>If you host your code on github, enabling <a href=\"https://travis-ci.org/\" class=\"external\" rel=\"external noopener noreferrer\">travis</a> takes\nless than 5 minutes and it runs your tests at every push automatically.</li>\n</ul>\n<p><strong>Happy coding!</strong></p>","fields":{"isPage":false,"slug":"/2018/starting-python-project"},"frontmatter":{"title":"Starting a Python Project","classname":null,"date":"2018-09-14T00:00:00.000Z","formattedDate":"September 14, 2018","isoDate":"2018-09-14T00:00:00+00:00"},"headings":[{"value":"What do we need?","depth":1},{"value":"A simple template","depth":1},{"value":"Tools","depth":2},{"value":"Layout","depth":2},{"value":"More tips and resources","depth":1}],"image":null,"series":{"name":"python","fullName":null,"fields":{"slug":"/python"}},"tags":[{"name":"code","slug":"/tag/code"}]}},"pageContext":{"series":"python","slug":"/2018/starting-python-project","previous":{"fields":{"slug":"/2018/cryptomate/the-story-so-far"},"frontmatter":{"title":"The Story So Far","series":"cryptomate"},"tags":[{"name":"architecture","slug":"/tag/architecture"}]},"next":{"fields":{"slug":"/2018/cryptomate/groundwork"},"frontmatter":{"title":"Laying the Groundwork","series":"cryptomate"},"tags":[{"name":"code","slug":"/tag/code"}]},"seriesPrevious":null,"seriesNext":{"fields":{"slug":"/2018/testing-aiohttp-client"},"frontmatter":{"title":"Unit Testing aiohttp Clients","series":"python"},"tags":[{"name":"code","slug":"/tag/code"},{"name":"testing","slug":"/tag/testing"}]}}},
    "staticQueryHashes": ["1733002695","4006707078"]}