Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use p-ranav/argparse framework for command line argument parsing #9445

Merged
merged 14 commits into from
Mar 22, 2024

Conversation

rouault
Copy link
Member

@rouault rouault commented Mar 11, 2024

Cf email thread at https://lists.osgeo.org/pipermail/gdal-dev/2024-March/thread.html#58647

Up to now, sozip, gdal_viewshed, nearblack, ogrinfo, gdaladdo, gdal_translate, ogr2ogr (so a mix of pure command line utilitys and utility-as-a-C-function) have been converted. This should exercise pretty much all what we need: optional and positional arguments, boolean/integer/double data types, repeated arguments, mutually exclusive arguments. So I'm quite confident now we could generalize the use of that framework to all other utilities

I've had to extend p-ranav/argparse with various changes to improve the usage/synopsis output, and add some helpers to make it easier to use:

  • add Argument::store_into(variable) helpers to define in the same time the argument and where its value is stored (EDIT: upstreamed)
  • allow using a locale-independent strtod() for floating-point parsing (EDIT: upstreamed)
  • add hidden alias for deprecated versions of option names (EDIT: upstreamed)
  • allow positional arguments to be put anywhere, and not just after optional arguments (that one was tricky!) (EDIT: argparse related change now upstreamed; another part is in the GDALArgumentParser extended class)
  • add "groups" to categorize optional arguments, like between basic/regular and advanced options (EDIT: upstreamed)
  • ask for the usage summary to be split on multiple lines, and nicer way of presenting mutually exclusive arguments (EDIT: upstreamed)
  • add "..." for repeated arguments in the synosys (EDIT: upstreamed)

All of the above changes have been merged by upstream.
I'll try to submit them to upstream if they are interested into them (I've started with a bugfix to make the library usable with clang's -fsanitize=undefined-integer-overflow that we use in one of our CI config. EDIT: now merged upstream)

I've added a GDALArgumentParser class extending the base argparse::ArgumentParse that adds a few GDAL specific helpers, in particuler to define arguments that are common to multiple utilities (like -of, -co, etc.)

A few examples:

  • Running sozip without required argument outputs the short usage. This also demonstrates a separation between basic/regular and advanced options:
Error: zip_filename: 1 argument(s) expected. 0 provided.
Usage: sozip [--help] [--long-usage] [--help-general] [--recurse-paths]
             [[--grow]|[--overwrite]]
             [[--list]|[--validate]|[--optimize-from <input.zip>]
             <zip_filename> [<input_files>]...

Advanced options:
             [[--quiet]|[--verbose]]
             [--junk-paths] [--enable-sozip auto|yes|no] [--sozip-chunk-size <value in bytes or with K/M suffix>]
             [--sozip-min-file-size <value in bytes or with K/M/G suffix>] [--content-type <string>]

Note: sozip --long-usage for full help.
  • sozip --long-usage:
Usage: sozip [--help] [--long-usage] [--help-general]
             [--recurse-paths]
             [[--grow]|[--overwrite]]
             [[--list]|[--validate]|[--optimize-from <input.zip>]
             <zip_filename> [<input_files>]...

Advanced options:
             [[--quiet]|[--verbose]]
             [--junk-paths] [--enable-sozip auto|yes|no] [--sozip-chunk-size <value in bytes or with K/M suffix>]
             [--sozip-min-file-size <value in bytes or with K/M/G suffix>] [--content-type <string>]

Generate a seek-optimized ZIP (SOZip) file.

Positional arguments:
  <zip_filename>                                               ZIP filename 
  <input_files>                                                Filename of the file to add. [nargs: 0 or more] 

Optional arguments:
  -h, --help                                                   Shows short help message and exits 
  --long-usage                                                 Shows long help message and exits 
  --help-general                                               Report detailed help on general options 
  -r, --recurse-paths                                          Travels the directory structure of the specified directories recursively. 
  -g, --grow                                                   Grow an existing zip file with the content of the specified filename(s). Default mode 
  --overwrite                                                  Overwrite the target zip file if it already exists. 
  -l, --list                                                   List the files contained in the zip file 
  --validate                                                   Validates a ZIP/SOZip file 
  --optimize-from <input.zip>                                  Re-process {input.zip} to generate a SOZip-optimized .zip 

Advanced options: (detailed usage)
  --quiet                                                      Quiet mode. No progress message is emitted on the standard output. 
  --verbose                                                    Verbose mode 
  -j, --junk-paths                                             Store just the name of a saved file (junk the path), and do not store directory names. 
  --enable-sozip auto|yes|no                                   In auto mode, a file is seek-optimized only if its size is above the value of
                                                               --sozip-chunk-size. In yes mode, all input files will be seek-optimized.
                                                               In no mode, no input files will be seek-optimized. 
  --sozip-chunk-size <value in bytes or with K/M suffix>       Chunk size for a seek-optimized file. Defaults to 32768 bytes. 
  --sozip-min-file-size <value in bytes or with K/M/G suffix>  Minimum file size to decide if a file should be seek-optimized. Defaults to 1 MB byte. 
  --content-type <string>                                      Store the Content-Type for the file being added 

For more details, consult https://gdal.org/programs/sozip.html
  • gdal_viewshed --long-usage:
Usage: gdal_viewshed [--help] [--long-usage] [--help-general]
                     [-of <output_format>] -ox <value> -oy <value> [-oz <value>]
                     [-vv <value>] [-iv <value>] [-ov <value>] [-co <KEY=VALUE>]...
                     [-a_nodata <value>] [-tz <value>] [-md <value>] [-cc <value>] [-b <value>] [-om NORMAL|DEM|GROUND]
                     [--quiet]
                     <src_filename> <dst_filename>

Calculates a viewshed raster from an input raster DEM.

Positional arguments:
  <src_filename>         
  <dst_filename>         

Optional arguments:
  -h, --help             Shows short help message and exits 
  --long-usage           Shows long help message and exits 
  --help-general         Report detailed help on general options 
  -of <output_format>    Output format 
  -ox <value>            The X position of the observer (in SRS units). [required]
  -oy <value>            The Y position of the observer (in SRS units). [required]
  -oz <value>            The height of the observer above the DEM surface in the height unit of the DEM. [default: 2]
  -vv <value>            Pixel value to set for visible areas. [default: 255]
  -iv <value>            Pixel value to set for invisible areas. [default: 0]
  -ov <value>            Pixel value to set for the cells that fall outside of the range specified by the observer location and the maximum distance. [default: 0]
  -co <KEY=VALUE>        Creation option(s) [may be repeated]
  -a_nodata <value>      The value to be set for the cells in the output raster that have no data. [default: -1]
  -tz <value>            The height of the target above the DEM surface in the height unit of the DEM. [default: 0]
  -md <value>            Maximum distance from observer to compute visibility. [default: 0]
  -cc <value>            Coefficient to consider the effect of the curvature and refraction. [default: 0.85714]
  -b <value>             Select an input band band containing the DEM data. [default: 1]
  -om NORMAL|DEM|GROUND  Sets what information the output contains. [default: "NORMAL"]
  -q, --quiet            Quiet mode. No progress message is emitted on the standard output. 

For more details, consult https://gdal.org/programs/gdal_viewshed.html
  • ogr2ogr: Ported, and improve categorization of options
Usage: ogr2ogr [--help] [--long-usage] [--help-general]
               [-of <output_format>] [-dsco <NAME>=<VALUE>]... [-lco <NAME>=<VALUE>]...
               [[-append]|[-upsert]|[-overwrite]]
               [-update] [-sql <statement>|@<filename>] [-dialect <dialect>] [-spat <xmin> <ymin> <xmax> <ymax>]
               [-where <restricted_where>|@<filename>] [-select <field_list>] [-nln <name>] [-nlt <type>]...
               [-s_srs <srs_def>]
               [[-a_srs <srs_def>]|[-t_srs <srs_def>]]
               <dst_dataset_name> <src_dataset_name> [<layer_name>]...

Field related options:
               [-addfields] [-relaxedFieldNameMatch] [-fieldTypeToString All|<type1>[,<type2>]...]
               [-mapFieldType <srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...] [-fieldmap <field_1>[,<field_2>]...]
               [-splitlistfields] [-maxsubfields <n>] [-emptyStrAsNull] [-forceNullable] [-unsetFieldWidth]
               [-unsetDefault] [-resolveDomains] [-dateTimeTo UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>] [-noNativeData]

Advanced geometry and SRS related options:
               [-dim layer_dim|2|XY|3|XYZ|XYM|XYZM] [-s_coord_epoch <epoch>] [-a_coord_epoch <epoch>]
               [-t_coord_epoch <epoch>] [-ct <pipeline_def>] [-spat_srs <srs_def>] [-geomfield <name>]
               [-segmentize <max_dist>] [-simplify <tolerance>] [-makevalid] [-wrapdateline]
               [-datelineoffset <val_in_degree>] [-clipsrc [<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent]
               [-clipsrcsql <sql_statement>] [-clipsrclayer <layername>] [-clipsrcwhere <expression>]
               [-clipdst [<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>] [-clipdstsql <sql_statement>]
               [-clipdstlayer <layername>] [-clipdstwhere <expression>] [-explodecollections] [-zfield <name>]
               [-gcp <ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]]... [-tps] [-order 1|2|3]
               [-xyRes <val>[ m|mm|deg]] [-zRes <val>[ m|mm]] [-mRes <val>] [-unsetCoordPrecision]

Other options:
               [--quiet] [-progress] [-if <format>]... [-oo <NAME>=<VALUE>]... [-doo <NAME>=<VALUE>]...
               [-fid <FID>] [-preserve_fid] [-unsetFid]
               [[-skipfailures]|[-gt <n>|unlimited]]
               [-limit <nb_features>] [-ds_transaction] [-mo <NAME>=<VALUE>]... [-nomd]

@coveralls
Copy link
Collaborator

coveralls commented Mar 11, 2024

Coverage Status

coverage: 68.946% (+0.02%) from 68.93%
when pulling 64dfb95 on rouault:argparse
into 35c4345 on OSGeo:master.

@rouault rouault force-pushed the argparse branch 25 times, most recently from 5341f30 to 8e78e06 Compare March 13, 2024 20:00
@rouault rouault changed the title [WIP] Use (enhanced) p-ranav/argparse framework for command line argument parsing [WIP] Use p-ranav/argparse framework for command line argument parsing Mar 14, 2024
@rouault rouault force-pushed the argparse branch 3 times, most recently from 5212a05 to f4a1350 Compare March 14, 2024 01:30
@rouault rouault changed the title [WIP] Use p-ranav/argparse framework for command line argument parsing Use p-ranav/argparse framework for command line argument parsing Mar 14, 2024
@rouault rouault force-pushed the argparse branch 4 times, most recently from eb2b522 to dc69a7d Compare March 19, 2024 13:25
@@ -381,7 +381,7 @@ double CPLStrtodDelim(const char *nptr, char **endptr, char point)
}
else
{
errno = answer.ptr == nptr ? EINVAL : ERANGE;
errno = answer.ptr == nptr ? 0 : ERANGE;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? This isn't an error anymore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to make it compliant with the documented semantics of strtod. This change was triggered by https://github.com/p-ranav/argparse which relies on that at https://github.com/p-ranav/argparse/blob/a1c41c5537c919c1a56661ec1cdf5a49b9e99af6/include/argparse/argparse.hpp#L380 to determine if a string is a number or not

apps/gdalargumentparser.h Show resolved Hide resolved
apps/gdal_translate_lib.cpp Outdated Show resolved Hide resolved
apps/gdal_translate_lib.cpp Show resolved Hide resolved
apps/gdal_translate_lib.cpp Show resolved Hide resolved
apps/ogrinfo_lib.cpp Outdated Show resolved Hide resolved
apps/sozip.cpp Outdated Show resolved Hide resolved
apps/sozip.cpp Outdated Show resolved Hide resolved
apps/sozip.cpp Outdated Show resolved Hide resolved
apps/sozip.cpp Outdated Show resolved Hide resolved
@rouault rouault merged commit 7b43d55 into OSGeo:master Mar 22, 2024
31 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants