Giter Site home page Giter Site logo

docopt / docopt.net Goto Github PK

View Code? Open in Web Editor NEW
348.0 348.0 33.0 19.18 MB

Port of docopt to .net

Home Page: https://docopt.github.io/docopt.net/

License: Other

C# 96.95% Python 0.32% HTML 1.50% CSS 0.89% Batchfile 0.02% PowerShell 0.19% Shell 0.02% Dockerfile 0.12%
cli command-line docopt hacktoberfest

docopt.net's Introduction

docopt creates beautiful command-line interfaces

https://travis-ci.org/docopt/docopt.svg?branch=master

Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python

New in version 0.6.1:

  • Fix issue #85 which caused improper handling of [options] shortcut if it was present several times.

New in version 0.6.0:

  • New argument options_first, disallows interspersing options and arguments. If you supply options_first=True to docopt, it will interpret all arguments as positional arguments after first positional argument.
  • If option with argument could be repeated, its default value will be interpreted as space-separated list. E.g. with [default: ./here ./there] will be interpreted as ['./here', './there'].

Breaking changes:

  • Meaning of [options] shortcut slightly changed. Previously it meant "any known option". Now it means "any option not in usage-pattern". This avoids the situation when an option is allowed to be repeated unintentionally.
  • argv is None by default, not sys.argv[1:]. This allows docopt to always use the latest sys.argv, not sys.argv during import time.

Isn't it awesome how optparse and argparse generate help messages based on your code?!

Hell no! You know what's awesome? It's when the option parser is generated based on the beautiful help message that you write yourself! This way you don't need to write this stupid repeatable parser-code, and instead can write only the help message--the way you want it.

docopt helps you create most beautiful command-line interfaces easily:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)

Beat that! The option parser is generated based on the docstring above that is passed to docopt function. docopt parses the usage pattern ("Usage: ...") and option descriptions (lines starting with dash "-") and ensures that the program invocation matches the usage pattern; it parses options, arguments and commands based on that. The basic idea is that a good help message has all necessary information in it to make a parser.

Also, PEP 257 recommends putting help message in the module docstrings.

Installation

Use pip or easy_install:

pip install docopt==0.6.2

Alternatively, you can just drop docopt.py file into your project--it is self-contained.

docopt is tested with Python 2.7, 3.4, 3.5, and 3.6.

Testing

You can run unit tests using the command:

python setup.py test

API

from docopt import docopt
docopt(doc, argv=None, help=True, version=None, options_first=False)

docopt takes 1 required and 4 optional arguments:

  • doc could be a module docstring (__doc__) or some other string that contains a help message that will be parsed to create the option parser. The simple rules of how to write such a help message are given in next sections. Here is a quick example of such a string:
"""Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]

-h --help    show this
-s --sorted  sorted output
-o FILE      specify output file [default: ./test.txt]
--quiet      print less text
--verbose    print more text

"""
  • argv is an optional argument vector; by default docopt uses the argument vector passed to your program (sys.argv[1:]). Alternatively you can supply a list of strings like ['--verbose', '-o', 'hai.txt'].

  • help, by default True, specifies whether the parser should automatically print the help message (supplied as doc) and terminate, in case -h or --help option is encountered (options should exist in usage pattern, more on that below). If you want to handle -h or --help options manually (as other options), set help=False.

  • version, by default None, is an optional argument that specifies the version of your program. If supplied, then, (assuming --version option is mentioned in usage pattern) when parser encounters the --version option, it will print the supplied version and terminate. version could be any printable object, but most likely a string, e.g. "2.1.0rc1".

    Note, when docopt is set to automatically handle -h, --help and --version options, you still need to mention them in usage pattern for this to work. Also, for your users to know about them.

  • options_first, by default False. If set to True will disallow mixing options and positional argument. I.e. after first positional argument, all arguments will be interpreted as positional even if the look like options. This can be used for strict compatibility with POSIX, or if you want to dispatch your arguments to other programs.

The return value is a simple dictionary with options, arguments and commands as keys, spelled exactly like in your help message. Long versions of options are given priority. For example, if you invoke the top example as:

naval_fate.py ship Guardian move 100 150 --speed=15

the return dictionary will be:

{'--drifting': False,    'mine': False,
 '--help': False,        'move': True,
 '--moored': False,      'new': False,
 '--speed': '15',        'remove': False,
 '--version': False,     'set': False,
 '<name>': ['Guardian'], 'ship': True,
 '<x>': '100',           'shoot': False,
 '<y>': '150'}

Help message format

Help message consists of 2 parts:

  • Usage pattern, e.g.:

    Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]
    
  • Option descriptions, e.g.:

    -h --help    show this
    -s --sorted  sorted output
    -o FILE      specify output file [default: ./test.txt]
    --quiet      print less text
    --verbose    print more text
    

Their format is described below; other text is ignored.

Usage pattern format

Usage pattern is a substring of doc that starts with usage: (case insensitive) and ends with a visibly empty line. Minimum example:

"""Usage: my_program.py

"""

The first word after usage: is interpreted as your program's name. You can specify your program's name several times to signify several exclusive patterns:

"""Usage: my_program.py FILE
          my_program.py COUNT FILE

"""

Each pattern can consist of the following elements:

  • <arguments>, ARGUMENTS. Arguments are specified as either upper-case words, e.g. my_program.py CONTENT-PATH or words surrounded by angular brackets: my_program.py <content-path>.
  • --options. Options are words started with dash (-), e.g. --output, -o. You can "stack" several of one-letter options, e.g. -oiv which will be the same as -o -i -v. The options can have arguments, e.g. --input=FILE or -i FILE or even -iFILE. However it is important that you specify option descriptions if you want your option to have an argument, a default value, or specify synonymous short/long versions of the option (see next section on option descriptions).
  • commands are words that do not follow the described above conventions of --options or <arguments> or ARGUMENTS, plus two special commands: dash "-" and double dash "--" (see below).

Use the following constructs to specify patterns:

  • [ ] (brackets) optional elements. e.g.: my_program.py [-hvqo FILE]
  • ( ) (parens) required elements. All elements that are not put in [ ] are also required, e.g.: my_program.py --path=<path> <file>... is the same as my_program.py (--path=<path> <file>...). (Note, "required options" might be not a good idea for your users).
  • | (pipe) mutually exclusive elements. Group them using ( ) if one of the mutually exclusive elements is required: my_program.py (--clockwise | --counter-clockwise) TIME. Group them using [ ] if none of the mutually-exclusive elements are required: my_program.py [--left | --right].
  • ... (ellipsis) one or more elements. To specify that arbitrary number of repeating elements could be accepted, use ellipsis (...), e.g. my_program.py FILE ... means one or more FILE-s are accepted. If you want to accept zero or more elements, use brackets, e.g.: my_program.py [FILE ...]. Ellipsis works as a unary operator on the expression to the left.
  • [options] (case sensitive) shortcut for any options. You can use it if you want to specify that the usage pattern could be provided with any options defined below in the option-descriptions and do not want to enumerate them all in usage-pattern.
  • "[--]". Double dash "--" is used by convention to separate positional arguments that can be mistaken for options. In order to support this convention add "[--]" to your usage patterns.
  • "[-]". Single dash "-" is used by convention to signify that stdin is used instead of a file. To support this add "[-]" to your usage patterns. "-" acts as a normal command.

If your pattern allows to match argument-less option (a flag) several times:

Usage: my_program.py [-v | -vv | -vvv]

then number of occurrences of the option will be counted. I.e. args['-v'] will be 2 if program was invoked as my_program -vv. Same works for commands.

If your usage patterns allows to match same-named option with argument or positional argument several times, the matched arguments will be collected into a list:

Usage: my_program.py <file> <file> --path=<path>...

I.e. invoked with my_program.py file1 file2 --path=./here --path=./there the returned dict will contain args['<file>'] == ['file1', 'file2'] and args['--path'] == ['./here', './there'].

Option descriptions format

Option descriptions consist of a list of options that you put below your usage patterns.

It is necessary to list option descriptions in order to specify:

  • synonymous short and long options,
  • if an option has an argument,
  • if option's argument has a default value.

The rules are as follows:

  • Every line in doc that starts with - or -- (not counting spaces) is treated as an option description, e.g.:

    Options:
      --verbose   # GOOD
      -o FILE     # GOOD
    Other: --bad  # BAD, line does not start with dash "-"
    
  • To specify that option has an argument, put a word describing that argument after space (or equals "=" sign) as shown below. Follow either <angular-brackets> or UPPER-CASE convention for options' arguments. You can use comma if you want to separate options. In the example below, both lines are valid, however you are recommended to stick to a single style.:

    -o FILE --output=FILE       # without comma, with "=" sign
    -i <file>, --input <file>   # with comma, without "=" sign
    
  • Use two spaces to separate options with their informal description:

    --verbose More text.   # BAD, will be treated as if verbose option had
                           # an argument "More", so use 2 spaces instead
    -q        Quit.        # GOOD
    -o FILE   Output file. # GOOD
    --stdout  Use stdout.  # GOOD, 2 spaces
    
  • If you want to set a default value for an option with an argument, put it into the option-description, in form [default: <my-default-value>]:

    --coefficient=K  The K coefficient [default: 2.95]
    --output=FILE    Output file [default: test.txt]
    --directory=DIR  Some directory [default: ./]
    
  • If the option is not repeatable, the value inside [default: ...] will be interpreted as string. If it is repeatable, it will be splited into a list on whitespace:

    Usage: my_program.py [--repeatable=<arg> --repeatable=<arg>]
                         [--another-repeatable=<arg>]...
                         [--not-repeatable=<arg>]
    
    # will be ['./here', './there']
    --repeatable=<arg>          [default: ./here ./there]
    
    # will be ['./here']
    --another-repeatable=<arg>  [default: ./here]
    
    # will be './here ./there', because it is not repeatable
    --not-repeatable=<arg>      [default: ./here ./there]
    

Examples

We have an extensive list of examples which cover every aspect of functionality of docopt. Try them out, read the source if in doubt.

Subparsers, multi-level help and huge applications (like git)

If you want to split your usage-pattern into several, implement multi-level help (with separate help-screen for each subcommand), want to interface with existing scripts that don't use docopt, or you're building the next "git", you will need the new options_first parameter (described in API section above). To get you started quickly we implemented a subset of git command-line interface as an example: examples/git

Data validation

docopt does one thing and does it well: it implements your command-line interface. However it does not validate the input data. On the other hand there are libraries like python schema which make validating data a breeze. Take a look at validation_example.py which uses schema to validate data and report an error to the user.

Using docopt with config-files

Often configuration files are used to provide default values which could be overriden by command-line arguments. Since docopt returns a simple dictionary it is very easy to integrate with config-files written in JSON, YAML or INI formats. config_file_example.py provides and example of how to use docopt with JSON or INI config-file.

Development

We would love to hear what you think about docopt on our issues page

Make pull requests, report bugs, suggest ideas and discuss docopt. You can also drop a line directly to <[email protected]>.

Porting docopt to other languages

We think docopt is so good, we want to share it beyond the Python community! All official docopt ports to other languages can be found under the docopt organization page on GitHub.

If your favourite language isn't among then, you can always create a port for it! You are encouraged to use the Python version as a reference implementation. A Language-agnostic test suite is bundled with Python implementation.

Porting discussion is on issues page.

Changelog

docopt follows semantic versioning. The first release with stable API will be 1.0.0 (soon). Until then, you are encouraged to specify explicitly the version in your dependency tools, e.g.:

pip install docopt==0.6.2
  • 0.6.2 Bugfix release.
  • 0.6.1 Bugfix release.
  • 0.6.0 options_first parameter. Breaking changes: Corrected [options] meaning. argv defaults to None.
  • 0.5.0 Repeated options/commands are counted or accumulated into a list.
  • 0.4.2 Bugfix release.
  • 0.4.0 Option descriptions become optional, support for "--" and "-" commands.
  • 0.3.0 Support for (sub)commands like git remote add. Introduce [options] shortcut for any options. Breaking changes: docopt returns dictionary.
  • 0.2.0 Usage pattern matching. Positional arguments parsing based on usage patterns. Breaking changes: docopt returns namespace (for arguments), not list. Usage pattern is formalized.
  • 0.1.0 Initial release. Options-parsing only (based on options description).

docopt.net's People

Contributors

adamchester avatar atifaziz avatar baruchiro avatar comandermuffif avatar forki avatar iwillspeak avatar jefim avatar kyle-fritz-zocdoc avatar smoothdeveloper avatar stoneman avatar voieducode avatar vvivanloc avatar youssef1313 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

docopt.net's Issues

Some option lines are not being parsed correctly

If I have the following DocOpt doc string:

    private const string usage = @"Test

Usage:
    test.exe test [--verbose] [--testopt]

    test.exe (-h | --help)

Commands:
    test
        test stuff

        -t, --testopt       A test option

General Options:
    -v, --verbose                           Enables verbose output.
    -h, --help                              Show this screen.";

...and I call "test.exe test -t", I get the usage screen and DocOpt fails to parse the options correctly. The program only responds to "--testopt". If I use the same doc string using the Ruby implementation, it responds to "-t" just fine and properly sets the "--testopt" option to true.

Nested class using `[DocoptArguments]` fails to build

Suppose a project has the following in a file named Program.cs:

static class Program
{
    [DocoptNet.DocoptArguments]
    sealed partial class Arguments
    {
        const string Help = "Usage: program";
    }
}

The project will fail to build due to the following error:

error CS0103: The name 'Help' does not exist in the current context

Duplicate property names generated into T4DocoptNet.cs

Consider this doc excerpt:

Usage:
   Send.exe (table|view) TABLE [-a alias] -s <instance> -d <database> 
                                        [-m <queueManagerName>] -q <queueName> [-p
   Send.exe message MESSAGE [-m <queueManagerName>] -q <queueName

The resulting generated code duplicates OptQueuemanager and OptQueue properties.
This was resolved by adding Distinct() in the final loop of Docopt.GenerateCode():

    foreach (var p in res.Flat().Distinct())
    {
        sb.AppendLine(p.GenerateCode());
    }
    return sb.ToString();

Source generator fails with arguments classes in separate files

Suppose a project with File1.cs that reads:

namespace Namespace1;

[DocoptNet.DocoptArguments]
sealed partial class ProgramArguments
{
    const string Help = "Usage: program";
}

Suppose further that the same project has File2.cs that reads:

namespace Namespace2;

[DocoptNet.DocoptArguments]
sealed partial class ProgramArguments
{
    const string Help = "Usage: program";
}

When built, the source generator will fail due to the following error:

Generator 'SourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'Syntax node is not within syntax tree'

Reinstalling docopt.net

Discussed in #190

Originally posted by shandysawyer November 28, 2023
I have a .NET 4.8 Framework Console Project that has docopt.net 0.6.1.10 installed. However I cannot get the T4 template to recompile itself, I get the following errors:
image

What are my options for fixing this? All I see are instructions for how install docopt.net on a new project, but nothing for an existing project. What are my options to fixing an existing install?

Source generator fails when arguments classes are named the same but belong to different namespaces

If two arguments classes in the same project are named identically but belong in different namespace:

using DocoptNet;

namespace Namespace1
{
    [DocoptArguments]
    sealed partial class ProgramArguments
    {
        const string Help = "Usage: program";
    }
}

namespace Namespace2
{
    [DocoptArguments]
    sealed partial class ProgramArguments
    {
        const string Help = "Usage: program";
    }
}

then build fails with the following error indicating that the source generator failed:

error CS8785: Generator 'SourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'The hintName 'ProgramArguments.cs' of the added source file must be unique within a generator.

T4 generated strongly typed docopt return object

As an alternative to the return dictionary we should use a T4 template to generate a strongly typed return object for each usage text defined in the project.

  • T4 template called docopt.tt
  • Usage strings should be defined in files called *.usage.txt
  • For each usage file X.usage.txt, when applied the T4 template will create a new C# file called X.docopt.cs defining a class called XArgs with a strongly typed property for each option or argument.

No supplied parameters prints only the Usage part but not the Options description

Just create a new console project, add the NuGet package and this line to Program.cs:


Then, run the application.
The output is this:

Usage:
  prog command ARG <myarg> [OPTIONALARG] [-o -s=<arg> --long=ARG --switch]
  prog files FILE...

Expected (at least):

Usage:
  prog command ARG <myarg> [OPTIONALARG] [-o -s=<arg> --long=ARG --switch]
  prog files FILE...

Options:
 -o           Short switch.
 -s=<arg>     Short option with arg.
 --long=ARG   Long option with arg.
 --swith      Long switch.

Multiple Definition of Properties

Test host app for T4 Docopt.NET

Usage:
prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch]
prog command2 arg [OPTIONALARG]
prog files FILE...

Options:
-o Short switch.
-s= Short option with arg.
--long=ARG Long option with arg.
--switch Long switch.

Explanation:
This is a test usage file.

Using the above usage statement results in ArgMyarg and OPTIONALARG being defined twice in the T4DocoptNet.cs source file.

        public bool CmdCommand { get { return _args["command"].IsTrue; } }
        public string ArgArg { get { return null == _args["ARG"] ? null : _args["ARG"].ToString(); } }
        public string ArgMyarg  { get { return null == _args["<myarg>"] ? null : _args["<myarg>"].ToString(); } }
        public string ArgOptionalarg { get { return null == _args["OPTIONALARG"] ? null : _args["OPTIONALARG"].ToString(); } }
        public bool OptO { get { return _args["-o"].IsTrue; } }
        public string OptS { get { return null == _args["-s"] ? null : _args["-s"].ToString(); } }
        public string OptLong { get { return null == _args["--long"] ? null : _args["--long"].ToString(); } }
        public bool OptSwitch { get { return _args["--switch"].IsTrue; } }
        public bool CmdCommand2 { get { return _args["command2"].IsTrue; } }
        public bool CmdArg { get { return _args["arg"].IsTrue; } }
        public string ArgMyarg  { get { return null == _args["<myarg>"] ? null : _args["<myarg>"].ToString(); } }
        public string ArgOptionalarg { get { return null == _args["OPTIONALARG"] ? null : _args["OPTIONALARG"].ToString(); } }
        public bool CmdFiles { get { return _args["files"].IsTrue; } }
        public ArrayList ArgFile { get { return _args["FILE"].AsList; } }

This functionality does not appear to be intended as the example on docopt.org also causes this issue.

unmatched '('

using DocoptNet;
namespace ConsoleApplication1 {
    internal class Program {
        private static void Main(string[] args) {
            const string USAGE =
@"Usage: Conversion (load | brokers | loadnonxl | <pn>... [--clean]) [--whatif]

-h --help    show this
--verbose    print more text
";

            var docopt = new Docopt();
            var arguments = docopt.Apply(USAGE, args, exit: true);
        }
    }
}

prints
unmatched '('
but http://try.docopt.org/?doc=Usage%3A+Conversion+%28load+%7C+brokers+%7C+loadnonxl+%7C+%3Cpn%3E...+%5B--clean%5D%29+%5B--whatif%5D%0D%0A%0D%0A-h+--help++++show+this%0D%0A--verbose++++print+more+text&argv=dfg67+dfg4+dg2+--clean

parse it

Argument that is both boolean and string (git exec-path option)

Found an odd scenario in the git command line. Not sure how to handle this.

Git exec path oddity.

Usage:
 git [--exec-path[=<path>]] <command> [<args>]

Options:
  --exec-path[=<path>]
       Path to wherever your core Git programs are installed. This
       can also be controlled by setting the GIT_EXEC_PATH
       environment variable. If no path is given, git will print the
       current setting and then exit.

Compilation error: "A namespace cannot directly contain members such as fields or methods"

I just tried to compile the docopt.net example (shown on the readme) using Visual Studio 2013 Community Edition and I got the following compilation error:

"A namespace cannot directly contain members such as fields or methods"

I installed doctopt.net using the builtin Visual Studio package manager. I copied the "NavalFate" example and tried to compile it, getting the error above. This seems similar to issue #4.

Feature Request: Description in summary comments

Thank you for your work on this project, it is wonderful.

I was curious what you would think about being able to take the descriptions of arguments and options and put them in summary comments for the properties.

For

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored|--drifting]
  naval_fate.py -h | --help
  naval_fate.py --version
Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

It would be cool to get

//other code 

/// <summary> Speed in knots [default: 10]. </summary>
public string OptSpeed { get { return null == _args["--speed"] ? null : _args["--speed"].ToString(); } }

// more code 

Default Options Are Ignored

Currently default values for options are not used. The value is parsed but never used when generating code.

The following usage statement:

Test host app for T4 Docopt.NET

Usage:
prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch-dash]
prog command2 ARG
prog files FILE...

Options:
-o Short switch.
-s= Short option with arg. [default: 128]
--long=ARG Long option with arg.
--switch-dash Long switch.

Explanation:
This is a test usage file.

Results in the following code:

public string OptS { get { return null == _args["-s"] ? null : _args["-s"].ToString(); } }

When it should be:

public string OptS { get { return null == _args["-s"] ? "128" : _args["-s"].ToString(); } }

The path in T4DocoptNet.tt is incorrect

The path to DocoptNet.dll inside T4Docoptnet.tt was incorrect and I had to adjust it manually.

According to the comment above it, this seems to be a problem with the install.ps1 script.

In my case, the correct path was $(SolutionDir)..\packages\nuget\docopt.net.0.6.1.5\lib\net40\DocoptNet.dll but it got created as $(SolutionDir)packages\docopt.net.0.6.1.5\lib\net40\DocoptNet.dll

Hint: I am using a nuget.config in my solutions root folder to change to packages path.

I would guess that changing this line:

$p = '$(SolutionDir)' + "packages\" + $package.Id + "." + $package.Version + "\lib\net40\DocoptNet.dll"

to this

$p = $installPath + "DocoptNet.dll"

will fix that bug.

Unfortunately, I don't see how I could test this, so I can't fix it myself.

Using docopt.net in C++/CLR

Hi!

How i can to use docopt.net in C++/CLR ?

Main class looks like:

using namespace System;
using namespace System::IO;
using namespace System::Collections::Generic;
using namespace System::Data;
using namespace DocoptNet;

int main(array<System::String ^> ^args)
{

}

But in C++/CLR not exists "var" type.

Assembly version is 0.0.0.0

Install dotnet-script:

dotnet tool install --global dotnet-script --version 1.2.1

Run dotnet script and type the following lines on each prompt:

#r "nuget: docopt.net, 0.6.1.11"
using DocoptNet;
typeof(Docopt).Assembly

The last line prints:

[DocoptNet, Version=0.0.0.0, Culture=neutral, PublicKeyToken=7a38c71da49a547e]

Here is how the complete session should look like:

โฏ dotnet script
> #r "nuget: docopt.net, 0.6.1.11"
> using DocoptNet;
> typeof(Docopt).Assembly
[DocoptNet, Version=0.0.0.0, Culture=neutral, PublicKeyToken=7a38c71da49a547e]

Note that the assembly version is 0.0.0.0.

@voieducode, was this intentional (to avoid strong naming issues?) or a slip?

Usage

Hi,

I'm new to .NET development, so when I saw that DocOpt had been ported from Python, I was very excited. However, I am unable to get even the Naval Fate example to run without an exception.

I am using Visual Studio Express 2012 for Windows Desktop and the current docoptnet from NuGet. The exception reads as follows at the bottom of the comment.

So it looks like DocOpt can't parse the usage string. Is there some setting I am missing? Maybe something to do with how the IDE handles tabs and spaces?

  An unhandled exception of type 'DocoptNet.DocoptInputErrorException' occurred in DocoptNet.dll

  Additional information: Usage:

  naval_fate.exe ship new <name>...

  naval_fate.exe ship <name> move <x> <y> [--speed=<kn>]

  naval_fate.exe ship shoot <x> <y>

  naval_fate.exe mine (set|remove) <x> <y> [--moored | --drifting]

  naval_fate.exe (-h | --help)

  naval_fate.exe --version

Sync PR builds not occurring during CI on AppVeyor

Unfortunately, once PR #104 was merged, the build failed on master due to compilation errors:

C:\projects\docopt-net\src\DocoptNet\Docopt.cs(174,88): error CS1503: Argument 2: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(175,123): error CS1503: Argument 4: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(174,88): error CS1503: Argument 2: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(175,123): error CS1503: Argument 4: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(174,88): error CS1503: Argument 2: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(175,123): error CS1503: Argument 4: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(182,20): error CS8619: Nullability of reference types in value of type 'TSource[]' doesn't match target type 'IEnumerable<T>'. [C:\projects\docopt-net\src\DocoptNet\DocoptNet.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(174,88): error CS1503: Argument 2: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet.Playground\DocoptNet.Playground.csproj]
C:\projects\docopt-net\src\DocoptNet\Docopt.cs(175,123): error CS1503: Argument 4: cannot convert from 'DocoptNet.Value' to 'DocoptNet.ValueObject' [C:\projects\docopt-net\src\DocoptNet.Playground\DocoptNet.Playground.csproj]

From what I understand, AppVeyor builds are triggered on:

  • push to branch
  • merge PR to branch
  • open PR
  • sync PR (when you do push to branch with open PR)

It seems that PR #105 was merged into master before, but did not trigger a build for PR #104 that was also targeting the same branch (sync PR case above). Had that happened then the build errors would have been caught before breaking master.

/cc @voieducode


๐Ÿ“Ž log.txt

Add MatchAsync to `IParser<T>.IResult`

It is common that the executing code is async, and it is not easily doable with the current API.
We need a Task/ValueTask returning Func for the first argument, so async/await can be used.

This is my current workaround:

ProgramArguments programArguments;
var result = ProgramArguments.CreateParser()
.WithVersion("Naval Fate 2.0")
.Parse(args)
.Match(p => { programArguments = p; return -1; },
    result => { WriteLine(result.Help); return 0; },
    result => { WriteLine(result.Version); return 0; },
    result => { Error.WriteLine(result.Usage); return 1; });
if (result > -1) return result;
// continues with async/await...
return 0;

Leading dot in generated hint name when project has no namespace

If a project has no namespace (that is, the project file has <RootNamespace></RootNamespace>) then the hint name of the source-generated files start with a dot (.). For example, if the source file is named Program.docopt.txt then the hint name of the generated file will be .ProgramArguments.cs:

image

T4 template doesn't run in "T4DocoptNetHostApp"

When running the custom tool from within VS, it fails with the following error:

Compiling transformation: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.

on line 62 of T4DocoptNet.tt:

var s = new Docopt().GenerateCode(entry.Usage);

It looks like I broke something with PR #59 in spite of testing on my end. ๐Ÿ˜ž

The error message makes sense and while it looks like other people are running into a similar using libraries targeting .NET Standard in T4, I don't see a good solution yet. Even if we manage to find a workaround, I think the following line is going to be troublesome:

<#@ assembly name="$(ProjectDir)$(OutDir)DocoptNet.dll" #>

It means, targets will have to be added and maintained across all supported runtimes, including .NET Framework, .NET Core and .NET 5+, which seems too burdensome.

One option to explore would be to use mono/t4 that's now available as a tool. The integration with VS may not be as sweet though but that could be worked around with some sort of a watcher tool.

Make entire code base null-safe

Some parts of the code base enable the nullable context #nullable enable while other remain null-agnostic. The entire code base should be made consistently null-safe by enabling nullable context at the level of projects/solution.

Better Exception handling

Hi there

Given this piece of code:

           try
           {
                var docopt = new Docopt();
                var res = docopt.Apply(Usage, args, help: true, exit: true)
           }            
           catch (Exception ex)
           {
                throw new InvalidOperationException("Unable to parse command line arguments", ex);
           }

If I give docopt bad arguments, instead of catching the exception, I got :

A first chance exception of type 'DocoptNet.DocoptInputErrorException' occurred in DocoptNet.dll

Am I doing anything wrong? What would be the correct usage to trap bad arguments ?

Thanks

Missing required parameter throws exception instead of printing and exiting

The documentation says:

exit, by default true. If set to false will raise a DocoptExitException instead of printing and exiting. Note that this behaviour will kick in only if a Docopt.PrintExit event handler is not provided.

This suggests to me that if you have a required parameter that isn't provided, calling DocOpt.Apply() should just print the usage and exit. However, instead it is throwing an exception.

Here's a reproducible case:

var arguments = new Docopt().Apply("Usage: DocOptTest REQUIRED", args);

I'm using DocoptNet v0.6.1.3 from NuGet. Thanks for the great tool, by the way!

Bad example or bug in new parser implementation?

The example given at https://docopt.github.io/docopt.net/dev/#help-in-a-external-file has this code:

return Docopt.CreateParser(help)
             .WithVersion("Naval Fate 2.0")
             .Parse(args)
             .Match(Run,
                    result => ShowHelp(result.Help),
                    result => ShowVersion(result.Version),
                    result => OnError(result.Usage));

but there is no public parser variation with a Match method that takes three functions for help, version and usage. It's not clear to me from looking at the source code in Parser.cs whether this is an oversight or working as designed (i.e., there is an IHelpFeaturingParser and an IVersionFeaturingParser but no IHelpAndVersionFeaturingParser).

condition to properly build the project and have it work correctly

As a beginner I'm watching carefully at what exists and is smart using in the field of commandline application. Such is docopt.

The documentation of the docopt.net naval_fate application is certainly a very complete one, but it still leaves me asking to myself what is the very first step when creating a new file to work with.

I suppose the answer is somehow obvious for many people but still (believe me ), it isn't for me.

I need help.

Thanks a lot.

Unintuitive `ValueObject` behavior

ValueObject, the object that is returned from Docopt.Apply() has some unintuitive behavior in its type checking properties. This class is a wrapper around an object that was parsed from the user args. Helpfully, the ValueObject contract has several properties that allow one to check the type of the argument token: IsList, IsString, IsInt.

My main issue is with the IsInt property. As far as I can tell, it is never true, even when integer arguments are supplied. That's because the IsInt property is implemented by doing a type check with the is keyword on the object with which the ValueObject is constructed. However, the ValueObject is constructed with the string-typed token. While something like that might work in python, it will fail consistently in .NET. This results in a weird situation where objects that have IsInt = false have proper values for their AsInt properties.

There's a couple ways one could fix this. Changing the IsInt property to return the result of a call to Int32.TryParse() would work. Alternatively, the code that instantiates ValueObject could attempt to convert the string prior to invoking the constructor.

I may be off-base here if the IsInt property was never meant to be used be consumers of this library. If that is the case and this property is behaving in this way purposely, may I ask that we make it internal instead of public?

How to create optional arguments?

I seem unable to create optional arguments. Many examples on the net show things such as:

my_app [OPTIONAL]

But when I do this I get a this code generated:

public string ArgOptional { get { return _args["OPTIONAL"].ToString(); } }

So, if I don't pass the OPTIONAL argument, as soon as I try to access it I get an exception due to ToString being called on null. As I want this argument to be optional I expect it to return null or String.Empty not to throw!

Exception when using in VS2015...

Hi,

While pulling from NuGet I get the following exceptionj. Same occurrs if I run the T3DocoptNet.tt T4 template.

Severity    Code    Description Project File    Line    Suppression State
Error       An exception was thrown while trying to compile the transformation code. The following Exception was thrown:
System.IO.FileNotFoundException: Could not find file 'D:\Data\TFS\Ozcruising\VS 2015\OzCruisingImporters\Csv\OzCsvImporter\packages\docopt.net.0.6.1.6DocoptNet.dll'.
File name: 'D:\Data\TFS\Ozcruising\VS 2015\OzCruisingImporters\Csv\OzCsvImporter\packages\docopt.net.0.6.1.6DocoptNet.dll'
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.OpenRead(String path)
   at Roslyn.Utilities.FileUtilities.OpenFileStream(String path)
   at Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(String path, MetadataReferenceProperties properties, DocumentationProvider documentation)
   at Microsoft.VisualStudio.TextTemplating.CompilerBridge.<>c.<.ctor>b__15_0(String x)
   at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
   at System.Linq.Enumerable.<UnionIterator>d__66`1.MoveNext()
   at System.Linq.Enumerable.<UnionIterator>d__66`1.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at System.Collections.Immutable.ImmutableArray.CreateRange[T](IEnumerable`1 items)
   at Microsoft.CodeAnalysis.ImmutableArrayExtensions.AsImmutableOrEmpty[T](IEnumerable`1 items)
   at Microsoft.CodeAnalysis.Compilation.ValidateReferences[T](IEnumerable`1 references)
   at Microsoft.CodeAnalysis.CSharp.CSharpCompilation.WithReferences(IEnumerable`1 references)
   at Microsoft.CodeAnalysis.CSharp.CSharpCompilation.CommonWithReferences(IEnumerable`1 newReferences)
   at Microsoft.VisualStudio.TextTemplating.CompilerBridge.PrepareNewCompilation()
   at Microsoft.VisualStudio.TextTemplating.CompilerBridge.Compile()
   at Microsoft.VisualStudio.TextTemplating.TransformationRunner.Compile(String source, String inputFile, IEnumerable`1 references, Boolean debug, SupportedLanguage language, String compilerOptions)          1   

spaces in filenames

It does not appear to like args with spaces in them. Which makes file paths on windows difficult.

Here is a snippet for my USAGE

prog PREPARE (--folderpath= | --azure --jobid= --simrun= --host= --token=

I have also tried --folderpathpath

Both with = and work, when the path has no spaces. They both fail when I add spaces.

Add a space to the below example and it will fail to parse

.NET string snippet @"prepare --folderpath=""c:\thisthat"" "

T4 macro is broken (0.6.1.6)

Create a brand new console app and create Main.usage.txt as shown in the docs. T4DocoptNet.tt contains this line:

<#@ assembly name="c:\temp\ConsoleApplication2\packages\docopt.net.0.6.1.6DocoptNet.dll"  #>

which refers to a file that does not exist. I changed it to

<#@ assembly name="C:\Temp\ConsoleApplication2\packages\docopt.net.0.6.1.6\lib\net40\DocoptNet.dll" #>

which does exist, but still getting

ErrorGeneratingOutput

in my T4DocoptNet.cs.

run naval_fate

Program.txt
Hello,
Why is this Program.cs version of .txt not permitting to run the application yet?

Thank you.

Patrick

Code style errors can break building of user project

If a user project enforces code style during build via EnforceCodeStyleInBuild and warnings are treated as errors, then the following issues get flagged and can break the build:

  • IDE0010: Add missing cases to switch statement
  • IDE0055: Fix formatting
  • IDE0058: Remove unused expression value
  • IDE0065: using directive placement
  • IDE0240: Nullable directive is redundant

Steps to Reproduce

These instruction assume that the .NET SDK 8.0.300 is the latest installed.

Ensure the template is installed:

dotnet new install docopt.net.templates::0.1.0

Create a new project using the template:

mkdir demo
cd demo
dotnet new docopt-console -o . -n Demo

Build the project:

dotnet build

It should succeed without errors. Next, create an .editorconfig file with the following content in the same directory:

root = true

[*.cs]
dotnet_analyzer_diagnostic.category-Style.severity = warning

Update Demo.csproj by adding <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> to the first property group section so that the file's content read as follows:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <!-- ADDED -->
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="docopt.net" Version="0.8.0" />
    <PackageReference Include="ThisAssembly.AssemblyInfo" Version="1.0.9" />
  </ItemGroup>

</Project>

Re-build the project:

dotnet build

While the build will succeed, it will issue over 300 warnings! If <TreatWarningsAsErrors>true</TreatWarningsAsErrors> is also added to the project file then the project will fail to build.

IsNullOrEmpty on a command throws System.NullReferenceException

When a command is not present, I should be able to reference it in the dictionary and use .IsNullOrEmpty to check for it's present. But it throws System.NullReferenceException instead.

In my case, I did not mark as optional. I used the version where I gave 2 example command lines, each with a different COMMAND perhaps that's the issue?

There is a workaround below, but I would have thought you were populate a default Object in the dictionary so that the IsNullOrEmpty could be used.

Snippet of syntax below.

[TestMethod]
public void Test_CommandLine()
{
const string USAGE = @"prog.

        Usage: prog PREPARE (--folderpath <path> | --azure --jobid <jobid> --simrun <simrun> --token <token> --host <host>)
               prog SIMIULATE --scenario <scenario_name> (--folderpath <path> | --azure --simrun <simrun> --token <token> --host <host>)";

        var opt = new Docopt();

        var arguments = opt.Apply(USAGE, "simulate --scenario senario1 --azure --simrun simrun --token token --host host");
        
        //This would crash
        if(arguments["PREPARE"].IsNullOrEmpty)
        {

        }

        //So would have to do this instead.
        if (arguments["PREPARE"] != null)
        {

        }
    }

Incorrect behavior with invalid args and exit: true

As I understand it, calling Docopt.Apply with invalid args is supposed to cause the usage to be printed and the process to exit. Instead of this, it's throwing a not printing anything and throwing a DocoptExitException exception.

I'm using version 0.6.1.4.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.