2019年3月12日 星期二

[ Python 文章收集 ] How To Package Your Python Code - Minimal Structure

Source From Here 
Preface 
This tutorial aims to put forth an opinionated and specific pattern to make trouble-free packages for community use. It doesn’t describe the only way of doing things, merely one specific approach that works well. In particular, packages should make it easy: 
* To install with pip or easy_install.
* To specify as a dependency for another package.
* For other users to download and run tests.
* For other users to work on and have immediate familiary with the basic directory structure.
* To add and distribute documentation.

We’ll walk through the basic steps of building up a contrived package funniest to support these things: 
* Minimal Structure
* Specifying Dependencies
* Better Package Metadata
* Let There Be Tests
* Command Line Scripts
* Adding Non-Code Files
* Putting It All Together
* About This Tutorial / Contributing


Minimal Structure 
We’ll start with some Python code. Native German speakers, please proceed with caution
  1. def joke():  
  2.     return (u'Wenn ist das Nunst\u00fcck git und Slotermeyer? Ja! ... '  
  3.             u'Beiherhund das Oder die Flipperwaldt gersput.')  
The beauty and elegance of this implementation simply demands that it be packaged properly for distribution. 

Picking A Name 
Python module/package names should generally follow the following constraints: 
* All lowercase
* Unique on pypi, even if you don’t want to make your package publicly available (you might want to specify it privately as a dependency later). You can install pypi-check and check it this way:
# pypi-check fpu
✓ fpu is available!

* Underscore-separated or no word separators at all (don’t use hyphens)

We’ve decided to turn our bit of code into a module called funniest

Creating The Scaffolding 
The initial directory structure for funniest should look like this: 
  1. funniest/  
  2.     funniest/  
  3.         __init__.py  
  4.     setup.py  
The top level directory is the root of our SCM repo, e.g. funniest.git. The subdir, also called funniest, is the actual Python module. For starters we’ll put the joke() function in __init__.py, so it just contains: 
  1. def joke():  
  2.     return (u'Wenn ist das Nunst\u00fcck git und Slotermeyer? Ja! ... '  
  3.             u'Beiherhund das Oder die Flipperwaldt gersput.')  
The main setup config file, setup.py, should contain a single call to setuptools.setup(), like so: 
- setup.py 
  1. from setuptools import setup  
  2.   
  3. setup(name='funniest',  
  4.       version='0.1',  
  5.       description='The funniest joke in the world',  
  6.       url='http://github.com/storborg/funniest',  
  7.       author='Flying Circus',  
  8.       author_email='flyingcircus@example.com',  
  9.       license='MIT',  
  10.       packages=['funniest'],  
  11.       zip_safe=False)  
Now we can install the package locally (for use on our system), with: 
# pip install .
Processing /home/john/funniest
Installing collected packages: funniest
Found existing installation: funniest 0.1
Uninstalling funniest-0.1:
Successfully uninstalled funniest-0.1
Running setup.py install for funniest ... done
Successfully installed funniest-0.1


# pip freeze | grep funniest
funniest==0.1

# pip show funniest
Name: funniest
Version: 0.1
Summary: The funniest joke in the world
Home-page: http://github.com/storborg/funniest
Author: Flying Circus
Author-email: flyingcircus@example.com
License: MIT
Location: /usr/local/lib/python3.6/site-packages
Requires:
Required-by:

We can also install the package with a symlink, so that changes to the source files will be immediately available to other users of the package on our system: 
# pip install -e .

Anywhere else in our system using the same Python, we can do this now: 
>>> import funniest
>>> print(funniest.joke())
Wenn ist das Nunstück git und Slotermeyer? Ja! ... Beiherhund das Oder die Flipperwaldt gersput.

Publishing On PyPI 
The setup.py script is also our main entrypoint to register the package name on PyPI and upload source distributions. To “register” the package (this will reserve the name, upload package metadata, and create the pypi.python.org webpage): 
# python setup.py register

If you haven’t published things on PyPI before, you’ll need to create an account by following the steps provided at this point. At this point you can view the (very minimal) page on PyPI describing funniest: 
http://pypi.python.org/pypi/funniest/0.1 

Although users can follow the URL link to find our git repository, we’ll probably want to upload a source distribution so that the package can be installed without cloning the repository. This will also enable automated installation and dependency resolution tools to install our package. 

First create a source distribution with: 
# python setup.py sdist

This will create dist/funniest-0.1.tar.gz inside our top-level directory. If you like, copy that file to another host and try unpacking it and install it, just to verify that it works for you. 

That file can then be uploaded to PyPI with: 
# python setup.py sdist upload

You can combine all of these steps, to update metadata and publish a new build in a single step: 
# python setup.py register sdist upload

For a detailed list of all available setup.py commands, do: 
# python setup.py --help-commands
Standard commands:
build build everything needed to install
...
install install everything from build directory
install_lib install all Python modules (extensions and pure Python)
install_headers install C/C++ header files
install_scripts install scripts (Python or otherwise)
install_data install data files
sdist create a source distribution (tarball, zip file, etc.)
register register the distribution with the Python package index
bdist create a built (binary) distribution
bdist_dumb create a "dumb" built distribution
bdist_rpm create an RPM distribution
bdist_wininst create an executable installer for MS Windows
upload upload binary package to PyPI
check perform some checks on the package
...

Installing the Package 
At this point, other consumers of this package can install the package with pip
# pip install funniest

They can specify it as a dependency for another package, and it will be automatically installed when that package is installed (we’ll get to how to do that later). 

Adding Additional Files 
Most of the time we’ll want more than one file containing code inside of our module. Additional files should always be added inside the inner funniest directory. For example, let’s move our one function to a new text submodule, so our directory hierarchy looks like this: 
  1. funniest/  
  2.     funniest/  
  3.         __init__.py  
  4.         text.py  
  5.     setup.py  
In __init__.py
  1. from .text import joke  
In text.py
  1. def joke():  
  2.     return (u'Wenn ist das Nunst\u00fcck git und Slotermeyer? Ja! ... '  
  3.             u'Beiherhund das Oder die Flipperwaldt gersput.')  
All additional Python code belongs in the funniest/funniest/ directory. 

Ignoring Files (.gitignore, etc) 
There’s one more thing we’ll probably want in a ‘bare bones’ package: a .gitignore file, or the equivalent for other SCMs. The Python build system creates a number of intermediary files we’ll want to be careful to not commit to source control. Here’s an example of what .gitignore should look like for funniest
  1. # Compiled python modules.  
  2. *.pyc  
  3.   
  4. # Setuptools distribution folder.  
  5. /dist/  
  6.   
  7. # Python egg metadata, regenerated from source files by setuptools.  
  8. /*.egg-info  
That’s All You Need 
The structure described so far is all that’s necessary to create reusable simple packages with no ‘packaging bugs’. If every published Python tool or library used followed these rules, the world would be a better place. But wait, there’s more! Most packages will want to add things like command line scripts, documentation, tests, and analysis tools. Read on for more (Next section - Specifying Dependencies).

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...