Publish a (Perfect) Python Package on PyPI
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Subtitle |
| |
Title of Series | ||
Number of Parts | 118 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/44830 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
| |
Keywords |
00:00
Smith chartPerfect groupPoint cloudGoogolLecture/Conference
00:32
Perfect groupSoftware developerTwitterSoftwareSoftware developerAsynchronous Transfer ModeRepresentational state transferService (economics)Computer animation
01:01
Computing platformWeb 2.0Software developerForm (programming)TelecommunicationWeb applicationService (economics)Asynchronous Transfer ModeServer (computing)Multiplication signMobile WebVideoconferencingComputer animation
01:25
CodeRevision controlAdditionInformationInstallation artString (computer science)LengthCASE <Informatik>Moment (mathematics)Computer fileDirectory serviceLine (geometry)Computer programmingControl flowEntire functionMiniDiscDistribution (mathematics)Process (computing)2 (number)Error messageWordMultiplication signFlagBookmark (World Wide Web)WebsiteText editorWeb serviceFunctional (mathematics)Descriptive statisticsPoint (geometry)Integrated development environmentUtility softwareModule (mathematics)Electronic mailing listParameter (computer programming)Library (computing)CodeSoftware developerConfiguration spaceTwitterBitSystem callSource codeLevel (video gaming)Revision controlInformationSoftwareQuicksortGraphics tabletNumberStandard deviationMaxima and minimaUniform resource locatorPeer-to-peerExterior algebraMereologyCartesian coordinate systemSoftware bugEquivalence relationForm (programming)OvalRepository (publishing)Web 2.0Arrow of timeFrequencyInstallation artComputer animation
10:45
Formal languageIndependence (probability theory)Physical systemModule (mathematics)Open setLibrary (computing)Installation artRevision controlSource codeLibrary (computing)CodeSoftware testingProjective planeRevision controlBitDifferent (Kate Ryan album)Product (business)Poisson-KlammerSoftwareFormal languageComputer fileString (computer science)Software developerAxiom of choiceUniform resource locatorFile formatModule (mathematics)Descriptive statisticsParameter (computer programming)Type theoryMoment (mathematics)Core dumpSystem callContent (media)Operating systemDirectory serviceSheaf (mathematics)WebsiteSampling (statistics)Web browserElectronic mailing listComputer configurationPoint (geometry)Radical (chemistry)Multiplication signConfiguration spaceFunctional (mathematics)Standard deviationOrder (biology)Reading (process)Block (periodic table)Open setIntelligent NetworkWritingWordSquare numberOcean currentLine (geometry)Key (cryptography)Coma BerenicesCASE <Informatik>TheoryGreatest elementVirtual realityCoefficient of determinationDistribution (mathematics)Repository (publishing)CuboidInstallation artSoftware frameworkFilm editingInteractive televisionComputer animation
20:05
Control flowMobile appNumberRevision controlComputing platformSoftware testingSoftware maintenanceSource codeSmith chartInformationBuildingPasswordDistribution (mathematics)Computer virusLink (knot theory)Installation artModule (mathematics)Formal languageScripting languageCodeMetric systemLogistic distributionTwitterSlide ruleLibrary (computing)Projective planeoutputComputer fileCodeMoment (mathematics)FlagTwitterMultiplication signLink (knot theory)Line (geometry)Distribution (mathematics)CuboidMathematicsOrder (biology)Software testingNetwork topologyGroup actionLatent heatComputer configurationPoint (geometry)Integrated development environmentVideo gameSoftware developerGreatest elementBounded variationCASE <Informatik>Web pageProduct (business)Operator (mathematics)Virtual machineFunction (mathematics)FreezingRootDirectory serviceSingle-precision floating-point formatConfiguration spaceBitEmailBinary codeDifferent (Kate Ryan album)Revision controlMobile appSource codeData managementNumberPhysical systemThermal conductivitySheaf (mathematics)HTTP cookieSet (mathematics)Software maintenanceVirtual realityHome pageAuthorizationFinite differenceTemplate (C++)Uniform resource locatorStructural loadAddress spaceTheorySlide ruleProcess (computing)Boilerplate (text)Metric systemGoodness of fitDirection (geometry)Core dumpStability theoryComputer animation
29:25
Lecture/Conference
Transcript: English(auto-generated)
00:32
for 30 minutes anyway, but I still have to talk about something first that's more important than Python packaging, and that's me. So my name is not gg2k, but this is my handle
00:44
more or less everywhere online. Feel free to follow me on Twitter, I tweet about Python and Brexit occasionally, angrily. My real name is Mark Smith, I'm a developer advocate for Nexmo, one of the conference sponsors. I would be remiss if I didn't briefly talk
01:00
about Nexmo. We are a software as a service company, we offer REST APIs that allow you to do telecommunications and various other forms of communication, including video streaming online to mobile devices and your web apps and things like that. If that sounds interesting, come and talk to us at the Nexmo booth or send me a tweet or come and talk to me around the conference, I'm happy to talk about that another time.
01:22
So, now I've talked about Nexmo, let me talk about JavaScript. So in March 2016, a developer removed a library called LeftPad from NPM, the Node.js equivalent of PyPI, it's a big web service, holds packages, when you need to pull down those packages and install them
01:41
into your JavaScript application, you run NPM and it downloads them and installs them so that you can access them from your program. LeftPad, so it broke lots of packages that depended on LeftPad, it turns out that quite a lot of packages on NPM depended on LeftPad, in fact it had been downloaded 2,486,696 times in the month before it was removed
02:06
from the NPM repository. It was just one function and it was 11 lines of code that padded a string to a certain length by adding characters to the start of that string. And lots of people thought that this made the JavaScript community look kind of silly.
02:25
It's why would anybody publish a package that only consisted of 11 lines of code, why would anybody use a package that only consisted of 11 lines of code? I don't think it made the JavaScript community look silly, I think actually it made the JavaScript community
02:41
look pretty awesome. Obviously there's some problems with the fact that people can remove a package that everybody is depending on and kind of break the entire JavaScript community's software, but in general why was this package published? So if you don't agree that this made the JavaScript community look awesome, feel free to fight me on Twitter.
03:02
So the LeftPad, LeftPad is not a problem, LeftPad was a solution, so because the JavaScript standard library is relatively small and doesn't contain lots of useful functions that say the Python standard library does contain, like the ability to LeftPad
03:21
a string with some characters, a developer wrote a solution for it himself. And because NPM makes it easy to publish small items of code, he did, and he made that code available to other developers so that they then didn't have to reinvent the wheel and that means that people can bug fix in one location, they can submit PRs to improve these
03:41
11 lines of code and then ultimately people can, well, ideally depend upon it. The alternative to this is copy and paste. Copy and paste, I think you can agree, is not how you should share your code. Because it's really easy to share with NPM, people do, and even with really small libraries. And I don't think that's really the case with Python, because people find Python packaging slightly fiddly. There are some slightly
04:04
odd things which we'll go through about pushing your first Python package to PyPI. I made it difficult for myself to say some of these sentences as well. So people are a bit afraid of setup.py. There is good documentation out there, lots of it conflicts with each other, but there is, I think, a growing movement to bring
04:24
some of this stuff together and make it easier to find current best practices. Hopefully this talk will help a little bit. So what I really want everybody in this room to feel at the end of this talk is confident to publish packages to PyPI. Relatively small packages, ideally pure Python packages,
04:41
which is what the example is going to be. So I would like you all to make a package. What we're going to do in this talk is I am going to show you how to make a package. So the first thing, the assumption is that you already have some code which is general enough or close to general enough that you think it would be useful for other people.
05:01
So let's take some useful general purpose code like a function that prints hello world. Now who in this room hasn't written this program in some form? Exactly. Now that is totally wasted time. Everybody in this room has written this program. Wouldn't it be so much better if you could pip install it and call that code from somewhere else?
05:20
So that's what we're going to do. Also note there is an F string here. F strings are awesome. So the idea is you've written some code that you're proud of, you would like to share it with the world. So the first thing to do is extract it from your code base so that it is independent of that code base. That's your problem, I'm not going to show you how to do that. In this case we're going to extract this code into a file called hello world.py. This is a Python module. Next we're going to put that
05:46
module in a source directory and I will explain towards the end of the talk why we did that. For the moment just assume that Hinik is excitedly clapping for the second time today. Awkward. So I'll explain why later, but for the moment just take this as
06:08
correct practice. And then in the same directory as the source directory, the directory that contains our source directory, we're going to create our set up py file. You can open
06:21
something like this into the file. So the first thing to note here is that we're importing from set up tools, not distutils. You will still find documentation online that recommends importing from distutils, don't do that, it's not that powerful compared to set up tools. PIP already is distributed with set up tools. So if you're installing packages with PIP, you have set up tools, it's not a third party dependency anymore.
06:44
And then we have this function underneath it, we call set up that we've imported from the set up tools module. It's a bit weird, for now just don't think of it as a function call, think of it as configuration. Each of those parameters is essentially a line of configuration that you are giving to PIP to tell it how to install your package.
07:04
So this is pretty much the bare minimum set up information you need to provide. So we start with a name, name is what you PIP install. So this is the name on PyPI that it will be uploaded under, so people will PIP install it. It doesn't have to be the name of the Python code that people will import, it's a separate thing. Usually
07:23
they're the same, sometimes they're different. We need to pick a version number, here I've just started with 001. 00X version numbers imply that it's unstable. There is a good chance that the first few times you upload this to PyPI there will be a minor packaging mistake, so this is a good stage to start to upload packages to PyPI while you've still
07:45
got this unstable version number, so you're not worried about breaking, people seeing instability that's not actually your code base, it's actually your packaging configuration. Then we have a description, this is usually a one-liner at this point, say hello is not a very useful description, but we'll leave it at that. Then we have Pymodules,
08:04
which is a list of the actual Python code modules, so we have a file called hello world.py, so in here we're saying this is the code that we want to distribute, so that's what people import, not what they PIP install. And then finally, again this is a kind of cargo copy and paste, set up config, we have this package deer line which is a map
08:24
that says empty string and source, all that is doing is telling set up tools that our code is under a source directory, so don't worry, put it in your code, forget about it after that. So now we've built a package, so let's build it, potentially we could distribute it.
08:42
So we run the set up file we just created with the bdist wheel command, this tells it to create a wheel file, something that is appropriate for uploading to PyPI, it will spit out a load of output, most of which I've deleted from here, but the line that I've highlighted in bold up here is the one that's important, so what that's saying is that it's just copied our hello world py code file into the lib directory,
09:04
which means that it will end up in our wheel. If that's not there, then essentially there will be no code, we'll have an empty wheel file and it won't work. So we can now look at what's been created as part of that bdist wheel command, so here are the directories and files, so remember we've only actually created two files so far,
09:24
hello world py and set up py, so everything else here was created by set up tools, so we have a few things here, it's created an egg info directory in our source directory, you'll want to git ignore this, I'll show you how to do that in a moment, this is horrible, I wish it didn't do this, I'm going to ignore it from now on.
09:42
Then we have a build directory, so this is where set up tools kind of moved our files to, in the process of building our wheel file, you will see the hello, the arrow is not in the right place, but you will see the hello world py file in there, so again validated that our code is actually going to be in our wheel, and then finally we've got the actual wheel file here,
10:01
that it's put in our dist directory, so that is our final distribution. So now we can install it locally, so this is just effectively testing our packaging, so it's not testing our code but it's testing our set up py file, so here we are going to pip install and then with the minus C flag and the full stop period dot whatever you want to call it,
10:23
this can be confusing to people if you haven't seen this before, just out of interest, who hasn't seen this before? Yeah, I thought so, this is actually an essential command if you are building Python packages, or rather they're essential flags, so the minus E, normally when you install a Python package,
10:40
it installs it into your site packages folder, inside your Python distribution, it copies the code into your Python distribution, we don't really want to do that, while we're working on our project, we wanted to just work with the code that's in our source directory, so that's what minus E does, it essentially links to the code that you're working on, instead of copying code into another location,
11:03
so that means once we've installed this package, we can continue to work with it, continue to run it, continue to write code against it, without having these two copies of our code that is just going to cause us problems further down the line. The full stop at the end means install the package in the current directory, so it's looking at the set up py file, so it's saying install this package by linking to the code that I'm working on.
11:26
You run this every so often, every time you change your set up py file, you essentially run this again to make sure that your package is installing correctly, and that your Python code is available to you. So bear in mind our code is under a source directory at the moment, so if we run Python in our current directory, we can't import hello world yet, because it's not in our path.
11:45
So let's, in theory, let's test it. So here we run Python, the REPL, and then we do our from hello world import say hello. Because we've just installed our code into our current virtual environment, this will work now. Even though our code is under the source directory,
12:00
Python has been told where our code is by the set up py file. So we can execute the say hello function, we can execute it by passing it the optional parameter, everything works as we would hope. So it's some rough testing, we'll get onto better testing at the moment, but it's just a confirmation that our code is installing correctly. So at this point, we have a working package with some useful code in it.
12:21
So we could upload that to PyPI immediately, but I would say that there's a few things that we really need to do before we get to that point. That's documentation and testing, but also just a little bit of housekeeping, which I'll run through now. So as I said, there's some files created that you really don't want to add to your git repository, so it's useful to have a gitignore file.
12:41
This website is fantastic. They make it easy to get hold of GitHub's standard gitignore files that they publish for different language and operating system communities. So you would write Python in that text box, hit create, and it will just spit out a text file into the web browser that you can copy and paste into a .gitignore file. So now we're ignoring all the main files that Python creates,
13:03
so it will stop you from uploading PYC files and a bunch of other artifacts on a Python project. If we're going to publish this code, we also need a license. If we don't have a license, we haven't given people permission to run our code. They can look at it, but they can't copy it or use it, which is not greatly useful. So we need a license.txt file,
13:21
and a good way to... If you don't know the ins and outs of the different licenses and the restrictions and freedoms they grant the software that you're publishing, this website, choosealicense.com, is incredibly useful. It essentially asks you lots of questions and then gives you your options and how they compare to each other. So it's a good way, it's a human way for non-legal people to understand the differences
13:42
between different software licenses. We need to add some classifiers to our setup.py file so that people can find the project in PyPI by searching on or filtering on common criteria. So here we say that this is Python 3 code. It runs under Python 3.6 and 3.7. We haven't really tested that yet,
14:01
but we know that it only runs under those versions of Python because there was an F string in the code, as I pointed out. I chose the GPLv2, so we put that in there. That was a bit of an arbitrary choice. These can all be looked up in this URL at the bottom, pypi.org.classifiers. There's a bunch of them. Try and apply all the useful classifiers to your project
14:22
so that you're describing what this project is for and how it's used. Then you need some documentation. But before you write some documentation, you need to work out what format you're going to write your documentation in. You basically have two choices at the moment. One is restructured text, which is written in Python. It's used widely in the Python community.
14:41
All of the Python core documentation is written in it. A whole bunch of the libraries you use have written in restructured text. But it is a Python solution, and if you're working on a project that has some Python code and maybe some Rust code or some C code or something like that, those people will probably not have encountered restructured text before, but they will probably have encountered markdown.
15:01
And markdown is a valid choice. It is simpler, but also less powerful. So you're making some compromises here. Both of them allow you to use tools like Sphinx for restructured text or MakeDock for markdown to compile a directory of markdown or rest files into a directory of documentation
15:21
that's all linked together. And both of these are supported by readthedocs. So you can publish either of these documentation kind of sites to read the docs and then not have to worry about hosting them yourself. So once we've decided, and I've chosen markdown, again, kind of arbitrarily, we need to write a readme. That's pretty much essential for any modern project.
15:42
Here we have the title of the project. We have a small paragraph describing what the project does. We should have a section describing how to install the project with some sample command line code for pip installing this project. We should have some sample code just to tell people how to use the useful code
16:01
that we've published to PyPI. And then once we've written this, it's nice to have this also published on PyPI. So as well as publishing on, say, GitHub or GitLab or wherever you're publishing your code, it would be really nice if we could insert, make this essentially the official description of our project, and we can do that. So this, again, this is,
16:21
even if you've published packages before and you used restructured text to write your readme, this is now a new feature in PyPI as of about a year ago. PyPI supports markdown directly, so you don't need to convert your markdown to restructured text before pushing it up to PyPI. So here I've just got, we're taking advantage of the fact that our setup.py file is code
16:41
and not configuration by opening the readme file, reading in this block of markdown, and then we apply that string to our setup call. So we use the long description parameter just to provide this string value that we put into a variable, and then very importantly, we need to tell PyPI this is markdown and not restructured text, which we do by providing this MIME type
17:03
as this content type parameter at the end. I wanted to talk about dependencies. I've cut this talk down a bit, so we won't actually show any code that uses blessings, but for example, if we use this terminal coloring library called blessings, this is how we would add it to our setup.py file.
17:21
So we have an install requires parameter. It's a list of these specifiers that describe the library and the versions we're prepared to accept. I will talk a little bit more about those in a moment. If we change the library dependencies or anything else, as I said, we should run our pip install minus e.command again just to reinstall the package
17:40
and just make sure it actually pulls down the dependencies and that these things work together, and then we should run some tests. But we don't have tests, and we shouldn't just keep on opening up the REPL and randomly calling functions to make sure that things work. I would recommend you write your tests with pytest. Pytest is awesome. But in order to write tests with pytest, again, we need more dependencies.
18:00
But this time, we're not talking about dependency of our library like blessings, so we're not saying this is needed to run. We're saying this is a development dependency. So this is something people need to install in order to develop code with our library. And in order to develop dev dependencies, I recommend you add them as extras into your setup.py. But a lot of people here, I suspect,
18:21
are using requirements.txt for this. If you have a setup.py file, I would argue you do not need a requirements.txt. You can do all of this within Python's standard packaging framework, and you get some advantages. Because again, this is code, not configuration. So the way this works, it looks a little bit like our install requires, but it's got an extra layer of indirection.
18:42
So you'll see that it's a dictionary rather than a list, but you still see that list in there as the first value. So the key is the name of your extra. So in this case, we're saying dev. We will tell people that they need to install the dev extras in order to work with our project. And then after that, it is just a list of dependencies. So in this case, we're saying pytest
19:01
above or equal to the value of version 3.7. And then we can tell people how to use it. So again, we update the readme. We have a section saying, if you would like to help develop Hello World, this is how you install the development dependencies so that you can run the tests. And it looks very similar to before, but you'll see we have the word dev in square brackets.
19:22
Afterwards, it's saying we're installing our current module with the dev extras. You may have used this with other packages, maybe not seen how that was specified. I stole this straight from ATAs, which I think is why Hinnick is here. So yes, if we install the extras, you will see that it installs a whole bunch
19:41
of other stuff, basically dependencies for pytest. So the difference between install requires and extras requires is that install requires is for production dependencies, things like Flask, Click, NumPy, Pandas, and the version should be as relaxed as they possibly can be. So you should be testing against multiple versions of each dependency.
20:00
In this way, you're not locking your users into a specific version of a shared dependency. So if both you and your user are using ATAs, ideally you need an overlap there. So if you're using version three, they're using version four, they're not gonna be able to use your package unless they make some changes. Extras require is different. It's for optional requirements for development or testing
20:22
or whatever groups of extras you want to create, and the version should be, in my opinion, as specific as possible, because you're trying to get your developers up and running as quickly as possible. And so creating an identical environment to yours and the other developers who have been working with the code, that's just going to make
20:42
everybody's life easier, rather than trying to debug minor variations in your development dependencies. Requirements.txt still has a place, but I would argue it's for apps that you deploy onto machines that you control. So in this case, you're pinning every single production requirement to a specific version so that you're producing a well-tested collection
21:00
of code on a destination machine. So you use fixed version numbers with a double equals operator, and you use pip freeze to just spit out all of the things that are currently installed straight into your requirements.txt. So here we write some tests. I'm going to zoom through this a bit because I'm running slowly, slower than I would like.
21:21
But yes, we run our code. Now we just need to run pytest to actually test our code each time. It's much easier than actually executing code by hand. It will spit out a bunch of stuff to say what version of Python you're using and things like that, and then it will spit out hopefully that your tests passed. So now what we've done so far, this is what we've produced.
21:40
We've got our license file, our readme file, setup file, source directory with our code, and a test. You can obviously stick your tests in a test directory if you have more test files. It's good to distribute source distributions as well as binary distributions for various reasons. People can check the code before they run it. They may not have access to GitHub to access the code.
22:00
They may just need to verify the code before they run it. When you run sdist against our setup py file, we actually get some warnings saying it would like some more data. For some reason, sdist would really like to know the maintainer and maintainer email or the author email. So it's told us that. So we can just add those in. That's three lines. We add the URL of the project,
22:21
a link to GitHub in this case, my name and my email address. Oh, excuse me. So now we need to test that, make sure that source distribution contains all the files that we want it to. So it just, when you run sdist, it just creates, in this case, a gzip tarball, and we can use the tar command to unzip that and have a look at the stuff inside.
22:41
And when we have a look at it, we notice that it hasn't got our license txt file or our test hello world file. Ideally, our source distribution should contain everything that is in this snapshot of code. So everything we're distributing, everything that gets built into the binary distribution. In order to add those missing files
23:02
into our source distribution, we need to write a manifest input file. They are fiddly and annoying. Fortunately, there's a tool called check manifest that does pretty much all of this for us, or at least will get us started quickly. So you can pip install it, you can add it to your development dependencies if you like, you run it for the first time with this create flag,
23:22
and then it will create you a manifest.in. I recommend having a look at it. It's just things like includes and excludes lines for various files that it's found in the project. It tries to make sure that everything you have in git ends up in your source distribution. So it's finding these files and adding them to the manifest input file. So then if we build our source distribution again,
23:42
we can unzip it, and then we see that now, just out of the box, the check manifest has created a manifest file that includes the files that were missing. So now let's publish it. It's good to publish earlier rather than later. If you try to perfect everything, you will really never publish the package. So as soon as at the point you have something useful,
24:03
not necessarily perfect, try and get it up. Apart from anything else, it will register your package name on PyPI to your project. So you're not letting somebody else just kind of come in in the months while you're working on your project. You used to be able to register your project before you uploaded code. Now you need to actually upload the code
24:22
in order to register a name. So here we run a setup py with the bdist wheel and the sdist command. And in our dist directory, we will now have our wheel file and our source distribution. In order to push to PyPI, you need to use Twine for various reasons. It separates the build step from the upload step,
24:41
which means that you can do these manual checks of your distribution files before you upload to PyPI. Otherwise, it's a single command to kind of build and push up your code. If you get it wrong, it's gonna mess things up for you. So here we install Twine. We use the twine upload command. It also uses HTTPS, whereas for a while, pip didn't.
25:01
So it's safer. Sorry, setup source didn't. If you get to PyPI, the website, quickly enough, you will see the name of your project on the home page as the most recently updated package, and that's kind of cool. If you click on it, you will then get to the project page. You can see our readme file is essentially duplicated here. There's a GitHub link that I've just cut off at the bottom.
25:23
I had to change the name of the project, by the way, because there is a hello world package on PyPI. Obviously, somebody has done that. So there's still some more stuff that we need to do. I would recommend using Tox. I really am running out of time, so I apologize for running through these. I recommend using Tox for testing against different distributions of Python
25:42
and different versions of the libraries that you depend on. Here, we're just testing against Python 3.6, 3.7. You install Tox. You have that Tox configuration file. It spits out loads of output when you run Tox, and hopefully, at the end, you get, for each one of your targets, you get a command succeeded and a little smiley face at the end,
26:01
which I always think is rather lovely. Here's why we use the source directory. So our root directory is the directory we have, I've been working in. If our code was in this directory, if we import hello world while running the tests, it will run the code in our source directory, sorry, in our current directory, but we don't want it to do that.
26:21
We want it to test installing the package and using the code from there. By having a source directory, you are forcing it to use the version that was just installed into the virtual environment. You should also build on clean machines. In the past, I've used Travis for this. I am probably moving my stuff to Azure Pipelines, depending on when Hinnik gets his stuff stabilized.
26:45
Yes, I won't talk about that anymore. For extra credit, you can add badges to your readme for code coverage, for quality metrics. You can manage versions with bump version. That's quite nice. You can test on different operating systems. You can write more documentation. You can always write more documentation and tests.
27:01
You can add a contributed section to your readme. You can implement a code of conduct. And there's lots that you can do, but I recommend that you don't do any of the stuff that I've described in this talk. So there's a project called Cookie Cutter that generates sets of files from templates, and people have already created template projects
27:21
for PyPI, for Python projects. So if you install Cookie Cutter, and then you run this command to download Jonald's, there's a few of them out there. I quite like Jonald's. It's similar to my own way of thinking of these things. This Cookie Cutter library, it will download the template from GitHub. It will ask you lots of questions
27:41
because it's much more flexible than all the, I've given you one option for each step. He offers you lots of options, different testing libraries and things like that. And then at the end of it, you're done, in theory. You will probably have to go and tweak some of these files, because they won't be quite the way you want, but it took me five minutes to get up and running
28:00
using this process. And then it created all of this. So you will recognize some of the stuff in here from the tutorial that we've been through. There is extra stuff in there. There is a Sphinx directory of documentation with just boilerplate documentation in there at the moment, but just waiting for you to fill it out. You copy in your code, and then you're done.
28:23
So that took me about five minutes. Could have cut this talk down to the last two slides if I'd wanted, instead of wasting all of your time for half an hour. But hopefully this gives you an overview of good packaging practice and all the things that you need to do to kind of build a well-rounded package. There's obviously different directions you can move in,
28:41
but this is a really good core understanding of the things you should do for a professionally released package. There are other projects for distributing libraries these days that are very interesting, that don't use setup py, or use it in different ways. I would really recommend having a look at them if you're struggling with setup py. Poetry is getting a lot of mind share at the moment.
29:01
I haven't really used them, so I can't really recommend them. I'm trying to push current most common best practice. If you are interested in the slides or the code for this talk, they are available on this bit.ly link. Follow me on Twitter. If you have any questions, feel free to grab me at the conference,
29:21
come to the Nexmo booth, tweet at me, preferably not abuse. But thank you very much for coming to my talk.