Skip to content
Open
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
30 changes: 15 additions & 15 deletions docs/developers/python/classical/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sidebar_label: Classic Style
Lets's create an Arkitekt App, as it is the connection layer between your code and the arkitet server. If you don't know what we mean by an App, check out the [App](/docs/design/terminology/app) section of the terminology page.

```python
from arkitekt import easy
from arkitekt_next import easy


app = easy("my-app-name")
Expand All @@ -28,7 +28,7 @@ setup:
pointing the app to an arkitekt instance. This is by design. Your code should not be aware of the backend it is connecting to, as this allows easy installation of your code anywhere. Arkitekt uses the fakt service to discover the backend, and will retrieve its configuration from the backend, before connecting to it, on the first call within the context (a useful feature for system admins to configure apps after deployment). Of course you can opt out of this behaviours by passing an explicity url of the arkitekt server or by changing the fakts attributes before entering the context.

```python
from arkitekt import easy
from arkitekt_next import easy
from fakts.grants.remote import AnyOtherGrantType

app = easy("my-app-name")
Expand All @@ -51,29 +51,29 @@ setup:
4. The context manager also sets some context specific variables (contextvars).
This means we can inject its dependencys within this context automatically sing the governing
app context. This allows for more functional code. For example, you can use simply call
`from_xarray` to save an xarray on the mikro instance of the governing app context, without
`from_array_like` to save an xarray on the mikro instance of the governing app context, without
explicitly passing the apps mikro server to the function. You can always opt out of this behaviour
by specifically passing the desired context to the function.

```python
from arkitekt import easy
from mikro.api.schema import from_xarray
from arkitekt_next import easy
from mikro_next.api.schema import from_array_like
import xarray as xr

app = easy("my-app-name")

with app:
image = from_xarray(xr.DataArray((100,100,1), dims=["x", "y", "z"])) # stores the xarray on the mikro instance of the governing app context
image = from_array_like(xr.DataArray((100,100,1), dims=["x", "y", "z"])) # stores the xarray on the mikro instance of the governing app context

# or

image = from_xarray(xr.DataArray((100,100,1), dims=["x", "y", "z"]), rath=app.mikro.rath) # stores the xarray on the specified mikro instance
image = from_array_like(xr.DataArray((100,100,1), dims=["x", "y", "z"]), rath=app.mikro.rath) # stores the xarray on the specified mikro instance
```

:::note
This behaviour allows for more functional and concise code but can also lead to unexpected
behaviour. For example, if you have multiple app contexts running in parallel, the
`from_xarray` function will use the app context that is currently active. This can lead to
`from_array_like` function will use the app context that is currently active. This can lead to
unexpected behaviour if you are not aware of this.
:::

Expand All @@ -86,10 +86,10 @@ setup:
sync code

```python
from arkitekt import Arkitekt
from arkitekt_next import easy
import asyncio

app = Arkitekt()
app = easy("my-app-name")

async def main():
async with app:
Expand All @@ -110,16 +110,16 @@ setup:
of the context in which your code is running.

```python
from arkitekt import easy
from mikro.api.schema import from_xarray
from arkitekt_next import easy
from mikro_next.api.schema import from_array_like

app = Arkitekt()
app = easy("my-app-name")

with app:
# do stuff with arkitekt
from_xarray(xr.DataArray((100,100,1), dims=["x", "y", "z"]), name="my-image")
from_array_like(xr.DataArray((100,100,1), dims=["x", "y", "z"]), name="my-image")

from_xarray(xr.DataArray((100,100,1), dims=["x", "y", "z"]), name="my-failed-image") # will fail
from_array_like(xr.DataArray((100,100,1), dims=["x", "y", "z"]), name="my-failed-image") # will fail
```

# Lets get started
Expand Down
16 changes: 8 additions & 8 deletions docs/developers/python/classical/read-write.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Lets start with the simplest example. Imaging you have a numpy array that you wa
Lets first look at what code we need to upload the data to Arkitekt.

```python
from arkitekt import easy
from mikro.api.schema import from_xarray
from arkitekt_next import easy
from mikro_next.api.schema import from_array_like
import xarray as xr
import numpy as np

Expand All @@ -41,7 +41,7 @@ i = np.random.rand(100,100,1)
image_data = xr.DataArray(i, dims=["x", "y", "c"])

with app:
image = from_xarray(image_data, name="Random image") # stores the xarray on the mikro instance
image = from_array_like(image_data, name="Random image") # stores the array on the mikro instance
print(image.data)
```

Expand Down Expand Up @@ -71,16 +71,16 @@ The python API heavily relies on the concept of context managers. This is a pyth
## About that line of code

```python
image = from_xarray(image_data, name="Random image")
image = from_array_like(image_data, name="Random image")
print(image.data)
```

These two lines of code is a bit more complex than the other lines of code in this tutorial. And it is important to understand a few things about what is happening here. Lets take a closer look at what is happening here, and what is happening behind the scenes.

### Functions are your friend

First lets talk about the function `from_xarray`. As you might notice its imported from the `mikro.api.schema` module, which contains a plethora of methods to interact with the Mikro data server (e.g for creating images, marking rois, commenting, subscribe to image events, ...). These functions
will provide ways of briding your local data with the data on the server. The `from_xarray` function is one of these functions. It will take an array-like structure as an argument and create an image on the server, that is then stored in the database and the object store, and return a reference to that back to you.
First lets talk about the function `from_array_like`. As you might notice it's imported from the `mikro_next.api.schema` module, which contains a plethora of methods to interact with the Mikro data server (e.g for creating images, marking rois, commenting, subscribe to image events, ...). These functions
will provide ways of bridging your local data with the data on the server. The `from_array_like` function is one of these functions. It will take any array-like structure (numpy array, xarray DataArray, etc.) as an argument and create an image on the server, stored in the database and the object store, and return a reference back to you.

### But there are steps in between

Expand All @@ -95,14 +95,14 @@ You might notice that we don't pass a reference to **where** our server is locat
While we personally love the flexibility of context managers, some prefer being more explicit about the context. If you are one of those people, you can also pass the underlying `App` mikro api client object to the `from_xarray` function as an argument. This will make the code more explicit, but also more verbose. We will use the context manager in this tutorial, but feel free to use the explicit way if you prefer that.

```python
image = from_xarray(image_data, name="Random image", rath=app.mikro.rath) # this uses the mikro service graphql client (rath) directly
image = from_array_like(image_data, name="Random image", rath=app.mikro.rath) # this uses the mikro service graphql client (rath) directly
```

2. Configuration, Authentication, Authentication

But hey, wasn't Arkitekt a secure and modular platform? How does our app now on which service to store our data? And how do we ensure that not everyone can upload data? This is where the configuration and authentication part comes in. Our app also contains a strategy of how we want to authentication our python script and ourselves against the Arkitekt server. So when we call this function for the first time, the `App` will try to establish a trust relationship with the server. Which strategy we will use greatly depends on how you would like your app to be used, and is highly custimizable. By default and suitable for most usecasses (if you use the `easy`builder ) it will now open a webbrowser for you where you will see the Arkitekt Server, ask you if you trust this app, and if you would like to (temporarilly) grant it access to your data. If you accept, the app will be granted access to the server, and will be send a token that it can use to authenticate itself against the server in the future. Importantly

1. We are calling the `from_xarray` function from the `mikro.api.schema` module. This function is a convenience function that will in turn call the apps mikro services api, with the given parameters. Lets inspect these parameters on their way to the server:
1. We are calling the `from_array_like` function from the `mikro_next.api.schema` module. This function is a convenience function that will in turn call the apps mikro services api, with the given parameters. Lets inspect these parameters on their way to the server:

### Illustration of the upload process

Expand Down
12 changes: 6 additions & 6 deletions docs/developers/python/classical/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ authentication, waiting for assignemnts from the server, etc.). This App object
adjusted to fit your exact configuration need by using different builders (more on this later).

```python
from arkitekt import easy
from arkitekt_next import easy

app = easy("your_app_name", version="your_app_version")

Expand Down Expand Up @@ -53,20 +53,20 @@ A few words about this setup:
by specifically passing the desired context to the function.

```python
from arkitekt import Arkitekt
from mikro import from_xarray
from arkitekt_next import easy
from mikro_next.api.schema import from_array_like
import xarray as xr

app = easy()

with app:
image = from_xarray(xr.DataArray((100,100,1), dims=["x", "y", "z"]), name="image name") # stores the xarray on the mikro instance of the governing app context
image = from_array_like(xr.DataArray((100,100,1), dims=["x", "y", "z"]), name="image name") # stores the array on the mikro instance of the governing app context
```

:::note
This behaviour allows for more functional and concise code but can also lead to unexpected
behaviour. For example, if you have multiple app contexts running in parallel, the
`from_xarray` function will use the app context that is currently active. You can always opt out of this behaviour
`from_array_like` function will use the app context that is currently active. You can always opt out of this behaviour
by specifically passing the desired context to the function.
:::

Expand All @@ -79,7 +79,7 @@ A few words about this setup:
sync code.

```python
from arkitekt import Arkitekt
from arkitekt_next import easy
import asyncio

app = easy()
Expand Down
8 changes: 4 additions & 4 deletions docs/developers/python/graphql.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ To get started, you will need to create a new project using the Arkitekt CLI. Yo

```bash

arkitekt init
arkitekt-next init

```

Expand All @@ -61,7 +61,7 @@ for the GraphQL API:
We can now generate a configuration file for our code generation for our project by running the following command:

```bash
arkitekt gen init mikro
arkitekt-next gen init mikro
```

It will ask you where you want to generate the module for your generated code. Leave it as the default and press enter.
Expand Down Expand Up @@ -98,7 +98,7 @@ This is a simple query that retrieves all datasets from the server. After saving

```bash

arkitekt gen compile mikro
arkitekt-next gen compile mikro

```

Expand All @@ -109,7 +109,7 @@ This should now create a directory named `api` in the same directory, that conta
To use the generated code, you will need to import the generated query and use it to interact with the GraphQL API. You can do this by running the following code:

```python
from arkitekt import easy
from arkitekt_next import easy
from api.mikro import first_query

# Create a new app
Expand Down
76 changes: 36 additions & 40 deletions docs/developers/python/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ import TabItem from "@theme/TabItem";

# Getting Started!

The easiest way to install the library is to use poetry or pip:
The easiest way to install the library is to use pip:

```python
pip install "arkitekt[all]"
```bash
pip install "arkitekt-next[all]"
```

This will install the library with all its dependencies, including the Arkitekt
CLI as well as all supporting libraries for each service.

This is the recommend way to install arkitekt, especially if you are not planning
to use arkitekt as a dependency in another project.
This is the recommended way to install arkitekt-next, especially if you are not planning
to use it as a dependency in another project.

:::info Modular Arkitekt
If you are planning to only
use arkitekt as a dependency in another project, you can install it without the
CLI and add it additional dependencies as needed.
use arkitekt-next as a dependency in another project, you can install it without the
CLI and add additional dependencies as needed.

```python
pip install arkitekt
# pip install mikro (for microscopy support)
# pip install rekuest (for registering nodes)
```bash
pip install arkitekt-next
pip install mikro-next # for microscopy image support
pip install rekuest-next # for registering nodes
```

:::
Expand All @@ -50,20 +50,18 @@ The Arkitekt API here sits in the background just like any other python library,
are in full control of the execution of your code.

```python
from arkitekt import easy
from mikro.api.schema import from_xarray
from arkitekt_next import easy
from mikro_next.api.schema import from_array_like
import numpy as np

# whatever python code

with easy("my_little_app", url="http://localhost:8000"):
with easy("my_little_app", url="http://localhost:8000"):
# do stuff with the arkitekt api
# new image
img = np.random.rand(100, 100)
image = from_xarray(img, name="my_image") # uploads image to the mikro service
image = from_array_like(img, name="my_image") # uploads image to the mikro service

# Whatever python code

```

This is a very simple example of how you can use the Arkitekt API to interact with the
Expand All @@ -76,18 +74,19 @@ To get started with the classical style, you can follow the [Classic Tutorial](/

## Plugin

App that follow the `integrated style` are more integrated into the Arkitekt ecosystem.
The Integrated style is your best choice if you want to **provide new functionality** (nodes)
and develop your own Arkitekt App. In the integrated style the Arkitekt CLI takes more control over your development process, ands streamline
the process of developing and your app publishing apps so that it can be used by other users.
Apps that follow the `plugin style` are more integrated into the Arkitekt ecosystem.
The Plugin style is your best choice if you want to **provide new functionality** (nodes)
and develop your own Arkitekt App. In the plugin style the Arkitekt CLI takes more control over your development process, and streamlines
the process of developing and publishing apps so that they can be used by other users.


```python
from arkitekt import register
from mikro.api.schema import from_xarray, RepresentationFragment
from arkitekt_next import register
from mikro_next.api.schema import from_array_like, Image
import numpy as np

@register
def create_random_image(x_size: int, y_size: int) -> RepresentationFragment:
def create_random_image(x_size: int, y_size: int) -> Image:
""" Random Image

Creates a random image with the given size.
Expand All @@ -101,42 +100,39 @@ def create_random_image(x_size: int, y_size: int) -> RepresentationFragment:

Returns
-------
RepresentationFragment
Image
The created image.
"""

img = np.random.rand(100, 100)

return from_xarray(image, "Random Image")
img = np.random.rand(x_size, y_size)
return from_array_like(img, name="Random Image")


if __name__ == "__main__":
# here you can run other code, that
# will not be executed when the app is
# run by the arkitekt cli
# run by the arkitekt-next cli
pass

```

Here we are creating an app that can be run by the Arkitekt CLI and that
provides a Node (Add two Numbers) that can be used by other apps. The
`@register` decorator is used to mark a function as a node.
provides a Node that can be used by other apps. The
`@register` decorator is used to mark a function as a node.

While you can run this script like any other python script ( executing the
`if __name__ == "__main__"` block ) in the integrated style you are using
the Arkitekt CLI to run yout app via:
While you can run this script like any other python script (executing the
`if __name__ == "__main__"` block), in the plugin style you use
the Arkitekt CLI to run your app via:

```bash
arkitekt run dev
arkitekt-next run dev
```

The CLI will then create the App context for your app and register the functions
that are marked with the `@register` decorator as nodes
that are marked with the `@register` decorator as nodes.

:::info Why do we use this?

This pattern might seem strange at first, but it has a few advantages, such as nice developer experience features like hot-reloading,
but most importantly and easy portability of your app to other Arkitekt instances.
but most importantly an easy portability of your app to other Arkitekt instances.
:::

To get started with the integrated style, you can follow the [Integrated Tutorial](//docs/developers/python/plugin)
To get started with the plugin style, you can follow the [Plugin Tutorial](/docs/developers/python/plugin)
Loading