Skip to content

Adds files.getInfo / files.get_info methods to retrieve information about directory/files #724

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
6 changes: 6 additions & 0 deletions .changeset/proud-ants-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@e2b/python-sdk': patch
'e2b': patch
---

added getInfo/get_info method for file information
77 changes: 77 additions & 0 deletions apps/web/src/app/(docs)/docs/filesystem/info/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Get information about a file or directory

You can get information about a file or directory using the `files.getInfo()` / `files.get_info()` methods. Information such as file name, type, and path is returned.

### Getting information about a file

<CodeGroup>
```js
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

// Create a new file
await sandbox.files.write('test_file.txt', 'Hello, world!')

// Get information about the file
const info = await sandbox.files.getInfo('test_file.txt')

console.log(info)
// {
// name: 'test_file.txt',
// type: 'file',
// path: '/home/user/test_file.txt'
// }
```
```python
from e2b_code_interpreter import Sandbox

sandbox = Sandbox()

# Create a new file
sandbox.files.write('test_file', 'Hello, world!')

# Get information about the file
info = sandbox.files.get_info('test_file')

print(info)
# EntryInfo(name='test_file.txt', type=<FileType.FILE: 'file'>, path='/home/user/test_file.txt')
```
</CodeGroup>

### Getting information about a directory

<CodeGroup>
```js
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

// Create a new directory
await sandbox.files.makeDir('test_dir')

// Get information about the directory
const info = await sandbox.files.getInfo('test_dir')

console.log(info)
// {
// name: 'test_dir',
// type: 'dir',
// path: '/home/user/test_dir'
// }
```
```python
from e2b_code_interpreter import Sandbox

sandbox = Sandbox()

# Create a new directory
sandbox.files.make_dir('test_dir')

# Get information about the directory
info = sandbox.files.get_info('test_dir')

print(info)
# EntryInfo(name='test_dir', type=<FileType.DIR: 'dir'>, path='/home/user/test_dir')
```
</CodeGroup>
12 changes: 11 additions & 1 deletion apps/web/src/components/Navigation/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Braces, CheckCircle, Home, KeyRound, MessagesSquare } from 'lucide-react'
import {
Braces,
CheckCircle,
Home,
KeyRound,
MessagesSquare,
} from 'lucide-react'
import sdkRefRoutesJson from './sdkRefRoutes.json'

enum Tag {
Expand Down Expand Up @@ -353,6 +359,10 @@ export const docRoutes: NavGroup[] = [
title: 'Read & write',
href: '/docs/filesystem/read-write',
},
{
title: 'Get info about a file or directory',
href: '/docs/filesystem/info',
},
{
title: 'Watch directory for changes',
href: '/docs/filesystem/watch',
Expand Down
28 changes: 28 additions & 0 deletions packages/js-sdk/src/sandbox/filesystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,34 @@ export class Filesystem {
}
}

/**
* Get information about a file or directory.
*
* @param path path to a file or directory.
* @param opts connection options.
*
* @returns information about the file or directory like name, type, and path.
*/
async getInfo(
path: string,
opts?: FilesystemRequestOpts
): Promise<EntryInfo> {
try {
const res = await this.rpc.stat(
{ path },
{ headers: authenticationHeader(opts?.user) }
)

return {
name: res.entry!.name,
type: mapFileType(res.entry!.type),
path: res.entry!.path,
}
} catch (err) {
throw handleRpcError(err)
}
}

/**
* Start watching a directory for filesystem events.
*
Expand Down
43 changes: 43 additions & 0 deletions packages/js-sdk/tests/sandbox/files/info.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { assert } from 'vitest'
import { expect } from 'vitest'
import { NotFoundError } from '../../../src/errors.js'

import { sandboxTest } from '../../setup.js'

sandboxTest('get info of a file', async ({ sandbox }) => {
const filename = 'test_file.txt'

await sandbox.files.write(filename, 'test')
const info = await sandbox.files.getInfo(filename)
const { stdout: currentPath } = await sandbox.commands.run('pwd')

assert.equal(info.name, filename)
assert.equal(info.type, 'file')
assert.equal(info.path, currentPath.trim() + '/' + filename)
})

sandboxTest('get info of a file that does not exist', async ({ sandbox }) => {
const filename = 'test_does_not_exist.txt'
await expect(sandbox.files.getInfo(filename)).rejects.toThrow(NotFoundError)
})

sandboxTest('get info of a directory', async ({ sandbox }) => {
const dirname = 'test_dir'

await sandbox.files.makeDir(dirname)
const info = await sandbox.files.getInfo(dirname)
const { stdout: currentPath } = await sandbox.commands.run('pwd')

assert.equal(info.name, dirname)
assert.equal(info.type, 'dir')
assert.equal(info.path, currentPath.trim() + '/' + dirname)
})

sandboxTest(
'get info of a directory that does not exist',
async ({ sandbox }) => {
const dirname = 'test_does_not_exist_dir'

await expect(sandbox.files.getInfo(dirname)).rejects.toThrow(NotFoundError)
}
)
32 changes: 32 additions & 0 deletions packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,38 @@ async def exists(
return False
raise handle_rpc_exception(e)

async def get_info(
self,
path: str,
user: Username = "user",
request_timeout: Optional[float] = None,
) -> EntryInfo:
"""
Get information about a file or directory.

:param path: Path to a file or a directory
:param user: Run the operation as this user
:param request_timeout: Timeout for the request in **seconds**

:return: Information about the file or directory like name, type, and path
"""
try:
r = await self._rpc.astat(
filesystem_pb2.StatRequest(path=path),
request_timeout=self._connection_config.get_request_timeout(
request_timeout
),
headers=authentication_header(user),
)

return EntryInfo(
name=r.entry.name,
type=map_file_type(r.entry.type),
path=r.entry.path,
)
except Exception as e:
raise handle_rpc_exception(e)

async def remove(
self,
path: str,
Expand Down
32 changes: 32 additions & 0 deletions packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,38 @@ def exists(
return False
raise handle_rpc_exception(e)

def get_info(
self,
path: str,
user: Username = "user",
request_timeout: Optional[float] = None,
) -> EntryInfo:
"""
Get information about a file or directory.

:param path: Path to a file or a directory
:param user: Run the operation as this user
:param request_timeout: Timeout for the request in **seconds**

:return: Information about the file or directory like name, type, and path
"""
try:
r = self._rpc.stat(
filesystem_pb2.StatRequest(path=path),
request_timeout=self._connection_config.get_request_timeout(
request_timeout
),
headers=authentication_header(user),
)

return EntryInfo(
name=r.entry.name,
type=map_file_type(r.entry.type),
path=r.entry.path,
)
except Exception as e:
raise handle_rpc_exception(e)

def remove(
self,
path: str,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pytest
from e2b.exceptions import NotFoundException
from e2b import AsyncSandbox, FileType

@pytest.mark.asyncio
async def test_get_info_of_file(async_sandbox: AsyncSandbox):
filename = "test_file.txt"

await async_sandbox.files.write(filename, "test")
info = await async_sandbox.files.get_info(filename)
current_path = await async_sandbox.commands.run("pwd")

assert info.name == filename
assert info.type == FileType.FILE
assert info.path == f"{current_path.stdout.strip()}/{filename}"

@pytest.mark.asyncio
async def test_get_info_of_nonexistent_file(async_sandbox: AsyncSandbox):
filename = "test_does_not_exist.txt"

with pytest.raises(NotFoundException) as exc_info:
await async_sandbox.files.get_info(filename)

@pytest.mark.asyncio
async def test_get_info_of_directory(async_sandbox: AsyncSandbox):
dirname = "test_dir"

await async_sandbox.files.make_dir(dirname)
info = await async_sandbox.files.get_info(dirname)
current_path = await async_sandbox.commands.run("pwd")

assert info.name == dirname
assert info.type == FileType.DIR
assert info.path == f"{current_path.stdout.strip()}/{dirname}"

@pytest.mark.asyncio
async def test_get_info_of_nonexistent_directory(async_sandbox: AsyncSandbox):
dirname = "test_does_not_exist_dir"

with pytest.raises(NotFoundException) as exc_info:
await async_sandbox.files.get_info(dirname)
37 changes: 37 additions & 0 deletions packages/python-sdk/tests/sync/sandbox_sync/files/test_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from e2b.exceptions import NotFoundException
from e2b import Sandbox, FileType

def test_get_info_of_file(sandbox: Sandbox):
filename = "test_file.txt"

sandbox.files.write(filename, "test")
info = sandbox.files.get_info(filename)
current_path = sandbox.commands.run("pwd")

assert info.name == filename
assert info.type == FileType.FILE
assert info.path == f"{current_path.stdout.strip()}/{filename}"

def test_get_info_of_nonexistent_file(sandbox: Sandbox):
filename = "test_does_not_exist.txt"

with pytest.raises(NotFoundException) as exc_info:
sandbox.files.get_info(filename)

def test_get_info_of_directory(sandbox: Sandbox):
dirname = "test_dir"

sandbox.files.make_dir(dirname)
info = sandbox.files.get_info(dirname)
current_path = sandbox.commands.run("pwd")

assert info.name == dirname
assert info.type == FileType.DIR
assert info.path == f"{current_path.stdout.strip()}/{dirname}"

def test_get_info_of_nonexistent_directory(sandbox: Sandbox):
dirname = "test_does_not_exist_dir"

with pytest.raises(NotFoundException) as exc_info:
sandbox.files.get_info(dirname)