Parser Backends¶
Note
If you’re looking for custom parsing of individual arguments, you probably want Arg.parse or Arg.action.
This document is concerned with the actual e2e CLI parsing process.
Cappa is designed in two parts:
The “frontend”, which is the vast majority of the public API. All the available objects and functions, the annotation inference engine, the invoke/dependency system, etc.
The parser “backend”, which takes the object graph produced by your CLI definition and parses the raw CLI (into a form the “frontend” can understand).
The backend also controls the help-text formatter
There are currently two backend options:
A custom parser maintained inside cappa itself
An Argparse backend
A large majority of tests are run with both parsers to ensure general compatibility. Any difference in backend parse behavior should be considered a bug. However, error messaging will not match exactly across backends.
You select a backend by providing the backend argument to parse
or invoke.
import cappa
cappa.parse(..., backend=cappa.argparse.backend)
cappa.invoke(..., backend=cappa.argparse.backend)
cappa.parse(..., backend=cappa.backend)
cappa.invoke(..., backend=cappa.backend)
Cappa backend¶
This is the default backend.
The main “headline” feature you get when using the cappa backend is: Automatic completion support. However, generally it’s going to be easier to support arbitrary features with the native parser than with an external backend.
It is roughly 1/3 the size in LOC, given that much of the featureset and flexibility of argparse are unused and a source of contention with cappa’s design (The whole native parser is ~500 LOC, whereas just the argparse adapter is ~350 LOC).
Argparse backend¶
Cappa was originally written against the argparse backend, a testament to the flexibility of its API, that it’s even possible.
The main “problem” with the argparse backend is that cappa replaces much of the higher level features it provides at a higher level, outside the parser itself. A majority of the backend’s source is working around specific argparse API decisions, and redefining argparse’s objects with necessary modifications.
This backend will be maintained for the foreseeable future, if for no other reason than it’s a useful benchmark for parser compatibility.
Some potential reasons you want want to use the argparse backend:
Argparse is also obviously fairly battle tested, and therefore theoretically less likely to contain bugs that might exist in the native cappa backend.
Argparse may have pre-existing libraries designed to extend it. (While we cant guarantee an arbitrary argparse extension will function correctly with cappa, but to the extent possible, it’s a goal that they should be supported if possible.
Custom Backends¶
cappa.invoke/cappa.parse both accept a backend= argument which is used to
select between the existing two backends shipped with Cappa.
Technically, you could use this backend argument to author an entirely new
backend to a different argument parser, like click for example (although
a click backend was attempted at some point and later abandoned due to unforeseen
complexities). This would allow you to retain all of cappa’s pre-parsing and inference
capabilities, as well as the post-processing, mapping, and invoke/dependency injection
infrastructure.
With that said, it’s much more likely that it could be useful to make use of the backend argument to wrap one of the existing backends, and mutate the resultant output structure of the backend before it’s passed further downstream. This is somewhat of an interesting usecase, and again if you find yourself making use of this in order to work around potential upstream deficiencies in cappa, please bring it up in an issue/discussion!
Note
The backend interface is currently not set in stone. Before relying on the specific details of the input/output shape of a backend, please bring it up in an issue/discussion in hopes that customizing the backend may be made to not be necessary!
Further, it’s likely that the backend interface is more formalized at some point in the future; at which point it may break those assumptions.