{"id":2113,"date":"2019-12-04T04:24:26","date_gmt":"2019-12-04T04:24:26","guid":{"rendered":"http:\/\/kusuaks7\/?p=1718"},"modified":"2024-02-14T14:17:58","modified_gmt":"2024-02-14T14:17:58","slug":"ten-steps-to-set-up-your-python-project-for-success","status":"publish","type":"post","link":"https:\/\/www.experfy.com\/blog\/bigdata-cloud\/ten-steps-to-set-up-your-python-project-for-success\/","title":{"rendered":"Ten Steps to Set Up Your Python Project for Success"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"2113\" class=\"elementor elementor-2113\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"has_eae_slider elementor-section elementor-top-section elementor-element elementor-element-26849f39 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"26849f39\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"has_eae_slider elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6fceb336\" data-id=\"6fceb336\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-42a77cb elementor-widget elementor-widget-heading\" data-id=\"42a77cb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><h2>How to add tests, CI, code coverage, and more<\/h2><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f2a578c elementor-widget elementor-widget-text-editor\" data-id=\"f2a578c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"053a\" data-selectable-paragraph=\"\">In this guide we\u2019ll walk through adding tests and integrations to speed development and improve code quality and consistency. If don\u2019t have a basic working Python package, check out my guide to building one and then meet right back here.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3a76622 elementor-widget elementor-widget-text-editor\" data-id=\"3a76622\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<ol>\n \t<li id=\"d20b\" data-selectable-paragraph=\"\">Install Black<\/li>\n \t<li id=\"4172\" data-selectable-paragraph=\"\">Create .pycache<\/li>\n \t<li id=\"2508\" data-selectable-paragraph=\"\">Install pytest<\/li>\n \t<li id=\"04a6\" data-selectable-paragraph=\"\">Create Tests<\/li>\n \t<li id=\"4a18\" data-selectable-paragraph=\"\">Sign up for Travis CI and Configure<\/li>\n \t<li id=\"1edd\" data-selectable-paragraph=\"\">Create .travis.yaml<\/li>\n \t<li id=\"e917\" data-selectable-paragraph=\"\">Test Travis CI<\/li>\n \t<li id=\"fcf7\" data-selectable-paragraph=\"\">Add Code Coverage<\/li>\n \t<li id=\"b13a\" data-selectable-paragraph=\"\">Add Coveralls<\/li>\n \t<li id=\"fa1b\" data-selectable-paragraph=\"\">Add PyUp<\/li>\n<\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-05941ef elementor-widget elementor-widget-text-editor\" data-id=\"05941ef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"c170\" data-selectable-paragraph=\"\">This guide is for macOS with Python 3.7. Everything works as of early 2019, but things change fast.<\/p>\n<p id=\"530b\" data-selectable-paragraph=\"\">We\u2019ve got work to do. Let\u2019s hop to it!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9d3b494 elementor-widget elementor-widget-heading\" data-id=\"9d3b494\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"449f\" data-selectable-paragraph=\"\">Step 1: Install Black<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b2821ab elementor-widget elementor-widget-image\" data-id=\"b2821ab\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1200\/1*YbycVK-2veijOocpbSKLuw.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-21924b6 elementor-widget elementor-widget-text-editor\" data-id=\"21924b6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"59aa\" data-selectable-paragraph=\"\">Your package code should follows common style conventions.\u00a0<a href=\"https:\/\/github.com\/ambv\/black\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Black<\/a>\u00a0is a Python package that automatically formats your code for you so that it meet\u00a0<a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0008\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">PEP 8<\/a>. Black is relatively new and already has over a million downloads. Using it has quickly become a best practice in Python coding.\u00a0<a href=\"https:\/\/www.mattlayman.com\/blog\/2018\/python-code-black\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\" class=\"broken_link\">Here\u2019s a good guide<\/a>\u00a0to Black.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c8e6f8d elementor-widget elementor-widget-text-editor\" data-id=\"c8e6f8d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"c498\" data-selectable-paragraph=\"\">I\u2019m using Atom for my editor, so I added the\u00a0<em>Python-Black\u00a0<\/em>package to Atom\u00a0<em>\u2014\u00a0<\/em>install info is\u00a0<a href=\"https:\/\/atom.io\/packages\/python-black\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">here<\/a>. Now Atom will reformat your code when you save your file.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6b705f0 elementor-widget elementor-widget-text-editor\" data-id=\"6b705f0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"88f6\" data-selectable-paragraph=\"\">While we\u2019re at it, let\u2019s add Black to the development environment for our collaborators. Eventually, anyone who works on the project will adhere to the same style guide, or else their pull request won\u2019t be accepted.<\/p>\n<p id=\"fc34\" data-selectable-paragraph=\"\">Add\u00a0<code>black==18.9b0<\/code>\u00a0to the next empty line of requirements_dev.txt and run\u00a0<code>pip install -r requirements_dev.txt<\/code>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6efcf59 elementor-widget elementor-widget-text-editor\" data-id=\"6efcf59\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"4881\" data-selectable-paragraph=\"\">Black makes 88 characters the default max line length. Some guides and programs require 79 characters, e.g.\u00a0<a href=\"https:\/\/documentation-style-guide-sphinx.readthedocs.io\/en\/latest\/style-guide.html\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Sphinx style guide<\/a>. In the Black Atom, package you can set the max length.<\/p>\n<p id=\"f93c\" data-selectable-paragraph=\"\">Now that we\u2019re set up to save time writing code, let\u2019s save time pushing our app to PyPI.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cbe7bd9 elementor-widget elementor-widget-heading\" data-id=\"cbe7bd9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"f9fe\" data-selectable-paragraph=\"\">Step 2: Create .pypirc<\/h1><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f11551 elementor-widget elementor-widget-text-editor\" data-id=\"2f11551\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"5ffa\" data-selectable-paragraph=\"\">When we use\u00a0<a href=\"https:\/\/twine.readthedocs.io\/en\/latest\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">twine<\/a>\u00a0to push our builds to TestPyPI and PyPI we need to enter our login info manually. See\u00a0<a href=\"https:\/\/towardsdatascience.com\/build-your-first-open-source-python-project-53471c9942a7\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"broken_link\">my previous article<\/a>\u00a0if you aren\u2019t familiar with twine. Let\u2019s automate that process.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8c0c328 elementor-widget elementor-widget-text-editor\" data-id=\"8c0c328\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"862a\" data-selectable-paragraph=\"\">Twine will look for a file named\u00a0<em>.pypirc<\/em>\u00a0in our home directory. It will grab our url, login, and password when uploading our file.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7b4bb87 elementor-widget elementor-widget-text-editor\" data-id=\"7b4bb87\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"ab9c\" data-selectable-paragraph=\"\">Create your\u00a0<em>.pypirc<\/em>\u00a0file in your home directory with:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6aad9f3 elementor-widget elementor-widget-text-editor\" data-id=\"6aad9f3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"e42f\" data-selectable-paragraph=\"\"><code>touch ~\/.pypirc<\/code><\/p>\n<p id=\"bbe4\" data-selectable-paragraph=\"\">Add the following contents to your\u00a0<em>.pypirc<\/em>\u00a0file:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-34e9424 elementor-widget elementor-widget-text-editor\" data-id=\"34e9424\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"54ce\" data-selectable-paragraph=\"\">Replace with your username and passwords. Make sure to save this file in your home directory and not your current working directory. If you want to make sure other users are on your machine can\u2019t access this file, you can change its permissions from the command line:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4f0b4e2 elementor-widget elementor-widget-text-editor\" data-id=\"4f0b4e2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"ac1c\" data-selectable-paragraph=\"\"><code>chmod 600 ~\/.pypirc<\/code><\/p>\n<p id=\"23bc\" data-selectable-paragraph=\"\">Now you can upload your package to TestPyPI with the following command:<\/p>\n<p id=\"c0c7\" data-selectable-paragraph=\"\"><code>twine upload -r testpypi dist\/*<\/code><\/p>\n<p id=\"d94c\" data-selectable-paragraph=\"\">Upload to the real PyPI with this command:<\/p>\n<p id=\"7080\" data-selectable-paragraph=\"\"><code>twine upload dist\/*<\/code><\/p>\n<p id=\"c16d\" data-selectable-paragraph=\"\">No more usernames and passwords to enter. Isn\u2019t that nice?<\/p>\n<p id=\"2406\" data-selectable-paragraph=\"\">Now let\u2019s add some tests to make sure our package works.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d99d6b4 elementor-widget elementor-widget-heading\" data-id=\"d99d6b4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"dab4\" data-selectable-paragraph=\"\">Step 3: Install and Configure pytest<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-102ba30 elementor-widget elementor-widget-text-editor\" data-id=\"102ba30\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"be8b\" data-selectable-paragraph=\"\"><a href=\"https:\/\/docs.pytest.org\/en\/latest\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Pytest<\/a>\u00a0is the most popular, easy-to-use library for testing your Python code. In this example, we\u2019ll add simple tests to our project. If you want to learn about pytest,\u00a0<a href=\"https:\/\/semaphoreci.com\/community\/tutorials\/testing-python-applications-with-pytest\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">here\u2019s<\/a>\u00a0a nice intro tutorial. Another good guide is\u00a0<a href=\"https:\/\/medium.com\/u\/aa64089587cf?source=post_page-----14ff88b5d13----------------------\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"broken_link\">Brian Okken<\/a>\u2019s book,\u00a0<a href=\"https:\/\/www.amazon.com\/Python-Testing-pytest-Effective-Scalable\/dp\/1680502409\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Python Testing with Pytest<\/a>.<\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-96f0db7 elementor-widget elementor-widget-text-editor\" data-id=\"96f0db7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"c929\" data-selectable-paragraph=\"\">Add pytest to your requirements_dev.txt file with<\/p>\n<p id=\"549c\" data-selectable-paragraph=\"\"><code>pytest==4.3.0<\/code><\/p>\n<p id=\"e010\" data-selectable-paragraph=\"\">Run\u00a0<code>pip install requirements_dev.txt<\/code><\/p>\n<p id=\"bd35\" data-selectable-paragraph=\"\">Then run the following so that pytest can find your package:<\/p>\n<p id=\"413f\" data-selectable-paragraph=\"\"><code>pip install -e .<\/code><\/p>\n<p id=\"8684\" data-selectable-paragraph=\"\">If you deactivate your virtual environment, you\u2019ll need to run both pip commands again to run your tests.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b14bd68 elementor-widget elementor-widget-image\" data-id=\"b14bd68\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1920\/1*MhJEtYJmK97GY651EqeT9g.jpeg\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0e1d988 elementor-widget elementor-widget-heading\" data-id=\"0e1d988\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"b9ca\" data-selectable-paragraph=\"\">Step 4: Create Tests<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6d69a24 elementor-widget elementor-widget-text-editor\" data-id=\"6d69a24\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"9718\" data-selectable-paragraph=\"\">Add a\u00a0<em>tests<\/em>\u00a0folder in the top level of your project. Add a file inside it called<code>test_your_package_name.py<\/code>. My file is named\u00a0<code>test_notebookc.py<\/code>. Starting the file with\u00a0<code>test_<\/code>\u00a0makes it automatically discoverable by pytest.<\/p>\n<p id=\"0e90\" data-selectable-paragraph=\"\">In\u00a0<code>test_notebookc.py<\/code>\u00a0I added the following test to check whether the correct name prints as part of the function output. Modify to fit your own file and function names.<\/p>\n<p id=\"2111\" data-selectable-paragraph=\"\">What\u2019s going on here?<\/p>\n<p id=\"6a87\" data-selectable-paragraph=\"\">We first import our module. Then we create a function with\u00a0<code>test_my_function_name<\/code>. This naming convention is helpful for other people and the code coverage package we\u2019ll add soon.<\/p>\n<p id=\"569a\" data-selectable-paragraph=\"\">Then we call our function,\u00a0<em>convert<\/em>, with\u00a0<em>\u201cJill\u201d<\/em>\u00a0as the argument. Then we capture the output. As a reminder, our\u00a0<em>convert<\/em>\u00a0function is extremely basic \u2014 it takes the parameter\u00a0<em>my_name<\/em>\u00a0and outputs a line:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-169f6aa elementor-widget elementor-widget-text-editor\" data-id=\"169f6aa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"2d6d\" data-selectable-paragraph=\"\"><code>print(f\u201dI\u2019ll convert a notebook for you some day, {my_name}.\u201d)<\/code><\/p>\n<p id=\"cfea\" data-selectable-paragraph=\"\">Pytest checks to see if the string \u201cJall\u201d is in the output. It shouldn\u2019t be present, because we passed in \u201cJill\u201d. See the pytest documentation on capturing output\u00a0<a href=\"https:\/\/docs.pytest.org\/en\/latest\/capture.html\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">here<\/a>.<\/p>\n<p id=\"cc72\" data-selectable-paragraph=\"\">Run your test by entering\u00a0<code>pytest<\/code>\u00a0on the command line. Your test should fail with red text.<\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bdbfb0f elementor-widget elementor-widget-image\" data-id=\"bdbfb0f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1402\/1*_RApIDfhuCSduQ9GY6KjDA.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bc830f2 elementor-widget elementor-widget-text-editor\" data-id=\"bc830f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"4fa3\" data-selectable-paragraph=\"\">It\u2019s good practice to make sure your tests fail when they should. Don\u2019t just write them so they are green right away. Otherwise, your tests might not be testing what you think they are.<\/p>\n<p id=\"af0f\" data-selectable-paragraph=\"\">After we have a failing test we can change our expected output from\u00a0<code>Jall<\/code>\u00a0to<code>\u00a0Jill<\/code>, and our tests should pass in green.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6eea846 elementor-widget elementor-widget-image\" data-id=\"6eea846\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1408\/1*YI7jk4AR3TLV3Edwnmh9bA.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-56d4bb9 elementor-widget elementor-widget-text-editor\" data-id=\"56d4bb9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"e111\" data-selectable-paragraph=\"\">Yep, all good. Now we have a test that ensures that when someone passes a string value to our function, that string is printed.<\/p>\n<p id=\"96e0\" data-selectable-paragraph=\"\">Let\u2019s add a test to check that only a string has been passed to our function. If anything other than a string is passed, then a TypeError should be raised.\u00a0<a href=\"https:\/\/www.datacamp.com\/community\/tutorials\/exception-handling-python\" target=\"_blank\" rel=\"noopener nofollow noreferrer\" class=\"broken_link\">Here\u2019s a good guide<\/a>\u00a0on exceptions and error handling in Python.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c109e19 elementor-widget elementor-widget-text-editor\" data-id=\"c109e19\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"4616\" data-selectable-paragraph=\"\">When we write the test before we write the code that makes the test pass, we\u2019re doing test-driven development (TDD). TDD is a proven method to write code with fewer errors.\u00a0<a href=\"https:\/\/medium.freecodecamp.org\/test-driven-development-what-it-is-and-what-it-is-not-41fa6bca02a2\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Here\u2019s a nice article<\/a>\u00a0on TDD.<\/p>\n<p id=\"0477\" data-selectable-paragraph=\"\">Let\u2019s try something different this time. As an exercise, add your own test and code to ensure only a string can be passed as the argument to\u00a0<code>convert()<\/code>. Hint: integers, lists, and dicts get type-converted to strings. Follow me on Twitter @discdiver and I\u2019ll post the solution there.<\/p>\n<p id=\"021b\" data-selectable-paragraph=\"\">After we have passing tests we are ready to integrate our package with a CI service.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fd1c48d elementor-widget elementor-widget-heading\" data-id=\"fd1c48d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"aea5\" data-selectable-paragraph=\"\">Step 5: Sign up for Travis CI and Configure<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b422991 elementor-widget elementor-widget-image\" data-id=\"b422991\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/312\/1*AFDSQ9JKpdWo0KGXalR9cQ.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7ca8a96 elementor-widget elementor-widget-text-editor\" data-id=\"7ca8a96\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"5e94\" data-selectable-paragraph=\"\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Travis_CI\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Travis CI<\/a>\u00a0is a \u201chosted, distributed continuous integration service used to build and test software projects\u201d. It was recently acquired by\u00a0<a href=\"https:\/\/www.ideracorp.com\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Idera<\/a>. There are other CI options, but Travis CI is popular, free for open-source, and well-documented.<\/p>\n<p id=\"f564\" data-selectable-paragraph=\"\">Travis CI makes it easier to ensure that only code that passes your tests and standards is integrated into your project. Learn more about Travis CI\u00a0<a href=\"https:\/\/docs.travis-ci.com\/user\/for-beginners\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">here<\/a>\u00a0and more about continuous integration\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Continuous_integration\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">here<\/a>.<\/p>\n<p id=\"451e\" data-selectable-paragraph=\"\">Sign up for an account at\u00a0<a href=\"https:\/\/travis-ci.org\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">https:\/\/travis-ci.org\/<\/a>. Click on the\u00a0<em>Review and add your authorized organizations<\/em>\u00a0link from your Travis CI profile page. You\u2019ll be prompted for your GitHub password. Click\u00a0<em>Grant<\/em>\u00a0next to your organization access.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f10078 elementor-widget elementor-widget-image\" data-id=\"2f10078\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1058\/1*eVM9caZR7eoQ5CH-3zJhtg.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-997043d elementor-widget elementor-widget-text-editor\" data-id=\"997043d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"6fab\" data-selectable-paragraph=\"\">I had to sync my account for\u00a0<em>notebooktoall<\/em>\u00a0to show as an organization and for the\u00a0<em>notebookc<\/em>\u00a0repository to appear. It often takes a minute or more for data to start flowing. Then toggle your repo to\u00a0<em>on<\/em>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a91c87a elementor-widget elementor-widget-image\" data-id=\"a91c87a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/948\/1*eMsqAwXG3zfLe2Tn6_4UXA.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-caf6a15 elementor-widget elementor-widget-text-editor\" data-id=\"caf6a15\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"18b4\" data-selectable-paragraph=\"\">Click on\u00a0<em>settings<\/em>. You can choose whether you want Travis to build on pushed pull requests and\/or on pushed branches.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3b9db31 elementor-widget elementor-widget-image\" data-id=\"3b9db31\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/562\/1*f_C-x_lEoO3Li2VwpOoUXw.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a9b288c elementor-widget elementor-widget-text-editor\" data-id=\"a9b288c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"fb0b\" data-selectable-paragraph=\"\">Now we need to configure a file locally so that Travis will build for each pull request.<\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-71c0698 elementor-widget elementor-widget-heading\" data-id=\"71c0698\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"c1a0\" data-selectable-paragraph=\"\">Step 6: Create .travis.yml<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b50178d elementor-widget elementor-widget-text-editor\" data-id=\"b50178d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"7471\" data-selectable-paragraph=\"\">In the top level of your project folder, add a .<em>travis.yml<\/em>\u00a0file with these contents:<\/p>\n<p id=\"c8de\" data-selectable-paragraph=\"\"><code>dist: xenial<\/code>\u00a0is needed to specify that Travis should use Ubuntu Xenial 16.04 for its virtual environment. Xenial must be specified for testing Python 3.7 code. More info\u00a0<a href=\"https:\/\/docs.travis-ci.com\/user\/reference\/xenial\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">here<\/a>.<\/p>\n<p id=\"d841\" data-selectable-paragraph=\"\">Different versions of Python can be specified for testing. We\u2019ll get into that topic in a future article. Follow\u00a0<a href=\"https:\/\/medium.com\/@jeffhale\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"broken_link\">me<\/a>\u00a0to make sure you don\u2019t miss it!<\/p>\n<p id=\"1a6c\" data-selectable-paragraph=\"\">The\u00a0<code>install<\/code>\u00a0section ensures our packages for development are installed.\u00a0<code>pip install -e .<\/code>\u00a0installs your package as a wheel into Travis\u2019s virtual environment. Then Travis will find your package when it runs pytest.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8ea9649 elementor-widget elementor-widget-heading\" data-id=\"8ea9649\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"19a9\" data-selectable-paragraph=\"\">Step 7: Test Travis CI<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8714e17 elementor-widget elementor-widget-text-editor\" data-id=\"8714e17\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"4181\" data-selectable-paragraph=\"\">Commit your changes, push to GitHub, make a PR. Travis should start to run automatically within a few seconds.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6d0c24b elementor-widget elementor-widget-image\" data-id=\"6d0c24b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1570\/1*gopc8pdZSGtH_vSjiX-MsQ.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-96491ca elementor-widget elementor-widget-text-editor\" data-id=\"96491ca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"5d4c\" data-selectable-paragraph=\"\">Here\u2019s what Travis is doing.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7b62e1d elementor-widget elementor-widget-image\" data-id=\"7b62e1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/407\/1*q4dFomCCuht7DDrKhl2HyA.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bf94335 elementor-widget elementor-widget-text-editor\" data-id=\"bf94335\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\" data-selectable-paragraph=\"\"><span style=\"font-size: 11px;\">From travis.ci<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4d8b190 elementor-widget elementor-widget-text-editor\" data-id=\"4d8b190\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"e43c\" data-selectable-paragraph=\"\">Travis will tell you if your PR fails.<\/p>\n<p id=\"8583\" data-selectable-paragraph=\"\">Note that if a pull request fails, you can push to the same branch and Travis automatically reruns.<\/p>\n<p id=\"28f7\" data-selectable-paragraph=\"\">Go to your repo\u2019s page on Travis and have a look around. There\u2019s lots of info on Travis about your builds. You\u2019ll probably be visiting this site a good bit in the future trying to figure out why your build didn\u2019t pass.<\/p>\n<p id=\"50f8\" data-selectable-paragraph=\"\">Assuming everything is green, you\u2019re good to go!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-974258c elementor-widget elementor-widget-image\" data-id=\"974258c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1852\/1*f_U1tvYvkPoKLBEdniu7hA.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a74bcc4 elementor-widget elementor-widget-text-editor\" data-id=\"a74bcc4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"3041\" data-selectable-paragraph=\"\">If you don\u2019t see any red or green, click on the\u00a0<em>More options\u00a0<\/em>menu and select\u00a0<em>Requests<\/em>\u00a0from the dropdown. If you see red, have a look at the error messages. If you see the error\u00a0<em>Build config file is required,\u00a0<\/em>then Travis isn\u2019t finding your .travis.yml file on GitHub. Make sure it\u2019s in your GitHub repo.<\/p>\n<p id=\"51c2\" data-selectable-paragraph=\"\">Travis sends you emails to let you know when a build fails and when a failed build has been fixed.<\/p>\n<p id=\"d0b8\" data-selectable-paragraph=\"\">Remember that you can keep pushing your commits to an open PR and Travis will rerun automatically.<\/p>\n<p id=\"70bb\" data-selectable-paragraph=\"\">Let\u2019s see just how much of our code has test coverage.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-12966a5 elementor-widget elementor-widget-heading\" data-id=\"12966a5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"aff7\" data-selectable-paragraph=\"\">Step 8: Add Code Coverage<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f2defa8 elementor-widget elementor-widget-text-editor\" data-id=\"f2defa8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"e69b\" data-selectable-paragraph=\"\">A code coverage report shows you what percentage of your code has at least some test coverage. We\u2019ll add the\u00a0<a href=\"https:\/\/pypi.org\/project\/pytest-cov\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">pytest-cov<\/a>\u00a0package to create a report.<\/p>\n<p id=\"f973\" data-selectable-paragraph=\"\">Add the following line to\u00a0<em>requirements_dev.txt<\/em>:<\/p>\n<p id=\"dd44\" data-selectable-paragraph=\"\"><code>pytest-cov==2.6.1<\/code><\/p>\n<p id=\"6db4\" data-selectable-paragraph=\"\">Run with\u00a0<code>pytest --cov=my_project_name<\/code><\/p>\n<p id=\"d6d3\" data-selectable-paragraph=\"\">My output of\u00a0<code>pytest --cov=notebookc<\/code>\u00a0looks like this:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-adfdb96 elementor-widget elementor-widget-image\" data-id=\"adfdb96\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1408\/1*B92pusXAZvhddy3sANu95w.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ccd4111 elementor-widget elementor-widget-text-editor\" data-id=\"ccd4111\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"f203\" data-selectable-paragraph=\"\">Sweet, all our code is covered! When you only have a few lines that\u2019s not a high bar. \u00a0But we don\u2019t need to tell the world that \u2014 let\u2019s show them that we\u2019ve got coverage!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-731042b elementor-widget elementor-widget-heading\" data-id=\"731042b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"83d7\" data-selectable-paragraph=\"\">Step 9: Add Coveralls<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a5ad063 elementor-widget elementor-widget-text-editor\" data-id=\"a5ad063\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"ce92\" data-selectable-paragraph=\"\">Coveralls provides a history of your code coverage for all the world to see.<\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4df6f33 elementor-widget elementor-widget-image\" data-id=\"4df6f33\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/701\/1*1yCE0wWzZWR2YJZyPG4oOw.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ec33f33 elementor-widget elementor-widget-text-editor\" data-id=\"ec33f33\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"408d\" data-selectable-paragraph=\"\">Head over to\u00a0<a href=\"https:\/\/coveralls.io\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">https:\/\/coveralls.io\/<\/a>\u00a0and signup for an account using your GitHub credentials. Add your organization and toggle on your repo when it appears.<\/p>\n<p id=\"672e\" data-selectable-paragraph=\"\">In\u00a0<em>requirements_dev.txt<\/em>\u00a0add\u00a0<code>coveralls==1.6.0<\/code>. Your\u00a0<em>requirements_dev.txt\u00a0<\/em>should now look like this:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6506aa7 elementor-widget elementor-widget-text-editor\" data-id=\"6506aa7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"af56\" data-selectable-paragraph=\"\">Alter your\u00a0<em>.travis.yml<\/em>\u00a0file so it looks like the following (substituting your package name):<\/p>\n<p id=\"dac7\" data-selectable-paragraph=\"\">Now when Travis builds your project, it will install the necessary packages, run your tests, and create a coverage report. Then it sends the coverage report to coveralls.<\/p>\n<p id=\"28e8\" data-selectable-paragraph=\"\">Commit, push to GitHub, and watch the magic happen. It can take a few minutes for your coverage report to flow, so be patient.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9a384e2 elementor-widget elementor-widget-image\" data-id=\"9a384e2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1562\/1*akLrDRzv75zO40h9__Tafg.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2af693d elementor-widget elementor-widget-text-editor\" data-id=\"2af693d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"dd3f\" data-selectable-paragraph=\"\">Now coveralls shows in your PR checks. Cool!<\/p>\n<p id=\"52e3\" data-selectable-paragraph=\"\">Over on the Coveralls webpage, we should show 100% coverage.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-add03b2 elementor-widget elementor-widget-image\" data-id=\"add03b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1746\/1*WD85YI7iGKQ1M8plysU1cQ.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7289f2a elementor-widget elementor-widget-text-editor\" data-id=\"7289f2a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"bdee\" data-selectable-paragraph=\"\">Alright, let\u2019s add one more tool to our belt.<\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7a90832 elementor-widget elementor-widget-heading\" data-id=\"7a90832\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"5837\" data-selectable-paragraph=\"\">Step 10: Add PyUp<\/h1><\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"has_eae_slider elementor-section elementor-top-section elementor-element elementor-element-3000f07 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"3000f07\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"has_eae_slider elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4d5d728\" data-id=\"4d5d728\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6f85806 elementor-widget elementor-widget-text-editor\" data-id=\"6f85806\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"389b\" data-selectable-paragraph=\"\">PyUp.io lets you know when package dependencies are out of date or have security vulnerabilities. It automatically makes a pull request to update the package on GitHub.<\/p>\n<p id=\"088d\" data-selectable-paragraph=\"\">Go to\u00a0<a href=\"https:\/\/pyup.io\/\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">https:\/\/pyup.io\/<\/a>, register through GitHub, and connect your organization.<\/p>\n<p id=\"2a25\" data-selectable-paragraph=\"\">When you add your repo, I suggest you toggle your update schedule to every week. Then you won\u2019t get lots of pull requests if you have a bunch of package dependencies.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2ab100e elementor-widget elementor-widget-image\" data-id=\"2ab100e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1182\/1*GuTtNftSWVPVN71XuSmbAw.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-931a970 elementor-widget elementor-widget-text-editor\" data-id=\"931a970\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"00aa\" data-selectable-paragraph=\"\">Here\u2019s an example of a repository on PyUp that shows some out of date packages.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9c7d71a elementor-widget elementor-widget-image\" data-id=\"9c7d71a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1259\/1*nVWn7gBMK426ojtnk8SpSA.png\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1722d0e elementor-widget elementor-widget-text-editor\" data-id=\"1722d0e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"3ed7\" data-selectable-paragraph=\"\">Now you\u2019ll know when a package is updated \u2014 and knowing is half the battle. Automated pull requests must be the other half, right?<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-953682e elementor-widget elementor-widget-heading\" data-id=\"953682e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><h1 id=\"b1c0\" data-selectable-paragraph=\"\">Wrap<\/h1>\n<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d9d262b elementor-widget elementor-widget-text-editor\" data-id=\"d9d262b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p id=\"abae\" data-selectable-paragraph=\"\">In this article, you\u2019ve learned how to add and configure Black, pytest, Travis CI, Coveralls, and PyUp. We\u2019ve set the stage for more secure code with more consistent style.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Python is an interpreted, high-level, general-purpose programming language. Python&#8217;s design philosophy emphasizes code readability with its notable use of significant whitespace.&nbsp; In this article, you will learn how to add and configure Black, pytest, Travis CI, Coveralls, and PyUp. We&rsquo;ve set the stage for more secure code with more consistent style. Here&rsquo;s our ten-step plan for this article. This guide is for macOS with Python 3.7. Everything works as of early 2019, but things change fast.<\/p>\n","protected":false},"author":369,"featured_media":2960,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"content-type":"","footnotes":""},"categories":[187],"tags":[94],"ppma_author":[2134],"class_list":["post-2113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bigdata-cloud","tag-data-science"],"authors":[{"term_id":2134,"user_id":369,"is_guest":0,"slug":"jeff-hale","display_name":"Jeff Hale","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","user_url":"","last_name":"Hale","first_name":"Jeff","job_title":"","description":"Jeff Hale is a co-founder of Rebel Desk, where he oversees technology, finance, and operations for this company. He&nbsp;is an experienced entrepreneur who has managed technology, operations, and finances for several companies.&nbsp;"}],"_links":{"self":[{"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/posts\/2113","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/users\/369"}],"replies":[{"embeddable":true,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/comments?post=2113"}],"version-history":[{"count":5,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/posts\/2113\/revisions"}],"predecessor-version":[{"id":36004,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/posts\/2113\/revisions\/36004"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/media\/2960"}],"wp:attachment":[{"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/media?parent=2113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/categories?post=2113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/tags?post=2113"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.experfy.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}