Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ajatkj committed Jul 6, 2024
0 parents commit 2796344
Show file tree
Hide file tree
Showing 33 changed files with 6,447 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.mypy_cache
.nox
.ruff_cache
.vscode
__pycache__
dist
site
env
env*
.env*
venv
*.egg-info
build

# vim temporary files
*~
.*.sw?
.cache

# macOS
.DS_Store
22 changes: 22 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_language_version:
python: python3.10
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-added-large-files
- id: check-toml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.1.14
hooks:
- id: ruff
args:
- --fix
- id: ruff-format
ci:
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit hook autoupdate
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Coming soon
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2024 Ankit Jain ([email protected])

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
402 changes: 402 additions & 0 deletions README.md

Large diffs are not rendered by default.

Binary file added assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added examples/__init__.py
Empty file.
56 changes: 56 additions & 0 deletions examples/example_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
import sys
from typing import Dict, List, Optional, Tuple, Union

cwd = os.path.dirname(os.path.realpath(__file__))
sys.path.append(f"{cwd}/../")

from typed_argparser import ArgumentClass # noqa: E402
from typed_argparser.fields import argfield # noqa: E402


class Example1(ArgumentClass):
"""This example shows how to use some of the basic types in typed_argparser."""

# Positional arguments do not generate short or long options
opt1: Union[int, str] = argfield(help="opt1 is a mandatory argument which can be an integer or a string")
opt2: List[str] = argfield(help="opt2 is a mandatory argument and can be used multiple times")
# Optional arguments generate only long option by default if no short option is provided
opt3: Optional[str] = argfield(help="this is an optional argument.")
# Use Dict type to accept multiple key value pairs
opt4: Optional[Dict[str, int]] = argfield(help="accept key value pairs. can be used multiple times.")
# Use Tuple type to accept exactly n no. of arguments
opt5: Optional[Tuple[str, ...]] = argfield("-o", "--option5", nargs=4, help="accept multiple options")


cli = Example1()


"""
usage: example1 [--opt3 <value>] [--opt4 <key=value>] [-o <value1> <value2> <value3> <value4>] [--help]
<opt1> <opt2>
description:
This example shows how to use some of the basic types in typed_argparser.
positional:
<opt1> opt1 is a mandatory argument which can be an integer or a string [(int|str)]
<opt2> opt2 is a mandatory argument and can be used multiple times [str]
(multiple allowed)
options:
--opt3 <value> this is an optional argument. [str]
--opt4 <key=value> accept key value pairs. can be used multiple times. [str, int]
(multiple allowed)
-o, --option5 <value1> <value2> <value3> <value4> accept multiple options [(str,...)]
miscellaneous:
--help show this help message and exit
"""

cli.parse("--opt4 abc=10 --opt4 xyz=20 --option5 a b c d 20 abc")

"""
ParsedExample1(opt1=20, opt2=['abc'], opt3=None, opt4={'abc': 10, 'xyz': 20}, opt5=('a', 'b', 'c', 'd'))
"""
print(cli)
61 changes: 61 additions & 0 deletions examples/example_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from io import TextIOWrapper
import os
import sys
from typing import Dict, List, Optional, Union
from typing_extensions import Annotated
from pathlib import Path


cwd = os.path.dirname(os.path.realpath(__file__))
sys.path.append(f"{cwd}/../")

from typed_argparser.types import Args # noqa: E402
from typed_argparser import ArgumentClass # noqa: E402
from typed_argparser.fields import argfield # noqa: E402


class Example2(ArgumentClass):
"""This example shows how to use the `execute` decorator to execute functions based on the arguments provided."""

# Positional arguments do not generate short or long options
opt1: Union[int, str] = argfield(help="opt1 is a mandatory argument which can be an integer or a string")
opt2: List[str] = argfield(help="opt2 is a mandatory argument and can be used multiple times")
# Use Annotated from typing to provide arguments to types as shown below
opt3: Annotated[Optional[Path], Args(mode="w")] = argfield(help="this is an output file argument.")
# Use Dict type to accept multiple key value pairs
opt4: Optional[Dict[str, int]] = argfield(help="accept key value pairs. can be used multiple times.")


cli = Example2()

cli.parse("--opt3 output.txt 20 abc")


@cli.execute("opt1", "opt2")
def execute_1(opt1: str, opt2: List[str]):
print("This function is executed when both function arguments are provided.")
print(f"opt1: {opt1}, opt2: {opt2}")


@cli.execute("opt3")
def execute_2(opt3: TextIOWrapper):
opt3.write("This is written to the output file.")


@cli.execute("opt4")
def execute_3(opt4: Dict[str, int]):
print("This will not be executed as opt4 is not provided.")


"""
Output:
This function is executed when all positional arguments are provided
opt1: 20, opt2: ['abc']
> cat output.txt
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: output.txt
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ This is written to the output file
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
"""
Empty file added examples/git_cli/__init__.py
Empty file.
124 changes: 124 additions & 0 deletions examples/git_cli/add_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from typing import List, Optional
from pathlib import Path

from typing_extensions import Annotated, Doc

from typed_argparser import SUPPRESS, ArgumentClass
from typed_argparser.fields import argfield
from typed_argparser.groups import ArgumentGroup


from .common import CommonParameters


class AddCommand(CommonParameters, ArgumentClass):
__description__ = """\
This command updates the index using the current content found in the working tree,
to prepare the content staged for the next commit. It typically adds the current content
of existing paths as a whole, but with some options it can also be used to add content
with only part of the changes made to the working tree files applied, or remove paths that
do not exist in the working tree anymore.
The "index" holds a snapshot of the content of the working tree, and it is this snapshot that
is taken as the contents of the next commit. Thus after making any changes to the working
tree, and before running the commit command, you must use the add command to add any new or
modified files to the index.
This command can be performed multiple times before a commit. It only adds the content of the
specified file(s) at the time the add command is run; if you want subsequent changes included
in the next commit, then you must run git add again to add the new content to the index.
The git status command can be used to obtain a summary of which files have changes that are
staged for the next commit.
The git add command will not add ignored files by default. If any ignored files were explicitly
specified on the command line, git add will fail with a list of ignored files. Ignored files
reached by directory recursion or filename globbing performed by Git (quote your globs before
the shell) will be silently ignored. The git add command can be used to add ignored files with
the -f (force) option.
Please see git-commit(1) for alternative ways to add content to a commit.
"""
pass


class MoveCommand(ArgumentClass):
"""
Move or rename a file, directory, or symlink.
\tgit mv [-v] [-f] [-n] [-k] <source> <destination>
\tgit mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
In the first form, it renames <source>, which must exist and be either a file, symlink or directory, to <destination>.
In the second form, the last argument has to be an existing directory; the given sources will be moved into this directory.
The index is updated after successful completion, but the change must still be committed.
"""

source: Annotated[List[Path], Doc("Source path")] = argfield(nargs="+", help=SUPPRESS)
desination: Annotated[Path, Doc("Destination file or directory")] = argfield(help=SUPPRESS)

__epilog__ = """
This is how move command works
"""


class RestoreCommand(ArgumentClass):
__description__ = """
Remove command
"""
source: Annotated[
Optional[Path],
Doc(
"""\
Restore the working tree files with the content from the given tree. It is common to specify the source
tree by naming a commit, branch or tag associated with it.
If not specified, the contents are restored from HEAD if --staged is given, otherwise from the index.
As a special case, you may use "A...B" as a shortcut for the merge base of A and B if there is exactly one merge base.
You can leave out at most one of A and B, in which case it defaults
to HEAD.
"""
),
] = argfield()
pass


class RemoveCommand(ArgumentClass, CommonParameters):
__description__ = """\
This command updates the index using the current content found in the working tree,
to prepare the content staged for the next commit. It typically adds the current content of existing paths
as a whole, but with some options it can also be used to add content with only part of the changes made
to the working tree files applied, or remove paths that do not exist in the working
tree anymore.
The "index" holds a snapshot of the content of the working tree, and it is this snapshot that is taken
as the contents of the next commit. Thus after making any changes to the working tree,
and before running the commit command, you must use the add command to add any new or modified files to the index.
This command can be performed multiple times before a commit. It only adds the content of the specified
file(s) at the time the add command is run; if you want subsequent changes included in
the next commit, then you must run git add again to add the new content to the index.
The git status command can be used to obtain a summary of which files have changes that are staged for the next commit.
The git add command will not add ignored files by default. If any ignored files were explicitly specified on the
command line, git add will fail with a list of ignored files. Ignored files
reached by directory recursion or filename globbing performed by Git (quote your globs before the shell) will be
silently ignored. The git add command can be used to add ignored files with the -f (force) option.
Please see git-commit(1) for alternative ways to add content to a commit.
"""
pass


class AddGroup(ArgumentGroup):
__title__ = "add"
__hide_title__ = True
__group_description__ = "work on the current change (see also: git help everyday)"

add: Annotated[AddCommand, Doc("Add file contents to the index")] = argfield()
mv: Annotated[MoveCommand, Doc("Move or rename a file, a directory, or a symlink")] = argfield()
restore: Annotated[RestoreCommand, Doc("Restore working tree files")] = argfield()
remove: Annotated[RemoveCommand, Doc("Remove files from the working tree and from the index")] = argfield()
29 changes: 29 additions & 0 deletions examples/git_cli/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from pathlib import Path

from typing_extensions import Annotated, Doc, List

from typed_argparser.constants import SUPPRESS
from typed_argparser.fields import argfield


class CommonParameters:
pathspec: Annotated[
List[Path],
Doc(
"""\
Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching
files. Also a leading directory name (e.g. dir to add dir/file1 and dir/file2)
can be given to update the index to match the current state of the directory as a
whole (e.g. specifying dir will record not just a file dir/file1 modified in the
working tree, a file dir/file2 added to the working tree, but also a file dir/file3
removed from the working tree). Note that older versions of Git used to ignore
removed files; use --no-all option if you want to add modified or new files but
ignore removed ones.
For more details about the <pathspec> syntax, see the pathspec entry in gitglossary(7)."""
),
] = argfield(nargs="*")


class Directory:
directory: Path = argfield(default=None, help=SUPPRESS, nargs="?")
Loading

0 comments on commit 2796344

Please sign in to comment.