Package: quicklib
Build hassle-free setup scripts for your python libraries, with
practical versioning, requirements specification, and more (to come).InstallationInstall using:pip install quicklibOr clone this project’srepoand run:python setup.py installCreating librariesTL;DR- runpython-mquicklib.bootstrapin a new folder and
answer some questions, and you’re good to go coding. Look atexamplelibraryfor an example created with this bootstrap process.Also, your library needs to be in a git-managed folder, and needs at
least one numericmajor.minortag in your current history.If you have no version tags yet, create the first one now and push it:git tag -a 0.1 -m "first version tag: 0.1"
git push origin 0.1File structureThe recommended library file structure is something like:mylibrary/
  |----- setup.py
  |  | OR
  |  --- quicklib_setup.yml
  |-- README.md
  |-- [requirements.txt]
  mypackage/
    |-- __init__.py
    |-- version.py
    |-- module1.py
    |-- module2.py
    |-- subpackage/
      |-- __init__.py
      |-- module3.pyIf you want to include more than one top-level package in your library,
place additional ones next tomypackage.For a deeper dive into recommended structure and other possible options,
check outStructuring Your Projectat the Hitchhiker’s Guide to
Python.Setup scriptFor an examplesetup.pyfile seeexamplelibrary’s setup.py.The setup script must include this fixed stub copy-pasted verbatim:# -------- quicklib direct/bundled import, copy pasted --------------------------------------------importsysas_sys,globas_glob,osas_osis_packaging=not_os.path.exists("PKG-INFO")ifis_packaging:importquicklibelse:zips=_glob.glob("quicklib_incorporated.*.zip")iflen(zips)!=1:raiseException("expected exactly one incorporated quicklib zip but found%s"%(zips,))_sys.path.insert(0,zips[0]);importquicklib;_sys.path.pop(0)# -------------------------------------------------------------------------------------------------After that, where you would usually callsetuptools.setup(...), callquicklib.setup(...)instead:quicklib.setup(name='examplelibrary',url="https://example.com/",author='ACME Inc.',author_email='user@example.com',description='examplelibrary: a library to demonstrate how quicklib is used to quickly setup python libraries',license='Copyright ACME Inc.',platforms='any',classifiers=['Programming Language :: Python','Development Status :: 4 - Beta','Natural Language :: English','Intended Audience :: Developers','Operating System :: OS Independent','Topic :: Software Development :: Libraries :: Python Modules',],version_module_paths=["examplepackage/version.py",],)Most parameters are exactly the same as they are insetuptools.Additional parameters:version_module_paths- see details in “Versioning” belowModified parameter defaults:ifpackagesis not given,find_packages()is used
automatically to discover packages under your library’s top
directory.YAML-based setupThe easiest way for simple libraries is to provide all necessary details
in a YAML file. This is essentially the same as creating a setup.py that
uses the YAML dictionary as its kwargs.For example, create aquicklib_setup.ymlfile at the root of your
project:setup:
  name: mylibrary
  description: a library for doing some stuff
  version: 1.0And runquicklib-setupsdist(instead ofpython setup.py sdist)
to create the library package.You can alsoincludeadditional files of a similar format (overriding each other in order of appearance), e.g. to use as common template of values:# mylib_setup.yml
include:
    - ../common_properties.yml
setup:
    name: mylibrary

# common_properties.yml
setup:
    author: ACME Inc.
    author_email: user@example.comFor additional parameters, see the rest of this documentation and
provide parameters toquicklib.setup(...)as values under thesetupdictionary in yourquicklib_setup.ymlfile.Take a look at theminimal example libraryfor usage example.Setup script in non-standard locationIt is possible to build libraries with quicklib from setup scripts
other than “top level setup.py”. This allows building more than one
library (or variants of a single library) from a single repository.Look atexamplelibrary2for two such example library variants built
from the same sources.Just place your setup code in any folder and run it the same way as
usual, e.g.:python my_other_setup.py sdist bdist_wheelNote that if you want to have aMANIFEST.infile to go with the
script, you can put it alongside it and using the same base name,
e.g.:...
|-- my_other_setup.py
|-- my_other_setup.MANIFEST.in
...If no such alternative MANIFEST.in file is present and a top-level
MANIFEST.in exists, it will be used as usual.VersioningThe build process automatically sets your library version based on the
git log and tags. This version information is applied to the built
library and can later be programmatically queried by library package
users.version value inferenceItgit-describes theHEADsearching for the latest
annotated (!) tag with amajor.minorlabelIf the tag is placed directly on the currentHEADthen this is
the version labelotherwise, a.microsuffix is added denoting the number of
commits between the tag andHEADFinally, if there are any local modifications, a.dirtysuffix is
addedadding version info to your packagesAdd aversion.pystub file under any of your top-level packages with
this fixed template:# quicklib version boilerplateDEV_VERSION="0.0.0.dev0"__version__=DEV_VERSIONIn addition, tellsetup.pywhere to find those files:quicklib.setup(version_module_paths=["mypackage/version.py",# ... you can specify more than one],)Then, your users can programmatically query this version value by running
e.g.:importmypackageprint(mypackage.version.__version__)versioning multiple packagesIf your library contains multiple top-level packages, aversion.pyfile should usually be added under each of them. This allows your
library users to ask about the version of each of your individual
packages while being agnostic to the fact that they come from the same
library. If you find this confusing, you may want to stick to one
top-level package per library.Choosing packages to includeThe default behavior callssetuptools.find_packages()and typically collects all top-level packages found. To disable this behavior, providepackagesyourself.Another alternative is to provide a list of top-level package names in thetop_packagesargument. In this case,find_packages()is called when only these top-level packages are included in the search.RequirementsTo add requirements to your library, add them in arequirements.txtfile at the project root.Use syntax such as:numpy
pandas==0.18.1
yarg~=0.1.1Freezing requirementsSometimes you want to hardcode the versions of your dependencies. This
helps provide your users the exact same configuration you built and
tested with. To avoid having to manually update those numbers, you can
keep your requirements specified as usual but activate “requirement
freezing”.Do this by passingfreeze_requirements=Trueto thequicklib.setup(...)call insetup.py. At packaging time, the
available versions will be retrieved frompypi.python.org, and the
latest matching version will be hardcoded as the requirement.Note: if your library depends on a hardcodeddep==1.0butdepdid not hardcode its dependencies, your users might get different
packages. To get around that you can specify your requirements’
requirements as your own requirements. Automatically fetching this
information is on this library’s roadmap.when not using pypi.python.orgIf your dependency libraries come from another package repository, you
can specify another address or even provide your own plugin to retrieve
information from such a server.To do this, provide a dictionary of options infreeze_requirements:quicklib.setup(# ...freeze_requirements={# alternative pypi server address'pypi_server':'https://my-private-pypi.com/packages/',# when given, this is imported at packaging time and used to find package versions.# see quicklib/requirements.py for the StandardPypiServerPlugin default plugin, and follow its interface.'server_plugin':'foo.bar:baz()',})