(BENTO)
A packaging solution for python software
WHAT’S PACKAGING ?
• Whatever     that has to happen between svn/git/etc... and the
 end-user

• Different   end-users, different workflows: not just tarballs




                                (maybe those guys don’t need
                                         packaging)
DISTUTILS

• De-facto   solution since ±2000

• Works   well for simple packages:

• Setuptools/distribute

  • add   package dependencies
DISTUTILS ISSUES

• Make   one’s head
 hurt:
 • Hard   to extend
 • Fragile   codebase
 • Reliability   issues
BENTO

• Declarative   description of package: metadata inspection
 is simple

• Flexible   installation scheme: install any file anywhere

• Layered    internal architecture: easy to extend

• Scaledown and up: simpler for small packages, more
 flexible for big ones
A SIMPLE BENTO FILE

Name: foo
Version: 0.1
Description:
    Package description.

Library:
    Packages:
!       foo, foo.core
BENTOMAKER

• Command-line   interface to bento


    $   bentomaker configure
    $   bentomaker build
    $   bentomaker install
    #   Or more simply
    $   bentomaker install
ADDING DATA-FILES
Datafiles: pdf_documentation
    TargetDir: $pdfdoc
    Files: main.pdf



$ bentomaker configure --pdfdoc=/usr/pdfdoc




# ant-like glob format supported
Datafiles: pdf_documentation
    TargetDir: $pdfdoc
    Files: doc/**/*.pdf
CUSTOM INSTALL PATHS
 Path: foodir
     Description: foo directory
     Default: $datadir/foo

 Datafiles: fubar-doc
     TargetDir: $foodir
     Files: main.foo




 $ bentomaker configure --foodir=/usr/pdfdoc
HOOK FILES
• Can “hook” python   files into the build process

     from bento.commands import hooks
     @hooks.command
     def hello(context):
         print "hello"


     $ bentomaker hello
     hello



• Hook   are pure python: no auto-import, etc...
FITTING IN THE PYTHON
        ECOSYSTEM
Convert distutils package to bento
    # Convert a setup.py to bento.info
    $ bentomaker convert


Distutils compatibility layer (pip-installable !)
    # setup.py
    import setuptools
    import bento.distutils
    bento.distutils.monkey_patch()
    # grab metadata from bento.info
    setuptools.setup()
INTERNALS
DESIGN PRINCIPLES


• Usable   as a library (still a few singleton to remove...)

• Low-couplingof commands: new package format should not
 care about building phase

• Driven   by real packages (numpy, scipy, twisted, ipython, etc...)
CODE ORGANIZATION
• bento/core

  • ply-based     parser (bento/core/parser)

  • python      representation of bento.info

• bento/commands

  • commands       and contexts

• bento/distutils

  • distutils   compat layer
COMMANDS AND
               CONTEXTS

           Context                       Command
         self.pkg                         self.run(context)
         self.cmd_argv
         self.run_node




•   Contexts encapsulate a command ‘environment’
•   Context-command relationship is overridable (hook)
    • e.g. mechanism to interact with 3rd party build tools
MORE ABOUT COMMANDS
• Command   options defined externally: any command can
 query any other’s options

• Commands   dependencies resolved at runtime

          @hooks.command
          def hello(context):
              print "hello"
          @hooks.command
          def goodbye(context):
              print "goodbye"
          @hooks.startup
          def startup(context):
              context.set_before("goodbye", "hello")
BUILD MANIFEST

• Goal: decouple      build and install

• format: a    json file containing info about built parts

  • Inspired     by cabal (‘distutils’ for haskell)

  • build     command produces a build manifest

  • install   only knows about build manifest

• Install   only install built files
NODE
•   Every file is represented internally as a node (waf concept)

    •   nodes are a in-memory representation of the fs

    •   gives reliable relative paths between files

            sdir = os.getcwd()
            bdir = os.path.join(os.getcwd(), "build")
            root = create_root_with_source_tree(sdir, bdir)
            top_node = root.find_node(sdir)
            build_node = root.find_node(bdir)
            print top_node.path_from(build_node)
SOME NEAT FEATURES (1)
• Using   metadata in the packaged software


 Name: foo                           # foo.py.in
 Version: 1.0                        name = $NAME
 MetaTemplateFile: foo.py.in         version = $VERSION




                   # foo.py.in
                   name = "foo"
                   version = "1.0"
SOME NEAT FEATURES (2)

• Sane   way to load data files

                   Name: foo
                   Version: 1.0
                   ConfigPy: __config.py




                   # __config.py
                   BINDIR = r”/usr/bin”
                   ...
SOME NEAT FEATURES (3)

• Out   of tree build (bye bye source tree pollution)



         # Convert a setup.py to bento.info
         $ bentomaker --bento-info=../source_dir/bento.info
A FEW NUMBERS

• bento: ±   8000 LOC (not including ± 2500 LOC for tests)

• numpy.distutils: ±10000    LOC

• distutils: ±   10000 LOC

• numpy: ±2000      LOC for distutils vs ±1000 LOC for bento

• scipy: ±1600    LOC vs ±1100 LOC
DEMO ON NUMPY
WHERE TO GET IT ?


• Getting   bento on github: http://github.com/cournape/Bento.git

• Bento   doc: http://cournape.github.com/Bento

• Bento   mailing-list: bento@librelist.com

Bento lunch talk

  • 1.
    (BENTO) A packaging solutionfor python software
  • 2.
    WHAT’S PACKAGING ? •Whatever that has to happen between svn/git/etc... and the end-user • Different end-users, different workflows: not just tarballs (maybe those guys don’t need packaging)
  • 3.
    DISTUTILS • De-facto solution since ±2000 • Works well for simple packages: • Setuptools/distribute • add package dependencies
  • 4.
    DISTUTILS ISSUES • Make one’s head hurt: • Hard to extend • Fragile codebase • Reliability issues
  • 5.
    BENTO • Declarative description of package: metadata inspection is simple • Flexible installation scheme: install any file anywhere • Layered internal architecture: easy to extend • Scaledown and up: simpler for small packages, more flexible for big ones
  • 6.
    A SIMPLE BENTOFILE Name: foo Version: 0.1 Description: Package description. Library: Packages: ! foo, foo.core
  • 7.
    BENTOMAKER • Command-line interface to bento $ bentomaker configure $ bentomaker build $ bentomaker install # Or more simply $ bentomaker install
  • 8.
    ADDING DATA-FILES Datafiles: pdf_documentation TargetDir: $pdfdoc Files: main.pdf $ bentomaker configure --pdfdoc=/usr/pdfdoc # ant-like glob format supported Datafiles: pdf_documentation TargetDir: $pdfdoc Files: doc/**/*.pdf
  • 9.
    CUSTOM INSTALL PATHS Path: foodir Description: foo directory Default: $datadir/foo Datafiles: fubar-doc TargetDir: $foodir Files: main.foo $ bentomaker configure --foodir=/usr/pdfdoc
  • 10.
    HOOK FILES • Can“hook” python files into the build process from bento.commands import hooks @hooks.command def hello(context): print "hello" $ bentomaker hello hello • Hook are pure python: no auto-import, etc...
  • 11.
    FITTING IN THEPYTHON ECOSYSTEM Convert distutils package to bento # Convert a setup.py to bento.info $ bentomaker convert Distutils compatibility layer (pip-installable !) # setup.py import setuptools import bento.distutils bento.distutils.monkey_patch() # grab metadata from bento.info setuptools.setup()
  • 12.
  • 13.
    DESIGN PRINCIPLES • Usable as a library (still a few singleton to remove...) • Low-couplingof commands: new package format should not care about building phase • Driven by real packages (numpy, scipy, twisted, ipython, etc...)
  • 14.
    CODE ORGANIZATION • bento/core • ply-based parser (bento/core/parser) • python representation of bento.info • bento/commands • commands and contexts • bento/distutils • distutils compat layer
  • 15.
    COMMANDS AND CONTEXTS Context Command self.pkg self.run(context) self.cmd_argv self.run_node • Contexts encapsulate a command ‘environment’ • Context-command relationship is overridable (hook) • e.g. mechanism to interact with 3rd party build tools
  • 16.
    MORE ABOUT COMMANDS •Command options defined externally: any command can query any other’s options • Commands dependencies resolved at runtime @hooks.command def hello(context): print "hello" @hooks.command def goodbye(context): print "goodbye" @hooks.startup def startup(context): context.set_before("goodbye", "hello")
  • 17.
    BUILD MANIFEST • Goal:decouple build and install • format: a json file containing info about built parts • Inspired by cabal (‘distutils’ for haskell) • build command produces a build manifest • install only knows about build manifest • Install only install built files
  • 18.
    NODE • Every file is represented internally as a node (waf concept) • nodes are a in-memory representation of the fs • gives reliable relative paths between files sdir = os.getcwd() bdir = os.path.join(os.getcwd(), "build") root = create_root_with_source_tree(sdir, bdir) top_node = root.find_node(sdir) build_node = root.find_node(bdir) print top_node.path_from(build_node)
  • 19.
    SOME NEAT FEATURES(1) • Using metadata in the packaged software Name: foo # foo.py.in Version: 1.0 name = $NAME MetaTemplateFile: foo.py.in version = $VERSION # foo.py.in name = "foo" version = "1.0"
  • 20.
    SOME NEAT FEATURES(2) • Sane way to load data files Name: foo Version: 1.0 ConfigPy: __config.py # __config.py BINDIR = r”/usr/bin” ...
  • 21.
    SOME NEAT FEATURES(3) • Out of tree build (bye bye source tree pollution) # Convert a setup.py to bento.info $ bentomaker --bento-info=../source_dir/bento.info
  • 22.
    A FEW NUMBERS •bento: ± 8000 LOC (not including ± 2500 LOC for tests) • numpy.distutils: ±10000 LOC • distutils: ± 10000 LOC • numpy: ±2000 LOC for distutils vs ±1000 LOC for bento • scipy: ±1600 LOC vs ±1100 LOC
  • 23.
  • 24.
    WHERE TO GETIT ? • Getting bento on github: http://github.com/cournape/Bento.git • Bento doc: http://cournape.github.com/Bento • Bento mailing-list: bento@librelist.com