Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions packages/python-sdk/e2b/sandbox_async/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,108 @@ async def commit(
args, path, envs, user, cwd, timeout, request_timeout
)

async def reset(
self,
path: str,
mode: Optional[str] = None,
target: Optional[str] = None,
paths: Optional[List[str]] = None,
envs: Optional[Dict[str, str]] = None,
user: Optional[str] = None,
cwd: Optional[str] = None,
timeout: Optional[float] = None,
request_timeout: Optional[float] = None,
):
"""
Reset the current HEAD to a specified state.

:param path: Repository path
:param mode: Reset mode (soft, mixed, hard, merge, keep)
:param target: Commit, branch, or ref to reset to (defaults to HEAD)
:param paths: Paths to reset
:param envs: Environment variables used for the command
:param user: User to run the command as
:param cwd: Working directory to run the command
:param timeout: Timeout for the command connection in **seconds**
:param request_timeout: Timeout for the request in **seconds**
:return: Command result from the command runner
"""
allowed_modes = {"soft", "mixed", "hard", "merge", "keep"}
if mode and mode not in allowed_modes:
raise InvalidArgumentException(
f"Reset mode must be one of {', '.join(sorted(allowed_modes))}."
)

args = ["reset"]
if mode:
args.append(f"--{mode}")
if target:
args.append(target)
if paths:
args.append("--")
args.extend(paths)
return await self._run_git(
args, path, envs, user, cwd, timeout, request_timeout
)

async def restore(
self,
path: str,
paths: List[str],
staged: Optional[bool] = None,
worktree: Optional[bool] = None,
source: Optional[str] = None,
envs: Optional[Dict[str, str]] = None,
user: Optional[str] = None,
cwd: Optional[str] = None,
timeout: Optional[float] = None,
request_timeout: Optional[float] = None,
):
"""
Restore working tree files or unstage changes.

:param path: Repository path
:param paths: Paths to restore (use ["."] for all)
:param staged: When True, restore the index (unstage)
:param worktree: When True, restore working tree files
:param source: Restore from the given source (commit, branch, or ref)
:param envs: Environment variables used for the command
:param user: User to run the command as
:param cwd: Working directory to run the command
:param timeout: Timeout for the command connection in **seconds**
:param request_timeout: Timeout for the request in **seconds**
:return: Command result from the command runner
"""
if not paths:
raise InvalidArgumentException("At least one path is required.")

resolved_staged = staged
resolved_worktree = worktree
if staged is None and worktree is None:
resolved_worktree = True
elif staged is True and worktree is None:
resolved_worktree = False
elif staged is None and worktree is not None:
resolved_staged = False

if resolved_staged is False and resolved_worktree is False:
raise InvalidArgumentException(
"At least one of staged or worktree must be true."
)

args = ["restore"]
if resolved_worktree:
args.append("--worktree")
if resolved_staged:
args.append("--staged")
if source:
args.extend(["--source", source])
args.append("--")
args.extend(paths)
return await self._run_git(
args, path, envs, user, cwd, timeout, request_timeout
)

async def push(
self,
path: str,
Expand Down
34 changes: 34 additions & 0 deletions packages/python-sdk/tests/shared/git/test_parity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import asyncio
import inspect

from e2b.sandbox_async.git import Git as AsyncGit
from e2b.sandbox_sync.git import Git as SyncGit


def _public_methods(cls):
return {
name: getattr(cls, name)
for name in sorted(dir(cls))
if not name.startswith("_") and callable(getattr(cls, name))
Comment thread
matthewlouisbrockman marked this conversation as resolved.
}


def test_identical_method_signatures():
sync = _public_methods(SyncGit)
async_ = _public_methods(AsyncGit)

assert set(sync) == set(async_), (
f"missing from async: {set(sync) - set(async_)}, "
f"missing from sync: {set(async_) - set(sync)}"
)

for name in sync:
assert inspect.signature(sync[name]) == inspect.signature(async_[name]), (
f"{name}: sync{inspect.signature(sync[name])} "
f"!= async{inspect.signature(async_[name])}"
)


def test_async_methods_are_coroutines():
for name, method in _public_methods(AsyncGit).items():
assert asyncio.iscoroutinefunction(method), f"AsyncGit.{name} is not async"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Getting DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead down to use the inspect function instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for flagging this! I wasn’t available at the time, but I see you’ve already resolved it - turns out my local dev env was using an older Python binary.

Loading