noteable-origami


Namenoteable-origami JSON
Version 2.0.0 PyPI version JSON
download
home_pagehttps://github.com/noteable-io/origami
SummaryThe Noteable API interface
upload_time2023-11-06 20:05:00
maintainerMatt Seal
docs_urlNone
authorMatt Seal
requires_python>=3.8,<4.0
licenseBSD-3-Clause
keywords notebook api noteable
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Origami

<p align="center">
<img src="docs/papersnake.svg" width="250px" />
<br />
Launch, edit, and share Jupyter notebooks <i>in automation</i>.
</p>

<p align="center">
<a href="https://github.com/noteable-io/origami/actions/workflows/ci.yaml">
    <img src="https://github.com/noteable-io/origami/actions/workflows/ci.yaml/badge.svg" alt="CI" />
</a>
<a href="https://codecov.io/gh/noteable-io/origami" > 
 <img src="https://codecov.io/gh/noteable-io/origami/branch/main/graph/badge.svg" alt="codecov code coverage"/> 
 </a>
<img alt="PyPI - License" src="https://img.shields.io/pypi/l/noteable-origami" />
<img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/noteable-origami" />
<img alt="PyPI" src="https://img.shields.io/pypi/v/noteable-origami">
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>

---

[Install](#installation) | [Getting Started](#getting-started) | [Documentation](https://noteable-origami.readthedocs.io) | [License](./LICENSE) | [Code of Conduct](./CODE_OF_CONDUCT.md) | [Contributing](./CONTRIBUTING.md)

<!-- --8<-- [start:intro] -->

## Intro to Origami

Origami is a 🐍 Python library for talking to [Noteable notebooks](https://noteable.io/). This is the official way to access the full breadth of API calls and access patterns in async Python for rich programmatic access to notebooks. You can use [Noteable for free](https://app.noteable.io) with a quick signup.

<!-- --8<-- [end:intro] -->

<!-- --8<-- [start:requirements] -->

## Requirements

Python 3.8+

<!-- --8<-- [end:requirements] -->

<!-- --8<-- [start:install] -->

## Installation

For stable release:

```bash
pip install noteable-origami
```

```bash
poetry add noteable-origami
```

For alpha pre-release:

```bash
pip install noteable-origami --pre
```

<!-- --8<-- [end:install] -->

## Getting Started

> **Note**
> Developer note: For pre-1.0 release information, see the [pre-1.0 README](https://github.com/noteable-io/origami/blob/release/0.0.35/README.md)

### API Tokens
<!-- --8<-- [start:api-tokens] -->
The Noteable API requires an authentication token. You can manage tokens at the Noteable user settings page.

1. Log in to [Noteable](https://app.noteable.io) (sign up is free).
2. In the User Settings tab, navigate to `API Tokens` and generate a new token.
![](./screenshots/user_settings__api_tokens.png)
3. Copy the generated token to the clipboard and save in a secure location, to be read into your Python environment later.
![](./screenshots/user_settings__api_tokens2.png)

The token can be passed directly in to `APIClient` on initialization, or set it as env var `NOTEABLE_TOKEN`.

### Usage
<!-- --8<-- [end:api-tokens] -->

The example below will guide you through the basics of creating a notebook, adding content, executing code, and seeing the output. For more examples, see our [Use Cases](../usage) section.

### Setting up the `APIClient`
<!-- --8<-- [start:api-client] -->
Using the API token you created previously, load it into your notebook environment so it can be passed into the `APIClient` directly. (If you're in [Noteable](https://app.noteable.io), you can create a [Secret](https://docs.noteable.io/product-docs/collaborate/access-and-visibility/secrets-permissions) that can be read in as an environment variable.)

```python
import os
from origami.clients.api import APIClient

# if we have the `NOTEABLE_TOKEN` environment variable set,
# we don't need to pass it in to the APIClient directly
api_client = APIClient()
```
*The `APIClient` is what we'll use to make HTTP requests to Noteable's REST API.*
<!-- --8<-- [end:api-client] -->

### Checking your user information
<!-- --8<-- [start:user-info] -->
```python
user = await api_client.user_info()
user
```
``` {.python .no-copy }
User(
    id=UUID('f1a2b3c4-5678-4d90-ef01-23456789abcd'),
    created_at=datetime.datetime(2023, 1, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
    updated_at=datetime.datetime(2023, 1, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
    deleted_at=None,
    handle='ori.gami',
    email='origami@noteable.io',
    first_name='Ori',
    last_name='Gami',
    origamist_default_project_id=UUID('a1b2c3d4-e5f6-4a7b-8123-abcdef123456'),
    principal_sub='pat:0a1b2c3d4e5f6g7h8i9j10k11l',
    auth_type='pat:0a1b2c3d4e5f6g7h8i9j10k11l'
)
```
(The information returned should match your user account information associated with the previously-generated API token.)
<!-- --8<-- [end:user-info] -->

### Creating a new Notebook

> **Note**
> For this example, we're using the `origamist_default_project_id`, which is the default project designed to be used by the ChatGPT plugin. Feel free to replace it with projects you have access to in [Noteable](https://app.noteable.io/)!

<!-- --8<-- [start:create-notebook] -->
Provide a file `path` as well as a `project_id` (UUID) where the Notebook will exist.
```python
project_id = user.origamist_default_project_id

file = await api_client.create_notebook(
    project_id=project_id,
    path="Origami Demo.ipynb"
)
file
```
``` {.python .no-copy }
File(
    id=UUID('bcd12345-6789-4abc-d012-3456abcdef90'),
    created_at=datetime.datetime(2023, 2, 2, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
    updated_at=datetime.datetime(2023, 2, 2, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),
    deleted_at=None,
    filename='Origami Demo.ipynb',
    path=PosixPath('Origami Demo.ipynb'),
    project_id=UUID('a1b2c3d4-e5f6-4a7b-8123-abcdef123456'),
    space_id=UUID('7890ab12-3412-4cde-8901-2345abcdef67'),
    size=0,
    mimetype=None,
    type='notebook',
    current_version_id=None,
    presigned_download_url=None,
    url='https://app.noteable.io/f/abc12312-3412-4abc-8123-abc12312abc1/Origami Demo.ipynb'
)
```
<!-- --8<-- [end:create-notebook] -->

### Launching a Kernel
<!-- --8<-- [start:launch-kernel] -->
At a minimum, the `file_id` from the Notebook is required. Additionally, you can specify:

+ `kernel_name` (default `python3`, see more about [available kernels](https://docs.noteable.io/product-docs/work-with-notebooks/manage-kernels/noteable-provided-kernels))
+ `hardware_size` (default `small`, see more about [hardware options](https://docs.noteable.io/product-docs/work-with-notebooks/manage-hardware)).

```python
kernel_session = await api_client.launch_kernel(file_id=file.id)
kernel_session
```
```{.python .no-copy}
KernelSession(
    id=UUID('e1f2a345-6789-4b01-cdef-1234567890ab'),
    kernel=KernelDetails(
        name='python3',
        last_activity=datetime.datetime(2023, 2, 2, 1, 0, 0, 0, tzinfo=datetime.timezone.utc),
        execution_state='idle'
    )
)
```
<!-- --8<-- [end:launch-kernel] -->

### Adding Cells
<!-- --8<-- [start:connect-rtu] -->
Content updates and code execution is handled through the Noteable Real-Time Update (RTU) websocket connection.
```python
realtime_notebook = await api_client.connect_realtime(file)
```
<!-- --8<-- [end:connect-rtu] -->

> **Warning**
> You may see messages like `Received un-modeled RTU message msg.channel= ...`. This is expected as we update the Noteable backend services' messaging.

<!-- --8<-- [start:add-cells] -->
Once the RTU client is connected, we can begin adding cells, executing code, and more! First, let's add a code cell with a basic Python `print` statement.
```python
from origami.models.notebook import CodeCell

cell = CodeCell(source="print('Hello World')")
await realtime_notebook.add_cell(cell=cell)
```
(You can also pass code source directly into `.add_cell(source='CODE HERE')` as a shortcut.)
<!-- --8<-- [end:add-cells] -->

### Running a Code Cell
<!-- --8<-- [start:run-code-cell] -->
The returned value is a dictionary of `asyncio.Future`s. Awaiting those futures will block until the cells have completed execution.
The return value of the Futures is the up-to-date cell. If there's output, an output collection id will be set on the cell metadata.
```python
import asyncio

queued_execution = await realtime_notebook.queue_execution(cell.id)
cells = await asyncio.gather(*queued_execution)
cell = cells[0]
cell
```
```{.python .no-copy}
CodeCell(
    id='2345ab6c-de78-4901-bcde-f1234567890a',
    source="print('Hello World')",
    metadata={
        'noteable': {'output_collection_id': UUID('d1234e5f-6789-4a0b-c123-4567890abcdef')},
        'ExecuteTime': {
            'start_time': '2023-02-02T01:00:00.000000+00:00',
            'end_time': '2023-02-02T01:00:00.050000+00:00'
        }
    },
    cell_type='code',
    execution_count=None,
    outputs=[]
)
```
<!-- --8<-- [end:run-code-cell] -->

### Getting Cell Output
<!-- --8<-- [start:get-cell-output] -->
We can call the `.output_collection_id` property on cells directly, rather than having to parse the cell metadata.
```python
output_collection = await api_client.get_output_collection(cell.output_collection_id)
output_collection
```
```{.python .no-copy}
KernelOutputCollection(
    id=UUID('d1234e5f-6789-4a0b-c123-4567890abcdef'),
    created_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),
    updated_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),
    deleted_at=None,
    cell_id='2345ab6c-de78-4901-bcde-f1234567890a',
    widget_model_id=None,
    file_id=UUID('bcd12345-6789-4abc-d012-3456abcdef90'),
    outputs=[
        KernelOutput(
            id=UUID('abcdef90-1234-4a56-7890-abcdef123456'),
            created_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),
            updated_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),
            deleted_at=None,
            type='stream',
            display_id=None,
            available_mimetypes=['text/plain'],
            content_metadata=KernelOutputContent(raw='{"name":"stdout"}', url=None, mimetype='application/json'),
            content=KernelOutputContent(raw='Hello World\n', url=None, mimetype='text/plain'),
            content_for_llm=KernelOutputContent(raw='Hello World\n', url=None, mimetype='text/plain'),
            parent_collection_id=UUID('d1234e5f-6789-4a0b-c123-4567890abcdef')
        )
    ]
)
```
<!-- --8<-- [end:get-cell-output] -->

## CLI

Origami has a small CLI for fetching the content of a Notebook, and tailing a Notebook to see all RTU messages being emitted on the relevant RTU channels.

```
pip install noteable-origami[cli]
poetry install -E cli
```

1. Fetch the content of a Notebook and write to file: `origami fetch <file-id> > notebook.ipynb`
2. Tail a Notebook, useful when debugging RTU messages: `origami tail <file-id>`

## Dev ENV settings

- Use `NOTEABLE_API_URL` to point to non-production clusters, such as `http://localhost:8001/api` for local Gate development
- E2E tests will use `TEST_SPACE_ID`, `TEST_PROJECT_ID`, and `TEST_USER_ID` env vars when running, useful in CI

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md).

---

<p align="center">Open sourced with ❤️ by <a href="https://noteable.io">Noteable</a> for the community.</p>

<img href="https://pages.noteable.io/private-beta-access" src="https://assets.noteable.io/github/2022-07-29/noteable.png" alt="Boost Data Collaboration with Notebooks">

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/noteable-io/origami",
    "name": "noteable-origami",
    "maintainer": "Matt Seal",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "matt@noteable.io",
    "keywords": "notebook,api,noteable",
    "author": "Matt Seal",
    "author_email": "matt@noteable.io",
    "download_url": "https://files.pythonhosted.org/packages/d7/9a/42faa16f403551761e596e2c9c95fb41a3da45c161c5ca0181d9afced824/noteable_origami-2.0.0.tar.gz",
    "platform": null,
    "description": "# Origami\n\n<p align=\"center\">\n<img src=\"docs/papersnake.svg\" width=\"250px\" />\n<br />\nLaunch, edit, and share Jupyter notebooks <i>in automation</i>.\n</p>\n\n<p align=\"center\">\n<a href=\"https://github.com/noteable-io/origami/actions/workflows/ci.yaml\">\n    <img src=\"https://github.com/noteable-io/origami/actions/workflows/ci.yaml/badge.svg\" alt=\"CI\" />\n</a>\n<a href=\"https://codecov.io/gh/noteable-io/origami\" > \n <img src=\"https://codecov.io/gh/noteable-io/origami/branch/main/graph/badge.svg\" alt=\"codecov code coverage\"/> \n </a>\n<img alt=\"PyPI - License\" src=\"https://img.shields.io/pypi/l/noteable-origami\" />\n<img alt=\"PyPI - Python Version\" src=\"https://img.shields.io/pypi/pyversions/noteable-origami\" />\n<img alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/noteable-origami\">\n<a href=\"https://github.com/psf/black\"><img alt=\"Code style: black\" src=\"https://img.shields.io/badge/code%20style-black-000000.svg\"></a>\n</p>\n\n---\n\n[Install](#installation) | [Getting Started](#getting-started) | [Documentation](https://noteable-origami.readthedocs.io) | [License](./LICENSE) | [Code of Conduct](./CODE_OF_CONDUCT.md) | [Contributing](./CONTRIBUTING.md)\n\n<!-- --8<-- [start:intro] -->\n\n## Intro to Origami\n\nOrigami is a \ud83d\udc0d Python library for talking to [Noteable notebooks](https://noteable.io/). This is the official way to access the full breadth of API calls and access patterns in async Python for rich programmatic access to notebooks. You can use [Noteable for free](https://app.noteable.io) with a quick signup.\n\n<!-- --8<-- [end:intro] -->\n\n<!-- --8<-- [start:requirements] -->\n\n## Requirements\n\nPython 3.8+\n\n<!-- --8<-- [end:requirements] -->\n\n<!-- --8<-- [start:install] -->\n\n## Installation\n\nFor stable release:\n\n```bash\npip install noteable-origami\n```\n\n```bash\npoetry add noteable-origami\n```\n\nFor alpha pre-release:\n\n```bash\npip install noteable-origami --pre\n```\n\n<!-- --8<-- [end:install] -->\n\n## Getting Started\n\n> **Note**\n> Developer note: For pre-1.0 release information, see the [pre-1.0 README](https://github.com/noteable-io/origami/blob/release/0.0.35/README.md)\n\n### API Tokens\n<!-- --8<-- [start:api-tokens] -->\nThe Noteable API requires an authentication token. You can manage tokens at the Noteable user settings page.\n\n1. Log in to [Noteable](https://app.noteable.io) (sign up is free).\n2. In the User Settings tab, navigate to `API Tokens` and generate a new token.\n![](./screenshots/user_settings__api_tokens.png)\n3. Copy the generated token to the clipboard and save in a secure location, to be read into your Python environment later.\n![](./screenshots/user_settings__api_tokens2.png)\n\nThe token can be passed directly in to `APIClient` on initialization, or set it as env var `NOTEABLE_TOKEN`.\n\n### Usage\n<!-- --8<-- [end:api-tokens] -->\n\nThe example below will guide you through the basics of creating a notebook, adding content, executing code, and seeing the output. For more examples, see our [Use Cases](../usage) section.\n\n### Setting up the `APIClient`\n<!-- --8<-- [start:api-client] -->\nUsing the API token you created previously, load it into your notebook environment so it can be passed into the `APIClient` directly. (If you're in [Noteable](https://app.noteable.io), you can create a [Secret](https://docs.noteable.io/product-docs/collaborate/access-and-visibility/secrets-permissions) that can be read in as an environment variable.)\n\n```python\nimport os\nfrom origami.clients.api import APIClient\n\n# if we have the `NOTEABLE_TOKEN` environment variable set,\n# we don't need to pass it in to the APIClient directly\napi_client = APIClient()\n```\n*The `APIClient` is what we'll use to make HTTP requests to Noteable's REST API.*\n<!-- --8<-- [end:api-client] -->\n\n### Checking your user information\n<!-- --8<-- [start:user-info] -->\n```python\nuser = await api_client.user_info()\nuser\n```\n``` {.python .no-copy }\nUser(\n    id=UUID('f1a2b3c4-5678-4d90-ef01-23456789abcd'),\n    created_at=datetime.datetime(2023, 1, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),\n    updated_at=datetime.datetime(2023, 1, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),\n    deleted_at=None,\n    handle='ori.gami',\n    email='origami@noteable.io',\n    first_name='Ori',\n    last_name='Gami',\n    origamist_default_project_id=UUID('a1b2c3d4-e5f6-4a7b-8123-abcdef123456'),\n    principal_sub='pat:0a1b2c3d4e5f6g7h8i9j10k11l',\n    auth_type='pat:0a1b2c3d4e5f6g7h8i9j10k11l'\n)\n```\n(The information returned should match your user account information associated with the previously-generated API token.)\n<!-- --8<-- [end:user-info] -->\n\n### Creating a new Notebook\n\n> **Note**\n> For this example, we're using the `origamist_default_project_id`, which is the default project designed to be used by the ChatGPT plugin. Feel free to replace it with projects you have access to in [Noteable](https://app.noteable.io/)!\n\n<!-- --8<-- [start:create-notebook] -->\nProvide a file `path` as well as a `project_id` (UUID) where the Notebook will exist.\n```python\nproject_id = user.origamist_default_project_id\n\nfile = await api_client.create_notebook(\n    project_id=project_id,\n    path=\"Origami Demo.ipynb\"\n)\nfile\n```\n``` {.python .no-copy }\nFile(\n    id=UUID('bcd12345-6789-4abc-d012-3456abcdef90'),\n    created_at=datetime.datetime(2023, 2, 2, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),\n    updated_at=datetime.datetime(2023, 2, 2, 0, 0, 0, 0, tzinfo=datetime.timezone.utc),\n    deleted_at=None,\n    filename='Origami Demo.ipynb',\n    path=PosixPath('Origami Demo.ipynb'),\n    project_id=UUID('a1b2c3d4-e5f6-4a7b-8123-abcdef123456'),\n    space_id=UUID('7890ab12-3412-4cde-8901-2345abcdef67'),\n    size=0,\n    mimetype=None,\n    type='notebook',\n    current_version_id=None,\n    presigned_download_url=None,\n    url='https://app.noteable.io/f/abc12312-3412-4abc-8123-abc12312abc1/Origami Demo.ipynb'\n)\n```\n<!-- --8<-- [end:create-notebook] -->\n\n### Launching a Kernel\n<!-- --8<-- [start:launch-kernel] -->\nAt a minimum, the `file_id` from the Notebook is required. Additionally, you can specify:\n\n+ `kernel_name` (default `python3`, see more about [available kernels](https://docs.noteable.io/product-docs/work-with-notebooks/manage-kernels/noteable-provided-kernels))\n+ `hardware_size` (default `small`, see more about [hardware options](https://docs.noteable.io/product-docs/work-with-notebooks/manage-hardware)).\n\n```python\nkernel_session = await api_client.launch_kernel(file_id=file.id)\nkernel_session\n```\n```{.python .no-copy}\nKernelSession(\n    id=UUID('e1f2a345-6789-4b01-cdef-1234567890ab'),\n    kernel=KernelDetails(\n        name='python3',\n        last_activity=datetime.datetime(2023, 2, 2, 1, 0, 0, 0, tzinfo=datetime.timezone.utc),\n        execution_state='idle'\n    )\n)\n```\n<!-- --8<-- [end:launch-kernel] -->\n\n### Adding Cells\n<!-- --8<-- [start:connect-rtu] -->\nContent updates and code execution is handled through the Noteable Real-Time Update (RTU) websocket connection.\n```python\nrealtime_notebook = await api_client.connect_realtime(file)\n```\n<!-- --8<-- [end:connect-rtu] -->\n\n> **Warning**\n> You may see messages like `Received un-modeled RTU message msg.channel= ...`. This is expected as we update the Noteable backend services' messaging.\n\n<!-- --8<-- [start:add-cells] -->\nOnce the RTU client is connected, we can begin adding cells, executing code, and more! First, let's add a code cell with a basic Python `print` statement.\n```python\nfrom origami.models.notebook import CodeCell\n\ncell = CodeCell(source=\"print('Hello World')\")\nawait realtime_notebook.add_cell(cell=cell)\n```\n(You can also pass code source directly into `.add_cell(source='CODE HERE')` as a shortcut.)\n<!-- --8<-- [end:add-cells] -->\n\n### Running a Code Cell\n<!-- --8<-- [start:run-code-cell] -->\nThe returned value is a dictionary of `asyncio.Future`s. Awaiting those futures will block until the cells have completed execution.\nThe return value of the Futures is the up-to-date cell. If there's output, an output collection id will be set on the cell metadata.\n```python\nimport asyncio\n\nqueued_execution = await realtime_notebook.queue_execution(cell.id)\ncells = await asyncio.gather(*queued_execution)\ncell = cells[0]\ncell\n```\n```{.python .no-copy}\nCodeCell(\n    id='2345ab6c-de78-4901-bcde-f1234567890a',\n    source=\"print('Hello World')\",\n    metadata={\n        'noteable': {'output_collection_id': UUID('d1234e5f-6789-4a0b-c123-4567890abcdef')},\n        'ExecuteTime': {\n            'start_time': '2023-02-02T01:00:00.000000+00:00',\n            'end_time': '2023-02-02T01:00:00.050000+00:00'\n        }\n    },\n    cell_type='code',\n    execution_count=None,\n    outputs=[]\n)\n```\n<!-- --8<-- [end:run-code-cell] -->\n\n### Getting Cell Output\n<!-- --8<-- [start:get-cell-output] -->\nWe can call the `.output_collection_id` property on cells directly, rather than having to parse the cell metadata.\n```python\noutput_collection = await api_client.get_output_collection(cell.output_collection_id)\noutput_collection\n```\n```{.python .no-copy}\nKernelOutputCollection(\n    id=UUID('d1234e5f-6789-4a0b-c123-4567890abcdef'),\n    created_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),\n    updated_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),\n    deleted_at=None,\n    cell_id='2345ab6c-de78-4901-bcde-f1234567890a',\n    widget_model_id=None,\n    file_id=UUID('bcd12345-6789-4abc-d012-3456abcdef90'),\n    outputs=[\n        KernelOutput(\n            id=UUID('abcdef90-1234-4a56-7890-abcdef123456'),\n            created_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),\n            updated_at=datetime.datetime(2023, 2, 2, 1, 0, 1, 000000, tzinfo=datetime.timezone.utc),\n            deleted_at=None,\n            type='stream',\n            display_id=None,\n            available_mimetypes=['text/plain'],\n            content_metadata=KernelOutputContent(raw='{\"name\":\"stdout\"}', url=None, mimetype='application/json'),\n            content=KernelOutputContent(raw='Hello World\\n', url=None, mimetype='text/plain'),\n            content_for_llm=KernelOutputContent(raw='Hello World\\n', url=None, mimetype='text/plain'),\n            parent_collection_id=UUID('d1234e5f-6789-4a0b-c123-4567890abcdef')\n        )\n    ]\n)\n```\n<!-- --8<-- [end:get-cell-output] -->\n\n## CLI\n\nOrigami has a small CLI for fetching the content of a Notebook, and tailing a Notebook to see all RTU messages being emitted on the relevant RTU channels.\n\n```\npip install noteable-origami[cli]\npoetry install -E cli\n```\n\n1. Fetch the content of a Notebook and write to file: `origami fetch <file-id> > notebook.ipynb`\n2. Tail a Notebook, useful when debugging RTU messages: `origami tail <file-id>`\n\n## Dev ENV settings\n\n- Use `NOTEABLE_API_URL` to point to non-production clusters, such as `http://localhost:8001/api` for local Gate development\n- E2E tests will use `TEST_SPACE_ID`, `TEST_PROJECT_ID`, and `TEST_USER_ID` env vars when running, useful in CI\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n---\n\n<p align=\"center\">Open sourced with \u2764\ufe0f by <a href=\"https://noteable.io\">Noteable</a> for the community.</p>\n\n<img href=\"https://pages.noteable.io/private-beta-access\" src=\"https://assets.noteable.io/github/2022-07-29/noteable.png\" alt=\"Boost Data Collaboration with Notebooks\">\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "The Noteable API interface",
    "version": "2.0.0",
    "project_urls": {
        "Homepage": "https://github.com/noteable-io/origami",
        "Repository": "https://github.com/noteable-io/origami"
    },
    "split_keywords": [
        "notebook",
        "api",
        "noteable"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f1b4cfd3a0a3a580a11e78825202d4c948e88bda897c040f34a287e96d8b035c",
                "md5": "1cb887a5305ecd9f99dacffcccf67fb0",
                "sha256": "5bee40b8cae7b1e78ac75ffec3a88d71e818c1edfb27d2ebd919712d24b3e416"
            },
            "downloads": -1,
            "filename": "noteable_origami-2.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1cb887a5305ecd9f99dacffcccf67fb0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 50408,
            "upload_time": "2023-11-06T20:04:58",
            "upload_time_iso_8601": "2023-11-06T20:04:58.393446Z",
            "url": "https://files.pythonhosted.org/packages/f1/b4/cfd3a0a3a580a11e78825202d4c948e88bda897c040f34a287e96d8b035c/noteable_origami-2.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d79a42faa16f403551761e596e2c9c95fb41a3da45c161c5ca0181d9afced824",
                "md5": "558527f3be2a20c3c7456d55c7f861a5",
                "sha256": "9d96f9c48902adbb8b633c806a73563ee461b5e1c64c9894fa00e6890c240aa8"
            },
            "downloads": -1,
            "filename": "noteable_origami-2.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "558527f3be2a20c3c7456d55c7f861a5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 43055,
            "upload_time": "2023-11-06T20:05:00",
            "upload_time_iso_8601": "2023-11-06T20:05:00.239123Z",
            "url": "https://files.pythonhosted.org/packages/d7/9a/42faa16f403551761e596e2c9c95fb41a3da45c161c5ca0181d9afced824/noteable_origami-2.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-06 20:05:00",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "noteable-io",
    "github_project": "origami",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "noteable-origami"
}
        
Elapsed time: 0.40002s