Description

The grampg code provides you with a password generator object, a bottomless barrel from which you can pull passwords. The difference between this generator object and something like /dev/random or ''.join([random.choice(letters) for i in range(LEN)]) is that you get to build that generator with great specificity, to obtain passwords adequate to your needs.

You will first have to build the generator, though. This could be a tedious, and a difficult task. Consider the following example:

how would you tell the builder you want passwords 10 characters long,
with lower letters and at least 3 numbers, starting with a letter?

grampg provides an easy to use interface, aimed at translating your needs intuitively.

Building the generator object is done in steps, using a builder object. At each step you add a spec (think of it as a piece of specification). You proceed working on the builder object accumulating specs, all of which add up to the requirements your passwords must satisfy. In the case of the example, you could use something like this:

gen = PasswordGenerator().of().length(10).at_most(10, 'lower_letters')
                                         .at_least(3, 'numbers')
                                         .beginning_with('lower_letters')
                                         .done()

The expression above will yield a generator object ready to produce passwords, exactly as you require them.

Note

The order in which specs are added is irrelevant. You are encourage to declare your specs as they sound more natural in your head; doing so greatly improves maintainability of the code.

Now that you have your generator object, you can use it throughout your own code:

passwords = [gen.generate() for i in xrange(so_many_passwords)]

And that’s what grampg offers: a simple way to specify contrived password schema.

Note

In case you’re wondering, passwords generated by the resulting generator object are strong. You can revise the algorithm later in this docs. XXX add reference to that.

The PasswordGenerator / Generator duality

Apart from a small hierarchy of three exceptions to deal with errors, the grampg exposes two classes to the user: the Generator and the PasswordGenerator. The naming might be confusing, but (as much in the design of this library) it is for the sake of code readability.

Of the two classes, the grampg.Generator is the actual password generator. It accumulates and holds your specs, generates the passwords and is the object which the user will keep reference to (in most, but not all, use cases). It implements the grampg.Generator.generate() method, and that says it all.

The grampg.PasswordGenerator, on the other hand, is the builder class. Its instances will create and stow away a grampg.Generator instance for the user, and will act as its interface as specs are added. It relinquishes control of the generator object only when the building phase is terminated (when it receives a call to done()).

This explains the naming choices: the user should never have the need to write Generator() but PasswordGenerator.of() (both idioms being equivalent, the second instantiates the generator object internally).

Technical description

The two classes exposed by the grampg module constitute a builder and product pair. The builder aids the user in specifying an adequate representation of the product.

Generators are instances of grampg.Generator. A generator object is instantiated with the sets of characters to use, and is responsible for accumulating the specs through method calls. The user, however, does not need to know any of that. The user never really interacts with a grampg.Generator instance directly, but through the builder. For the user, generator objects have one method of interest, generate(), which produces a single, independent and strong password string each time it’s called, but which can be called only when the specification phase is done.

A builder object is an instances of grampg.PasswordGenerator, and provides a fluent interface to the Generator internal object being specified. The interface leverages method chaining and the builder pattern to provide a quick and easy specification phase. The grampg.PasswordGenerator provides a means of defining non-default character sets (characters to choose from when generating passwords), and passes user specs to the generator object being built. The builder object returns the generator object only when a call to done() succeeds. The generator object returned is ready to receive calls to generate().