Unified representation
Run code and inspect results using the same abstraction. Check out the example below ⏬
diff --git a/404.html b/404.html index a3a81f6c..b45736e7 100644 --- a/404.html +++ b/404.html @@ -6,7 +6,7 @@
404
But if you don't change your direction, and if you keep looking, you may end up where you are heading.
from typing import List, Optional
+# your code
from typing import List, Optional
import os
diff --git a/assets/examples_aimstack-storage_index.md.d9e0c71a.lean.js b/assets/examples_aimstack-storage_index.md.f9cfa005.lean.js
similarity index 100%
rename from assets/examples_aimstack-storage_index.md.d9e0c71a.lean.js
rename to assets/examples_aimstack-storage_index.md.f9cfa005.lean.js
diff --git a/assets/examples_globus-storage_index.md.f41bddd7.js b/assets/examples_globus-storage_index.md.f366404a.js
similarity index 99%
rename from assets/examples_globus-storage_index.md.f41bddd7.js
rename to assets/examples_globus-storage_index.md.f366404a.js
index bb1a652e..e55abf40 100644
--- a/assets/examples_globus-storage_index.md.f41bddd7.js
+++ b/assets/examples_globus-storage_index.md.f366404a.js
@@ -13,7 +13,7 @@ import{_ as s,o as n,c as a,O as l}from"./chunks/framework.62020867.js";const i=
print(matches)
# download from globus
-storage.download(matches[0].uuid)
from typing import TYPE_CHECKING, List
+storage.download(matches[0].uuid)
from typing import TYPE_CHECKING, List
import os
import time
diff --git a/assets/examples_globus-storage_index.md.f41bddd7.lean.js b/assets/examples_globus-storage_index.md.f366404a.lean.js
similarity index 100%
rename from assets/examples_globus-storage_index.md.f41bddd7.lean.js
rename to assets/examples_globus-storage_index.md.f366404a.lean.js
diff --git a/assets/examples_mpi-execution_index.md.11015463.js b/assets/examples_mpi-execution_index.md.afc18990.js
similarity index 99%
rename from assets/examples_mpi-execution_index.md.11015463.js
rename to assets/examples_mpi-execution_index.md.afc18990.js
index 6c7a6d60..1cd1851f 100644
--- a/assets/examples_mpi-execution_index.md.11015463.js
+++ b/assets/examples_mpi-execution_index.md.afc18990.js
@@ -1,7 +1,7 @@
import{_ as s,o as n,c as a,O as l}from"./chunks/framework.62020867.js";const i=JSON.parse('{"title":"MPI execution","description":"","frontmatter":{},"headers":[],"relativePath":"examples/mpi-execution/index.md","filePath":"examples/mpi-execution/index.md"}'),p={name:"examples/mpi-execution/index.md"},o=l(`MPI execution
Integration to launch MPI jobs.
Usage example
pythonfrom machinable import get
with get("mpi", {"ranks": 8}):
- ... # your MPI ready component
Source
pyfrom typing import Literal, Optional, Union
+ ... # your MPI ready component
Source
pyfrom typing import Literal, Optional, Union
import sys
diff --git a/assets/examples_mpi-execution_index.md.11015463.lean.js b/assets/examples_mpi-execution_index.md.afc18990.lean.js
similarity index 100%
rename from assets/examples_mpi-execution_index.md.11015463.lean.js
rename to assets/examples_mpi-execution_index.md.afc18990.lean.js
diff --git a/assets/examples_require-execution_index.md.d36d8037.js b/assets/examples_require-execution_index.md.e31ee6e4.js
similarity index 98%
rename from assets/examples_require-execution_index.md.d36d8037.js
rename to assets/examples_require-execution_index.md.e31ee6e4.js
index 59a58971..94804841 100644
--- a/assets/examples_require-execution_index.md.d36d8037.js
+++ b/assets/examples_require-execution_index.md.e31ee6e4.js
@@ -1,7 +1,7 @@
import{_ as s,o as a,c as n,O as l}from"./chunks/framework.62020867.js";const C=JSON.parse('{"title":"Require execution","description":"","frontmatter":{},"headers":[],"relativePath":"examples/require-execution/index.md","filePath":"examples/require-execution/index.md"}'),p={name:"examples/require-execution/index.md"},o=l(`Require execution
A way to assert that components have been cached.
Usage example
pythonfrom machinable import get
with get("require"):
- ... # components to check
Source
pyfrom machinable import Execution
+ ... # components to check
Source
pyfrom machinable import Execution
class Require(Execution):
diff --git a/assets/examples_require-execution_index.md.d36d8037.lean.js b/assets/examples_require-execution_index.md.e31ee6e4.lean.js
similarity index 100%
rename from assets/examples_require-execution_index.md.d36d8037.lean.js
rename to assets/examples_require-execution_index.md.e31ee6e4.lean.js
diff --git a/assets/examples_slurm-execution_index.md.5a3e6e18.js b/assets/examples_slurm-execution_index.md.2dac90d8.js
similarity index 99%
rename from assets/examples_slurm-execution_index.md.5a3e6e18.js
rename to assets/examples_slurm-execution_index.md.2dac90d8.js
index 010b7f99..30a3a47b 100644
--- a/assets/examples_slurm-execution_index.md.5a3e6e18.js
+++ b/assets/examples_slurm-execution_index.md.2dac90d8.js
@@ -1,7 +1,7 @@
import{_ as s,o as n,c as a,O as l}from"./chunks/framework.62020867.js";const i=JSON.parse('{"title":"Slurm execution","description":"","frontmatter":{},"headers":[],"relativePath":"examples/slurm-execution/index.md","filePath":"examples/slurm-execution/index.md"}'),o={name:"examples/slurm-execution/index.md"},p=l(`Slurm execution
Integration to submit to the Slurm scheduler.
Usage example
pythonfrom machinable import get
with get("slurm", {"ranks": 8, 'preamble': 'mpirun'}):
- ... # your component
Source
pyfrom typing import Literal, Optional, Union
+ ... # your component
Source
pyfrom typing import Literal, Optional, Union
import os
import subprocess
diff --git a/assets/examples_slurm-execution_index.md.5a3e6e18.lean.js b/assets/examples_slurm-execution_index.md.2dac90d8.lean.js
similarity index 100%
rename from assets/examples_slurm-execution_index.md.5a3e6e18.lean.js
rename to assets/examples_slurm-execution_index.md.2dac90d8.lean.js
diff --git a/assets/guide_component.md.1db4b50c.js b/assets/guide_component.md.3a63595a.js
similarity index 99%
rename from assets/guide_component.md.1db4b50c.js
rename to assets/guide_component.md.3a63595a.js
index 19754183..e8bc1ce8 100644
--- a/assets/guide_component.md.1db4b50c.js
+++ b/assets/guide_component.md.3a63595a.js
@@ -17,7 +17,7 @@ import{_ as p,D as t,o as c,c as r,z as n,a as s,G as o,B as l,O as e}from"./chu
>>> mnist.launch()
Downloading 'mnist' ...
If the execution is successful, the component is marked as finished.
python>>> mnist.execution.is_finished()
True
By design, component instances can only be executed once. They are automatically assigned a timestamp, random seed, as well as a nickname for easy identification.
python>>> mnist.seed
-1632827863
Invocations of launch()
after successful execution, do not trigger another execution since the component is marked as cached. On the other hand, if the execution failed, calling launch()
will resume the execution with the same configuration.
Implementing custom execution
Components can be executed in different ways. You may, for example, like to run components using multiprocessing or execute in a cloud environment. However, instead of adding the execution logic directly to your component code, machinable makes it easy to separate concerns. You can encapsulate the execution implementation in its own execution class that can then be used to execute the component.
`,8),C=e(`pythonfrom multiprocessing import Pool
+1632827863
Invocations of launch()
after successful execution, do not trigger another execution since the component is marked as cached. On the other hand, if the execution failed, calling launch()
will resume the execution with the same configuration.
Implementing custom execution
Components can be executed in different ways. You may, for example, like to run components using multiprocessing or execute in a cloud environment. However, instead of adding the execution logic directly to your component code, machinable makes it easy to separate concerns. You can encapsulate the execution implementation in its own execution class that can then be used to execute the component.
`,8),C=e(`pythonfrom multiprocessing import Pool
from machinable import Execution
diff --git a/assets/guide_component.md.1db4b50c.lean.js b/assets/guide_component.md.3a63595a.lean.js
similarity index 100%
rename from assets/guide_component.md.1db4b50c.lean.js
rename to assets/guide_component.md.3a63595a.lean.js
diff --git a/assets/guide_interface.md.50ffde76.js b/assets/guide_interface.md.5c24027f.js
similarity index 96%
rename from assets/guide_interface.md.50ffde76.js
rename to assets/guide_interface.md.5c24027f.js
index c068331d..154b0c41 100644
--- a/assets/guide_interface.md.50ffde76.js
+++ b/assets/guide_interface.md.5c24027f.js
@@ -1,4 +1,4 @@
-import{_ as t,D as p,o as c,c as r,z as a,a as s,G as l,B as o,O as e}from"./chunks/framework.62020867.js";const k=JSON.parse('{"title":"Interface","description":"","frontmatter":{},"headers":[],"relativePath":"guide/interface.md","filePath":"guide/interface.md"}'),i={name:"guide/interface.md"},y=a("h1",{id:"interface",tabindex:"-1"},[s("Interface "),a("a",{class:"header-anchor",href:"#interface","aria-label":'Permalink to "Interface"'},"")],-1),D=a("p",null,[a("a",{href:"./element.html"},"Elements"),s(" by themselves are limited in that they are effectively stateless. You can construct and use them but any computed result or additional information will not be persisted.")],-1),F=e(`pythonfrom machinable import Interface
+import{_ as e,D as p,o as c,c as r,z as a,a as s,G as l,B as o,O as t}from"./chunks/framework.62020867.js";const k=JSON.parse('{"title":"Interface","description":"","frontmatter":{},"headers":[],"relativePath":"guide/interface.md","filePath":"guide/interface.md"}'),i={name:"guide/interface.md"},y=a("h1",{id:"interface",tabindex:"-1"},[s("Interface "),a("a",{class:"header-anchor",href:"#interface","aria-label":'Permalink to "Interface"'},"")],-1),D=a("p",null,[a("a",{href:"./element.html"},"Elements"),s(" by themselves are limited in that they are effectively stateless. You can construct and use them but any computed result or additional information will not be persisted.")],-1),F=t(`pythonfrom machinable import Interface
class MnistData(Interface):
"""A dataset of handwritten characters"""
@@ -11,17 +11,17 @@ import{_ as t,D as p,o as c,c as r,z as a,a as s,G as l,B as o,O as e}from"./chu
>>> mnist.local_directory()
'./storage/29f034ad2d1a46b8b71c9b30222b5b88'
>>> Interface.from_directory('./storage/29f034ad2d1a46b8b71c9b30222b5b88')
-Interface [29f034] # reloaded interface
During commit, machinable collects information like a unique ID (e.g. 29f034
), the used configuration, and other meta-data and saves it in a unique storage (e.g. a local directory) from which it can be reloaded later.
get
In practice, however, it may be cumbersome to keep track of long IDs to reload existing interfaces. To avoid this issue, one of the fundamental ideas in the design of machinable is to make retrieval identical to initial instantiation.
`,6),A=a("code",null,"MnistData()",-1),d=e(`pythonfrom machinable import get
+Interface [29f034] # reloaded interface
During commit, machinable collects information like a unique ID (e.g. 29f034
), the used configuration, and other meta-data and saves it in a unique storage (e.g. a local directory) from which it can be reloaded later.
get
In practice, however, it may be cumbersome to keep track of long IDs to reload existing interfaces. To avoid this issue, one of the fundamental ideas in the design of machinable is to make retrieval identical to initial instantiation.
`,6),A=a("code",null,"MnistData()",-1),d=t(`pythonfrom machinable import get
mnist = get(MnistData, {"batch_size": 8})
# -> this is equivalent to: MnistData({"batch_size": 8})
mnist.commit()
Now, if we later want to retrieve this instance, we can use the same code in place of a unique ID:
pythonmnist_reloaded = get(MnistData, {"batch_size": 8})
-assert mnist == mnist_reloaded
`,3),C=a("code",null,"MnistData",-1),u=a("code",null,"batch_size",-1),h=a("code",null,"8",-1),m=e(`The module convention
As your project grows, the classes that you implement should be moved into their own Python module. You are free to structure your code as you see fit but there is one hard constraint that classes must be placed in their own modules. The project source code may, for instance, be organized like this:
example_project/
+assert mnist == mnist_reloaded
`,3),C=a("code",null,"MnistData",-1),u=a("code",null,"batch_size",-1),h=a("code",null,"8",-1),m=t(`The module convention
As your project grows, the classes that you implement should be moved into their own Python module. You are free to structure your code as you see fit but there is one hard constraint that classes must be placed in their own modules. The project source code may, for instance, be organized like this:
example_project/
├─ estimate_gravity.py # contains a data analysis component
├─ evolution/
| └─ simulate_offspring.py # contains a evolutionary simulation
-└─ main.py # main script to execute
The benefit of this requirement is that you can refer to the classes via their module import path. For example, using this module convention, you can simplify the instantiation of classes that are located in different modules:
pythonfrom machinable import get
+└─ main.py # main script to execute
The benefit of this requirement is that you can refer to the classes via their module import path. For example, using this module convention, you can simplify the instantiation of classes that are located in different modules:
pythonfrom machinable import get
from estimate_gravity import EstimateGravity
from evolution.simulate_offspring import SimulateOffspring
@@ -30,14 +30,14 @@ import{_ as t,D as p,o as c,c as r,z as a,a as s,G as l,B as o,O as e}from"./chu
evolution = get(SimulateOffspring)
pythonfrom machinable import get
gravity = get('estimate_gravity')
-evolution = get('evolution.simulate_offspring')
Note that we do not refer to the classes by their name but just by the modules that contain them (since each module only contains one). As we will see later, importing and instantiating the classes this way has a lot of advantages, so it is the default way of instantiation in machinable projects.
Saving and loading state
`,7),f=e(`pythongravity.save_file('prediction.txt', 'a string') # text
+evolution = get('evolution.simulate_offspring')
Note that we do not refer to the classes by their name but just by the modules that contain them (since each module only contains one). As we will see later, importing and instantiating the classes this way has a lot of advantages, so it is the default way of instantiation in machinable projects.
Saving and loading state
`,7),f=t(`pythongravity.save_file('prediction.txt', 'a string') # text
gravity.save_file('settings.json', {'neurons': [1, 2]}) # jsonable
gravity.save_file('inputs.npy', np.array([1.0, 2.0])) # numpy
gravity.save_file('results.p', results) # pickled
>>> gravity.load_file('prediction.txt')
-'a string'
`,1),g=e(`pythonimport os
+'a string'
`,1),g=t(`pythonimport os
mnist = get("mnist_data")
with open(mnist.local_directory("download_script.sh"), "w") as f:
f.write(...)
- os.chmod(f.name, 0o755)
Overall, interfaces make it easy to associate data with code as instantiation, storage and retrieval are managed automatically behind the scenes.
`,2);function _(b,v,E,q,T,w){const n=p("Pydoc");return c(),r("div",null,[y,D,a("p",null,[s("To enable storage and retrival we can use an "),l(n,null,{default:o(()=>[s("machinable.Interface")]),_:1}),s(" class.")]),F,a("p",null,[s("Specifically, to instantiate an interface (e.g. "),A,s(") we can leverage the "),l(n,null,{default:o(()=>[s("machinable.get")]),_:1}),s(" function, which takes a class as the first argument and optional constructor arguments.")]),d,a("p",null,[s("What is happening here is that "),l(n,{caption:"get()"},{default:o(()=>[s("machinable.get")]),_:1}),s(" automatically searches the storage for an interface of type "),C,s(" with a "),u,s(" of "),h,s(". If such an instance has not been committed yet (like when initially running the code), a new instance with this configuration will be returned. But if such an instance has previously been committed, it will simply be reloaded.")]),m,a("p",null,[s("While machinable automatically commits crucial information about the interface, you can use "),l(n,null,{default:o(()=>[s("machinable.Interface.save_file")]),_:1}),s(" and "),l(n,null,{default:o(()=>[s("machinable.Interface.load_file")]),_:1}),s(" to easily store and retrieve additional custom data in different file formats:")]),f,a("p",null,[s("This may be useful to save and restore some custom state of the interface. Furthermore, you are free to implement your own methods to persist data by writing and reading from the interface's "),l(n,{caption:"local_directory()"},{default:o(()=>[s("machinable.Interface.local_directory")]),_:1}),s(":")]),g])}const S=t(i,[["render",_]]);export{k as __pageData,S as default};
+ os.chmod(f.name, 0o755)
Overall, interfaces make it easy to associate data with code as instantiation, storage and retrieval are managed automatically behind the scenes.
`,2);function _(b,v,E,q,T,w){const n=p("Pydoc");return c(),r("div",null,[y,D,a("p",null,[s("To enable storage and retrival we can use an "),l(n,null,{default:o(()=>[s("machinable.Interface")]),_:1}),s(" class.")]),F,a("p",null,[s("Specifically, to instantiate an interface (e.g. "),A,s(") we can leverage the "),l(n,null,{default:o(()=>[s("machinable.get")]),_:1}),s(" function, which takes a class as the first argument and optional constructor arguments.")]),d,a("p",null,[s("What is happening here is that "),l(n,{caption:"get()"},{default:o(()=>[s("machinable.get")]),_:1}),s(" automatically searches the storage for an interface of type "),C,s(" with a "),u,s(" of "),h,s(". If such an instance has not been committed yet (like when initially running the code), a new instance with this configuration will be returned. But if such an instance has previously been committed, it will simply be reloaded.")]),m,a("p",null,[s("While machinable automatically commits crucial information about the interface, you can use "),l(n,null,{default:o(()=>[s("machinable.Interface.save_file")]),_:1}),s(" and "),l(n,null,{default:o(()=>[s("machinable.Interface.load_file")]),_:1}),s(" to easily store and retrieve additional custom data in different file formats:")]),f,a("p",null,[s("This may be useful to save and restore some custom state of the interface. Furthermore, you are free to implement your own methods to persist data by writing and reading from the interface's "),l(n,{caption:"local_directory()"},{default:o(()=>[s("machinable.Interface.local_directory")]),_:1}),s(":")]),g])}const S=e(i,[["render",_]]);export{k as __pageData,S as default};
diff --git a/assets/guide_interface.md.50ffde76.lean.js b/assets/guide_interface.md.5c24027f.lean.js
similarity index 84%
rename from assets/guide_interface.md.50ffde76.lean.js
rename to assets/guide_interface.md.5c24027f.lean.js
index 48e28fb1..491332dd 100644
--- a/assets/guide_interface.md.50ffde76.lean.js
+++ b/assets/guide_interface.md.5c24027f.lean.js
@@ -1 +1 @@
-import{_ as t,D as p,o as c,c as r,z as a,a as s,G as l,B as o,O as e}from"./chunks/framework.62020867.js";const k=JSON.parse('{"title":"Interface","description":"","frontmatter":{},"headers":[],"relativePath":"guide/interface.md","filePath":"guide/interface.md"}'),i={name:"guide/interface.md"},y=a("h1",{id:"interface",tabindex:"-1"},[s("Interface "),a("a",{class:"header-anchor",href:"#interface","aria-label":'Permalink to "Interface"'},"")],-1),D=a("p",null,[a("a",{href:"./element.html"},"Elements"),s(" by themselves are limited in that they are effectively stateless. You can construct and use them but any computed result or additional information will not be persisted.")],-1),F=e("",6),A=a("code",null,"MnistData()",-1),d=e("",3),C=a("code",null,"MnistData",-1),u=a("code",null,"batch_size",-1),h=a("code",null,"8",-1),m=e("",7),f=e("",1),g=e("",2);function _(b,v,E,q,T,w){const n=p("Pydoc");return c(),r("div",null,[y,D,a("p",null,[s("To enable storage and retrival we can use an "),l(n,null,{default:o(()=>[s("machinable.Interface")]),_:1}),s(" class.")]),F,a("p",null,[s("Specifically, to instantiate an interface (e.g. "),A,s(") we can leverage the "),l(n,null,{default:o(()=>[s("machinable.get")]),_:1}),s(" function, which takes a class as the first argument and optional constructor arguments.")]),d,a("p",null,[s("What is happening here is that "),l(n,{caption:"get()"},{default:o(()=>[s("machinable.get")]),_:1}),s(" automatically searches the storage for an interface of type "),C,s(" with a "),u,s(" of "),h,s(". If such an instance has not been committed yet (like when initially running the code), a new instance with this configuration will be returned. But if such an instance has previously been committed, it will simply be reloaded.")]),m,a("p",null,[s("While machinable automatically commits crucial information about the interface, you can use "),l(n,null,{default:o(()=>[s("machinable.Interface.save_file")]),_:1}),s(" and "),l(n,null,{default:o(()=>[s("machinable.Interface.load_file")]),_:1}),s(" to easily store and retrieve additional custom data in different file formats:")]),f,a("p",null,[s("This may be useful to save and restore some custom state of the interface. Furthermore, you are free to implement your own methods to persist data by writing and reading from the interface's "),l(n,{caption:"local_directory()"},{default:o(()=>[s("machinable.Interface.local_directory")]),_:1}),s(":")]),g])}const S=t(i,[["render",_]]);export{k as __pageData,S as default};
+import{_ as e,D as p,o as c,c as r,z as a,a as s,G as l,B as o,O as t}from"./chunks/framework.62020867.js";const k=JSON.parse('{"title":"Interface","description":"","frontmatter":{},"headers":[],"relativePath":"guide/interface.md","filePath":"guide/interface.md"}'),i={name:"guide/interface.md"},y=a("h1",{id:"interface",tabindex:"-1"},[s("Interface "),a("a",{class:"header-anchor",href:"#interface","aria-label":'Permalink to "Interface"'},"")],-1),D=a("p",null,[a("a",{href:"./element.html"},"Elements"),s(" by themselves are limited in that they are effectively stateless. You can construct and use them but any computed result or additional information will not be persisted.")],-1),F=t("",6),A=a("code",null,"MnistData()",-1),d=t("",3),C=a("code",null,"MnistData",-1),u=a("code",null,"batch_size",-1),h=a("code",null,"8",-1),m=t("",7),f=t("",1),g=t("",2);function _(b,v,E,q,T,w){const n=p("Pydoc");return c(),r("div",null,[y,D,a("p",null,[s("To enable storage and retrival we can use an "),l(n,null,{default:o(()=>[s("machinable.Interface")]),_:1}),s(" class.")]),F,a("p",null,[s("Specifically, to instantiate an interface (e.g. "),A,s(") we can leverage the "),l(n,null,{default:o(()=>[s("machinable.get")]),_:1}),s(" function, which takes a class as the first argument and optional constructor arguments.")]),d,a("p",null,[s("What is happening here is that "),l(n,{caption:"get()"},{default:o(()=>[s("machinable.get")]),_:1}),s(" automatically searches the storage for an interface of type "),C,s(" with a "),u,s(" of "),h,s(". If such an instance has not been committed yet (like when initially running the code), a new instance with this configuration will be returned. But if such an instance has previously been committed, it will simply be reloaded.")]),m,a("p",null,[s("While machinable automatically commits crucial information about the interface, you can use "),l(n,null,{default:o(()=>[s("machinable.Interface.save_file")]),_:1}),s(" and "),l(n,null,{default:o(()=>[s("machinable.Interface.load_file")]),_:1}),s(" to easily store and retrieve additional custom data in different file formats:")]),f,a("p",null,[s("This may be useful to save and restore some custom state of the interface. Furthermore, you are free to implement your own methods to persist data by writing and reading from the interface's "),l(n,{caption:"local_directory()"},{default:o(()=>[s("machinable.Interface.local_directory")]),_:1}),s(":")]),g])}const S=e(i,[["render",_]]);export{k as __pageData,S as default};
diff --git a/assets/guide_introduction.md.5f258ae0.js b/assets/guide_introduction.md.baf96e4d.js
similarity index 97%
rename from assets/guide_introduction.md.5f258ae0.js
rename to assets/guide_introduction.md.baf96e4d.js
index fde3dabe..b75f4b85 100644
--- a/assets/guide_introduction.md.5f258ae0.js
+++ b/assets/guide_introduction.md.baf96e4d.js
@@ -1,4 +1,4 @@
-import{_ as s,o as a,c as n,O as l}from"./chunks/framework.62020867.js";const C=JSON.parse('{"title":"Introduction","description":"","frontmatter":{},"headers":[],"relativePath":"guide/introduction.md","filePath":"guide/introduction.md"}'),o={name:"guide/introduction.md"},p=l(`Introduction
What is machinable?
machinable is a Python API for research code. It provides an object-oriented skeleton that helps you develop and experiment in a unified interface while handling tedious housekeeping behind the scenes.
The key idea is to unify the running of code and the retrieval of produced results in one abstraction. A detailed discussion of this approach can be found in the about section, but for now, here is a minimal example that illustrates the idea.
- Write some code
pythonfrom random import random
+import{_ as s,o as a,c as n,O as l}from"./chunks/framework.62020867.js";const C=JSON.parse('{"title":"Introduction","description":"","frontmatter":{},"headers":[],"relativePath":"guide/introduction.md","filePath":"guide/introduction.md"}'),o={name:"guide/introduction.md"},p=l(`Introduction
What is machinable?
machinable is a Python API for research code. It provides an object-oriented skeleton that helps you develop and experiment in a unified interface while handling tedious housekeeping behind the scenes.
The key idea is to unify the running of code and the retrieval of produced results in one abstraction. A detailed discussion of this approach can be found in the about section, but for now, here is a minimal example that illustrates the idea.
- Write some code
pythonfrom random import random
from pydantic import BaseModel, Field
@@ -26,7 +26,7 @@ import{_ as s,o as a,c as n,O as l}from"./chunks/framework.62020867.js";const C=
print(
f"After {self.config.samples} samples, "
f"PI is approximately {self.load_file('result.json')['pi']}."
- )
- Run and inspect it using a unified abstraction
pythonfrom machinable import get
+ )
- Run and inspect it using a unified abstraction
pythonfrom machinable import get
# Imports component in \`montecarlo.py\` with samples=150;
# if an component with this configuration exists, it
diff --git a/assets/guide_introduction.md.5f258ae0.lean.js b/assets/guide_introduction.md.baf96e4d.lean.js
similarity index 100%
rename from assets/guide_introduction.md.5f258ae0.lean.js
rename to assets/guide_introduction.md.baf96e4d.lean.js
diff --git a/examples/aimstack-storage/index.html b/examples/aimstack-storage/index.html
index 4bda650f..8aa40d20 100644
--- a/examples/aimstack-storage/index.html
+++ b/examples/aimstack-storage/index.html
@@ -6,12 +6,12 @@
Aim storage | machinable
-
+
-
+
@@ -28,7 +28,7 @@
get("aimstack", {"repo": "./path/to/aim-repo"}).__enter__()
-# your code
Source
pyfrom typing import List, Optional
+# your code
Source
pyfrom typing import List, Optional
import os
@@ -84,7 +84,7 @@
for k, v in interface.__model__.model_dump().items():
run[k] = v
-
research code
A modular system to manage research code so you can move quickly while enabling reuse and collaboration.
Run code and inspect results using the same abstraction. Check out the example below ⏬
Spend more time experimenting while relying on machinable to keep things organized.
Tweak, extend, override while leveraging first-class support for Jupyter as well as the CLI.
Some research code
Running code ...
python regression.py --rate=0.1 --logs=1 --name=run-01
... and loading the corresponding results ...
python plot_regression_result.py --component=run-01
... are distinct and often redundant.
This means you have to manually keep track by remembering what the component with rate=0.1
was called.
machinable research code
Running code ...
machinable regression rate=0.1 logs_=True --launch
... and loading the corresponding results ...
machinable regression rate=0.1 logs_=True --launch --plot
... are distinct but use the same abstraction.
This means no need to worry about names as machinable automatically keeps track if you ran rate=0.1
before.
This page contains detailed API reference documentation. It is intended to be an in-depth resource for understanding the implementation details of machinable's interfaces. You may prefer reviewing the more explanatory guide before consulting this reference.