{
"cells": [
{
"cell_type": "markdown",
"id": "36307c9b",
"metadata": {
"id": "36307c9b"
},
"source": [
"## Using Git to track changes and using Memote"
]
},
{
"cell_type": "markdown",
"id": "1aad06c3",
"metadata": {
"id": "1aad06c3"
},
"source": [
"In the following, the changes made to the model are documented using Git and evaluated using [Memote](https://memote.io/) Kluyver et al. (2016), a test suite for standardized genome-scale metabolic model testing."
]
},
{
"cell_type": "markdown",
"id": "0502e201",
"metadata": {
"id": "0502e201"
},
"source": [
"For this we first install Memote.\n",
"\n",
"> `$ pip install memote`"
]
},
{
"cell_type": "markdown",
"id": "7a51f2bf",
"metadata": {
"id": "7a51f2bf"
},
"source": [
"To perform the next steps, we need a local copy of the model in SBML format.\n",
"\n",
"To be able to use Memote with all of its features a new repository needs to be created. This can be done using the following command.\n",
"(To use the online features of Memote, it is necessary to answer the questions regarding GitHub.)\n",
"\n",
"> `$ memote new`\n",
"\n",
"This command requires questions to be answered interactively. Thus it is not possible to execute this command in this tutorial Jupyter Notebooks.\n",
"\n",
"\n",
"During the interactions with Memote, the user needs to define the model name and the original location. Memote then creates a folder after a few more questions, in which configuration files for Memote and Git are automatically created and into which the model is copied.\n",
"\n",
"Here we use the default values for all questions."
]
},
{
"cell_type": "markdown",
"id": "e6a12042",
"metadata": {
"id": "e6a12042"
},
"source": [
"Next, we change the working directory to the folder created by Memote."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06a0e4b2",
"metadata": {
"id": "06a0e4b2"
},
"outputs": [],
"source": [
"directory = \"/home/jan/arbeit/memote_test/memote-model-repository\"\n",
"%cd $directory"
]
},
{
"cell_type": "markdown",
"id": "604bdc23",
"metadata": {
"id": "604bdc23"
},
"source": [
"Memote automatically installs [GitPython](https://gitpython.readthedocs.io/en/stable/), which enables using the functionalities of Git. Additionally, we import the following functions which will be used later."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8d8928f8",
"metadata": {
"id": "8d8928f8"
},
"outputs": [],
"source": [
"from git import Repo\n",
"from cobra.io import write_sbml_model, validate_sbml_model\n",
"from cobramod import add_reactions"
]
},
{
"cell_type": "markdown",
"id": "a3ecbab8",
"metadata": {
"id": "a3ecbab8"
},
"source": [
"In this folder, we can now work on the model with Memote and CobraMod. After the completed processing of the model, all changes can be saved via git using a commit.\n",
"\n",
"First, we import the model copied into the folder."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bce51d21",
"metadata": {
"id": "bce51d21",
"outputId": "1153e172-ef74-4516-a55d-ba29b48ce3b5"
},
"outputs": [
{
"data": {
"text/plain": [
"{'SBML_FATAL': [],\n",
" 'SBML_ERROR': [],\n",
" 'SBML_SCHEMA_ERROR': [],\n",
" 'SBML_WARNING': [],\n",
" 'COBRA_FATAL': [],\n",
" 'COBRA_ERROR': [],\n",
" 'COBRA_WARNING': [],\n",
" 'COBRA_CHECK': []}"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model, errors = validate_sbml_model(\"model.xml\")\n",
"errors"
]
},
{
"cell_type": "markdown",
"id": "da81634c",
"metadata": {
"id": "da81634c"
},
"source": [
"At this point, we can make changes to the current model, save additional files, such as a summary using CobraMod, special reports using Memote, or files we have created yourselves in the folder.\n",
"\n",
"Once all changes that should be saved have been made, we can save the current model in the previously created folder under the name chosen during `memote new`. This is done directly using COBRApy."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e33e8d87",
"metadata": {
"id": "e33e8d87"
},
"outputs": [],
"source": [
"write_sbml_model(model,\"model.xml\")"
]
},
{
"cell_type": "markdown",
"id": "193468b8",
"metadata": {
"id": "193468b8"
},
"source": [
"Next, the changes to be saved are passed to git. Using 'add', we can individually determine whether all/new/changed files should be added to the repository or not. This can also also be defined systematically via a \".gitignore\" file.\n",
"Finally, we perform a commit to track the changes made to the model. Here we provide a short description to summarize the changes in the model."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "69cd1111",
"metadata": {
"id": "69cd1111",
"outputId": "9a024f62-871a-47bc-c32c-035a17ac73f3"
},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from git import Repo\n",
"repo = Repo(directory)\n",
"repo.git.add(update=True)\n",
"repo.index.commit(\"This is a brief description of the changes.\")"
]
},
{
"cell_type": "markdown",
"id": "8b6a882b",
"metadata": {
"id": "8b6a882b"
},
"source": [
"If we want to send the changes to a configured Git server, we can execute the following commands. For this, a remote must be set for the repository."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fcd16ace",
"metadata": {
"id": "fcd16ace"
},
"outputs": [],
"source": [
"origin = repo.remote(name='origin')\n",
"origin.push()"
]
},
{
"cell_type": "markdown",
"id": "fba74b08",
"metadata": {
"id": "fba74b08"
},
"source": [
"All Git-related commands have been done here using GitPython but can also be replaced by the corresponding command-line commands."
]
},
{
"cell_type": "markdown",
"id": "Y73R2SG5mbNn",
"metadata": {
"id": "Y73R2SG5mbNn"
},
"source": [
"We now have finished preparing the project for the use of Memote and all of its functions can now be used. For those functions that require GitHub, a connection to GitHub must exist.\n",
"\n",
"The easiest way to do this is to answer the questions regarding GitHub during `memote new`. Alternatively, GitHub can be added as a remote at a later time. However, this will not be discussed here.\n",
"\n",
"Finally, we use `memote report snapshot` and obtain an HTML file that summarizes the state of the model and lists possible errors as shown in the following:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "OhcuGwWEli6B",
"metadata": {
"id": "OhcuGwWEli6B",
"outputId": "ec4eca48-c1c2-4c22-e6e9-40b6c00aa783",
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Scaling...\n",
" A: min|aij| = 1.000e+00 max|aij| = 1.000e+00 ratio = 1.000e+00\n",
"Problem data seem to be well scaled\n",
"The current solver interface glpk doesn't support setting the optimality tolerance.\n",
"\u001b[1m============================= test session starts ==============================\u001b[0m\n",
"platform linux -- Python 3.7.4, pytest-4.6.11, py-1.10.0, pluggy-0.13.1\n",
"rootdir: /home/jan\n",
"plugins: anyio-3.3.0\n",
"collected 146 items / 1 skipped / 145 selected \u001b[0m\n",
"\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_annotation.py \u001b[31mF\u001b[0m\u001b[36m [ 0%]\n",
"\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[36m [ 44%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_basic.py \u001b[32m.\u001b[0m\u001b[36m [ 45%]\n",
"\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[36m [ 60%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_biomass.py \u001b[32m.\u001b[0m\u001b[36m [ 60%]\n",
"\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[36m [ 67%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_consistency.py \u001b[32m.\u001b[0m\u001b[36m [ 67%]\n",
"\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[33ms\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[36m [ 86%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_essentiality.py \u001b[33ms\u001b[0m\u001b[36m [ 87%]\n",
"\u001b[0m\u001b[36m [ 87%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_growth.py \u001b[33ms\u001b[0m\u001b[36m [ 88%]\n",
"\u001b[0m\u001b[36m [ 88%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_matrix.py \u001b[32m.\u001b[0m\u001b[36m [ 89%]\n",
"\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[36m [ 91%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_sbml.py \u001b[32m.\u001b[0m\u001b[36m [ 91%]\n",
"\u001b[0m\u001b[32m.\u001b[0m\u001b[36m [ 92%]\u001b[0m\n",
"../../../miniconda3/envs/cobramod/lib/python3.7/site-packages/memote/suite/tests/test_sbo.py \u001b[32m.\u001b[0m\u001b[36m [ 93%]\n",
"\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[33ms\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[36m [100%]\u001b[0m\n",
"\n",
"\u001b[31m\u001b[1m=============== 63 failed, 64 passed, 20 skipped in 2.69 seconds ===============\u001b[0m\n",
"Writing snapshot report to 'index.html'.\n"
]
}
],
"source": [
"!memote report snapshot"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "367ec727",
"metadata": {
"id": "367ec727",
"outputId": "2fe08550-e0cc-48de-c8ae-f8aea775d595"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import IFrame\n",
"IFrame(src='./_static/memote.html', width=\"100%\", height=800)"
]
},
{
"cell_type": "markdown",
"id": "a2369624",
"metadata": {},
"source": [
".. bibliography::"
]
}
],
"metadata": {
"colab": {
"name": "memote.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
"autoclose": true,
"autocomplete": true,
"bibliofile": "biblio.bib",
"cite_by": "apalike",
"current_citInitial": 1,
"eqLabelWithNumbers": true,
"eqNumInitial": 1,
"hotkeys": {
"equation": "Ctrl-E",
"itemize": "Ctrl-I"
},
"labels_anchors": false,
"latex_user_defs": false,
"report_style_numbering": false,
"user_envs_cfg": false
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}