Paste Script: Development — Paste Script v1.7.4.1 documentation

### Navigation

- index
- modules |
- next |
- previous |
- Paste Script v1.7.4.1 documentation »

# Paste Script: Development

author: | Ian Bicking <ianb@colorstudy.com>
revision: | $Rev$
date: | $LastChangedDate$

Contents

- Paste Script: Development
  - Introduction
  - What Paste Script Can Do
  - How’s the Local Thing Work?
  - What Do Commands Look Like?
  - Templates

## Introduction

This document is an introduction to how you can extend `paster` and Paste Script for your system – be it a framework, server setup, or whatever else you want to do.

## What Paste Script Can Do

`paster` is a two-level command, where the second level (e.g., `paster help`, `paster create`, etc) is pluggable.

Commands are attached to Python Eggs, i.e., to the package you distribute and someone installs. The commands are identified using entry points.

To make your command available do something like this in your `setup.py` file:

    from setuptools import setup
    setup(...
        entry_points="""
        [paste.paster_command]
        mycommand = mypackage.mycommand:MyCommand

        [paste.global_paster_command]
        myglobal = mypackage.myglobal:MyGlobalCommand
        """)

This means that `paster mycommand` will run the `MyCommand` command located in the `mypackage.mycommand` module. Similarly with `paster myglobal`. The distinction between these two entry points is that the first will only be usable when `paster` is run inside a project that is identified as using your project, while the second will be globally available as a command as soon as your package is installed.

## How’s the Local Thing Work?

So if you have a local command, how does it get enabled? If the person is running `paster` inside their project directory, `paster` will look in `Project_Name.egg-info/paster_plugins.txt` which is a list of project names (the name of your package) whose commands should be made available.

This is for frameworks, so frameworks can add commands to `paster` that only apply to projects that use that framework.

## What Do Commands Look Like?

The command objects (like `MyCommand`) are subclasses of `paste.script.command.Command`. You can look at that class to get an idea, but a basic outline looks like this:

    from paste.script import command

    class MyCommand(command.Command):

        max_args = 1
        min_args = 1

        usage = "NAME"
        summary = "Say hello!"
        group_name = "My Package Name"

        parser = command.Command.standard_parser(verbose=True)
        parser.add_option('--goodbye',
                          action='store_true',
                          dest='goodbye',
                          help="Say 'Goodbye' instead")

        def command(self):
            name = self.args[0]
            if self.verbose:
                print "Got name: %r" % name
            if self.options.goodbye:
                print "Goodbye", name
            else:
                print "Hello", name

`max_args` and `min_args` are used to give error messages. You can also raise `command.BadCommand(msg)` if the arguments are incorrect in some way. (Use `None` here to give no restriction)

The `usage` variable means `paster mycommand -h` will give a usage of `paster mycommand [options] NAME`. `summary` is used with `paster help` (describing your command in a short form). `group_name` is used to group commands together for `paste help` under that title.

The `parser` object is an optparse <http://python.org/doc/current/lib/module-optparse.html> `OptionParser` object. `Command.standard_parser` is a class method that creates normal options, and enables options based on these keyword (boolean) arguments: `verbose`, `interactive`, `no_interactive` (if interactive is the default), `simulate`, `quiet` (undoes verbose), and `overwrite`. You can create the parser however you want, but using `standard_parser()` encourages a consistent set of shared options across commands.

When your command is run, `.command()` is called. As you can see, the options are in `self.options` and the positional arguments are in `self.args`. Some options are turned into instance variables – especially `self.verbose` and `self.simulate` (even if you haven’t chosen to use those options, many methods expect to find some value there, which is why they are turned into instance variables).

There are quite a few useful methods you can use in your command. See the Command class for a complete list. Some particulars:

`run_command(cmd, arg1, arg2, ..., cwd=os.getcwd(), capture_stderr=False)`:

> Runs the command, respecting verbosity and simulation. Will raise an error if the command doesn’t exit with a 0 code.

`insert_into_file(filename, marker_name, text, indent=False)`:

> Inserts a line of text into the file, looking for a marker like `-*- marker_name -*-` (and inserting just after it). If `indent=True`, then the line will be indented at the same level as the marker line.

`ensure_dir(dir, svn_add=True)`:

> Ensures that the directory exists. If `svn_add` is true and the parent directory has an `.svn` directory, add the new directory to Subversion.

`ensure_file(filename, content, svn_add=True)`:

> Ensure the file exists with the given content. Will ask the user before overwriting a file if `--interactive` has been given.

## Templates

The other pluggable part is “templates”. These are used to create new projects. Paste Script includes one template itself: `basic_package` which creates a new setuptools package.

To enable, add to `setup.py`:

    setup(...
        entry_points="""
        [paste.paster_create_template]
        framework = framework.templates:FrameworkTemplate
        """)

`FrameworkTemplate` should be a subclass of `paste.script.templates.Template`. An easy way to do this is simply with:

    from paste.script import templates

    class FrameworkTemplate(templates.Template):

        egg_plugins = ['Framework']
        summary = 'Template for creating a basic Framework package'
        required_templates = ['basic_package']
        _template_dir = 'template'
        use_cheetah = True

`egg_plugins` will add `Framework` to `paste_plugins.txt` in the package. `required_template` means those template will be run before this one (so in this case you’ll have a complete package ready, and you can just write your framework files to it). `_template_dir` is a module-relative directory to find your source files.

The source files are just a directory of files that will be copied into place, potentially with variable substitutions. Three variables are expected: `project` is the project name (e.g., `Project-Name`), `package` is the Python package in that project (e.g., `projectname`) and `egg` is the project’s egg name as generated by setuptools (e.g., `Project_Name`). Users can add other variables by adding `foo=bar` arguments to `paster create`.

Filenames are substituted with `+var_name+`, e.g., `+package+` is the package directory.

If a file in the template directory ends in `_tmpl` then it will be substituted. If `use_cheetah` is true, then it’s treated as a Cheetah template. Otherwise string.Template is used, though full expressions are allowed in `${expr}` instead of just variables.

See the templates module for more.

### Navigation

- index
- modules |
- next |
- previous |
- Paste Script v1.7.4.1 documentation »