gitbolt 0.0.0.dev15__tar.gz → 0.0.0.dev16__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.
Files changed (35) hide show
  1. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/PKG-INFO +29 -3
  2. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/README.md +28 -2
  3. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/pyproject.toml +2 -4
  4. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/base.py +103 -7
  5. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/runner/base.py +34 -1
  6. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/runner/simple.py +49 -2
  7. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt.egg-info/PKG-INFO +29 -3
  8. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/LICENSE +0 -0
  9. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/setup.cfg +0 -0
  10. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/__init__.py +0 -0
  11. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/_internal_init.py +0 -0
  12. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/add.py +0 -0
  13. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/base.py +0 -0
  14. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/constants.py +0 -0
  15. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/exceptions.py +0 -0
  16. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/ls_tree.py +0 -0
  17. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/models.py +0 -0
  18. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/py.typed +0 -0
  19. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/pytest_plugin.py +0 -0
  20. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/__init__.py +0 -0
  21. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/_internal_init.py +0 -0
  22. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/add.py +0 -0
  23. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/constants.py +0 -0
  24. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/exceptions.py +0 -0
  25. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/impl/__init__.py +0 -0
  26. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/impl/simple.py +0 -0
  27. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/ls_tree.py +0 -0
  28. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/runner/__init__.py +0 -0
  29. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/subprocess/utils.py +0 -0
  30. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt/utils.py +0 -0
  31. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt.egg-info/SOURCES.txt +0 -0
  32. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt.egg-info/dependency_links.txt +0 -0
  33. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt.egg-info/entry_points.txt +0 -0
  34. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt.egg-info/requires.txt +0 -0
  35. {gitbolt-0.0.0.dev15 → gitbolt-0.0.0.dev16}/src/gitbolt.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitbolt
3
- Version: 0.0.0.dev15
3
+ Version: 0.0.0.dev16
4
4
  Summary: Fast, flexible and type-safe Git commands in Python.
5
5
  Author-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
6
6
  Maintainer-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
@@ -327,10 +327,12 @@ no_advice_reset_git = overridden_git.git_opts_override(no_advice=False)
327
327
 
328
328
  At last, run unchecked commands in git.
329
329
 
330
- Introduced in `0.0.0dev4` to
330
+ Introduced in `0.0.0.dev4` to
331
331
  - experiment.
332
332
  - have consistent interfaced commands run until all subcommands are provided by the library.
333
333
 
334
+ #### 🖥️ Run one process per command
335
+
334
336
  ```python
335
337
  import gitbolt
336
338
 
@@ -340,9 +342,33 @@ git.subcmd_unchecked.run(['--version']) # run the version option for git.
340
342
  git.subcmd_unchecked.run(['version']) # run the version subcommand.
341
343
  ```
342
344
 
345
+ #### 🖥️ Run one long-running process and communicate with it
346
+
347
+ Introduced in `0.0.0.dev16` to:
348
+ - Make communicable processes using `subprocess.Popen`.
349
+
350
+ Get a long-running process and communicate with it for batching and faster operations.
351
+
352
+ ```python
353
+ import gitbolt
354
+ import sys
355
+
356
+ git = gitbolt.get_git_command()
357
+ with git.subcmd_unchecked.popen(["cat-file", "--batch-command"]) as cf:
358
+ cf.stdin.write(b"contents HEAD\n")
359
+ cf.stdin.flush()
360
+ header = cf.stdout.readline().strip()
361
+ print(f"HEADER: {header}", file=sys.stderr)
362
+ obj, typ, size = header.split()
363
+ print(cf.stdout.read(int(size)))
364
+ cf.stdout.readline()
365
+ ```
366
+
367
+ Error handling and I/O management is left to the client/caller.
368
+
343
369
  #### 💻 Run commands received from CLI
344
370
 
345
- Introduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
371
+ Introduced in `0.0.0.dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
346
372
 
347
373
  While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
348
374
  would be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before
@@ -291,10 +291,12 @@ no_advice_reset_git = overridden_git.git_opts_override(no_advice=False)
291
291
 
292
292
  At last, run unchecked commands in git.
293
293
 
294
- Introduced in `0.0.0dev4` to
294
+ Introduced in `0.0.0.dev4` to
295
295
  - experiment.
296
296
  - have consistent interfaced commands run until all subcommands are provided by the library.
297
297
 
298
+ #### 🖥️ Run one process per command
299
+
298
300
  ```python
299
301
  import gitbolt
300
302
 
@@ -304,9 +306,33 @@ git.subcmd_unchecked.run(['--version']) # run the version option for git.
304
306
  git.subcmd_unchecked.run(['version']) # run the version subcommand.
305
307
  ```
306
308
 
309
+ #### 🖥️ Run one long-running process and communicate with it
310
+
311
+ Introduced in `0.0.0.dev16` to:
312
+ - Make communicable processes using `subprocess.Popen`.
313
+
314
+ Get a long-running process and communicate with it for batching and faster operations.
315
+
316
+ ```python
317
+ import gitbolt
318
+ import sys
319
+
320
+ git = gitbolt.get_git_command()
321
+ with git.subcmd_unchecked.popen(["cat-file", "--batch-command"]) as cf:
322
+ cf.stdin.write(b"contents HEAD\n")
323
+ cf.stdin.flush()
324
+ header = cf.stdout.readline().strip()
325
+ print(f"HEADER: {header}", file=sys.stderr)
326
+ obj, typ, size = header.split()
327
+ print(cf.stdout.read(int(size)))
328
+ cf.stdout.readline()
329
+ ```
330
+
331
+ Error handling and I/O management is left to the client/caller.
332
+
307
333
  #### 💻 Run commands received from CLI
308
334
 
309
- Introduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
335
+ Introduced in `0.0.0.dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
310
336
 
311
337
  While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
312
338
  would be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gitbolt"
3
- version = "0.0.0dev15"
3
+ version = "0.0.0.dev16"
4
4
  description = "Fast, flexible and type-safe Git commands in Python."
5
5
  requires-python = ">=3.12"
6
6
  readme = "README.md"
@@ -45,9 +45,7 @@ pygit2 = ['pygit2']
45
45
  test = ['pytest']
46
46
 
47
47
  [dependency-groups]
48
- # TODO: report the mypy recent version (1.16.0, 1.16.1 issue) RuntimeError: ('Not implemented', <class 'mypy.types.TypeGuardedType'>)
49
- # btw, this error doesn't show in the latest developer version. So, this error will go away with 1.17.0 relase
50
- dev = ["mypy==1.15.0", "ruff"]
48
+ dev = ["mypy", "ruff"]
51
49
  doc = ['sphinx', 'sphinx-argparse']
52
50
  test = ["pytest", 'pytest-cov', "pytest-xdist"]
53
51
  multitest = ['tox']
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
  from abc import abstractmethod, ABC
11
11
  from collections.abc import Callable
12
12
  from pathlib import Path
13
- from subprocess import CompletedProcess
13
+ from subprocess import CompletedProcess, Popen, PIPE
14
14
  from typing import override, Protocol, Unpack, Self, overload, Literal, Any
15
15
 
16
16
  from vt.utils.commons.commons.core_py import is_unset, not_none_not_unset
@@ -584,12 +584,8 @@ class UncheckedSubcmd(GitSubcmdCommand, RootDirOp, Protocol):
584
584
 
585
585
  :return: ``CompletedProcess`` capturing all the required stdout, stderr, return-code etc.
586
586
  """
587
- main_cmd_args = self.git.build_main_cmd_args()
588
- envs_vars = self.git.build_git_envs()
589
- another_supplied_env = subprocess_run_kwargs.pop("env", None)
590
- if another_supplied_env:
591
- if envs_vars is not None:
592
- envs_vars.update(another_supplied_env)
587
+ main_cmd_args = self.git_main_cmd_args()
588
+ envs_vars = self.git_envs(subprocess_run_kwargs.pop("env", None))
593
589
  cwd = subprocess_run_kwargs.pop("cwd", self.root_dir)
594
590
  capture_output = subprocess_run_kwargs.pop("capture_output", True)
595
591
  check = subprocess_run_kwargs.pop("check", True)
@@ -607,3 +603,103 @@ class UncheckedSubcmd(GitSubcmdCommand, RootDirOp, Protocol):
607
603
  **subprocess_run_kwargs,
608
604
  )
609
605
  return result
606
+
607
+ @overload
608
+ def popen(
609
+ self,
610
+ subcommand_args: list[str],
611
+ *popen_args: Any,
612
+ text: Literal[True] = True,
613
+ **popen_kwargs: Any,
614
+ ) -> Popen[str]: ...
615
+
616
+ @overload
617
+ def popen(
618
+ self,
619
+ subcommand_args: list[str],
620
+ *popen_args: Any,
621
+ text: Literal[False] = False,
622
+ **popen_kwargs: Any,
623
+ ) -> Popen[bytes]: ...
624
+
625
+ def popen(
626
+ self,
627
+ subcommand_args: list[str],
628
+ *popen_args: Any,
629
+ text: Literal[True, False] = False,
630
+ **popen_kwargs: Any,
631
+ ) -> Popen[str] | Popen[bytes]:
632
+ """
633
+ Open unchecked git subcommand communicable process, using ``subprocess.Popen``.
634
+
635
+ All the arguments are congruent to ``subprocess.Popen`` and mostly passes as-is.
636
+
637
+ :param subcommand_args: the full subcommand argument list.
638
+ :param popen_args: additional subprocess positionals.
639
+ :param text: ``_input`` and returns both are str if this value is ``True``. Else, bytes are considered.
640
+ :param popen_kwargs: additional subprocess keyword arguments.
641
+
642
+ :return: ``Popen`` capturing all the required stdout, stderr etc and streaming stdin.
643
+ """
644
+ main_cmd_args = self.git_main_cmd_args()
645
+ envs_vars = self.git_envs(popen_kwargs.pop("env", None))
646
+ cwd = popen_kwargs.pop("cwd", self.root_dir)
647
+ stdin = popen_kwargs.pop("stdin", PIPE)
648
+ stdout = popen_kwargs.pop("stdout", PIPE)
649
+ stderr = popen_kwargs.pop("stderr", PIPE)
650
+ bufsize = popen_kwargs.pop("bufsize", 0)
651
+ # Popen the git command
652
+ result = self.git.runner.popen_git_command(
653
+ main_cmd_args,
654
+ subcommand_args,
655
+ *popen_args,
656
+ text=text,
657
+ env=envs_vars,
658
+ cwd=cwd,
659
+ stdin=stdin,
660
+ stdout=stdout,
661
+ stderr=stderr,
662
+ bufsize=bufsize,
663
+ **popen_kwargs,
664
+ )
665
+ return result
666
+
667
+ def make_cmd(self, subcommand_args: list[str]) -> list[str]:
668
+ """
669
+ Make full runnable command for execution from the supplied ``subcommand_args``.
670
+
671
+ As knowledge of the git program and the main command is encapsulated within this ``UncheckedSubcmd`` thus,
672
+ this is a convenience method for any external entities that want to run commands in their own subprocess.
673
+
674
+ :param subcommand_args: arguments for subcommand.
675
+ :returns: a fully made and runnable command for some external ``subprocess`` call.
676
+ """
677
+ return self.git.runner.make_cmd(self.git.build_main_cmd_args(), subcommand_args)
678
+
679
+ def git_main_cmd_args(self) -> list[str]:
680
+ """
681
+ Get CLI args for git main cli command.
682
+
683
+ For example, ``--no-pager --no-advice`` is the git main command in ``git --no-pager --no-advice log master -1``.
684
+
685
+ :return: CLI args for git main cli command.
686
+ """
687
+ return self.git.build_main_cmd_args()
688
+
689
+ def git_envs(
690
+ self, extra_git_envs: dict[str, str] | None = None
691
+ ) -> dict[str, str] | None:
692
+ """
693
+ Get Git environment variables from the merged ``GitEnvVars`` object.
694
+
695
+ Skips values that are ``Unset`` or ``None``-like using ``not_none_not_unset()``.
696
+ Converts ``Path`` and ``datetime`` instances to ``str``.
697
+
698
+ :param extra_git_envs: extraneous git envs supplied by the caller. These will be merged into the resultant
699
+ git envs and then returned.
700
+ :return: A cleaned and normalized GitEnvVars dict suitable for use in subprocesses.
701
+ """
702
+ env_vars = self.git.build_git_envs()
703
+ if extra_git_envs and env_vars is not None:
704
+ env_vars.update(extra_git_envs)
705
+ return env_vars
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  import pathlib
11
11
  from abc import abstractmethod
12
- from subprocess import CompletedProcess
12
+ from subprocess import CompletedProcess, Popen
13
13
  from typing import Protocol, overload, Any, Literal
14
14
 
15
15
 
@@ -64,6 +64,39 @@ class GitCommandRunner(Protocol):
64
64
  **subprocess_run_kwargs: Any,
65
65
  ) -> CompletedProcess[bytes]: ...
66
66
 
67
+ @overload
68
+ @abstractmethod
69
+ def popen_git_command(
70
+ self,
71
+ main_cmd_args: list[str],
72
+ subcommand_args: list[str],
73
+ *popen_run_args: Any,
74
+ text: Literal[False],
75
+ **popen_run_kwargs: Any,
76
+ ) -> Popen[bytes]: ...
77
+
78
+ @overload
79
+ @abstractmethod
80
+ def popen_git_command(
81
+ self,
82
+ main_cmd_args: list[str],
83
+ subcommand_args: list[str],
84
+ *popen_run_args: Any,
85
+ text: Literal[True],
86
+ **popen_run_kwargs: Any,
87
+ ) -> Popen[str]: ...
88
+
89
+ @abstractmethod
90
+ def make_cmd(self, main_cmd_args: list[str], sub_cmd_args: list[str]) -> list[str]:
91
+ """
92
+ Make command for execution for use in an external subprocess.
93
+
94
+ :param main_cmd_args: arguments for the main command.
95
+ :param sub_cmd_args: arguments for subcommand.
96
+ :returns: a fully made and runnable command for some external ``subprocess`` call.
97
+ """
98
+ ...
99
+
67
100
  @property
68
101
  @abstractmethod
69
102
  def git_prog(self) -> str | pathlib.Path:
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  import pathlib
11
11
  import subprocess
12
- from subprocess import CompletedProcess
12
+ from subprocess import CompletedProcess, Popen
13
13
  from typing import overload, override, Any, Literal
14
14
 
15
15
  from gitbolt.subprocess.constants import GIT_CMD
@@ -86,7 +86,7 @@ class SimpleGitCR(GitCommandRunner):
86
86
  ) -> CompletedProcess[str] | CompletedProcess[bytes]:
87
87
  try:
88
88
  return subprocess.run(
89
- [str(self.git_prog), *main_cmd_args, *subcommand_args],
89
+ self.make_cmd(main_cmd_args, subcommand_args),
90
90
  *subprocess_run_args,
91
91
  input=_input,
92
92
  text=text,
@@ -97,6 +97,53 @@ class SimpleGitCR(GitCommandRunner):
97
97
  e.stderr, called_process_error=e, exit_code=e.returncode
98
98
  ) from e
99
99
 
100
+ @overload
101
+ @override
102
+ def popen_git_command(
103
+ self,
104
+ main_cmd_args: list[str],
105
+ subcommand_args: list[str],
106
+ *popen_run_args: Any,
107
+ text: Literal[False],
108
+ **popen_run_kwargs: Any,
109
+ ) -> Popen[bytes]: ...
110
+
111
+ @overload
112
+ @override
113
+ def popen_git_command(
114
+ self,
115
+ main_cmd_args: list[str],
116
+ subcommand_args: list[str],
117
+ *popen_run_args: Any,
118
+ text: Literal[True],
119
+ **popen_run_kwargs: Any,
120
+ ) -> Popen[str]: ...
121
+
122
+ @override
123
+ def popen_git_command(
124
+ self,
125
+ main_cmd_args: list[str],
126
+ subcommand_args: list[str],
127
+ *popen_run_args: Any,
128
+ text: Literal[True, False],
129
+ **popen_run_kwargs: Any,
130
+ ) -> Popen[str] | Popen[bytes]:
131
+ try:
132
+ return subprocess.Popen(
133
+ self.make_cmd(main_cmd_args, subcommand_args),
134
+ *popen_run_args,
135
+ text=text,
136
+ **popen_run_kwargs,
137
+ )
138
+ except subprocess.CalledProcessError as e:
139
+ raise GitCmdException(
140
+ e.stderr, called_process_error=e, exit_code=e.returncode
141
+ ) from e
142
+
143
+ @override
144
+ def make_cmd(self, main_cmd_args: list[str], sub_cmd_args: list[str]) -> list[str]:
145
+ return [str(self.git_prog), *main_cmd_args, *sub_cmd_args]
146
+
100
147
  @override
101
148
  @property
102
149
  def git_prog(self) -> str | pathlib.Path:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitbolt
3
- Version: 0.0.0.dev15
3
+ Version: 0.0.0.dev16
4
4
  Summary: Fast, flexible and type-safe Git commands in Python.
5
5
  Author-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
6
6
  Maintainer-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
@@ -327,10 +327,12 @@ no_advice_reset_git = overridden_git.git_opts_override(no_advice=False)
327
327
 
328
328
  At last, run unchecked commands in git.
329
329
 
330
- Introduced in `0.0.0dev4` to
330
+ Introduced in `0.0.0.dev4` to
331
331
  - experiment.
332
332
  - have consistent interfaced commands run until all subcommands are provided by the library.
333
333
 
334
+ #### 🖥️ Run one process per command
335
+
334
336
  ```python
335
337
  import gitbolt
336
338
 
@@ -340,9 +342,33 @@ git.subcmd_unchecked.run(['--version']) # run the version option for git.
340
342
  git.subcmd_unchecked.run(['version']) # run the version subcommand.
341
343
  ```
342
344
 
345
+ #### 🖥️ Run one long-running process and communicate with it
346
+
347
+ Introduced in `0.0.0.dev16` to:
348
+ - Make communicable processes using `subprocess.Popen`.
349
+
350
+ Get a long-running process and communicate with it for batching and faster operations.
351
+
352
+ ```python
353
+ import gitbolt
354
+ import sys
355
+
356
+ git = gitbolt.get_git_command()
357
+ with git.subcmd_unchecked.popen(["cat-file", "--batch-command"]) as cf:
358
+ cf.stdin.write(b"contents HEAD\n")
359
+ cf.stdin.flush()
360
+ header = cf.stdout.readline().strip()
361
+ print(f"HEADER: {header}", file=sys.stderr)
362
+ obj, typ, size = header.split()
363
+ print(cf.stdout.read(int(size)))
364
+ cf.stdout.readline()
365
+ ```
366
+
367
+ Error handling and I/O management is left to the client/caller.
368
+
343
369
  #### 💻 Run commands received from CLI
344
370
 
345
- Introduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
371
+ Introduced in `0.0.0.dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
346
372
 
347
373
  While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
348
374
  would be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before
File without changes
File without changes