<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oscar Cortez</title>
    <description>The latest articles on DEV Community by Oscar Cortez (@oscarmcm).</description>
    <link>https://dev.to/oscarmcm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F168238%2Ffafef1f5-f61d-4d67-b134-1f13a8f3e8b8.jpg</url>
      <title>DEV Community: Oscar Cortez</title>
      <link>https://dev.to/oscarmcm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oscarmcm"/>
    <language>en</language>
    <item>
      <title>Distributing PyPI Packages using API Tokens in TravisCI</title>
      <dc:creator>Oscar Cortez</dc:creator>
      <pubDate>Sun, 11 Aug 2019 18:06:29 +0000</pubDate>
      <link>https://dev.to/oscarmcm/distributing-pypi-packages-using-api-tokens-in-travisci-1n9i</link>
      <guid>https://dev.to/oscarmcm/distributing-pypi-packages-using-api-tokens-in-travisci-1n9i</guid>
      <description>&lt;p&gt;The &lt;em&gt;PyPI&lt;/em&gt; package index is one of the tools that makes &lt;strong&gt;Python&lt;/strong&gt; so powerful, with just a simple command, you get access to thousands of cool libraries, ready for you to use in your project.&lt;/p&gt;

&lt;p&gt;Writing &lt;strong&gt;Python&lt;/strong&gt; packages and deploying them to &lt;em&gt;PyPI&lt;/em&gt; is one way for sharing libraries to the open-source community. For beginners, submitting a package to &lt;em&gt;PyPI&lt;/em&gt; is not an easy task, but the community is working hard, for make this process more easier, you can read more about packaging, following the official &lt;a href="https://packaging.python.org/tutorials/packaging-projects/" rel="noopener noreferrer"&gt;Python Packaging Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I'm going to skip some things/steps about packaging, and guide you through the process of using the newest &lt;a href="http://pyfound.blogspot.com/2019/07/pypi-now-supports-uploading-via-api.html" rel="noopener noreferrer"&gt;API Tokens&lt;/a&gt; feature in &lt;em&gt;PyPI&lt;/em&gt;, for your continuous integration and deployment (CI/CD).&lt;/p&gt;

&lt;p&gt;For this we'll use the &lt;a href="https://test.pypi.org/" rel="noopener noreferrer"&gt;PyPI Test&lt;/a&gt; instance, which is a better option for doing initial test in your packages, like: testing if the docs render correctly, or if the &lt;a href="https://pypi.org/classifiers/" rel="noopener noreferrer"&gt;classifiers&lt;/a&gt; in your &lt;code&gt;setup.py&lt;/code&gt; are correct, for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Travis CI
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Travis CI&lt;/em&gt; can automatically release your &lt;strong&gt;Python&lt;/strong&gt; packages to &lt;em&gt;PyPI&lt;/em&gt; after a successful build. For a minimal configuration, you can use the following code in your &lt;code&gt;.travis.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pypi&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;username"&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;password"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, as you may notice, this would expose your &lt;em&gt;PyPI&lt;/em&gt; password to the world, and that is a bad idea. What Travis recommend is to encrypt the password or save the credentials as Travis Environment Variables, you can read more about it on &lt;a href="https://docs.travis-ci.com/user/deployment/pypi/" rel="noopener noreferrer"&gt;Travis deployment docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get the PyPI tokens
&lt;/h3&gt;

&lt;p&gt;So, the first thing to do, is go to &lt;a href="https://test.pypi.org/" rel="noopener noreferrer"&gt;https://test.pypi.org/&lt;/a&gt; and create an account (if you don't have one) or login, after that, we're gonna need our &lt;em&gt;API Token&lt;/em&gt;.  How to get it? Go to your &lt;em&gt;PyPI&lt;/em&gt; account settings and select "Add API token". When you create an API token, you choose its scope: you can create a token that can be used to upload to all the projects you maintain or own, or you can limit its scope to just one project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjs4fdwiifbvbyvstc8zo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjs4fdwiifbvbyvstc8zo.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use the tokens
&lt;/h3&gt;

&lt;p&gt;API tokens provide an alternative way (instead of username and password) to authenticate when uploading packages to &lt;em&gt;PyPI&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;These API tokens can only be used to upload packages to PyPI, and not to log in more generally, since a thief who copies the token won't also gain the ability to delete the project, delete old releases or add/removed collaborators.&lt;/p&gt;

&lt;p&gt;As you can see on the following screenshot, I have successfully manually deployed the first version of the demo project on PyPI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxz68e9fukw7icfkui8a5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxz68e9fukw7icfkui8a5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to enable &lt;em&gt;Travis&lt;/em&gt; for this project, so go to &lt;strong&gt;&lt;a href="https://travis-ci.org/account/repositories" rel="noopener noreferrer"&gt;https://travis-ci.org/account/repositories&lt;/a&gt;&lt;/strong&gt; and enable it, after that we have to change the following things in our &lt;code&gt;.travis.yml&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set the username to &lt;code&gt;__token__&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the password to the token value, including the &lt;code&gt;pypi-&lt;/code&gt; prefix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more extra security, we're going to store the token as an environment variable, go to &lt;strong&gt;&lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;https://travis-ci.org/&lt;/a&gt;//settings&lt;/strong&gt; and now our &lt;code&gt;.travis.yml&lt;/code&gt; file will looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pypi&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;__token__&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$TEST_PYPI_TOKEN&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://test.pypi.org/legacy/&lt;/span&gt;
  &lt;span class="na"&gt;distributions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sdist&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bdist_wheel"&lt;/span&gt;
  &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$TRAVIS_PYTHON_VERSION = "3.6"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, every time we push code to the &lt;em&gt;staging&lt;/em&gt; branch, &lt;em&gt;Travis&lt;/em&gt; will trigger an automatic deploy to the &lt;em&gt;PyPI&lt;/em&gt; test instance. do a small changes in the codebase, and change the &lt;code&gt;setup.py&lt;/code&gt; version number, then push to the &lt;em&gt;staging&lt;/em&gt; branch, &lt;em&gt;Travis&lt;/em&gt; will trigger a build and if everything works deploy the new version to &lt;em&gt;PyPI&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj0n1h21o1ulv7in5rl86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj0n1h21o1ulv7in5rl86.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can inspect the build logs to see if the deploy process started correctly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhf1p4lgjx9aaqfsqf64y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhf1p4lgjx9aaqfsqf64y.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And voilà, on the line &lt;em&gt;271&lt;/em&gt; we see the deploy process started, if you expand the line you could see the following logs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fin5rcm8ljalsyfk8zvpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fin5rcm8ljalsyfk8zvpy.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That means that our new version was uploaded correctly and now we can see it available in &lt;em&gt;PyPI&lt;/em&gt;, automatically deployed with &lt;em&gt;Travis&lt;/em&gt; using the new API tokens:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fityi3uscghk93qsf7m98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fityi3uscghk93qsf7m98.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is a big step forward for the Python Package Index, increasing the security with new multiple features, and reducing all the characteristics that make it hard to work on, for the &lt;strong&gt;Python&lt;/strong&gt; community, thanks to the &lt;a href="https://wiki.python.org/psf/PackagingWG" rel="noopener noreferrer"&gt;Packaging Working Group&lt;/a&gt; and the grant from the &lt;a href="https://pyfound.blogspot.com/2019/03/commencing-security-accessibility-and.html" rel="noopener noreferrer"&gt;Open Technology Fund&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can read more about API tokens on the official &lt;a href="http://pyfound.blogspot.com/2019/07/pypi-now-supports-uploading-via-api.html" rel="noopener noreferrer"&gt;PSF Blog&lt;/a&gt; or help to test this &lt;a href="https://wiki.python.org/psf/WarehousePackageMaintainerTesting" rel="noopener noreferrer"&gt;beta feature&lt;/a&gt;. If do you want to read the Spanish version of this post, you can find it on &lt;a href="https://oscarmcm.com/essays/2019/distributing-packages-via-pypi-tokens" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;. Also the source code is available &lt;a href="https://github.com/oscarmcm/pypi-token-demo" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And that's it! From here you can automate the process for releasing new package versions, so let's go, publish something to &lt;em&gt;PyPI&lt;/em&gt; 🐍.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://twitter.com/Darwing1210/" rel="noopener noreferrer"&gt;@Darwing1210&lt;/a&gt; and &lt;a href="https://twitter.com/guadamzjj/" rel="noopener noreferrer"&gt;@guadamzjj&lt;/a&gt; for reviewing this document.&lt;/p&gt;

&lt;p&gt;With ❤️ from 🇳🇮.&lt;/p&gt;

</description>
      <category>python</category>
      <category>pypi</category>
      <category>tutorial</category>
      <category>travis</category>
    </item>
  </channel>
</rss>
