Q:

argparse: How to require a group of args which are not all mutually exclusive and not all optional?

I'm trying to make certain arguments pertaining to the primary functions of my program required within argparse.  However, I have two problems:

Not all of the arguments are mutually exclusive.
Even if they were all mutually exclusive, mutually exclusive groups
require that arguments be optional, and the primary function search (which is not required) uses positional argument(s).

Ideally, I consider 'search' to be the primary function.  As such, I'd like its arguments to be positional; albeit, search is not required.  But, at least one of the following is required:  search, --name, --list, --add, --import, --encrypt, --decrypt, --delete-database, --rename-database, --backup
Furthermore, --name is not a mutually exclusive option, and it is sort of multi-purpose:

If it is invoked by itself, its argument (a name for a database) will be created if it does not already exist.
If (the database) does exist, it is used as an argument to whatever other option's function it is invoked with:  e.g., -n myfirstdb --decrypt
Whereas, if --name is not present, I assume the most recently accessed database.

Currently, I have to run a check, which is starting to become burdensome, to see if any of the primary options has been invoked, along with testing for whether or not --name is present.
Finally, obviously the mutually exclusive options can't be used together.
How can I get search to be part of this required mutually exclusive group?  And how can I make --name also one of this required group, but not mutually exclusive to any of them?
I'm experimenting with subparsers, but I'm not sure if they are the solution to my problem.  Any suggestions will likely save me a few days of trial and error, and are greatly appreciated.
parser.add_argument(
    'search', nargs='*', type=str, metavar='S', help='search [field] for string(s)')
parser.add_argument(
    '--name', '-n', type=str, help='name of the database; created if does not exist')

main_ex_group = parser.add_argument_group(
    title='main functions').add_mutually_exclusive_group()
main_ex_group.add_argument(
    '--list', '-l', action='store_true', help='list databases')
main_ex_group.add_argument(
    '--add', '-a', action='store_true', help='add new record to database')
main_ex_group.add_argument(
    '--import','-i', dest='include', metavar='PATH', type=str,
    help='import file(s) at PATH')
main_ex_group.add_argument(
    '--encrypt', action='store_true', help='encrypt database')
main_ex_group.add_argument(
    '--decrypt', action='store_true', help='decrypt database')
main_ex_group.add_argument(
    '--delete-database', metavar='NAME', type=str,
    help='delete a database')
main_ex_group.add_argument(
    '--rename-database', nargs=2, metavar='NAME', type=str,
    help='rename a database')
main_ex_group.add_argument(
    '--backup', nargs=2, metavar='NAME DEST', type=str,
    help='copy database to destination')

import_group = parser.add_argument_group(title='options for import')
import_group.add_argument(
    '--parse-fields', action='store_true',
    help='extract keys/fields from included file(s); used as columns')
import_group.add_argument(
    '--delimiter', metavar='S', default='::', help='key-value separator')

A:

There are only two grouping tools built into argparse.  Mutually exclusive groups and subparsers.  A MEG is xor for all its Actions.  While the group itself may be required, all of its Actions must be optional. Most have to be flagged (optionals) but one may be an 'optional' positional (yes, the terminology can be confusing).
There's no provision for nesting groups, and no provision for other logic (and, or, any, not etc).  Those have been requested, and I've worked on a patch but it's not anywhere close to done.  Actually the testing itself is not hard; defining the groups in a clear way is harder, as is displaying the usage.  Once you allow nesting, and try to account for all logical possibilities, the amount of extra code grows substantially.
For now the best choice is to do your own testing after parsing is done.  As long as you use reasonable defaults (e.g. the default default None) it isn't hard.  
There is an internal variable, 'seen_actions` that would be nice to use for this testing, but I haven't figured out an easy way to make that available to programmers like you.  My initial idea for extending groups was to create a hook that would let you run a function of your own near the end of parsing with access to this variable.
Look at earlier answers in the side bar.

An argument group is a display tool - it groups the help lines.  You can nest a mutually exclusive group in an argument group. That effectively gives the MEG a title/description, and displays its arguments together. But that does not affect usage or testing.  And nesting in the other way is not meaningful.  MEG nested in a MEG is also possible but the net effect is to put all actions in one bigger group - and to mess up the usage (see are recent Python bug/issue).  The nesting that exists is more a feature of class inheritance than design.

I also like to ask people, how would you express your grouping(s) in a usage line?  It the requirements are hard to express in usage, they are hard to implement in argparse.

