fastgit 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastgit
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Use git from python, fast
5
5
  Author-email: Jeremy Howard <github@jhoward.fastmail.fm>
6
6
  License: Apache-2.0
@@ -23,9 +23,9 @@ Dynamic: license-file
23
23
 
24
24
  <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
25
25
 
26
- `fastgit` is a thin Python wrapper for the `git` CLI: one [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) object whose attribute calls run git commands, so if you know git, you already know fastgit. There is no reimplementation of git internals and no object model to learn – commands return git’s own output as (subclassed) `str`s.
26
+ `fastgit` is a Python wrapper for the `git` command line, for use in scripts and interactive sessions. You call git subcommands as Python methods and pass options as keyword arguments.
27
27
 
28
- It is designed for interactive use and automation alike: errors print tersely by default (like git itself) or raise on request, exit codes that mean “no” rather than “failed” are returned normally, and passing `sync=False` gives an async client for servers and concurrent code.
28
+ Commands run through the installed `git` executable and return its text output. There is no separate object model for repositories and commits. Both synchronous and asynchronous clients are available.
29
29
 
30
30
  ## Usage
31
31
 
@@ -39,7 +39,7 @@ $ pip install fastgit
39
39
 
40
40
  ### How to use
41
41
 
42
- Create a [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) for any directory; every command runs with that directory as its working tree. Method names map to git subcommands, and results come back as stripped strings:
42
+ Create a [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) object for the directory you want to work in. Every command runs in that directory. The default local runner expands `~` and resolves relative paths. A custom `runner` receives the supplied directory unchanged. Results have leading and trailing whitespace stripped:
43
43
 
44
44
  ``` python
45
45
  import shutil, tempfile
@@ -61,7 +61,11 @@ g.commit(m='add .gitignore')
61
61
 
62
62
  '[main (root-commit) 5113ce1] add .gitignore\n 1 file changed, 1 insertion(+)\n create mode 100644 .gitignore'
63
63
 
64
- Keyword arguments become options: single-letter names are short options (`n=1` → `-n 1`), longer names long options with underscores turned into dashes, and `True` passes the bare flag:
64
+ Keyword arguments become command-line options:
65
+
66
+ - Single-letter names produce short options, such as `n=1` for `-n 1`.
67
+ - Longer names produce long options, with underscores replaced by dashes.
68
+ - A value of `True` passes the flag without a value.
65
69
 
66
70
  ``` python
67
71
  g.log(n=1, oneline=True)
@@ -85,7 +89,9 @@ g.current_branch, g.commits
85
89
 
86
90
  ('main', ['5113ce1 add .gitignore'])
87
91
 
88
- A failed command prints git’s message and returns `None`; pass `raise_exc=True` (per call or at init) to raise instead. Where git uses exit 1 to mean “no” rather than “error” – like `grep` finding nothing – the output is returned as usual, with the code on `.returncode`:
92
+ Command output is returned in a `str` subclass with the exit code in `.returncode`. A failed command prints git’s message and returns `None`. Pass `raise_exc=True` to raise an exception instead. You can set this per call or when creating the client.
93
+
94
+ Some git commands use exit code 1 for a negative result. For example, `grep` returns 1 when nothing matches. fastgit returns the output for these results without treating them as failures:
89
95
 
90
96
  ``` python
91
97
  res = g.grep('missing')
@@ -94,7 +100,7 @@ res.returncode
94
100
 
95
101
  1
96
102
 
97
- Pass `sync=False` for an async client: the same commands and properties, each returning an awaitable, so a server never blocks its event loop on git:
103
+ Pass `sync=False` for an async client. Its commands and properties return awaitables. Waiting for git does not block the event loop:
98
104
 
99
105
  ``` python
100
106
  ag = Git(td, sync=False)
@@ -0,0 +1,90 @@
1
+ # fastgit
2
+
3
+
4
+ <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
5
+
6
+ `fastgit` is a Python wrapper for the `git` command line, for use in scripts and interactive sessions. You call git subcommands as Python methods and pass options as keyword arguments.
7
+
8
+ Commands run through the installed `git` executable and return its text output. There is no separate object model for repositories and commits. Both synchronous and asynchronous clients are available.
9
+
10
+ ## Usage
11
+
12
+ ### Installation
13
+
14
+ Install latest from [pypi](https://pypi.org/project/fastgit/)
15
+
16
+ ``` sh
17
+ $ pip install fastgit
18
+ ```
19
+
20
+ ### How to use
21
+
22
+ Create a [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) object for the directory you want to work in. Every command runs in that directory. The default local runner expands `~` and resolves relative paths. A custom `runner` receives the supplied directory unchanged. Results have leading and trailing whitespace stripped:
23
+
24
+ ``` python
25
+ import shutil, tempfile
26
+ ```
27
+
28
+ ``` python
29
+ td = tempfile.mkdtemp()
30
+ g = Git(td)
31
+ g.init(b='main')
32
+ ```
33
+
34
+ 'Initialized empty Git repository in /private/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/tmp8zyj76q7/.git/'
35
+
36
+ ``` python
37
+ (g.d/'.gitignore').mk_write('*.bak')
38
+ g.add('.gitignore')
39
+ g.commit(m='add .gitignore')
40
+ ```
41
+
42
+ '[main (root-commit) 5113ce1] add .gitignore\n 1 file changed, 1 insertion(+)\n create mode 100644 .gitignore'
43
+
44
+ Keyword arguments become command-line options:
45
+
46
+ - Single-letter names produce short options, such as `n=1` for `-n 1`.
47
+ - Longer names produce long options, with underscores replaced by dashes.
48
+ - A value of `True` passes the flag without a value.
49
+
50
+ ``` python
51
+ g.log(n=1, oneline=True)
52
+ ```
53
+
54
+ '5113ce1 add .gitignore'
55
+
56
+ You can also pass path arguments after `--` using the `__` parameter:
57
+
58
+ ``` python
59
+ g.log('--oneline', __=['.gitignore'])
60
+ ```
61
+
62
+ '5113ce1 add .gitignore'
63
+
64
+ Frequent queries are properties:
65
+
66
+ ``` python
67
+ g.current_branch, g.commits
68
+ ```
69
+
70
+ ('main', ['5113ce1 add .gitignore'])
71
+
72
+ Command output is returned in a `str` subclass with the exit code in `.returncode`. A failed command prints git’s message and returns `None`. Pass `raise_exc=True` to raise an exception instead. You can set this per call or when creating the client.
73
+
74
+ Some git commands use exit code 1 for a negative result. For example, `grep` returns 1 when nothing matches. fastgit returns the output for these results without treating them as failures:
75
+
76
+ ``` python
77
+ res = g.grep('missing')
78
+ res.returncode
79
+ ```
80
+
81
+ 1
82
+
83
+ Pass `sync=False` for an async client. Its commands and properties return awaitables. Waiting for git does not block the event loop:
84
+
85
+ ``` python
86
+ ag = Git(td, sync=False)
87
+ await ag.last_commit
88
+ ```
89
+
90
+ 'add .gitignore'
@@ -0,0 +1,9 @@
1
+ """Use git from python, fast
2
+
3
+ `fastgit` is a Python wrapper for the `git` command line, for use in scripts and interactive sessions. You call git subcommands as Python methods and pass options as keyword arguments.
4
+
5
+ Commands run through the installed `git` executable and return its text output. There is no separate object model for repositories and commits. Both synchronous and asynchronous clients are available."""
6
+
7
+ __version__ = "0.1.4"
8
+
9
+ from .core import *
@@ -20,8 +20,12 @@ d = { 'settings': { 'branch': 'main',
20
20
  'fastgit.core.Git.top': ('core.html#git.top', 'fastgit/core.py'),
21
21
  'fastgit.core.GitRes': ('core.html#gitres', 'fastgit/core.py'),
22
22
  'fastgit.core.GitRes.__new__': ('core.html#gitres.__new__', 'fastgit/core.py'),
23
+ 'fastgit.core._arunlocal': ('core.html#_arunlocal', 'fastgit/core.py'),
24
+ 'fastgit.core._depr_uname': ('core.html#_depr_uname', 'fastgit/core.py'),
23
25
  'fastgit.core._gitcmd': ('core.html#_gitcmd', 'fastgit/core.py'),
24
26
  'fastgit.core._gitres': ('core.html#_gitres', 'fastgit/core.py'),
27
+ 'fastgit.core._longopts': ('core.html#_longopts', 'fastgit/core.py'),
28
+ 'fastgit.core._runlocal': ('core.html#_runlocal', 'fastgit/core.py'),
25
29
  'fastgit.core.acallgit': ('core.html#acallgit', 'fastgit/core.py'),
26
30
  'fastgit.core.callgit': ('core.html#callgit', 'fastgit/core.py'),
27
31
  'fastgit.core.get_top': ('core.html#get_top', 'fastgit/core.py')}}}
@@ -12,6 +12,7 @@ from fastcore.utils import *
12
12
  from fastcore.aio import then
13
13
  import subprocess,asyncio
14
14
  from subprocess import CalledProcessError
15
+ from functools import cache
15
16
 
16
17
  # %% ../nbs/00_core.ipynb #880c6a46
17
18
  _ok1 = {'merge-tree','merge-base','grep','check-ignore','diff','diff-index','diff-files','diff-tree','show-ref','config','rev-parse'}
@@ -24,53 +25,83 @@ class GitRes(str):
24
25
  return self
25
26
 
26
27
  # %% ../nbs/00_core.ipynb #e4c0a290
27
- def _gitcmd(path, *args, uname=None, pre=None):
28
- assert not (uname and pre), "Pass `uname` or `pre`, not both"
29
- if uname:
30
- warn("`uname` is deprecated; pass e.g `pre=['/usr/bin/sudo','-u',uname]` instead", DeprecationWarning, stacklevel=3)
31
- pre = ['/usr/bin/sudo', '-u', uname]
28
+ def _gitcmd(path, *args, pre=None):
32
29
  cmd = ['git', '-C', str(Path(path).expanduser().resolve())] + list(args)
33
30
  return [*pre, *cmd] if pre else cmd
34
31
 
35
- def _gitres(cmd, args, out, err, returncode, ok_exit):
32
+ def _depr_uname(uname, pre):
33
+ assert not (uname and pre), "Pass `uname` or `pre`, not both"
34
+ if not uname: return pre
35
+ warn("`uname` is deprecated; pass e.g `pre=['/usr/bin/sudo','-u',uname]` instead", DeprecationWarning, stacklevel=4)
36
+ return ['/usr/bin/sudo', '-u', uname]
37
+
38
+ def _gitres(args, out, err, returncode, ok_exit):
36
39
  if ok_exit is None: ok_exit = 1 if args and args[0] in _ok1 else 0
37
- if returncode not in (0, *listify(ok_exit)): raise CalledProcessError(returncode, cmd, out, err)
40
+ if returncode not in (0, *listify(ok_exit)): raise CalledProcessError(returncode, ['git', *args], out, err)
38
41
  return GitRes((out + err).strip(), returncode)
39
42
 
40
- def callgit(path, *args, uname=None, pre=None, ok_exit=None):
41
- "Run git in `path`, returning stripped stdout+stderr as a `GitRes`; `ok_exit` adds accepted exit codes (default: 1 for `_ok1` commands)"
42
- cmd = _gitcmd(path, *args, uname=uname, pre=pre)
43
- r = subprocess.run(cmd, capture_output=True, text=True)
44
- return _gitres(cmd, args, r.stdout, r.stderr, r.returncode, ok_exit)
43
+ def _runlocal(path, args, pre=None):
44
+ "Default runner: compose the local argv and run it in a subprocess"
45
+ r = subprocess.run(_gitcmd(path, *args, pre=pre), capture_output=True, text=True)
46
+ return r.stdout, r.stderr, r.returncode
47
+
48
+ def callgit(
49
+ path, # Directory to run git in
50
+ *args, # git subcommand and arguments
51
+ uname=None, # Deprecated; use `pre`
52
+ pre=None, # argv prefix, e.g. a sudo wrapper
53
+ ok_exit=None, # Extra accepted exit codes (default: 1 for `_ok1` commands)
54
+ runner=None, # Replaces the local subprocess: `(path, args, pre) -> (stdout, stderr, returncode)`
55
+ ):
56
+ "Run git in `path`, returning stripped stdout+stderr as a `GitRes`"
57
+ out,err,rc = (runner or _runlocal)(path, list(args), pre=_depr_uname(uname, pre))
58
+ return _gitres(args, out, err, rc, ok_exit)
45
59
 
46
60
  # %% ../nbs/00_core.ipynb #4c0df6c6
47
- def get_top(folder):
48
- try: return callgit(folder, 'rev-parse', '--show-toplevel')
61
+ def get_top(folder, runner=None):
62
+ try: return callgit(folder, 'rev-parse', '--show-toplevel', runner=runner)
49
63
  except CalledProcessError: return None
50
64
 
65
+ # %% ../nbs/00_core.ipynb #2c57b813
66
+ @cache
67
+ def _longopts(cmd):
68
+ "Long options `git <cmd>` lists for completion; empty if unavailable"
69
+ try: r = subprocess.run(['git', cmd, '--git-completion-helper'], capture_output=True, text=True)
70
+ except OSError: return set()
71
+ return {o.rstrip('=') for o in r.stdout.split()} if r.returncode==0 else set()
72
+
51
73
  # %% ../nbs/00_core.ipynb #97f78839
52
74
  class Git:
53
75
  "Run git commands in dir `d`; `sync=False` makes every command return an awaitable"
54
- def __init__(self, d, pre=None, raise_exc=False, sync=True): self.d,self.pre,self.raise_exc,self._sync = Path(d).expanduser(),pre,raise_exc,sync
55
-
56
- def __call__(self, cmd, *args, mute_errors=False, raise_exc=None, ok_exit=None, **kwargs):
76
+ def __init__(self, d, pre=None, raise_exc=False, sync=True, runner=None): self.d,self.pre,self.raise_exc,self._sync,self.runner = Path(d),pre,raise_exc,sync,runner
77
+
78
+ def __call__(self,
79
+ cmd, # git subcommand to run
80
+ *args, # Positional arguments for the subcommand
81
+ mute_errors=False, # Suppress the printed ERROR line on failure?
82
+ raise_exc=None, # Raise `CalledProcessError` on failure? (default: `self.raise_exc`)
83
+ ok_exit=None, # Extra accepted exit codes (default: 1 for commands like `diff` where it isn't an error)
84
+ **kwargs # Become flags: short keys as `-k v`, long as `--key=v` (`_` to `-`; `True` bare, `False` dropped); `__` passes paths after `--`
85
+ ):
86
+ "Run `git cmd` in `self.d`, returning a `GitRes` (or an awaitable of one when `sync=False`)"
57
87
  paths = [str(p) for p in listify(kwargs.pop('__', None) or [])]
58
88
  args = listify(args)
59
89
  kwargs = {k:v for k,v in kwargs.items() if v is not False}
60
- args += concat((f'-{k}',str(v)) for k,v in kwargs.items() if len(k)==1 and v is not True)
61
- args += [f'-{k}' for k,v in kwargs.items() if len(k)==1 and v is True]
62
- args += [f'--{k.replace("_","-")}={v}' for k,v in kwargs.items() if len(k)>1 and v is not True]
63
- args += [f'--{k.replace("_","-")}' for k,v in kwargs.items() if len(k)>1 and v is True]
90
+ def _short(k): return len(k)==1 or (len(k)<=3 and k.isalnum() and (o:=_longopts(cmd)) and f'--{k}' not in o)
91
+ args += concat((f'-{k}',str(v)) for k,v in kwargs.items() if _short(k) and v is not True)
92
+ args += [f'-{k}' for k,v in kwargs.items() if _short(k) and v is True]
93
+ args += [f'--{k.replace("_","-")}={v}' for k,v in kwargs.items() if not _short(k) and v is not True]
94
+ args += [f'--{k.replace("_","-")}' for k,v in kwargs.items() if not _short(k) and v is True]
64
95
  if paths: args += ['--'] + paths
65
96
  f = self._run if self._sync else self._arun
66
97
  return f(cmd, args, mute_errors, ifnone(raise_exc, self.raise_exc), ok_exit)
67
98
 
68
99
  def _run(self, cmd, args, mute_errors, raise_exc, ok_exit):
69
- try: return callgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit)
100
+ try: return callgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit, runner=self.runner)
70
101
  except CalledProcessError as e: self._err(e, cmd, args, mute_errors, raise_exc)
71
102
 
72
103
  async def _arun(self, cmd, args, mute_errors, raise_exc, ok_exit):
73
- try: return await acallgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit)
104
+ try: return await acallgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit, runner=self.runner)
74
105
  except CalledProcessError as e: self._err(e, cmd, args, mute_errors, raise_exc)
75
106
 
76
107
  def _err(self, e, cmd, args, mute_errors, raise_exc):
@@ -101,9 +132,21 @@ def commits(self:Git): return then(self.log('--oneline', mute_errors=True, raise
101
132
  def current_branch(self:Git): return self.branch('--show-current')
102
133
 
103
134
  # %% ../nbs/00_core.ipynb #b69ecf1c
104
- async def acallgit(path, *args, uname=None, pre=None, ok_exit=None):
105
- "Async `callgit`: identical contract, run in an `asyncio` subprocess"
106
- cmd = _gitcmd(path, *args, uname=uname, pre=pre)
135
+ async def _arunlocal(path, args, pre=None):
136
+ "Async `_runlocal`"
137
+ cmd = _gitcmd(path, *args, pre=pre)
107
138
  p = await asyncio.create_subprocess_exec(*cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
108
139
  out,err = await p.communicate()
109
- return _gitres(cmd, args, out.decode(), err.decode(), p.returncode, ok_exit)
140
+ return out.decode(), err.decode(), p.returncode
141
+
142
+ async def acallgit(
143
+ path, # Directory to run git in
144
+ *args, # git subcommand and arguments
145
+ uname=None, # Deprecated; use `pre`
146
+ pre=None, # argv prefix, e.g. a sudo wrapper
147
+ ok_exit=None, # Extra accepted exit codes (default: 1 for `_ok1` commands)
148
+ runner=None, # Async runner replacing the local subprocess: `async (path, args, pre) -> (stdout, stderr, returncode)`
149
+ ):
150
+ "Async `callgit`: identical contract, run in an `asyncio` subprocess"
151
+ out,err,rc = await (runner or _arunlocal)(path, list(args), pre=_depr_uname(uname, pre))
152
+ return _gitres(args, out, err, rc, ok_exit)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastgit
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Use git from python, fast
5
5
  Author-email: Jeremy Howard <github@jhoward.fastmail.fm>
6
6
  License: Apache-2.0
@@ -23,9 +23,9 @@ Dynamic: license-file
23
23
 
24
24
  <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
25
25
 
26
- `fastgit` is a thin Python wrapper for the `git` CLI: one [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) object whose attribute calls run git commands, so if you know git, you already know fastgit. There is no reimplementation of git internals and no object model to learn – commands return git’s own output as (subclassed) `str`s.
26
+ `fastgit` is a Python wrapper for the `git` command line, for use in scripts and interactive sessions. You call git subcommands as Python methods and pass options as keyword arguments.
27
27
 
28
- It is designed for interactive use and automation alike: errors print tersely by default (like git itself) or raise on request, exit codes that mean “no” rather than “failed” are returned normally, and passing `sync=False` gives an async client for servers and concurrent code.
28
+ Commands run through the installed `git` executable and return its text output. There is no separate object model for repositories and commits. Both synchronous and asynchronous clients are available.
29
29
 
30
30
  ## Usage
31
31
 
@@ -39,7 +39,7 @@ $ pip install fastgit
39
39
 
40
40
  ### How to use
41
41
 
42
- Create a [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) for any directory; every command runs with that directory as its working tree. Method names map to git subcommands, and results come back as stripped strings:
42
+ Create a [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) object for the directory you want to work in. Every command runs in that directory. The default local runner expands `~` and resolves relative paths. A custom `runner` receives the supplied directory unchanged. Results have leading and trailing whitespace stripped:
43
43
 
44
44
  ``` python
45
45
  import shutil, tempfile
@@ -61,7 +61,11 @@ g.commit(m='add .gitignore')
61
61
 
62
62
  '[main (root-commit) 5113ce1] add .gitignore\n 1 file changed, 1 insertion(+)\n create mode 100644 .gitignore'
63
63
 
64
- Keyword arguments become options: single-letter names are short options (`n=1` → `-n 1`), longer names long options with underscores turned into dashes, and `True` passes the bare flag:
64
+ Keyword arguments become command-line options:
65
+
66
+ - Single-letter names produce short options, such as `n=1` for `-n 1`.
67
+ - Longer names produce long options, with underscores replaced by dashes.
68
+ - A value of `True` passes the flag without a value.
65
69
 
66
70
  ``` python
67
71
  g.log(n=1, oneline=True)
@@ -85,7 +89,9 @@ g.current_branch, g.commits
85
89
 
86
90
  ('main', ['5113ce1 add .gitignore'])
87
91
 
88
- A failed command prints git’s message and returns `None`; pass `raise_exc=True` (per call or at init) to raise instead. Where git uses exit 1 to mean “no” rather than “error” – like `grep` finding nothing – the output is returned as usual, with the code on `.returncode`:
92
+ Command output is returned in a `str` subclass with the exit code in `.returncode`. A failed command prints git’s message and returns `None`. Pass `raise_exc=True` to raise an exception instead. You can set this per call or when creating the client.
93
+
94
+ Some git commands use exit code 1 for a negative result. For example, `grep` returns 1 when nothing matches. fastgit returns the output for these results without treating them as failures:
89
95
 
90
96
  ``` python
91
97
  res = g.grep('missing')
@@ -94,7 +100,7 @@ res.returncode
94
100
 
95
101
  1
96
102
 
97
- Pass `sync=False` for an async client: the same commands and properties, each returning an awaitable, so a server never blocks its event loop on git:
103
+ Pass `sync=False` for an async client. Its commands and properties return awaitables. Waiting for git does not block the event loop:
98
104
 
99
105
  ``` python
100
106
  ag = Git(td, sync=False)
@@ -1,5 +1,4 @@
1
1
  LICENSE
2
- MANIFEST.in
3
2
  README.md
4
3
  pyproject.toml
5
4
  fastgit/__init__.py
fastgit-0.1.2/MANIFEST.in DELETED
@@ -1,5 +0,0 @@
1
- include settings.ini
2
- include LICENSE
3
- include CONTRIBUTING.md
4
- include README.md
5
- recursive-exclude * __pycache__
fastgit-0.1.2/README.md DELETED
@@ -1,84 +0,0 @@
1
- # fastgit
2
-
3
-
4
- <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
5
-
6
- `fastgit` is a thin Python wrapper for the `git` CLI: one [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) object whose attribute calls run git commands, so if you know git, you already know fastgit. There is no reimplementation of git internals and no object model to learn – commands return git’s own output as (subclassed) `str`s.
7
-
8
- It is designed for interactive use and automation alike: errors print tersely by default (like git itself) or raise on request, exit codes that mean “no” rather than “failed” are returned normally, and passing `sync=False` gives an async client for servers and concurrent code.
9
-
10
- ## Usage
11
-
12
- ### Installation
13
-
14
- Install latest from [pypi](https://pypi.org/project/fastgit/)
15
-
16
- ``` sh
17
- $ pip install fastgit
18
- ```
19
-
20
- ### How to use
21
-
22
- Create a [`Git`](https://AnswerDotAI.github.io/fastgit/core.html#git) for any directory; every command runs with that directory as its working tree. Method names map to git subcommands, and results come back as stripped strings:
23
-
24
- ``` python
25
- import shutil, tempfile
26
- ```
27
-
28
- ``` python
29
- td = tempfile.mkdtemp()
30
- g = Git(td)
31
- g.init(b='main')
32
- ```
33
-
34
- 'Initialized empty Git repository in /private/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/tmp8zyj76q7/.git/'
35
-
36
- ``` python
37
- (g.d/'.gitignore').mk_write('*.bak')
38
- g.add('.gitignore')
39
- g.commit(m='add .gitignore')
40
- ```
41
-
42
- '[main (root-commit) 5113ce1] add .gitignore\n 1 file changed, 1 insertion(+)\n create mode 100644 .gitignore'
43
-
44
- Keyword arguments become options: single-letter names are short options (`n=1` → `-n 1`), longer names long options with underscores turned into dashes, and `True` passes the bare flag:
45
-
46
- ``` python
47
- g.log(n=1, oneline=True)
48
- ```
49
-
50
- '5113ce1 add .gitignore'
51
-
52
- You can also pass path arguments after `--` using the `__` parameter:
53
-
54
- ``` python
55
- g.log('--oneline', __=['.gitignore'])
56
- ```
57
-
58
- '5113ce1 add .gitignore'
59
-
60
- Frequent queries are properties:
61
-
62
- ``` python
63
- g.current_branch, g.commits
64
- ```
65
-
66
- ('main', ['5113ce1 add .gitignore'])
67
-
68
- A failed command prints git’s message and returns `None`; pass `raise_exc=True` (per call or at init) to raise instead. Where git uses exit 1 to mean “no” rather than “error” – like `grep` finding nothing – the output is returned as usual, with the code on `.returncode`:
69
-
70
- ``` python
71
- res = g.grep('missing')
72
- res.returncode
73
- ```
74
-
75
- 1
76
-
77
- Pass `sync=False` for an async client: the same commands and properties, each returning an awaitable, so a server never blocks its event loop on git:
78
-
79
- ``` python
80
- ag = Git(td, sync=False)
81
- await ag.last_commit
82
- ```
83
-
84
- 'add .gitignore'
@@ -1,9 +0,0 @@
1
- """Use git from python, fast
2
-
3
- `fastgit` is a thin Python wrapper for the `git` CLI: one `Git` object whose attribute calls run git commands, so if you know git, you already know fastgit. There is no reimplementation of git internals and no object model to learn -- commands return git's own output as (subclassed) `str`s.
4
-
5
- It is designed for interactive use and automation alike: errors print tersely by default (like git itself) or raise on request, exit codes that mean "no" rather than "failed" are returned normally, and passing `sync=False` gives an async client for servers and concurrent code."""
6
-
7
- __version__ = "0.1.2"
8
-
9
- from .core import *
File without changes
File without changes
File without changes