diff --git a/environment.yml b/environment.yml index 483bec2..04b6ec0 100644 --- a/environment.yml +++ b/environment.yml @@ -21,6 +21,7 @@ dependencies: - statsmodels - scikit-learn - scikit-optimize + - typer - pip - pip: diff --git a/moepy/_nbdev.py b/moepy/_nbdev.py index 10bf655..825ea9d 100644 --- a/moepy/_nbdev.py +++ b/moepy/_nbdev.py @@ -71,13 +71,18 @@ "construct_df_pred": "05-price-moe.ipynb", "calc_error_metrics": "05-price-moe.ipynb", "get_model_pred_ts": "05-price-moe.ipynb", - "weighted_mean_s": "05-price-moe.ipynb"} + "weighted_mean_s": "05-price-moe.ipynb", + "app": "10-ci-cd.ipynb", + "get_current_package_version": "10-ci-cd.ipynb", + "increment_package_version": "10-ci-cd.ipynb", + "set_current_package_version": "10-ci-cd.ipynb"} modules = ["retrieval.py", "eda.py", "lowess.py", "surface.py", - "moe.py"] + "moe.py", + "cicd.py"] doc_url = "https://AyrtonB.github.io/Merit-Order-Effect/" diff --git a/moepy/cicd.py b/moepy/cicd.py new file mode 100644 index 0000000..efe2bfd --- /dev/null +++ b/moepy/cicd.py @@ -0,0 +1,64 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/10-ci-cd.ipynb (unless otherwise specified). + +__all__ = ['app', 'get_current_package_version', 'increment_package_version', 'set_current_package_version'] + +# Cell +import os +import re +import typer +import logging +from warnings import warn +from configparser import ConfigParser + +# Cell +app = typer.Typer() + +# Cell +@app.command() +def get_current_package_version(settings_fp: str='settings.ini'): + config = ConfigParser(delimiters=['=']) + config.read(settings_fp) + version = config.get('DEFAULT', 'version') + + return version + +# Cell +@app.command() +def increment_package_version(old_version: str, increment_level: str='micro'): + increment = lambda rev: str(int(rev)+1) + + major, minor, micro = old_version.split('.') # naming from - https://the-hitchhikers-guide-to-packaging.readthedocs.io/en/latest/specification.html#sequence-based-scheme + + if increment_level == 'major': + major = increment(major) + elif increment_level == 'minor': + minor = increment(minor) + elif increment_level == 'micro': + micro = increment(micro) + + new_version = '.'.join([major, minor, micro]) + + return new_version + +# Cell +@app.command() +def set_current_package_version(version: str, settings_fp: str='settings.ini'): + version = version.replace('v', '') + + config = ConfigParser(delimiters=['=']) + config.read(settings_fp) + + config.set('DEFAULT', 'version', version) + + with open(settings_fp, 'w') as configfile: + config.write(configfile) + + logger = logging.getLogger('package_release') + logger.setLevel('INFO') + logger.info(f'The package version has to be updated to {version}') + + return + +# Cell +if __name__ == '__main__' and '__file__' in globals(): + app() \ No newline at end of file diff --git a/nbs/10-ci-cd.ipynb b/nbs/10-ci-cd.ipynb new file mode 100644 index 0000000..89825e9 --- /dev/null +++ b/nbs/10-ci-cd.ipynb @@ -0,0 +1,360 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# default_exp cicd" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CI/CD\n", + "\n", + "
\n", + "\n", + "This notebook includes helper functions and processes used in the continuous integration and deployment of the `moepy` library.\n", + "\n", + "
\n", + "\n", + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "#exports\n", + "import os\n", + "import re\n", + "import typer\n", + "import logging\n", + "from warnings import warn\n", + "from configparser import ConfigParser" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "### Initialising CLI " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "#exports\n", + "app = typer.Typer()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "### Incrementing the Package Version\n", + "\n", + "We'll start by retrieving the current package version specified in `settings.ini`" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "#exports\n", + "@app.command()\n", + "def get_current_package_version(settings_fp: str='settings.ini'):\n", + " config = ConfigParser(delimiters=['='])\n", + " config.read(settings_fp)\n", + " version = config.get('DEFAULT', 'version')\n", + " \n", + " return version" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.0.3'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "settings_fp = '../settings.ini'\n", + "\n", + "original_version = get_current_package_version(settings_fp)\n", + "\n", + "original_version" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "We'll now increment the package version" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "#exports\n", + "@app.command()\n", + "def increment_package_version(old_version: str, increment_level: str='micro'):\n", + " increment = lambda rev: str(int(rev)+1)\n", + " \n", + " major, minor, micro = old_version.split('.') # naming from - https://the-hitchhikers-guide-to-packaging.readthedocs.io/en/latest/specification.html#sequence-based-scheme\n", + " \n", + " if increment_level == 'major':\n", + " major = increment(major)\n", + " elif increment_level == 'minor':\n", + " minor = increment(minor)\n", + " elif increment_level == 'micro':\n", + " micro = increment(micro)\n", + " \n", + " new_version = '.'.join([major, minor, micro])\n", + " \n", + " return new_version" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.0.4'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "increment_package_version(original_version)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "But what about if we've made large changes to the code-base and wish to express the size of these revisions in the version? For that we can specify the `increment_level`." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'1.0.3'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "increment_package_version(original_version, increment_level='major')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "And finally we can set the version" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "#exports\n", + "@app.command()\n", + "def set_current_package_version(version: str, settings_fp: str='settings.ini'):\n", + " version = version.replace('v', '')\n", + " \n", + " config = ConfigParser(delimiters=['='])\n", + " config.read(settings_fp)\n", + "\n", + " config.set('DEFAULT', 'version', version)\n", + "\n", + " with open(settings_fp, 'w') as configfile:\n", + " config.write(configfile)\n", + " \n", + " logger = logging.getLogger('package_release')\n", + " logger.setLevel('INFO')\n", + " logger.info(f'The package version has to be updated to {version}')\n", + " \n", + " return " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'9.9.9'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "set_current_package_version('9.9.9', settings_fp)\n", + "get_current_package_version(settings_fp)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "Before we move on we'll change the version on file back to the original" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.0.3'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "set_current_package_version(original_version, settings_fp)\n", + "get_current_package_version(settings_fp)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "Finally we need to ensure the CLI app is available when the module is loaded.\n", + "\n", + "N.b. we've included the condition `'__file__' in globals()` to make sure this isn't when inside the notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "#exports\n", + "if __name__ == '__main__' and '__file__' in globals():\n", + " app()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Converted 01-retrieval.ipynb.\n", + "Converted 02-eda.ipynb.\n", + "Converted 03-lowess.ipynb.\n", + "Converted 04-price-surface-estimation.ipynb.\n", + "Converted 05-price-moe.ipynb.\n", + "Converted 06-carbon-surface-estimation-and-moe.ipynb.\n", + "Converted 07-prediction-confidence-and-intervals.ipynb.\n", + "Converted 08-hyper-parameter-tuning.ipynb.\n", + "Converted 09-tables-and-figures.ipynb.\n", + "Converted 10-ci-cd.ipynb.\n" + ] + } + ], + "source": [ + "#hide\n", + "from nbdev.export import *\n", + "notebook2script()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "MOE", + "language": "python", + "name": "moe" + }, + "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.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/settings.ini b/settings.ini index ab51f9a..0ef8982 100644 --- a/settings.ini +++ b/settings.ini @@ -21,4 +21,5 @@ title = moepy doc_path = docs doc_host = https://AyrtonB.github.io doc_baseurl = /Merit-Order-Effect/ -requirements = pandas==1.2.0 numpy==1.19.5 matplotlib==3.3.3 seaborn==0.11.1 lxml==4.6.2 ipypb==0.5.2 dagster==0.9.21 scikit-learn==0.24.0 scipy==1.6.0 \ No newline at end of file +requirements = pandas==1.2.0 numpy==1.19.5 matplotlib==3.3.3 seaborn==0.11.1 lxml==4.6.2 ipypb==0.5.2 dagster==0.9.21 scikit-learn==0.24.0 scipy==1.6.0 +