{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Releasing-and-versioning)=\n", "# Releasing and versioning\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Previous chapters have focused on how to develop a Python package from scratch by creating the Python source code, developing a testing framework, writing documentation, and then releasing it online via PyPI (if desired). This chapter now describes the next step in the packaging workflow — updating your package!\n", "\n", "At any given time, your package's users (including you) will install a particular version of your package in a project. If you change the package's source code, their code could potentially break (imagine you change a module name, or remove a function argument a user was using). To solve this problem, developers assign a unique version number to each unique state of their package and release each new version independently. Most of the time, users will want to use the most up-to-date version of your package, but sometimes, they'll need to use an older version that is compatible with their project. Releasing versions is also an important way of communicating to your users that your package has changed (e.g., bugs have been fixed, new features have been added, etc.).\n", "\n", "In this chapter, we'll walk through the process of creating and releasing new versions of your Python package." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Version-numbering)=\n", "## Version numbering" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Versioning\\index{versioning} is the process of adding unique identifiers to different versions of your package. The unique identifier you use may be name-based or number-based, but most Python packages use [semantic versioning](https://semver.org)\\index{semantic versioning}. In semantic versioning, a version number consists of three integers A.B.C, where A is the \"major\" version, B is the \"minor\" version, and C is the \"patch\" version. The first version of a software usually starts at 0.1.0 and increments from there. We call an increment a \"bump\", and it consists of adding 1 to either the major, minor, or patch identifier as follows:\n", "\n", "- **Patch** release\\index{versioning!patch} (0.1.0 -> 0.1.**1**): patch releases are typically used for bug fixes, which are backward compatible. Backward compatibility refers to the compatibility of your package with previous versions of itself. For example, if a user was using v0.1.0 of your package, they should be able to upgrade to v0.1.1 and have any code they previously wrote still work. It's fine to have so many patch releases that you need to use two digits (e.g., 0.1.27).\n", "- **Minor** release\\index{versioning!minor} (0.1.0 -> 0.**2**.0): a minor release typically includes larger bug fixes or new features that are backward compatible, for example, the addition of a new function. It's fine to have so many minor releases that you need to use two digits (e.g., 0.13.0).\n", "- **Major** release\\index{versioning!major} (0.1.0 -> **1**.0.0): release 1.0.0 is typically used for the first stable release of your package. After that, major releases are made for changes that are not backward compatible and may affect many users. Changes that are not backward compatible are called \"breaking changes\". For example, changing the name of one of the modules in your package would be a breaking change; if users upgraded to your new package, any code they'd written using the old module name would no longer work, and they would have to change it.\n", "\n", "Most of the time, you'll be making patch and minor releases. We'll discuss major releases, breaking changes\\index{breaking change}, and how to deprecate package functionality (i.e., remove it) more in **{numref}`07:Breaking-changes-and-deprecating-package-functionality`**.\n", "\n", "Even with the guidelines above, versioning a package can be a little subjective and requires you to use your best judgment. For example, small packages might make a patch release for each individual bug fixed or a minor release for each new feature added. In contrast, larger packages will often group multiple bug fixes into a single patch release or multiple features into a single minor release, because making a release for every individual change would result in an overwhelming and confusing amount of releases! {numref}`07-release-table` shows some practical examples of major, minor, and patch releases made for the Python software itself. To formalize the circumstances under which different kinds of releases should be made, some developers create a \"version policy\" document for their package; the `pandas` [version policy](https://pandas.pydata.org/docs/development/policies.html#version-policy) is a good example of this.\n", "\n", "```{table} Examples of major, minor, and patch releases of Python.\n", ":name: 07-release-table\n", "|Release Type|Version Bump|Description|\n", "|:--- |:--- | :--- |\n", "|Major|2.X.X -> 3.0.0 (December, 2008)| This release included breaking changes, e.g., `print()` became a function, integer division resulted a float rather than an integer, built-in objects like dictionaries and strings changed considerably, and many old features were removed.|\n", "|Minor|3.8.X -> 3.9.0 (October, 2020)| New features and optimizations were added in this release, e.g., string methods to remove prefixes and suffixes (`.removeprefix()`/`.removesuffix()`) were added, and a new parser was implemented for CPython (the engine that compiles and executes your Python code).|\n", "|Patch|3.9.5 -> 3.9.6 (June, 2021)| This release contained bug and maintenance fixes, e.g., a confusing error message was updated in the `str.format()` method, and the version of `pip` bundled with Python downloads was updated from 21.1.2 -> 21.1.3, and parts of the documentation were updated.|\n", "```\n", "\n", "\\newpage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Version bumping" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "While we'll discuss the full workflow for releasing a new version of your package in **{numref}`07:Checklist-for-releasing-a-new-package-version`**, we first want to dicuss version bumping. That is, how to increment the version of your package when you're preparing a new release. This can be done manually or automatically as we'll show below." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Manual-version-bumping)=\n", "### Manual version bumping" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once you've decided what the new version\\index{versioning!manual} of your package will be (i.e., are you making a patch, minor, or major release) you need to update the package's version number in your source code. For a `poetry`-managed project\\index{poetry}, that information is in the *`pyproject.toml`* file\\index{pyproject.toml}. Consider the *`pyproject.toml`* file of the `pycounts` package we developed in **Chapter 3: {ref}`03:How-to-package-a-Python`**, the top of which looks like this:\n", "\n", "```{code-block} toml\n", "---\n", "emphasize-lines: 3\n", "---\n", "[tool.poetry]\n", "name = \"pycounts\"\n", "version = \"0.1.0\"\n", "description = \"Calculate word counts in a text file!\"\n", "authors = [\"Tomas Beuzen\"]\n", "license = \"MIT\"\n", "readme = \"README.md\"\n", "\n", "...rest of file hidden...\n", "```\n", "\n", "Imagine we wanted to make a patch release of our package. We could simply change the `version` number manually in this file to \"0.1.1\", and many developers do take this manual approach. An alternative method is to use the `poetry version` command. The `poetry version` command can be used with the arguments `patch`, `minor`, or `major` depending on how you want to update the version of your package. For example, to make a patch release, we could run the following at the command line:\n", "\n", "```{tip}\n", "If you're building the `pycounts` package with us in this book, you don't have to run the below command, it is just for demonstration purposes. We'll make a new version of `pycounts` later in this chapter.\n", "```\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry version patch\n", "```\n", "\n", "```md\n", "Bumping version from 0.1.0 to 0.1.1\n", "```\n", "\n", "This command changes the `version` variable in the `pyproject.toml` file:\n", "\n", "```{code-block} toml\n", "---\n", "emphasize-lines: 3\n", "---\n", "[tool.poetry]\n", "name = \"pycounts\"\n", "version = \"0.1.1\"\n", "description = \"Calculate word counts in a text file!\"\n", "authors = [\"Tomas Beuzen\"]\n", "license = \"MIT\"\n", "readme = \"README.md\"\n", "\n", "...rest of file hidden...\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Automatic-version-bumping)=\n", "### Automatic version bumping" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this book, we're interested in automating as much as possible of the packaging workflow. While the manual versioning approach described above in **{numref}`07:Manual-version-bumping`** is certainly used by many developers, we can do things more efficiently! To automate version bumping\\index{versioning!automatic}, you'll need to be using a version control system like Git. If you are not using version control\\index{version control} for your package, you can skip to **{numref}`07:Checklist-for-releasing-a-new-package-version`**.\n", "\n", "[Python Semantic Release\\index{versioning!Python Semantic Release}\\index{Python Semantic Release} (PSR)](https://python-semantic-release.readthedocs.io/en/latest/) is a tool that can automatically bump version numbers based on keywords it finds in commit messages. The idea is to use a standardized commit message format and syntax, which PSR can parse to determine how to increment the version number. The default commit message format used by PSR is the [Angular commit style](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format), which looks like this:\n", "\n", "```md\n", "(optional scope): short summary in present tense\n", "\n", "(optional body: explains motivation for the change)\n", "\n", "(optional footer: note BREAKING CHANGES here, and issues to be closed)\n", "```\n", "\n", "\\newpage\n", "\n", "`` refers to the kind of change made and is usually one of:\n", "\n", "- `feat`: A new feature.\n", "- `fix`: A bug fix.\n", "- `docs`: Documentation changes.\n", "- `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc).\n", "- `refactor`: A code change that neither fixes a bug nor adds a feature.\n", "- `perf`: A code change that improves performance.\n", "- `test`: Changes to the test framework.\n", "- `build`: Changes to the build process or tools.\n", "\n", "`scope` is an optional keyword that provides context for where the change was made. It can be anything relevant to your package or development workflow (e.g., it could be the module or function name affected by the change).\n", "\n", "Different text in the commit message will trigger PSR to make different kinds of releases:\n", "\n", "- A `` of `fix` triggers a patch version bump, e.g.:\n", "\n", " ```{prompt} bash \\$ auto\n", " $ git commit -m \"fix(mod_plotting): fix confusing error message in \\\n", " plot_words\"\n", " ```\n", "\n", "- A `` of `feat` triggers a minor version bump, e.g.:\n", "\n", " ```{prompt} bash \\$ auto\n", " $ git commit -m \"feat(package): add example data and new module to \\\n", " package\"\n", " ```\n", "\n", "- The text `BREAKING CHANGE:` in the `footer` will trigger a major release, e.g.: \n", "\n", " ```{prompt} bash \\$ auto\n", " $ git commit -m \"feat(mod_plotting): move code from plotting module \\\n", " to pycounts module\n", " $ \n", " $ BREAKING CHANGE: plotting module wont exist after this release.\"\n", " ```\n", "\n", "To use PSR we need to install and configure it. To install PSR as a development dependency of a `poetry`-managed project, you can use the following command:\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry add --group dev python-semantic-release\n", "```\n", "\n", "To configure PSR, we need to tell it where the version number of our package is stored. The package version is stored in the *`pyproject.toml`* file for a `poetry`-managed project. It exists as the variable `version` under the table `[tool.poetry]`. To tell PSR this, we need to add a new table to the *`pyproject.toml`* file called `[tool.semantic_release]` within which we specify that our `version_variable` is stored at `pyproject.toml:version`:\n", "\n", "```toml\n", "...rest of file hidden...\n", "\n", "[tool.semantic_release]\n", "version_variable = \"pyproject.toml:version\"\n", "```\n", "\n", "Finally, you can use the command `semantic-release version` at the command line to get PSR to automatically bump your package's version number. PSR will parse all the commit messages since the last tag of your package to determine what kind of version bump to make. For example, imagine the following three commit messages have been made since tag v0.1.0:\n", "\n", "```xml\n", "1. \"fix(mod_plotting): raise TypeError in plot_words\"\n", "2. \"fix(mod_plotting): fix confusing error message in plot_words\"\n", "3. \"feat(package): add example data and new module to package\"\n", "```\n", "\n", "PSR will note that there are two \"fix\" and one \"feat\" keywords. \"fix\" triggers a patch release, but \"feat\" triggers a minor release, which trumps a patch release, so PSR would make a minor version bump from v0.1.0 to v0.2.0.\n", "\n", "As a more practical demonstration of how PSR works, imagine we have a package at version 0.1.0, make a bug fix and commit our changes with the following message:\n", "\n", "```{tip}\n", "If you're building the `pycounts` package with us in this book, you don't have to run the below commands, they are just for demonstration purposes. We'll make a new version of `pycounts` later in this chapter.\n", "```\n", "\n", "```{prompt} bash \\$ auto\n", "$ git add src/pycounts/plotting.py\n", "$ git commit -m \"fix(code): change confusing error message in \\\n", " plotting.plot_words\"\n", "```\n", "\n", "We then run `semantic-release version` to update our version number. In the command below, we'll specify the argument `-v DEBUG` to ask PSR to print extra information to the screen so we can get an inside look at how PSR works:\n", "\n", "```{prompt} bash \\$ auto\n", "$ semantic-release version -v DEBUG\n", "```\n", "\n", "```md\n", "Creating new version\n", "debug: get_current_version_by_config_file()\n", "debug: Parsing current version: path=PosixPath('pyproject.toml')\n", "debug: Regex matched version: 0.1.0\n", "debug: get_current_version_by_config_file -> 0.1.0\n", "Current version: 0.1.0\n", "debug: evaluate_version_bump('0.1.0', None)\n", "debug: parse_commit_message('fix(code): change confusing error... )\n", "debug: parse_commit_message -> ParsedCommit(bump=1, type='fix')\n", "debug: Commits found since last release: 1\n", "debug: evaluate_version_bump -> patch\n", "debug: get_new_version('0.1.0', 'patch')\n", "debug: get_new_version -> 0.1.1\n", "debug: set_new_version('0.1.1')\n", "debug: Writing new version number: path=PosixPath('pyproject.toml')\n", "debug: set_new_version -> True\n", "debug: commit_new_version('0.1.1')\n", "debug: commit_new_version -> [main d82fa3f] 0.1.1\n", "debug: Author: semantic-release \n", "debug: 1 file changed, 5 insertions(+), 1 deletion(-)\n", "debug: tag_new_version('0.1.1')\n", "debug: tag_new_version -> \n", "Bumping with a patch version to 0.1.1\n", "```\n", "\n", "We can see that PSR found our commit messages, and decided that a patch release was necessary based on the text in the message. We can also see that command automatically updated the version number in the the *`pyproject.toml`* file and created a new version control tag for our package's source (we talked about tags in **{numref}`03:Tagging-a-package-release-with-version-control`**). In the next section, we'll go through a real example of using PSR with our `pycounts` package." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Checklist-for-releasing-a-new-package-version)=\n", "## Checklist for releasing a new package version" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we know about versioning and how to increment the version\\index{versioning} of our package, we're ready to run through a release checklist. We'll make a new minor release of the `pycounts` package we've been developing throughout this book, from v0.1.0 to v0.2.0, to demonstrate each step in the release checklist." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 1: make changes to package source files" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is an obvious one, but before you can make a new release, you need to make the changes to your package's source that will comprise your new release!\n", "\n", "Consider our `pycounts` package. We published the first release, v0.1.0, of our package in **Chapter 3: {ref}`03:How-to-package-a-Python`**. Since then, we've made a few changes. Specifically:\n", "\n", "- In **Chapter 4: {ref}`04:Package-structure-and-distribution`**, we added a new \"datasets\" module to our package along with some example data, a text file of the novel *Flatland* by Edwin Abbott{cite:p}`abbott1884`, that users could load to try out the functionality of our package.\n", "- In **Chapter 5: {ref}`05:Testing`**, we significantly upgraded our testing suite by adding several new unit, integration, and regression tests to the *`tests/test_pycounts.py`* file.\n", "\n", "```{tip}\n", "In practice, if you're using version control, changes are usually made to a package's source using [branches](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell). Branches isolate your changes so you can develop your package without affecting the existing, stable version. Only when you're happy with your changes do you merge them into the existing source.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 2: document your changes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before we make our new release, we should document everything we've changed in our changelog. For example, here's `pycounts`'s updated *`CHANGELOG.md`* file\\index{documentation!changelog}:\n", "\n", "```{tip}\n", "We talked about changelog file format and content in **{numref}`06:Changelog`**.\n", "```\n", "\n", "\\newpage\n", "\n", "```xml\n", "# Changelog\n", "\n", "\n", "\n", "## v0.2.0 (10/09/2021)\n", "\n", "### Feature\n", "\n", "- Added new datasets modules to load example data\n", "\n", "### Fix\n", "\n", "- Check type of argument passed to `plotting.plot_words()`\n", "\n", "### Tests\n", "\n", "- Added new tests to all package modules in test_pycounts.py\n", "\n", "## v0.1.0 (24/08/2021)\n", "\n", "- First release of `pycounts`\n", "```\n", "\n", "If using version control, you should commit this change to make sure it becomes part of your release:\n", "\n", "```{prompt} bash \\$ auto\n", "$ git add CHANGELOG.md\n", "$ git commit -m \"build: preparing for release v0.2.0\"\n", "$ git push\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 3: bump version number" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once your changes for the new release are ready, you need to bump the package version manually (**{numref}`07:Manual-version-bumping`**) or automatically with the PSR tool (**{numref}`07:Automatic-version-bumping`**).\n", "\n", "We'll take the automatic route using PSR\\index{versioning!Python Semantic Release}\\index{Python Semantic Release} here, but if you're not using Git as a version control system, you'll need to do this step manually. The changes we made to `pycounts`, described in the section above, constitute a minor release (we added a new feature to load example data and made some significant changes to our package's test framework). When we committed these changes in **{numref}`04:Version-control`** and **{numref}`05:Version-control`**, we did so with the following collection of commit messages:\n", "\n", "```{prompt} bash \\$ auto\n", "$ git commit -m \"feat: add example data and datasets module\"\n", "$ git commit -m \"test: add additional tests for all modules\"\n", "$ git commit -m \"fix: check input type to plot_words function\"\n", "```\n", "\n", "As we discussed in **{numref}`07:Automatic-version-bumping`**, PSR can automatically parse these commit messages to increment our package version for us. If you haven't already, install PSR as a development dependency using `poetry`:\n", "\n", "```{attention}\n", "If you're following on from **Chapter 3: {ref}`03:How-to-package-a-Python`** and created a virtual environment for your `pycounts` package using `conda`, as we did in **{numref}`03:Create-a-virtual-environment`**, be sure to activate that environment before continuing by running `conda activate pycounts` at the command line.\n", "```\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry add --group dev python-semantic-release\n", "```\n", "\n", "This command updated our recorded package dependencies in `pyproject.toml` and `poetry.lock`, so we should commit those changes to version control before we update our package version:\n", "\n", "```{prompt} bash \\$ auto\n", "$ git add pyproject.toml poetry.lock\n", "$ git commit -m \"build: add PSR as dev dependency\"\n", "$ git push\n", "```\n", "\n", "Now we can use PSR to automatically bump our package version with the `semantic-release version` command. If you want to see exactly what PSR found in your commit messages and why it decided to make a patch, minor, or major release, you can add the argument `-v DEBUG`.\n", "\n", "```{attention}\n", "Recall from **{numref}`07:Automatic-version-bumping`** that to use PSR, you need to tell it where your package's version number is stored by defining `version_variable = \"pyproject.toml:version\"` under the `[tool.semantic_release]` table in *`pyproject.toml`*.\n", "```\n", "\n", "```{prompt} bash \\$ auto\n", "$ semantic-release version\n", "```\n", "\n", "```md\n", "Creating new version\n", "Current version: 0.1.0\n", "Bumping with a minor version to 0.2.0\n", "```\n", "\n", "This step automatically updated our package's version in the *`pyproject.toml`* file and created a new tag for our package, \"v0.2.0\", which you could view by typing `git tag --list` at the command line:\n", "\n", "```{prompt} bash \\$ auto\n", "$ git tag --list\n", "```\n", "\n", "```md\n", "v0.1.0\n", "v0.2.0\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 4: run tests and build documentation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We've now prepped our package for release, but before we release it, it's important to check that its tests run and documentation builds successfully. To do this with our `pycounts` package, we should first install the package (we should re-install because we've created a new version):\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry install\n", "```\n", "\n", "```md\n", "Installing the current project: pycounts (0.2.0)\n", "```\n", "\n", "Now we'll check that our tests are still passing and what their coverage is using `pytest` and `pytest-cov` (we discussed these tools in **Chapter 5: {ref}`05:Testing`**):\n", "\n", "```{prompt} bash \\$ auto\n", "$ pytest tests/ --cov=pycounts\n", "```\n", "\n", "\\newpage\n", "\n", "```xml\n", "========================= test session starts =========================\n", "\n", "---------- coverage: platform darwin, python 3.9.6-final-0 -----------\n", "Name Stmts Miss Cover\n", "---------------------------------------------------\n", "src/pycounts/__init__.py 2 0 100%\n", "src/pycounts/data/__init__.py 0 0 100%\n", "src/pycounts/datasets.py 5 0 100%\n", "src/pycounts/plotting.py 12 0 100%\n", "src/pycounts/pycounts.py 16 0 100%\n", "---------------------------------------------------\n", "TOTAL 35 0 100%\n", "\n", "========================== 7 passed in 0.41s ==========================\n", "```\n", "\n", "Finally, to check that documentation still builds correctly you typically want to create the documentation from scratch, i.e., remove any existing built documentation in your package and then building it again. To do this, we first need to run `make clean` before running `make html` from the *`docs/`* directory (we discussed building documentation with these commands in **Chapter 6: {ref}`06:Documentation`**). In the spirit of efficiency we can combine these two commands together like we do below:\n", "\n", "```{prompt} bash \\$ auto\n", "$ cd docs\n", "$ make clean html\n", "```\n", "\n", "```md\n", "Running Sphinx\n", "...\n", "build succeeded.\n", "The HTML pages are in _build/html.\n", "```\n", "\n", "Looks like everything is working!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 5: tag a release with version control" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For those using remote version control on GitHub (or similar), it's time to tag\\index{version control!tag} a new release\\index{version control!release} of your repository on GitHub\\index{GitHub}. If you're not using version control, you can skip to the next section. We discussed how to tag a release and why we do this in **{numref}`03:Tagging-a-package-release-with-version-control`**. Recall that it's a two-step process:\n", "\n", "1. Create a tag marking a specific point in a repository's history using the command `git tag`.\n", "2. On GitHub, create a release of your repository based on the tag.\n", "\n", "If using PSR to bump your package version, then step 1 was done automatically for you. If you didn't use PSR, you can make a tag manually using the following command:\n", "\n", "```{prompt} bash \\$ auto\n", "$ git tag v0.2.0\n", "```\n", "\n", "You can now push any local commits and your new tag to GitHub with the following commands:\n", "\n", "```{prompt} bash \\$ auto\n", "$ git push\n", "$ git push --tags\n", "```\n", "\n", "After running those commands for our `pycounts` package, we can go to GitHub and navigate to the \"Releases\" tab to see our tag, as shown in {numref}`07-tag-fig`.\n", "\n", "```{figure} images/07-tag.png\n", "---\n", "width: 100%\n", "name: 07-tag-fig\n", "alt: Tag of v0.2.0 of pycounts on GitHub.\n", "---\n", "Tag of v0.2.0 of pycounts on GitHub.\n", "```\n", "\n", "\\newpage\n", "\n", "To create a release from this tag, click \"Draft a new release\". You can then identify the tag from which to create the release and optionally add a description of the release; often, this description links to the changelog, where changes have already been documented. {numref}`07-release-1-fig` shows the release of v0.2.0 of `pycounts` on GitHub.\n", "\n", "```{figure} images/07-release-1.png\n", "---\n", "width: 100%\n", "name: 07-release-1-fig\n", "alt: Release v0.2.0 of pycounts on GitHub.\n", "---\n", "Release v0.2.0 of pycounts on GitHub.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 6: build and release package to PyPI" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's now time to build the new distributions\\index{distribution} for our package (i.e., the sdist and wheel — we talked about these in **{numref}`04:Package-distribution-and-installation`**). We can do that with `poetry` using the following command run from the root package directory:\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry build\n", "```\n", "\n", "```md\n", "Building pycounts (0.2.0)\n", " - Building sdist\n", " - Built pycounts-0.2.0.tar.gz\n", " - Building wheel\n", " - Built pycounts-0.2.0-py3-none-any.whl\n", "```\n", "\n", "You can now use and share these distributions as you please, but most developers will want to upload them to PyPI, which is what we'll do here.\n", "\n", "As discussed in **{numref}`03:Publishing-to-TestPyPI`**, it's good practice to release your package on [TestPyPI](https://test.pypi.org/) before PyPI\\index{PyPI}, to test that everything is working as expected. We can do that with `poetry publish`:\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry publish -r test-pypi\n", "```\n", "\n", "```{attention}\n", "The above command assumes that you have added TestPyPI to the list of repositories `poetry` knows about via: `poetry config repositories.test-pypi https://test.pypi.org/legacy/`\n", "```\n", "\n", "Now you should be able to download your package from TestPyPI\\index{TestPyPI}:\n", "\n", "```{prompt} bash \\$ auto\n", "$ pip install --index-url https://test.pypi.org/simple/ \\\n", " --extra-index-url https://pypi.org/simple pycounts\n", "```\n", "\n", "```{note}\n", "By default `pip` will search PyPI for the named package. The argument `--index-url` points `pip` to the TestPyPI index instead. If your package has dependencies that are not on TestPyPI, you may need to tell `pip` to also search PyPI with the following argument: `--extra-index-url https://pypi.org/simple`.\n", "```\n", "\n", "If you're happy with how your newly versioned package is working, you can go ahead and publish to PyPI:\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry publish\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Automating releases" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you've seen in this chapter, there are quite a few steps to go through in order to make a new release of a package. In **Chapter 8: {ref}`08:Continuous-integration-and-deployment`** we'll see how we can automate the entire release process, including running tests, building documentation, and publishing to TestPyPI and PyPI." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Breaking-changes-and-deprecating-package-functionality)=\n", "## Breaking changes and deprecating package functionality" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As discussed earlier in the chapter, major version releases may come with backward incompatible changes, which we call \"breaking changes\\index{breaking change}\". Breaking changes affect your package's user base. The impact and importance of breaking changes is directly proportional to the number of people using your package. That's not to say that you should avoid breaking changes — there are good reasons for making them, such as improving software design mistakes, improving functionality, or making code simpler and easier to use.\n", "\n", "If you do need to make a breaking change, it is best to implement that change gradually, by providing adequate warning and advice to your package's user base through \"deprecation\\index{deprecation} warnings\".\n", "\n", "We can add a deprecation warning to our code by using the `warnings` [module](https://docs.python.org/3/library/warnings.html) from the Python standard library. For example, imagine that we want to remove the `get_flatland()` function from the `datasets` module of our `pycounts` package in the upcoming major v1.0.0 release. We can do this by adding a `FutureWarning` to our code, as shown in the *`datasets.py`* module below (we created this module back in **{numref}`04:Including-data-in-a-package`**).\n", "\n", "\\newpage\n", "\n", "```{tip}\n", "If you've used any larger Python libraries before (such as `NumPy`, `Pandas` or `scikit-learn`) you probably have seen deprecation warnings before! On that note, these large, established Python libraries offer great resources for learning how to properly manage your own package — don't be afraid to check out their source code and history on GitHub.\n", "```\n", "\n", "```{code-block} python\n", "---\n", "emphasize-lines: 2, 9-10 \n", "---\n", "from importlib import resources\n", "import warnings\n", "\n", "def get_flatland():\n", " \"\"\"Get path to example \"Flatland\" [1]_ text file.\n", "\n", " ...rest of docstring hidden...\n", " \"\"\"\n", " warnings.warn(\"This function will be deprecated in v1.0.0.\", \n", " FutureWarning)\n", " \n", " with resources.path(\"pycounts.data\", \"flatland.txt\") as f:\n", " data_file_path = f\n", " return data_file_path\n", "```\n", "\n", "If we were to try and use this function now, we would see the `FutureWarning` printed to our output:\n", "\n", "```{prompt} python >>> auto\n", ">>> from pycounts.datasets import get_flatland\n", ">>> flatland_path = get_flatland()\n", "```\n", "\n", "```md\n", "FutureWarning: This function will be deprecated in v1.0.0.\n", "```\n", "\n", "A few other things to think about when making breaking changes:\n", "\n", "- If you're changing a function significantly, consider keeping both the legacy version (with a deprecation warning) and new version of the function for a few releases to help users make a smoother transition to using the new function.\n", "- If you're deprecating a lot of code, consider doing it in small increments over multiple releases.\n", "- If your breaking change is a result of one of your package's dependencies changing, it is often better to warn your users that they require a newer version of a dependency rather than immediately making it a required dependency of your package.\n", "- Documentation is key! Don't be afraid to be verbose about documenting breaking changes in your package's documentation and changelog." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(07:Updating-dependencies)=\n", "## Updating dependency versions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If your package depends on other packages, like our `pycounts` package does, you'll need to think about updating your dependency version constraints as new versions of dependencies are released over time. This is true even for the version(s) of Python that your package supports.\n", "\n", "Luckily, `poetry` makes this a relatively simple process. The command `poetry update` can be used to update the version of installed dependencies in your virtual environment, within the constraints of the *`pyproject.toml`* file. This is useful for testing that your package works as expected with newer versions of its dependencies. For example, if we wanted to install the latest version of `matplotlib` compatible with our `pycounts` package, we could use the following code:\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry update matplotlib\n", "```\n", "\n", "However, `poetry update` won't update the constraints specified in your `pyproject.toml` file, or the metadata built into your package releases. To update that you have two options:\n", "\n", "1. Manually modify version constraints in *`pyproject.toml`*.\n", "2. Use `poetry add` to update a dependency to a specific version(s).\n", "\n", "For example, our current version constraint for `matplotlib` is shown in *`pyproject.toml`*:\n", "\n", "```toml\n", "[tool.poetry.dependencies]\n", "python = \">=3.9\"\n", "matplotlib = \">=3.4.3\"\n", "```\n", "\n", "If we wanted the minimum version of `matplotlib` to now be 3.5.0, we could manually adjust our *`pyproject.toml`* file as shown below:\n", "\n", "```toml\n", "[tool.poetry.dependencies]\n", "python = \">=3.9\"\n", "matplotlib = \">=3.5.0\"\n", "```\n", "\n", "Or we could run the following code:\n", "\n", "```{prompt} bash \\$ auto\n", "$ poetry add \"matplotlib>=3.5.0\"\n", "```\n", "\n", "```{note}\n", "We use double quotes in the command above because in many shells, like bash, `>` is a redirection operator. The double quotes are used to preserve the literal value of the contained characters (read more in the [documentation](http://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html)).\n", "```" ] } ], "metadata": { "celltoolbar": "Tags", "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.12" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "toc-autonumbering": false, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { "06e8b80b569b4ac2bb5a989af9695ced": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "height": "350px" } }, "07d43b717dd94d33a8eeae066f36d839": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "09294cf0fd6549c78d0f15acf20400b2": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "096724e20b094296bb243e553b2820e6": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "m", "layout": "IPY_MODEL_d2ef8aa5fad04047a98f733f89624812", "max": 2, "min": -2, "step": 0.1, "style": "IPY_MODEL_d3343e0c83844ad987beb592199dd6f6", "value": -0.1 } }, "0b412fd29e8a44f5bfaaa9a7122a33c3": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_1da474a760df45c3a290bbf3ba8a7f94", "IPY_MODEL_acc0b478d5b748c29c4683cbcfc8e0f3" ], "layout": "IPY_MODEL_9a4a74191d4b483f8e6ca535c155a33f" } }, "107d8e3c4e4249429f4ea5f86f97caa7": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "1455d02e130148c4a24a0943765db04a": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "1574978c1a56499dbe842cb3bf5b9e8f": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "16770b98026442368338a8d27ffceab4": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "1989b160147948d4a6414de3b6c60694": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "1a1f847a77d44da7977d6ed1ae70ac12": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "_dom_classes": [ "widget-interact" ], "children": [ "IPY_MODEL_884172dbe7194ea7aba24ace80d35049", "IPY_MODEL_384a6bfb62454f0bb09a41d14a5eb9c9", "IPY_MODEL_8cc71f1ee02d4a10acbda0a6f9cbc4fb" ], "layout": "IPY_MODEL_da554c291c9f4442991fcf6d620e017e" } }, "1cb1287d7a5940829cb770a5553a95b3": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "height": "350px" } }, "1da474a760df45c3a290bbf3ba8a7f94": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_323357ab97fc4ed0af4ab5743aa038cc", "style": "IPY_MODEL_64e2b864e41244388bcb173e865939f8" } }, "1ecb0c5110084d99bd02c6845b36b5f5": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "1ff35f5f7c9543158cd8fcb2fe45e951": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "200d9095bbf14c67af4083eebe042331": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_ce130e9bb1874109b6e9641a6f6b872a", "IPY_MODEL_544ffe02934f47abbe60aa68b1552268" ], "layout": "IPY_MODEL_2949d658a5e24ae8af8b48f1c68ca710" } }, "204835ba5cf741febeb96117f71f03db": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_e788ecb6fbad4de6aac05557dcf109f5", "style": "IPY_MODEL_871a273a718c4b7ab105f4bf6f9500e1" } }, "20f7461031e44d41bd5b14f4cdd8542a": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "24102f82e9cf49aca85e512f59a1db81": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "262d0a636bf64c67a8b3b7fdb6852569": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "2844ba0a05594aeeb871eaf4fae2c4b9": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "28a33b60ad9947cebcab993a3ecd7b01": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_1989b160147948d4a6414de3b6c60694", "style": "IPY_MODEL_f24ec537d93846e48f35cf5bca83e11d", "value": 40 } }, "2949d658a5e24ae8af8b48f1c68ca710": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "2ad8e9ec7f1d4f5f89fadb89c51892cd": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "m", "layout": "IPY_MODEL_3679e8d246954e7295c526cec653232b", "max": 2, "min": -2, "step": 0.1, "style": "IPY_MODEL_455179b0a10a4d3793163b6270e8c1d4" } }, "2be4850df84041778088cca110e64d11": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_3b84503a8368455bac727f95db5d01d0", "IPY_MODEL_5ed1935a5446410aa7103f97d2500695" ], "layout": "IPY_MODEL_5bc7f1fcf97f41fea3a8623cf73e21a3" } }, "2ec147d796d24e06a192384ff4f271d8": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_1ecb0c5110084d99bd02c6845b36b5f5", "style": "IPY_MODEL_750974cf708b48bcac5c4b3e178f9e34" } }, "323357ab97fc4ed0af4ab5743aa038cc": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "3679e8d246954e7295c526cec653232b": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "373d595c629d4c96ab6c69cabadfbae3": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "384a6bfb62454f0bb09a41d14a5eb9c9": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "b", "layout": "IPY_MODEL_79023cd4f95e412d86f33dacb04f9cce", "max": 3, "min": -3, "step": 0.5, "style": "IPY_MODEL_da243475d71a41f48bf4855c01052769" } }, "3966b0590b414fe1873b43e1835dbc0b": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "_dom_classes": [ "widget-interact" ], "children": [ "IPY_MODEL_096724e20b094296bb243e553b2820e6", "IPY_MODEL_890cbfc7c0f343d2b7991c18b88b8177", "IPY_MODEL_fcc376497f9d4b8aa11a102ebc19b6ab" ], "layout": "IPY_MODEL_ae6272a2743a4752b8798fed0b5dc332" } }, "39af2f7e78ff42679117a13c8e3e0c02": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_43d437e0efff40b0b7c59c66b9b815f5", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "3ac4ddb748c447f9903d248db1422cf1": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_b8aa32ebeb924971ade818f6af335eec", "IPY_MODEL_e6a05e8e4f6a4cefb61f5f99b1eb13c2" ], "layout": "IPY_MODEL_e57657510026435496e5903d5c875cbe" } }, "3b84503a8368455bac727f95db5d01d0": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_ce130e9bb1874109b6e9641a6f6b872a", "IPY_MODEL_544ffe02934f47abbe60aa68b1552268" ], "layout": "IPY_MODEL_20f7461031e44d41bd5b14f4cdd8542a" } }, "3ccc38f44df249cd833536b7a8a34327": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "4007d719e1aa45349acb4e9f80f0e4ba": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_2ec147d796d24e06a192384ff4f271d8", "IPY_MODEL_f285911bbe39497a88f0994509363fbb" ], "layout": "IPY_MODEL_9ecdf012164d45aaa03c28b34bebf7fa" } }, "42727846507043a098dc2e932813ee65": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_16770b98026442368338a8d27ffceab4", "style": "IPY_MODEL_b1e4ec6cae8d454999896d5ec41be03c" } }, "43d437e0efff40b0b7c59c66b9b815f5": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "454c456031894c1498a69aaa4dcb0e97": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "455179b0a10a4d3793163b6270e8c1d4": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "479edca2ec334d01b8af52d21f4c1565": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "494640e15fe7442ebfa3b6786ef64d82": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "4af9e16a11ed4597bbd81a734add4f5c": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_535d254dd54d41ada990b62be72d5a14", "IPY_MODEL_e6a05e8e4f6a4cefb61f5f99b1eb13c2" ], "layout": "IPY_MODEL_7415264924174df19d8822f16c379f55" } }, "4c8b0dc16ddc40af8b131803f5280311": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_edcfad1763d44bbab957f8d4f981f4e4", "IPY_MODEL_d11a21b0488f4970babc1c7ad3f86aa8" ], "layout": "IPY_MODEL_ef77db303b044fe783f80b51f045e866" } }, "4d8487b20ef9419aab03dcc0c813fc77": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_cf422506005a43978b50beb43766a819", "IPY_MODEL_78efe79186ed46c78e9d91400f519f1d" ], "layout": "IPY_MODEL_ce3b1869747b4502b90f4448204f5d94" } }, "4f613b87c7184b80bbc2806c184eb4cb": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_9053f57dacfc4255ad1dc0b717cbd4be", "IPY_MODEL_42727846507043a098dc2e932813ee65" ], "layout": "IPY_MODEL_8c5220ab1fe748d0abf46067668fd9d1" } }, "50f2a1ea21a24ed9a0db566a4678e24e": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_933e89a135cd42e196abb362e0302570", "style": "IPY_MODEL_b4ed787903d4445cb7fd4c6827acf9cd" } }, "527235c0249e4be68af5cc1b5f6ecaa8": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "535d254dd54d41ada990b62be72d5a14": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_50f2a1ea21a24ed9a0db566a4678e24e", "IPY_MODEL_bfe8c68e54b24762adb625e2d926bc2e" ], "layout": "IPY_MODEL_d9616e978f2840609e88757e2e7e47f3" } }, "544ffe02934f47abbe60aa68b1552268": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_7acc7084e5c34c5a9b18b84c2a78660b", "style": "IPY_MODEL_d10b5afbdea647baa88b2156fda8c6c0" } }, "54bac03c012745098c9455c5a2325e0a": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_1cb1287d7a5940829cb770a5553a95b3", "outputs": [ { "data": { "image/png": "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\n", "text/plain": "
" }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ] } }, "57c1af3db3d44cc7bfcfc97614bea646": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_9053341eacf94d139041e6aa7cc93233", "style": "IPY_MODEL_527235c0249e4be68af5cc1b5f6ecaa8", "value": 40 } }, "587b16eff8dc4011bcc72b4f4070b14d": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "58a162ea4105481e9d1345fdc79c9f1d": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "5ab9a789ce9a4e97845523051ef0762c": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_965ef0e308be48eaa8b8ef19c63bed40", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "5bc7f1fcf97f41fea3a8623cf73e21a3": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "5d02d239659c496cbb1972806465cbba": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "5d68805b72bd49498579e5c204071464": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_1da474a760df45c3a290bbf3ba8a7f94", "IPY_MODEL_acc0b478d5b748c29c4683cbcfc8e0f3" ], "layout": "IPY_MODEL_72b02467571a402da6d4414c5e4489fa" } }, "5e5877766afd49fcbb63cdbbff1f5684": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "b", "layout": "IPY_MODEL_1ff35f5f7c9543158cd8fcb2fe45e951", "max": 3, "min": -3, "step": 0.5, "style": "IPY_MODEL_7bc761c122284f8b9822ff186e0f78bd", "value": -1 } }, "5ed1935a5446410aa7103f97d2500695": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_262d0a636bf64c67a8b3b7fdb6852569", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "645724dd1b174799b0ff40a9e6d6ab62": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_98b7be5be6ad4194bafdff2ffd9a89f0", "IPY_MODEL_e5aa35e4f4aa46cf8044c66339de4b96" ], "layout": "IPY_MODEL_454c456031894c1498a69aaa4dcb0e97" } }, "64c7a0f8b8904b1ca743bc4911a341b2": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "64e2b864e41244388bcb173e865939f8": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "6991e87f25be44a78f759d7fd412588b": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "_dom_classes": [ "widget-interact" ], "children": [ "IPY_MODEL_2ad8e9ec7f1d4f5f89fadb89c51892cd", "IPY_MODEL_5e5877766afd49fcbb63cdbbff1f5684", "IPY_MODEL_81a51a474122457fa2f9da64776cf5d1" ], "layout": "IPY_MODEL_8a2b88d881b247d08b03cb1b7183128d" } }, "6a03b9b6618c43bb80bcccfc6f7c19f9": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "height": "350px" } }, "6b15b70b85584ce18f7b6efe71563f96": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "6c890acf62af426cab22ed65ff429088": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "6ffdc8fcab164aedbf54cf3a45384d64": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "72b02467571a402da6d4414c5e4489fa": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "7415264924174df19d8822f16c379f55": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "750974cf708b48bcac5c4b3e178f9e34": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "78efe79186ed46c78e9d91400f519f1d": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_fdfc64c80c3c407bacf0a395dede228c", "style": "IPY_MODEL_8b9cd3fe33484cb794a9c2a4d60caa9a" } }, "79023cd4f95e412d86f33dacb04f9cce": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "7a81ba3691dc47449c052dcd9070b618": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "m", "layout": "IPY_MODEL_ac55030546d54b0ca4d7e4fbf355a3c8", "max": 2, "min": -2, "step": 0.1, "style": "IPY_MODEL_6b15b70b85584ce18f7b6efe71563f96" } }, "7acc7084e5c34c5a9b18b84c2a78660b": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "7b066d9aaaa34fcda5803a72047566f0": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_d6b85a8f0ec64ee491848be1b8bf8188", "style": "IPY_MODEL_3ccc38f44df249cd833536b7a8a34327", "value": 40 } }, "7bc761c122284f8b9822ff186e0f78bd": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "7c23e7df356f475e994f2f3e70730747": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "7d29dde0dd4046fb9717131bf06b637f": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "b", "layout": "IPY_MODEL_b674d805670c4a969daa587ae7d22805", "max": 3, "min": -3, "step": 0.5, "style": "IPY_MODEL_494640e15fe7442ebfa3b6786ef64d82", "value": -1 } }, "81a51a474122457fa2f9da64776cf5d1": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_94487d6608754721aa3f4401e77dc292", "outputs": [ { "data": { "image/png": "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\n", "text/plain": "
" }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ] } }, "856e6ab0a1b14ac490277652b9beabf6": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_0b412fd29e8a44f5bfaaa9a7122a33c3", "IPY_MODEL_5ab9a789ce9a4e97845523051ef0762c" ], "layout": "IPY_MODEL_f55ac2b80afd433a919cc2d7ab87b098" } }, "871a273a718c4b7ab105f4bf6f9500e1": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "884172dbe7194ea7aba24ace80d35049": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "m", "layout": "IPY_MODEL_d2e7ead2f8d74c5180cbabbb30b674a8", "max": 2, "min": -2, "step": 0.1, "style": "IPY_MODEL_373d595c629d4c96ab6c69cabadfbae3" } }, "890cbfc7c0f343d2b7991c18b88b8177": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatSliderModel", "state": { "description": "b", "layout": "IPY_MODEL_24102f82e9cf49aca85e512f59a1db81", "max": 3, "min": -3, "step": 0.5, "style": "IPY_MODEL_64c7a0f8b8904b1ca743bc4911a341b2", "value": -0.5 } }, "8a2b88d881b247d08b03cb1b7183128d": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "8b9cd3fe33484cb794a9c2a4d60caa9a": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "8c5220ab1fe748d0abf46067668fd9d1": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "8cc71f1ee02d4a10acbda0a6f9cbc4fb": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_6a03b9b6618c43bb80bcccfc6f7c19f9", "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAD4CAYAAADxeG0DAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAANZklEQVR4nO3df6xkZ13H8ffHLsUEKrTuQku3uG0kxKIm4E2DgkpoU9paWzFqSqIWa7JBQwIJpmltgih/IRGNEW1WaPxBY6tCpZIS2Eob4x9Ubmt//6ALFula2osoxZCgDV//mLNmejt379ydM/fuV9+v5OaeOeeZ53znOed+5swzM7upKiRJfX3HThcgSVqMQS5JzRnkktScQS5JzRnkktTcrp3Y6e7du2vfvn07sWtJauvOO+/8alXtWb9+R4J83759rK6u7sSuJamtJF+atd6pFUlqziCXpOYMcklqziCXpOYMcklqziCXpOYMcklqziCXpOYMcklqziCXpOYMcklqziCXpOYMcklqziCXpOYMcklqziCXpOYMcklqbrQgT3JCkn9K8omx+pQkbW7MK/J3AA+N2J8kaQ6jBHmSvcBPAB8aoz9J0vzGuiL/PeBK4NsbNUiyP8lqktW1tbWRditJWjjIk1wMPFVVdx6tXVUdqKqVqlrZs2fPoruVJA3GuCJ/HXBJkseAG4A3JvnICP1KkuawcJBX1dVVtbeq9gGXAZ+pqp9fuDJJ0lz8HLkkNbdrzM6q6nbg9jH7lCQdnVfkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzRnkktScQS5JzS0c5EnOSHJbkgeTPJDkHWMUJkmaz64R+ngGeFdV3ZXkJODOJAer6sER+pYkbWLhK/KqeqKq7hqWvwE8BJy+aL+SpPmMOkeeZB/wauCOMfuVJG1stCBP8kLgo8A7q+rpGdv3J1lNsrq2tjbWbiXp/71RgjzJ85iE+PVV9bFZbarqQFWtVNXKnj17xtitJIlxPrUS4MPAQ1X1gcVLkiRtxRhX5K8DfgF4Y5K7h5+LRuhXkjSHhT9+WFX/AGSEWiRJx8BvdkpScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtScwa5JDVnkEtSc6MEeZILkjyS5FCSq8boU5I0n4WDPMkJwAeBC4GzgbckOXvRfiVJ89k1Qh/nAIeq6osASW4ALgUeHKHvZ/nNv32AB//16bG7laRtc/bLvovf+MlXjdrnGFMrpwNfnrr9+LDuWZLsT7KaZHVtbW2E3UqSYJwr8rlU1QHgAMDKykodSx9jP4tJ0v8FY1yRHwbOmLq9d1gnSdoGYwT554BXJDkzyYnAZcDNI/QrSZrDwlMrVfVMkrcDnwJOAK6rqgcWrkySNJdR5sir6hbgljH6kiRtjd/slKTmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJas4gl6TmDHJJam6hIE/y/iQPJ7k3yU1JXjxWYZKk+Sx6RX4Q+P6q+kHg88DVi5ckSdqKhYK8qj5dVc8MNz8L7F28JEnSVow5R34F8MkR+5MkzWHXZg2S3AqcOmPTNVX18aHNNcAzwPVH6Wc/sB/g5S9/+TEVK0l6rk2DvKrOO9r2JG8FLgbOrao6Sj8HgAMAKysrG7aTJG3NpkF+NEkuAK4EfryqvjlOSZKkrVh0jvwPgJOAg0nuTnLtCDVJkrZgoSvyqvresQqRJB0bv9kpSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc2NEuRJ3pWkkuweoz9J0vwWDvIkZwDnA/+yeDmSpK0a44r8d4ErgRqhL0nSFi0U5EkuBQ5X1T1ztN2fZDXJ6tra2iK7lSRN2bVZgyS3AqfO2HQN8OtMplU2VVUHgAMAKysrXr1L0kg2DfKqOm/W+iQ/AJwJ3JMEYC9wV5Jzquoro1YpSdrQpkG+kaq6D3jJkdtJHgNWquqrI9QlSZqTnyOXpOaO+Yp8varaN1ZfkqT5eUUuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUnEEuSc0Z5JLUXKq2//9BTrIGfOkY774bOB7/Oznr2hrr2hrr2prjtS5YrLbvqao961fuSJAvIslqVa3sdB3rWdfWWNfWWNfWHK91wXJqc2pFkpozyCWpuY5BfmCnC9iAdW2NdW2NdW3N8VoXLKG2dnPkkqRn63hFLkmaYpBLUnPHZZAn+dkkDyT5dpKVdduuTnIoySNJ3rTB/c9McsfQ7sYkJy6hxhuT3D38PJbk7g3aPZbkvqHd6th1zNjfe5Icnqrtog3aXTCM4aEkV21DXe9P8nCSe5PclOTFG7TblvHa7PEnef5wjA8N59K+ZdUytc8zktyW5MHh/H/HjDZvSPL1qeP77mXXNez3qMclE78/jNe9SV6zDTW9cmoc7k7ydJJ3rmuzbeOV5LokTyW5f2rdKUkOJnl0+H3yBve9fGjzaJLLt7zzqjrufoDvA14J3A6sTK0/G7gHeD5wJvAF4IQZ9/9L4LJh+VrgV5Zc7+8A795g22PA7m0cu/cAv7ZJmxOGsTsLOHEY07OXXNf5wK5h+X3A+3ZqvOZ5/MCvAtcOy5cBN27DsTsNeM2wfBLw+Rl1vQH4xHadT/MeF+Ai4JNAgNcCd2xzfScAX2HyhZkdGS/gx4DXAPdPrftt4Kph+apZ5z1wCvDF4ffJw/LJW9n3cXlFXlUPVdUjMzZdCtxQVd+qqn8GDgHnTDdIEuCNwF8Pq/4U+Kll1Trs7+eAv1jWPpbgHOBQVX2xqv4LuIHJ2C5NVX26qp4Zbn4W2LvM/W1insd/KZNzBybn0rnDsV6aqnqiqu4alr8BPAScvsx9juhS4M9q4rPAi5Octo37Pxf4QlUd6zfGF1ZVfw98bd3q6fNooyx6E3Cwqr5WVf8OHAQu2Mq+j8sgP4rTgS9P3X6c557o3w38x1RozGozph8FnqyqRzfYXsCnk9yZZP8S65j29uHl7XUbvJSbZxyX6QomV2+zbMd4zfP4/7fNcC59ncm5tS2GqZxXA3fM2PzDSe5J8skkr9qmkjY7Ljt9Tl3GxhdTOzFeR7y0qp4Ylr8CvHRGm4XHbtex1ba4JLcCp87YdE1VfXy765llzhrfwtGvxl9fVYeTvAQ4mOTh4Zl7KXUBfwS8l8kf3nuZTPtcscj+xqjryHgluQZ4Brh+g25GH69ukrwQ+Cjwzqp6et3mu5hMH/zn8P7H3wCv2IayjtvjMrwHdglw9YzNOzVez1FVlWQpn/fesSCvqvOO4W6HgTOmbu8d1k37NyYv63YNV1Kz2oxSY5JdwE8DP3SUPg4Pv59KchOTl/UL/QHMO3ZJ/hj4xIxN84zj6HUleStwMXBuDZODM/oYfbxmmOfxH2nz+HCcX8Tk3FqqJM9jEuLXV9XH1m+fDvaquiXJHybZXVVL/Qei5jguSzmn5nQhcFdVPbl+w06N15Qnk5xWVU8MU01PzWhzmMlc/hF7mbw/OLduUys3A5cNnyg4k8kz6z9ONxgC4jbgZ4ZVlwPLusI/D3i4qh6ftTHJC5KcdGSZyRt+989qO5Z185Jv3mB/nwNekcmne05k8rL05iXXdQFwJXBJVX1zgzbbNV7zPP6bmZw7MDmXPrPRk89Yhjn4DwMPVdUHNmhz6pG5+iTnMPkbXuoTzJzH5WbgF4dPr7wW+PrUlMKybfiqeCfGa53p82ijLPoUcH6Sk4ep0POHdfPbjndzj+Hd3zczmSf6FvAk8Kmpbdcw+cTBI8CFU+tvAV42LJ/FJOAPAX8FPH9Jdf4J8LZ1614G3DJVxz3DzwNMphiWPXZ/DtwH3DucRKetr2u4fRGTT0V8YZvqOsRkHvDu4efa9XVt53jNevzAbzF5ogH4zuHcOTScS2dtwxi9nsmU2L1T43QR8LYj5xnw9mFs7mHypvGPbENdM4/LuroCfHAYz/uY+rTZkmt7AZNgftHUuh0ZLyZPJk8A/z3k1y8zeV/l74BHgVuBU4a2K8CHpu57xXCuHQJ+aav79iv6ktRct6kVSdI6BrkkNWeQS1JzBrkkNWeQS1JzBrkkNWeQS1Jz/wOt0eLL/K7pHwAAAABJRU5ErkJggg==\n", "text/plain": "
" }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ] } }, "8dda8bf6c916451e91b96e56fc4d2a76": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "9053341eacf94d139041e6aa7cc93233": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "9053f57dacfc4255ad1dc0b717cbd4be": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_ef44415ff8dd456681965184a2a299e8", "style": "IPY_MODEL_cc29a198d1d44797a909ea9a68a5d484" } }, "907bd0f286754766afa0d6ba1612d301": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_4d8487b20ef9419aab03dcc0c813fc77", "IPY_MODEL_d11a21b0488f4970babc1c7ad3f86aa8" ], "layout": "IPY_MODEL_1574978c1a56499dbe842cb3bf5b9e8f" } }, "90a70b5f560f437f9bb9422a4a6f6592": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "933e89a135cd42e196abb362e0302570": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "935fac04b32e4e0b9e1f9ea118a04ee1": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_b9e169b8efac4eeb990ae37db1e8de12", "max": 200, "style": "IPY_MODEL_9927296f85f248858bdc0a0abcc67e94", "value": 100 } }, "94487d6608754721aa3f4401e77dc292": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "height": "350px" } }, "965ef0e308be48eaa8b8ef19c63bed40": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "97c973da7b714095959a2a66d7d28c65": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "98b7be5be6ad4194bafdff2ffd9a89f0": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_b12e150681c94126b68be84b0d7cf158", "IPY_MODEL_204835ba5cf741febeb96117f71f03db" ], "layout": "IPY_MODEL_7c23e7df356f475e994f2f3e70730747" } }, "9927296f85f248858bdc0a0abcc67e94": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "9a4a74191d4b483f8e6ca535c155a33f": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "9c4a507b139f440fabaa95140d4b2193": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "9ecdf012164d45aaa03c28b34bebf7fa": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "a5e552b00bc54d1991d64d1e61258563": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "_dom_classes": [ "widget-interact" ], "children": [ "IPY_MODEL_7a81ba3691dc47449c052dcd9070b618", "IPY_MODEL_7d29dde0dd4046fb9717131bf06b637f", "IPY_MODEL_54bac03c012745098c9455c5a2325e0a" ], "layout": "IPY_MODEL_2844ba0a05594aeeb871eaf4fae2c4b9" } }, "ac55030546d54b0ca4d7e4fbf355a3c8": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "acc0b478d5b748c29c4683cbcfc8e0f3": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_c69f7b00b5a54f60908cb3d92021daf6", "style": "IPY_MODEL_479edca2ec334d01b8af52d21f4c1565" } }, "ae6272a2743a4752b8798fed0b5dc332": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "b070d7bd6a794d2ba0242e4220af368f": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "b12e150681c94126b68be84b0d7cf158": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_1455d02e130148c4a24a0943765db04a", "style": "IPY_MODEL_c2bcf8f8ff7b4623a8311427461ec26b" } }, "b1e4ec6cae8d454999896d5ec41be03c": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "b4ed787903d4445cb7fd4c6827acf9cd": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "b65b837d3b614513bef7014f6e97b8be": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_d9226ab50b4a4df9bdd6574f239a76a5", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "b674d805670c4a969daa587ae7d22805": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "b8aa32ebeb924971ade818f6af335eec": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_50f2a1ea21a24ed9a0db566a4678e24e", "IPY_MODEL_bfe8c68e54b24762adb625e2d926bc2e" ], "layout": "IPY_MODEL_587b16eff8dc4011bcc72b4f4070b14d" } }, "b9e169b8efac4eeb990ae37db1e8de12": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "bba860475dc34aa295f004356f4c7e70": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_4f613b87c7184b80bbc2806c184eb4cb", "IPY_MODEL_b65b837d3b614513bef7014f6e97b8be" ], "layout": "IPY_MODEL_f128f679eeb840f88c63d5fb65e08abe" } }, "be52a81fc3e44efc8f0d70d81da55763": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_4007d719e1aa45349acb4e9f80f0e4ba", "IPY_MODEL_39af2f7e78ff42679117a13c8e3e0c02" ], "layout": "IPY_MODEL_90a70b5f560f437f9bb9422a4a6f6592" } }, "bf592509273c491c9496cc5bce017755": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_200d9095bbf14c67af4083eebe042331", "IPY_MODEL_5ed1935a5446410aa7103f97d2500695" ], "layout": "IPY_MODEL_b070d7bd6a794d2ba0242e4220af368f" } }, "bfe8c68e54b24762adb625e2d926bc2e": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_09294cf0fd6549c78d0f15acf20400b2", "style": "IPY_MODEL_d5700c1140ff4a598008ed28c45f7d25" } }, "c2bcf8f8ff7b4623a8311427461ec26b": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "c2cc4c190c324cc0a0ce9bf781a499eb": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "c69f7b00b5a54f60908cb3d92021daf6": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "cc29a198d1d44797a909ea9a68a5d484": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "cd9593419907498e8a80fa9fb7850749": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "ce130e9bb1874109b6e9641a6f6b872a": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_c2cc4c190c324cc0a0ce9bf781a499eb", "style": "IPY_MODEL_cd9593419907498e8a80fa9fb7850749" } }, "ce3b1869747b4502b90f4448204f5d94": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "cf422506005a43978b50beb43766a819": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_9c4a507b139f440fabaa95140d4b2193", "style": "IPY_MODEL_107d8e3c4e4249429f4ea5f86f97caa7" } }, "d10b5afbdea647baa88b2156fda8c6c0": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "d11a21b0488f4970babc1c7ad3f86aa8": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_97c973da7b714095959a2a66d7d28c65", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "d2a772f4a9db458db7a47d77c13dd3d5": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_6ffdc8fcab164aedbf54cf3a45384d64", "style": "IPY_MODEL_e0dea1c96cc34a53938b3f0c52e09fe1", "value": 40 } }, "d2e7ead2f8d74c5180cbabbb30b674a8": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d2ef8aa5fad04047a98f733f89624812": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d3343e0c83844ad987beb592199dd6f6": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "d5700c1140ff4a598008ed28c45f7d25": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "d67190fd827a4b1a8ca8079df64d0a0a": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d6b85a8f0ec64ee491848be1b8bf8188": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d9226ab50b4a4df9bdd6574f239a76a5": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d9616e978f2840609e88757e2e7e47f3": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "da243475d71a41f48bf4855c01052769": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "da554c291c9f4442991fcf6d620e017e": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "e0dea1c96cc34a53938b3f0c52e09fe1": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "e57657510026435496e5903d5c875cbe": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "e5aa35e4f4aa46cf8044c66339de4b96": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_fc608307f2064139ade48955ecbaf7e9", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "e6a05e8e4f6a4cefb61f5f99b1eb13c2": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_d67190fd827a4b1a8ca8079df64d0a0a", "outputs": [ { "name": "stdout", "output_type": "stream", "text": "0 * 0 = 0\n" } ] } }, "e788ecb6fbad4de6aac05557dcf109f5": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "ea2be2adfc72403eb1236220a37dfd36": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_5d68805b72bd49498579e5c204071464", "IPY_MODEL_5ab9a789ce9a4e97845523051ef0762c" ], "layout": "IPY_MODEL_6c890acf62af426cab22ed65ff429088" } }, "ec1db3073c594dac8b081d2ad5e072e1": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_5d02d239659c496cbb1972806465cbba", "style": "IPY_MODEL_58a162ea4105481e9d1345fdc79c9f1d", "value": 40 } }, "edcfad1763d44bbab957f8d4f981f4e4": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_cf422506005a43978b50beb43766a819", "IPY_MODEL_78efe79186ed46c78e9d91400f519f1d" ], "layout": "IPY_MODEL_fd89962cc1214dd7afd0ee8f6c352b76" } }, "ef44415ff8dd456681965184a2a299e8": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "ef77db303b044fe783f80b51f045e866": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "f128f679eeb840f88c63d5fb65e08abe": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "f24ec537d93846e48f35cf5bca83e11d": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "" } }, "f285911bbe39497a88f0994509363fbb": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntSliderModel", "state": { "layout": "IPY_MODEL_07d43b717dd94d33a8eeae066f36d839", "style": "IPY_MODEL_8dda8bf6c916451e91b96e56fc4d2a76" } }, "f55ac2b80afd433a919cc2d7ab87b098": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "fc608307f2064139ade48955ecbaf7e9": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "fcc376497f9d4b8aa11a102ebc19b6ab": { "model_module": "@jupyter-widgets/output", "model_module_version": "1.0.0", "model_name": "OutputModel", "state": { "layout": "IPY_MODEL_06e8b80b569b4ac2bb5a989af9695ced", "outputs": [ { "data": { "image/png": "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\n", "text/plain": "
" }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ] } }, "fd89962cc1214dd7afd0ee8f6c352b76": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "fdfc64c80c3c407bacf0a395dede228c": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} } }, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }