diff --git a/Python/Module2_EssentialsOfPython/Functions.md b/Python/Module2_EssentialsOfPython/Functions.md index 2ad15dda..2d670f3d 100644 --- a/Python/Module2_EssentialsOfPython/Functions.md +++ b/Python/Module2_EssentialsOfPython/Functions.md @@ -137,7 +137,7 @@ Write a function named `count_even`. It should accept one input argument, named ## The `return` Statement -In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the `None` object*. +In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the* `None` *object*. ```python # this function returns `None` diff --git a/Python/Module3_IntroducingNumpy/Broadcasting.md b/Python/Module3_IntroducingNumpy/Broadcasting.md index 5c8a96fc..cd83934a 100644 --- a/Python/Module3_IntroducingNumpy/Broadcasting.md +++ b/Python/Module3_IntroducingNumpy/Broadcasting.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.3.0 kernelspec: display_name: Python 3 language: python @@ -486,16 +486,16 @@ Performing this computation using for-loops proceeds as follows: def pairwise_dists_looped(x, y): """ Computing pairwise distances using for-loops - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # `dists[i, j]` will store the Euclidean # distance between `x[i]` and `y[j]` dists = np.empty((5, 6)) @@ -545,18 +545,18 @@ Voilà! We have produced the distances in a vectorized way. Let's write this out def pairwise_dists_crude(x, y): """ Computing pairwise distances using vectorization. - This method uses memory-inefficient broadcasting. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + This method uses memory-inefficient broadcasting. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # The use of `np.newaxis` here is equivalent to our # use of the `reshape` function return np.sqrt(np.sum((x[:, np.newaxis] - y[np.newaxis])**2, axis=2)) @@ -628,23 +628,23 @@ In total, we have successfully used vectorization to compute the all pairs of di ```python def pairwise_dists(x, y): - """ Computing pairwise distances using memory-efficient - vectorization. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + """ Computing pairwise distances using memory-efficient + vectorization. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" dists = -2 * np.matmul(x, y.T) - dists += np.sum(x**2, axis=1)[:, np.newaxis] + dists += np.sum(x**2, axis=1)[:, np.newaxis] dists += np.sum(y**2, axis=1) - return np.sqrt(dists) + return np.sqrt(dists) ``` diff --git a/Python/Module5_OddsAndEnds/Modules_and_Packages.md b/Python/Module5_OddsAndEnds/Modules_and_Packages.md index 3324669e..471e1a4e 100644 --- a/Python/Module5_OddsAndEnds/Modules_and_Packages.md +++ b/Python/Module5_OddsAndEnds/Modules_and_Packages.md @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.3.0 kernelspec: display_name: Python 3 language: python @@ -406,15 +406,15 @@ It must be mentioned that we are sweeping some details under the rug here. Insta ### Installing Your Own Python Package -Suppose that we are happy with the work we have done on our `face_detector` project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter's working directory. Here we will construct a basic setup script that will allow us to accomplish this. +Suppose that we are happy with the work we have done on our `face_detector` project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter's working directory. Here we will construct a basic setup script that will allow us to accomplish this. For completeness, we will also indicate how one would include a test suite alongside the source code in this directory structure. We note outright that the purpose of this section is strictly to provide you with the minimum set of instructions needed to install a package. We will not be diving into what is going on under the hood at all. Please refer to [An Introduction to Distutils](https://docs.python.org/3/distutils/introduction.html#an-introduction-to-distutils) and [Packaging Your Project](https://packaging.python.org/tutorials/packaging-projects/#packaging-your-project) for a deeper treatment of this topic. Carrying on, we will want to create a setup-script, `setup.py`, *in the same directory as our package*. That is, our directory structure should look like: ``` -- setup.py -- face_detection/ +- setup.py # script responsible for installing `face_detection` package +- face_detection/ # source code of `face_detection` package |-- __init__.py |-- utils.py |-- database.py @@ -423,23 +423,34 @@ Carrying on, we will want to create a setup-script, `setup.py`, *in the same dir |-- __init__.py |-- calibration.py |-- config.py +- tests/ # test-suite for `face_detection` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_utils.py + |-- test_database.py + |-- test_model.py + |-- camera/ + |-- test_calibration.py + |-- test_config.py ``` +A `tests/` directory can be included at the same directory level as `setup.py` and `face_detection/`. +This is the recommended structure for using [pytest](https://docs.pytest.org/en/latest/) as our test-runner. + The bare bones build script for preparing your package for installation, `setup.py`, is as follows: ```python # contents of setup.py -import setuptools +from setuptools import find_packages, setup -setuptools.setup( +setup( name="face_detection", - version="1.0", - packages=setuptools.find_packages(), + version="1.0.0", + packages=find_packages(exclude=["tests", "tests.*"]), + python_requires=">=3.5", ) ``` - - +The `exclude` expression is used to ensure that specific directories or files are not included in the installation of `face_detection`. We use `exclude=["tests", "tests.*"]` to avoid installing the test-suite alongside `face_detection`. If you read through the additional materials linked above, you will see that there are many more fields of optional information that can be provided in this setup script, such as the author name, any installation requirements that the package has, and more. @@ -447,7 +458,7 @@ If you read through the additional materials linked above, you will see that the Armed with this script, we are ready to install our package locally on our machine! In your terminal, navigate to the directory containing this setup script and your package that it being installed. Run ```shell -python setup.py install +pip install . ``` and voilà, your package `face_detection` will have been installed to site-packages. You are now free to import this package from any directory on your machine. In order to uninstall this package from your machine execute the following from your terminal: @@ -456,10 +467,10 @@ and voilà, your package `face_detection` will have been installed to site-packa pip uninstall face_detection ``` -One final but important detail. The installed version of your package will no longer "see" the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead you can install your package in develop mode, such that a symbolic link to your source code is placed in your site-packages. Thus any changes that you make to your code will immediately be reflected in your system-wide installation. Thus, instead of running `python setup.py install`, execute the following to install a package in develop mode: +One final but important detail: the installed version of your package will no longer "see" the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead, you can install your package in "development mode", such that a symbolic link to your source code is placed in your site-packages. Thus, any changes that you make to your code will immediately be reflected in your system-wide installation. You can add the `--editable` flag to pip to install a package in development mode: ```shell -python setup.py develop +pip install --editable . ``` diff --git a/Python/Module5_OddsAndEnds/Writing_Good_Code.md b/Python/Module5_OddsAndEnds/Writing_Good_Code.md index 1fb91532..43be9158 100644 --- a/Python/Module5_OddsAndEnds/Writing_Good_Code.md +++ b/Python/Module5_OddsAndEnds/Writing_Good_Code.md @@ -636,7 +636,7 @@ To be more concrete, let's revisit our `count_vowels` function: ```python def count_vowels(x: str, include_y: bool = False) -> int: - """Returns the number of vowels contained in `in_string`""" + """Returns the number of vowels contained in `x`""" vowels = set("aeiouAEIOU") if include_y: vowels.update("yY") @@ -774,14 +774,16 @@ def pairwise_dists(x: np.ndarray, y: np.ndarray) -> np.ndarray: Parameters ---------- x : numpy.ndarray, shape=(M, D) - An optional description of ``x`` + An array of M, D-dimensional vectors. + y : numpy.ndarray, shape=(N, D) - An optional description of ``y`` + An array of N, D-dimensional vectors. Returns ------- numpy.ndarray, shape=(M, N) - The pairwise distances + The pairwise distances between the M rows of ``x`` and the N + rows of ``y``. Notes ----- @@ -829,7 +831,7 @@ def compute_student_stats(grade_book: Dict[str, Iterable[float]], Parameters ---------- - grade_book : Dict[str, List[float]] + grade_book : Dict[str, Iterable[float]] The dictionary (name -> grades) of all of the students' grades. diff --git a/Python/Module6_Testing/Hypothesis.md b/Python/Module6_Testing/Hypothesis.md new file mode 100644 index 00000000..119f6b31 --- /dev/null +++ b/Python/Module6_Testing/Hypothesis.md @@ -0,0 +1,131 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python [conda env:.conda-jupy] * + language: python + name: conda-env-.conda-jupy-py +--- + + +.. meta:: + :description: Topic: Writing tests for your code, Difficulty: Easy, Category: Section + :keywords: test, automated, pytest, parametrize, fixture, suite, decorator, clean directory + + + +# Describing Data with Hypothesis + +It is often the case that the process of *describing our data* is by far the heaviest burden that we must bear when writing tests. This process of assessing "what variety of values should I test?", "have I thought of all the important edge-cases?", and "how much is 'enough'?" will crop up with nearly every test that we write. +Indeed, these are questions that you may have been asking yourself when writing `test_count_vowels_basic` and `test_merge_max_mappings` in the previous sections of this module. + +[Hypothesis](https://hypothesis.readthedocs.io/) is a powerful Python library that empowers us to write a _description_ (specification, to be more precise) of the data that we want to use to exercise our test. +It will then *generate* test cases that satisfy this description and will run our test on these cases. + +Let's look at a simple example of Hypothesis in action. +In the preceding section, we learned to use pytest's parameterization mechanism to test properties of code over a set of values. +For example, we wrote the following trivial test: + +```python +import pytest + +# A simple parameterized test that only tests a few, conservative inputs. +# Note that this test must be run by pytest to work properly +@pytest.mark.parametrize("size", [0, 1, 2, 3]) +def test_range_length(size): + assert len(range(size)) == size +``` + +which tests the property that `range(n)` has a length of `n` for any non-negative integer value of `n`. +Well, it isn't *really* testing this property for all non-negative integers; clearly it is only testing the values 0-3. +We should probably also check much larger numbers and perhaps traverse various orders of magnitude (i.e. factors of ten) in our parameterization scheme. +No matter what set of values we land on, it seems like we will have to eventually throw our hands up and say "okay, that seems good enough." + +Instead of manually specifying the data to pass to `test_range_length`, let's use Hypothesis to simply describe the data: + + + +```python +from hypothesis import given + +# Hypothesis provides so-called "strategies" for us +# to describe our data +import hypothesis.strategies as st + +# Using hypothesis to test any integer value in [0, 10 ** 10] +@given(size=st.integers(min_value=0, max_value=1E10)) +def test_range_length(size): + assert len(range(size)) == size +``` + + + +Here we have specified that the `size` value in our test should take on any integer value within $[0, 10^{10}]$. +We did this by using the `integers` "strategy" that is provided by Hypothesis: `st.integers(min_value=0, max_value=1E10)`. +When we execute the resulting test (which can simply be run within a Jupyter cell or via pytest), this will trigger Hypothesis to generate test cases based on this specification; +by default, Hypothesis will generate 100 test cases - an amount that we can configure - and will evaluate our test for each one of them. + +```python +# Running this test once will trigger Hypothesis to +# generate 100 values based on the description of our data, +# and it will execute the test using each one of those values +>>> test_range_length() +``` + +With great ease, we were able to replace our pytest-parameterized test, which only very sparsely tested the property at hand, with a much more robust, hypothesis-driven test. +This will be a recurring trend: we will generally produce much more robust tests by _describing_ our data with Hypothesis, rather than manually specifying test values. + +The rest of this section will be dedicated to learning about the Hypothesis library and how we can leverage it to write powerful tests. + + + +
+ +**Hypothesis is _very_ effective...**: + +You may be wondering why, in the preceding example, I arbitrarily picked $10^{10}$ as the upper bound to the integer-values to feed to the test. +I actually didn't write the test that way initially. +Instead, I wrote the more general test: + +```python +@given(size=st.integers(min_value=0)) +def test_range_length(size): + assert len(range(size)) == size +``` + +which places no formal upper bound on the integers that Hypothesis will generate. +However, this test immediately found an issue (I hesitate to call it an outright bug): + +```python +Falsifying example: test_range_length( + size=9223372036854775808, +) + +----> 3 assert len(range(size)) == size + +OverflowError: Python int too large to convert to C ssize_t +``` + +This reveals that the implementation of the built-in `len` function is such that it can only handle non-negative integers smaller than $2^{63}$ (i.e. it will only allocate 64 bits to represent a signed integer - one bit is used to store the sign of the number). +Hypothesis revealed this by generating the failing test case `size=9223372036854775808`, which is exactly $2^{63}$. +I did not want this error to distract from what is otherwise merely a simple example, but it is very important to point out. + +Hypothesis has a knack for catching these sorts of unexpected edge cases. +Now we know that `len(range(size)) == size` _does not_ hold for "arbitrary" non-negative integers! +(I wonder how many of the Python core developers know about this 😄). + + +
+ + +## Links to Official Documentation + +- [Hypothesis](https://hypothesis.readthedocs.io/) + + +## Reading Comprehension Solutions diff --git a/Python/Module6_Testing/Intro_to_Testing.md b/Python/Module6_Testing/Intro_to_Testing.md new file mode 100644 index 00000000..35231320 --- /dev/null +++ b/Python/Module6_Testing/Intro_to_Testing.md @@ -0,0 +1,565 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +.. meta:: + :description: Topic: Writing tests for your code, Difficulty: Easy, Category: Section + :keywords: test, automated, unit, assert + + +# Introduction to Testing + +This section will show us just how simple it is to write rudimentary tests. We need only recall some of Python's basic scoping rules and introduce ourselves to the `assert` statement to write a genuine test function. That being said, we will quickly encounter some important questions to ponder. How do we know that our tests work? And, how do we know that our tests are effective? These questions will drive us deeper into the world of testing. + +Before we hit the ground running, let's take a moment to consider some motivations for testing out code. + + +## Why Should We Write Tests? + +The fact of the matter is that it is intuitive for most people to test their code to some extent. +After writing, say, a new function, it is only natural to contrive an input to feed it, and to check that the function returns the output that we expected. +To the extent that one would want to see evidence that their code works, we need not motivate the importance of testing. + +Less obvious are the massive benefits that we stand to gain from automating this testing process. +By "automating", we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. +We will accumulate these test functions into a "test suite" that we can run quickly and repeatedly. + +There are plenty of practical details ahead for us to learn, so let's expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite: + +**It saves us lots of time**: + +> After you have devised a test scenario for your code, it may only take us a second or so to run it; perhaps we need only run a couple of Jupyter notebook cells to verify the output of our code. +> This, however, will quickly become unwieldy as we write more code and devise more test scenarios. +> Soon we will be dissuaded from running our tests, except for on rare occasions. +> +> With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x's...) will summarize the health of our project (insofar as our tests serve as good diagnostics). +> This, of course, also means that we will find and fix bugs much faster! +> In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost. + +**It increases the "shelf life" of our code:** + +> If you've ever dusted off a project that you haven't used for years (or perhaps only months or weeks...), you might know the tribulations of getting old code to work. +> Perhaps, in the interim, new versions of our project's dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project's code. +> And perhaps _we can't even remember_ all of the ways in which our project is supposed to work. +> Our test suite provides us with a simple and incisive way to dive back into our work. +> It will point us to any potential incompatibilities that have accumulated over time. +> It also provides us with a large collection of detailed use-cases of our code; +> we can read through our tests and remind ourselves of the inner-workings of our project. + + +**It will inform the design and usability of our project for the better:** + +> Although it may not be obvious from the outset, writing testable code leads to writing better code. +> This is, in part, because the process of writing tests gives us the opportunity to actually _use_ our code under varied circumstances. +> The process of writing tests will help us suss out bad design decisions and redundancies in our code. Ultimately, if _we_ find it frustrating to use our code within our tests, then surely others will find the code frustrating to use in applied settings. + +**It makes it easier for others to contribute to a project:** + +> Having a healthy test suite lowers the barrier to entry for a project. +> A contributor can rely on our project's tests to quickly check to see if their changes to our code have broken the project or changed any of its behavior in unexpected ways. + +This all sounds great, but where do we even start the process of writing a test suite? +Let's begin by seeing what constitutes a basic test function. + + + +## Writing Our First Tests + +### Our "Source Code" +We need some code to test. For the sake of this introduction, let's borrow a couple of functions that may look familiar from previous modules. +These will serve as our "source code"; i.e. these are functions that we have written for our project and that need to be tested. + +```python +# Defining functions that we will be testing + +def count_vowels(x, include_y=False): + """Returns the number of vowels contained in `x`. + + The vowel 'y' is included optionally. + + Parameters + ---------- + x : str + The input string + + include_y : bool, optional (default=False) + If `True` count y's as vowels + + Returns + ------- + vowel_count: int + + Examples + -------- + >>> count_vowels("happy") + 1 + >>> count_vowels("happy", include_y=True) + 2 + """ + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + return sum(1 for char in x if char in vowels) + + +def merge_max_mappings(dict1, dict2): + """ Merges two dictionaries based on the largest value + in a given mapping. + + Parameters + ---------- + dict1 : Dict[str, float] + dict2 : Dict[str, float] + + Returns + ------- + merged : Dict[str, float] + The dictionary containing all of the keys common + between `dict1` and `dict2`, retaining the largest + value from common mappings. + + Examples + -------- + >>> x = {"a": 1, "b": 2} + >>> y = {"b": 100, "c": -1} + >>> merge_max_mappings(x, y) + {'a': 1, 'b': 100, 'c': -1} + """ + # `dict(dict1)` makes a copy of `dict1`. We do this + # so that updating `merged` doesn't also update `dict1` + merged = dict(dict1) + for key, value in dict2.items(): + if key not in merged or value > merged[key]: + merged[key] = value + return merged +``` + +As always, it is useful for us to follow along with this material in a Jupyter notebook. +We ought to take time to define these functions and run inputs through them to make sure that we understand what they are doing. +Testing code that we don't understand is a lost cause! + + +### The Basic Anatomy of a Test + +Let's write a test for `count_vowels`. For our most basic test, we can simply call `count_vowels` under various contrived inputs and *assert* that it returns the expected output. +The desired behavior for this test function, upon being run, is to: + +- Raise an error if any of our assertions *failed* to hold true. +- Complete "silently" if all of our assertions hold true (i.e. our test function will simply [return None](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Functions.html#The-return-Statement)) + +Here, we will be making use of Python's `assert` statements, whose behavior will be easy to deduce from the context of this test alone. +We will be formally introduced to the `assert` statement soon. + +```python +# Writing a rudimentary test function for `count_vowels` + +def test_count_vowels_basic(): + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 +``` + +To run this test, we simply call the function: + +```python +# running our test function +>>> test_count_vowels_basic() # passes: returns None | fails: raises error +``` + +As described above, the fact our function runs and simply returns `None` (i.e. we see no output when we run this test in a console or notebook cell) means that our code has passed this test. We've written and run our very first test! It certainly isn't the most robust test, but it is a good start. + +Let's look more carefully at the structure of `test_count_vowels_basic`. +Note that this function doesn't take in any inputs; +thanks to [Python's scoping rules](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Scope.html), we can reference our `count_vowels` function within our test as long as it is defined in the same "namespace" as `test_count_vowels_basic`. +That is, we can either define `count_vowels` in the same .py file (or Jupyter notebook, if you are following along with this material in a notebook) as `test_count_vowels_basic`, or we can [import](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Import-Statements) `count_vowels`, from wherever it is defined, into the file containing our test. +The latter scenario is by far the most common one in practice. +More on this later. + + + +
+ +**Takeaway**: + +A "test function" is designed to provide an encapsulated "environment" (namespace to be more precise) in which we can exercise parts of our source code and assert that the code behaves as expected. The basic anatomy of a test function is such that it: + +- contains one or more `assert` statements, each of which will raise an error if our source code misbehaves +- simply returns `None` if all of the aforementioned assertions held true +- can be run end-to-end simply by calling the test function without passing it any parameters; we rely on Python's scoping rules to call our source code within the body of the test function without explicitly passing anything to said test function + +
+ + +
+ +**Reading Comprehension: Adding Assertions to a Test** + +Add an additional assertion to the body of `test_count_vowels_basic`, which tests that `count_vowels` handles empty-string (`""`) input appropriately. +Make sure to run your updated test to see if it passes. + +
+ + +
+ +**Reading Comprehension: The Basic Anatomy of a Test** + +Write a rudimentary test function for `merge_max_mappings`. This should adhere to the basic structure of a test function that we just laid out. See if you can think of some "edge cases" to test, which we may have overlooked when writing `merge_max_mappings`. + +
+ + +## The `assert` Statement +With our first test functions under our belt, it is time for us to clearly understand how `assert` statements work and how they should be used. + +Similar to `return`, `def`, or `if`, the term `assert` is a reserved term in the Python language. +It has the following specialized behavior: + +```python +# demonstrating the rudimentary behavior of the `assert` statement + +# asserting an expression whose boolean-value is `True` will complete "silently" +>>> assert 1 < 2 + +# asserting an expression whose boolean-value is `False` raises an error +>>> assert 2 < 1 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert 2 < 1 + +AssertionError: + +# we can include an error message with our assertion +>>> assert 0 in [1, 2, 3], "0 is not in the list" +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert 0 in [1, 2, 3], "0 is not in the list" + +AssertionError: 0 is not in the list +``` + +The general form of an assertion statement is: + +```python +assert [, ] +``` + +When an assertion statement is executed, the built-in `bool` function is called on the object that is returned by ``; if `bool()` returns `False`, then an `AssertionError` is raised. +If you included a string in the assertion statement - separated from `` by a comma - then this string will be printed as the error message. + +See that the assertion statement: +```python +assert expression, error_message +``` + +is effectively shorthand for the following code (barring some additional details): + +```python +# long-form equivalent of: `assert expression, error_message` +if bool(expression) is False: + raise AssertionError(error_message) +``` + + + +
+ +**Reading Comprehension: Assertions** + +Given the following objects: + +```python +a_list = [] +a_number = 22 +a_string = "abcdef" +``` + +Write two assertion statements with the respective behaviors: + +- asserts that `a_list` is _not_ empty +- asserts that the number of vowels in `a_string` is less than `a_number`; include an error message that prints the actual number of vowels + +
+ + + +#### What is the Purpose of an Assertion? +In our code, an assertion should be used as _a statement that is true unless there is a bug in our code_. +It is plain to see that the assertions in `test_count_vowels_basic` fit this description. +However, it can also be useful to include assertions within our source code itself. +For instance, we know that `count_vowels` should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string. +We can explicitly assert that this is the case: + +```python +# an example of including an assertion within our source code + +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + count = sum(1 for char in x if char in vowels) + + # This assertion should always be true: it is asserting that + # the internal logic of our function is correct + assert isinstance(count, int) and 0 <= count <= len(x) + return count +``` + +Note that this assertion *is not meant to check if the user passed bad inputs for* `x` *and* `include_y`. +Rather, it is meant to assert that our own internal logic holds true. + +Admittedly, the `count_vowels` function is simple enough that the inclusion of this assertion is rather pedantic. +That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base. +We will also see that keen use of assertions can make it much easier for us to write good tests. + +
+ +**Disabling Assertions**: + +Python code can be run in an "optimized" mode such that *all assertions are skipped by the Python interpreter during execution*. +This can be achieved by specifying the command line option `-O` (the letter "O", not zero), e.g.: + +```shell +python -O my_code.py +``` + +or by setting the `PYTHONOPTIMIZE` [environment variable](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE). + +The idea here is that we may want assertions within our source code to perform expensive checks to guarantee internal consistency within our code, and that we want the ability to forgo these checks when we are no longer debugging our code. +Because they can be skipped in this way, *assertions should never be used for practical error handling*. + +
+ + + +## Testing Our Tests + +It is surprisingly easy to unwittingly write a broken test: a test that always passes, or a test that simply doesn't exercise our code in the way that we had intended. +Broken tests are insidious; they are alarms that fail to sound when they are supposed to. +They create misdirection in the bug-finding process and can mask problems with our code. +**Thus, a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior so that we can verify that our test works.** +Once we confirm that our test does indeed raise an error as expected, we restore the function to its original form and re-run the test to see that it passes. + +A practical note: we ought to mutate our function in a way that is trivial to undo. We can make use of code-comments towards this end. +All [IDEs](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) have the ability to "block-comment" selected code. +In order to block-comment code in a Jupyter notebook code cell, highlight the lines of code and press `CTRL + /`. +The same key-combination will also un-comment a highlighted block of commented code. + + + +
+ +**Reading Comprehension: Testing Your Test via Manual Mutation** + +Temporarily change the body of `count_vowels` such that the second assertion in `test_count_vowels_basic` raises an error. +Run the test to confirm that the second assertion raises, +and then restore `count_vowels` to its original form. +Finally, rerun the test to see that `count_vowels` once again passes all of the assertions. + +Repeat this process given the test that you wrote for `merge_max_mappings`. +Try breaking the function such that it always merges in values from `dict2`, even if those values are smaller. + +
+ + + +
+ +**Mutation Testing**: + +There is an entire subfield of automated testing known as ["mutation testing"](https://en.wikipedia.org/wiki/Mutation_testing), where tools like [Cosmic Ray](https://cosmic-ray.readthedocs.io/en/latest/index.html) are used to make temporary, incisive mutations to your source code - like change a `+` to a `-` or change a `1` to a `-1` - and then run your test suite. +The idea here is that such mutations *ought to cause one or more of your tests to fail*. +A mutation that does not trigger at least one test failure is likely an indicator that your tests could stand to be more robust. + +Automated mutation testing tools might be a bit too "heavy duty" at this point in our testing journey, but they are great to keep in mind. + +
+ + +## Our Work, Cut Out + +We see now that the concept of a "test function" isn't all that fancy. +Compared to other code that we have written, writing a function that simply runs a handful of assertions is far from a heavy lift for us. +Of course, we must be diligent and take care to test our tests, but we can certainly manage this as well. +With this in hand, we should take stock of the work and challenges that lie in our path ahead. + +It is necessary that we evolve beyond manual testing. +There are multiple facets to this observation. +First, we must learn how to organize our test functions into a test suite that can be run in one fell swoop. +Next, it will become increasingly apparent that a test function often contains large amounts of redundant code shared across its litany of assertions. +We will want to "parametrize" our tests to distill them down to their most concise and functional forms. +Finally, and most importantly, it may already be evident that the process of contriving known inputs and outputs to use in our tests is a highly manual and tedious process; furthermore, it is a process that will become increasingly cumbersome as our source code becomes more sophisticated. +To combat this, we will seek out alternative, powerful testing methodologies, including property-based testing. + + +## Links to Official Documentation + +- [The assert statement](https://docs.python.org/3/reference/simple_stmts.html?highlight=assert#the-assert-statement) +- [PYTHONOPTIMIZE environment variable](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE) + + +## Reading Comprehension Solutions + + +**Adding Assertions to a Test: Solution** + +Add an additional assertion to the body of `test_count_vowels_basic`, which tests whether `count_vowels` handles the empty-string (`""`) case appropriately. +Make sure to run your updated test to see if it passes. + +```python +def test_count_vowels_basic(): + # test basic strings with uppercase and lowercase letters + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 + + # test empty strings + assert count_vowels("", include_y=False) == 0 + assert count_vowels("", include_y=True) == 0 +``` + +```python +# running the test in a notebook-cell: the function should simply return +# `None` if all assertions hold true +>>> test_count_vowels_basic() +``` + + + +**The Basic Anatomy of a Test: Solution** + +Write a rudimentary test function for `merge_max_mappings`. + +> Let's test the use case that is explicitly documented in the Examples section of the function's docstring. +> We can also test cases where one or both of the inputs are empty dictionaries. +> These can often be problematic edge cases that we didn't consider when writing our code. + +```python +def test_merge_max_mappings(): + # test documented behavior + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 20, "c": -1} + expected = {'a': 1, 'b': 20, 'c': -1} + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict1 + dict1 = {} + dict2 = {"a": 10.2, "f": -1.0} + expected = dict2 + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict2 + dict1 = {"a": 10.2, "f": -1.0} + dict2 = {} + expected = dict1 + assert merge_max_mappings(dict1, dict2) == expected + + # test both empty + dict1 = {} + dict2 = {} + expected = {} + assert merge_max_mappings(dict1, dict2) == expected +``` + +```python +# running the test (seeing no errors means the tests all passed) +>>> test_merge_max_mappings() +``` + + + +**Assertions: Solution** +```python +a_list = [] +a_number = 22 +a_string = "abcdef" +``` + +Assert that `a_list` is _not_ empty: + +```python +>>> assert a_list +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert a_list + +AssertionError: +``` + +> You may have written `assert len(a_list) > 0` - this is also correct. +> However, recall that calling `bool` on any sequence (list, tuple, string, etc.) will return `False` if the sequence is empty. +> This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - `bool` will be called on whatever the provided expression is. + +Assert that the number of vowels in `a_string` is fewer than `a_number`; include an error message that prints the actual number of vowels: + +```python +>>> assert count_vowels(a_string) < a_number, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}" +``` + +> Note that we make use of an [f-string](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) as a convenient means for writing an informative error message. + + + +**Testing Your Test via Manual Mutation: Solution** + +Temporarily change the body of `count_vowels` such that the _second_ assertion in `test_count_vowels_basic` raises an error. +> Let's comment out the `if include_y` block in our code. This should prevent us from counting y's, and thus should violate the second assertion in our test. + +```python +# Breaking the behavior of `include_y=True` +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + # if include_y: + # vowels.update("yY") + return sum(1 for char in x if char in vowels) +``` + +```python +# the second assertion should raise an error +>>> test_count_vowels_basic() +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 test_count_vowels_basic() + + in test_count_vowels_basic() + 1 def test_count_vowels_basic(): + 2 assert count_vowels("aA bB yY", include_y=False) == 2 +----> 3 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: +``` + +> See that the error output, which is called a "stack trace", indicates with an ASCII-arrow that our second assertion is the one that is failing. +> Thus, we can be confident that that assertion really does help to ensure that we are counting y's correctly. + +Restore `count_vowels` to its original form and rerun the test to see that `count_vowels` once again passes all of the assertions. + +> We simply un-comment the block of code and rerun our test. + +```python +# Restore the behavior of `include_y=True` +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + return sum(1 for char in x if char in vowels) +``` + +```python +# confirming that we restored the proper behavior in `count_vowels` +>>> test_count_vowels_basic() +``` + diff --git a/Python/Module6_Testing/Pytest.md b/Python/Module6_Testing/Pytest.md new file mode 100644 index 00000000..cf71bd70 --- /dev/null +++ b/Python/Module6_Testing/Pytest.md @@ -0,0 +1,753 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +.. meta:: + :description: Topic: Introducing the pytest framework, Difficulty: Easy, Category: Section + :keywords: test, automated, pytest, parametrize, fixture, suite, decorator, clean directory + + +# The pytest Framework + +Thus far, our process for running tests has been an entirely manual one. It is time for us to arrange our test functions into a proper "test suite" and to learn to leverage [the pytest framework](https://docs.pytest.org/en/latest/) to run them. +We will begin by reorganizing our source code to create an installable [Python package](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Packages). +We will then learn how to structure and run a test suite for this Python package, using pytest. + +The pytest framework does much more than just run tests; +for instance, it will enrich the assertions in our tests to produce verbose, informative error messages. +Furthermore it provides valuable means for enhancing our tests via mechanisms like fixtures and parameterizing decorators. +Ultimately, all of this functionality helps to eliminate manual and redundant aspects of the testing process. + + + +
+ +**Note** + +It can be useful to [create a separate conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) for the sake of this lesson, so that we can work through this material starting from a blank slate. +If you do create a new conda environment, be sure to activate that environment and install NumPy and Jupyter notebook: `conda install numpy notebook` +
+ + + +Let's install pytest. Installing from [the conda-forge channel](https://conda-forge.org/) will install the most up-to-date version of pytest. In a terminal where conda can be accessed, run: + +```shell +conda install -c conda-forge pytest +``` + +Or, pytest is installable via pip: + +```shell +pip install pytest +``` + + +
+ +**Regarding Alternative Testing Frameworks** (a note from the author of PLYMI): + +When sifting through tutorials, blogs, and videos about testing in Python, it is common to see `pytest` presented alongside, and on an equal footing with, the alternative testing frameworks: `nose` and `unittest`. +This strikes me as... bizarre. + +`unittest` is the testing framework that comes with the Python standard library. +As a test runner, its design is clunky, archaic, and, ironically, un-pythonic. +While [unittest.mock](https://docs.python.org/3/library/unittest.mock.html) provides extremely valuable functionality for advanced testing, all of its functionality can be leveraged while using pytest as your testing framework. + +`nose`, which simply extends the functionality of `unittest`, **is no longer being maintained**. +There is a project, "Nose2", which is carrying the torch of `nose`. However, this is a fledgling project in comparison with `pytest`. +As of writing this, `pytest` was downloaded 12 million times last month versus `nose2`'s 150 thousand downloads. + +The takeaway here is that, when it comes to picking a testing framework for Python, `pytest` is the clear choice. +Any discussion that you come across to the contrary is likely outdated. +
+ + +## Creating a Python Package with Tests + +It's time to create a proper test suite. +Before proceeding any further, we should reread the material presented in [Module 5 - Import: Modules and Packages](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html) and recall the essentials of import statements, modules, and Python packages. +This material serves as the foundation for this section. + +### Organizing our Source Code +Let's create a Python package, which we will call `plymi_mod6`, with the following directory structure: + +``` +project_dir/ # the "parent directory" houses our source code, tests, and all other relevant files + - setup.py # script responsible for installing `plymi_mod6` package + - plymi_mod6/ # directory containing source code of `plymi_mod6` package + |-- __init__.py + |-- basic_functions.py + |-- numpy_functions.py + - tests/ # test-suite for `plymi_mod6` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_basic_functions.py + |-- test_numpy_functions.py +``` + +A reference implementation of this package can be found [in this GitHub repository](https://github.com/rsokl/plymi_mod6). +Populate the `basic_functions.py` file with the two functions that we were using as our source code in the previous section: `count_vowels` and `merge_max_mappings`. +In the `numpy_functions.py` module, add the `pairwise_dists` function that appears in [Module 3's discussion of optimized pairwise distances](https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/Broadcasting.html#Optimized-Pairwise-Distances). +Don't forget to include `import numpy as np` in your script in accordance with how `pairwise_dists` calls NumPy functions. + +We have arranged these functions so that they can be imported from the `basic_functions` module and the `numpy_functions` module, respectively, which reside in our `plymi_mod6` package. +Let's fill out our `setup.py` script and install this package so that we can import it regardless of our current working directory. The content of `setup.py` will be: + +```python +from setuptools import find_packages, setup + +setup( + name="plymi_mod6", + packages=find_packages(exclude=["tests", "tests.*"]), + version="1.0.0", + author="Your Name", + description="A template Python package for learning about testing", + install_requires=["numpy >= 1.10.0"], + tests_require=["pytest>=5.3", "hypothesis>=5.0"], + python_requires=">=3.6", +) +``` + +This setup file dictates that a user must have Python 3.6+ installed - we will bar Python 3.5 and below so that we are free to make use of [f-strings](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) in our code, which were introduced in Python 3.6. Additionally, we will require pytest and hypothesis for running tests; the Hypothesis library will be introduced in a later section. + +Finally, let's install our package locally [in development mode](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Installing-Your-Own-Python-Package). +Navigate to the directory containing `setup.py` and run: + +```shell +pip install --editable . +``` + +Now, we should be able to start a python console, IPython console, or Jupyter notebook in any directory and import our package: + +```python +# checking that we can import our `plymi_mod6` package +>>> from plymi_mod6.basic_functions import count_vowels +>>> count_vowels("Happy birthday", include_y=True) +5 +``` + + + +## Populating and Running Our Test Suite + +pytest's [system for "test discovery"](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) is quite simple: +pytest need only be pointed to a directory with files named `test_*.py` in it, and it will find all of the functions in these files _whose names start with the word "test"_ and will run all such functions. + +Thus, let's populate the file ``test_basic_functions.py`` with the functions `test_count_vowels_basic` and `test_merge_max_mappings`, which we wrote in the previous section of this module: + +```python +# The contents of test_basic_functions.py + +# we must import the functions we are testing +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings + + +def test_count_vowels_basic(): + # test basic strings with uppercase and lowercase letters + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 + + # test empty strings + assert count_vowels("", include_y=False) == 0 + assert count_vowels("", include_y=True) == 0 + + +def test_merge_max_mappings(): + # test documented behavior + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 20, "c": -1} + expected = {'a': 1, 'b': 20, 'c': -1} + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict1 + dict1 = {} + dict2 = {"a": 10.2, "f": -1.0} + expected = dict2 + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict2 + dict1 = {"a": 10.2, "f": -1.0} + dict2 = {} + expected = dict1 + assert merge_max_mappings(dict1, dict2) == expected + + # test both empty + dict1 = {} + dict2 = {} + expected = {} + assert merge_max_mappings(dict1, dict2) == expected + +``` + +As described before, `count_vowels` and `merge_max_mappings` must both be imported from our `plymi_mod6` package, so that our functions are in the same namespace as our tests. +A reference implementation of `test_basic_functions.py` can be viewed [here](https://github.com/rsokl/plymi_mod6/blob/master/tests/test_basic_functions.py). +Finally, add a dummy test - a test function that will always pass - to `test_basic_numpy.py`. +We will replace this with a useful test later. + +Without further ado, let's run our test suite! In our terminal, with the appropriate conda environment active, we navigate to the root directory of the project, which contains the `tests/` directory, and run `pytest tests/`. +The following output should appear: + + +``` +$ pytest tests/ +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +rootdir: C:\Users\plymi_user\plymi_root_dir +collected 3 items + +tests\test_basic_functions.py .. [ 66%] +tests\test_basic_numpy.py . [100%] + +============================== 3 passed in 0.04s ============================== +``` + + +This output indicates that three test-functions were found across two files and that all of the tests "passed"; i.e. the functions ran without raising any errors. +The first two tests are located in `tests/test_basic_functions.py`; the two dots indicate that two functions were run, and the `[66%]` indicator simply denotes that the test-suite is 66% (two-thirds) complete. +The following reading comprehension problem will lead us to see what it looks like for pytest to report a failing test. + + +
+ +**Reading Comprehension: Running a Test Suite** + +Temporarily add a new "broken" test to `tests/test_basic_functions.py`. +The name that you give this test should adhere to pytest's simple rules for test-discovery. +Design the test function so that is sure to fail when it is run. + +Rerun your test suite and compare its output to what you saw before - is it easy to identify which test failed and what caused it to fail? +Make sure to remove this function from your test suite once you are finished answering this question. + +
+ + + +We can also direct pytest to run the tests in a specific .py file. For example, executing: + +```shell +pytest tests/test_basic_functions.py +``` + +will cue pytest to only run the tests in `test_basic_functions.py`. + +A key component to leveraging tests effectively is the ability to exercise one's tests repeatedly and rapidly with little manual overhead. +Clearly, pytest is instrumental toward this end - this framework makes the process of organizing and running our test suite exceedingly simple! +That being said, there will certainly be occasions when we want to run a _specific_ test function. +Suppose, for instance, that we are writing a new function, and repeatedly want to run one of our tests that is pointing to a bug in our work-in-progress. +We can leverage pytest in conjunction with [an IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) to run our tests in such incisive ways. + + +### Utilizing pytest within an IDE + +Both [PyCharm and VSCode](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) can be configured to make keen use of pytest. +The following images show a couple of the enhancements afforded to us by PyCharm; comparable features are available in VSCode. +The IDEs will "discover" tests, and provide us with the ability to run individual tests. +For example, in the following image, the green "play button" allows us to run `test_count_vowels_basic`. + + +
+

+Running an individual test in PyCharm +

+
+ + +Furthermore, IDEs can provide a rich tree view of all the tests that are being run. +This is especially useful as our test suite grows to contain a considerable number of tests. +In the following image, we see that `test_version` is failing - we can click on the failing test in this tree-view, and our IDE will navigate us directly to the failing test. + + +
+

+Viewing an enhanced tree-view of your test suite +

+
+ + +The first step for leveraging these features in your IDE is to enable the pytest framework in the IDE. +The following links point to detailed instructions for configuring pytest with PyCharm and VSCode, respectively: + +- [Running tests in PyCharm](https://www.jetbrains.com/help/pycharm/pytest.html) +- [Running tests in VSCode](https://code.visualstudio.com/docs/python/testing) + +These linked materials also include advanced details, like instructions for running tests in parallel, which are beyond the scope of this material but are useful nonetheless. + + +## Enhanced Testing with pytest + +In addition to providing us with a simple means for organizing and running our test suite, pytest has powerful features that will both simplify and enhance our tests. +We will now leverage these features in our test suite. + + +### Enriched Assertions + +A failing "bare" assertion - an `assert` statement without an error message - can be a frustrating thing. +Suppose, for instance, that one of our test-assertions about `count_vowels` fails: + +```python +# a failing assertion without an error message is not informative + +assert count_vowels("aA bB yY", include_y=True) == 4 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: +``` + +The problem with this bare assertion is that we don't know what `count_vowels("aA bB yY", include_y=True)` actually returned! +We now have to go through the trouble of starting a python console, importing this function, and calling it with this specific input in order to see what our function was actually returning. An obvious remedy to this is for us to write our own error message, but this too is quite cumbersome when we consider the large number of assertions that we are destined to write. + +Fortunately, pytest comes to the rescue: it will "hijack" any failing bare assertion and will _insert a useful error message for us_. +This is known as ["assertion introspection"](https://docs.pytest.org/en/latest/assert.html#assertion-introspection-details). +For example, if the aforementioned assertion failed when being run by pytest, we would see the following output: + +```python +# pytest will write informative error messages for us + +assert count_vowels("aA bB yY", include_y=True) == 4 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) +~\Learning_Python\Python\Module6_Testing\Untitled1.ipynb in +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: assert 2 == 4 + + where 2 = ('aA bB yY', include_y=True +``` + +See that the error message that pytest included for us indicates that `count_vowels("aA bB yY", include_y=True)` returned `2`, when we expected it to return `4`. +From this we might suspect that `count_vowels` is not counting y's correctly. + +Here are some more examples of "enriched assertions", as provided by pytest. +See that these error messages even provide useful "diffs", which specify specifically _how_ two similar objects differ, where possible. + +```python +# comparing unequal lists +assert [1, 2, 3] == [1, 2] +E Left contains one more item: 3 +E Full diff: +E - [1, 2, 3] +E ? --- +E + [1, 2] +``` + +```python +# comparing unequal dictionaries +assert {"a": 1, "b": 2} == {"a": 1, "b": 3} +E AssertionError: assert {'a': 1, 'b': 2} == {'a': 1, 'b': 3} +E Omitting 1 identical items, use -vv to show +E Differing items: +E {'b': 2} != {'b': 3} +E Full diff: +E - {'a': 1, 'b': 2} +E ? ^ +E + {'a': 1, 'b': 3}... +``` + +```python +# comparing unequal strings +assert "moo" == "moon" +E AssertionError: assert 'moo' == 'moon' +E - moo +E + moon +E ? + +``` + + + + +### Parameterized Tests + +Looking back to both `test_count_vowels_basic` and `test_merge_max_mappings`, we see that there is a lot of redundancy within the bodies of these test functions. +The assertions that we make within a given test-function share identical forms - they differ only in the parameters that we feed into our functions and their expected output. +Another shortcoming of this test-structure is that a failing assertion will block subsequent assertions from being evaluated. +That is, if the second assertion in `test_count_vowels_basic` fails, the third and fourth assertions will not be evaluated in that run. +This precludes us from potentially seeing useful patterns among the failing assertions. + +pytest provides a useful tool that will allow us to eliminate these structural shortcomings by transforming our test-functions into so-called _parameterized tests_. Let's parametrize the following test: + +```python +# a simple test with redundant assertions + +def test_range_length_unparameterized(): + assert len(range(0)) == 0 + assert len(range(1)) == 1 + assert len(range(2)) == 2 + assert len(range(3)) == 3 +``` + +This test is checking the property `len(range(n)) == n`, where `n` is any non-negative integer. +Thus, the parameter to be varied here is the "size" of the range-object being created. +Let's treat it as such by using pytest to write a parameterized test: + +```python +# parameterizing a test +import pytest + +# note that this test must be run by pytest to work properly +@pytest.mark.parametrize("size", [0, 1, 2, 3]) +def test_range_length(size): + assert len(range(size)) == size +``` + +Make note that a pytest-parameterized test must be run using pytest; an error will raise if we manually call `test_range_length()`. +When executed, pytest will treat this parameterized test as _four separate tests_ - one for each parameter value: + +``` +test_basic_functions.py::test_range_length[0] PASSED [ 25%] +test_basic_functions.py::test_range_length[1] PASSED [ 50%] +test_basic_functions.py::test_range_length[2] PASSED [ 75%] +test_basic_functions.py::test_range_length[3] PASSED [100%] +``` + +See that we have successfully eliminated the redundancy from `test_range_length`; +the body of the function now contains only a single assertion, making obvious the property that is being tested. +Furthermore, the four assertions are now being run independently from one another and thus we can potentially see patterns across multiple fail cases in concert. + + + +#### Decorators + +The syntax used to parameterize this test may look alien to us, as we have yet to encounter this construct thus far. +`pytest.mark.parameterize(...)` is a _decorator_ - an object that is used to "wrap" a function in order to transform its behavior. +The `pytest.mark.parameterize(...)` decorator wraps our test function so that pytest can call it multiple times, once for each parameter value. +The `@` character, in this context, denotes the application of a decorator: + +```python +# general syntax for applying a decorator to a function + +@the_decorator +def the_function_being_decorated(): + pass +``` + +For an in-depth discussion of decorators, please refer to [Real Python's Primer on decorators](https://realpython.com/primer-on-python-decorators/#simple-decorators). + + + +#### Parameterization Syntax + +The general form for creating a parameterizing decorator with *a single parameter*, as we formed above, is: + +```python +@pytest.mark.parametrize("", [, , ...]) +def test_function(): + ... +``` + +We will often have tests that require multiple parameters. +The general form for creating the parameterization decorator for $N$ parameters, +each of which assume $J$ values, is: + +```python +@pytest.mark.parametrize(", , [...], ", + [(, , [...], ), + (, , [...], ), + ... + (, , [...], ), + ]) +def test_function(, , [...], ): + ... +``` + +For example, let's take the following trivial test: + +```python +def test_inequality_unparameterized(): + assert 1 < 2 < 3 + assert 4 < 5 < 6 + assert 7 < 8 < 9 + assert 10 < 11 < 12 +``` + +and rewrite it in parameterized form. +The decorator will have three distinct parameters, and each parameter, let's simply call them `a`, `b`, and `c`, will take on four values. + +```python +# the parameterized form of `test_inequality_unparameterized` +@pytest.mark.parametrize("a, b, c", [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]) +def test_inequality(a, b, c): + assert a < b < c +``` + + +
+ +**Note** + +The formatting for multi-parameter tests can quickly become unwieldy. +It isn't always obvious where one should introduce line breaks and indentations to improve readability. +This is a place where the ["black" auto-formatter](https://black.readthedocs.io/en/stable/) really shines! +Black will make all of these formatting decisions for us - we can write our parameterized tests as haphazardly as we like and simply run black to format our code. +
+ + + +
+ +**Reading Comprehension: Parameterizing Tests** + +Rewrite `test_count_vowels_basic` as a parameterized test with the parameters: `input_string`, `include_y`, and `expected_count`. + +Rewrite `test_merge_max_mappings` as a parameterized test with the parameters: `dict_a`, `dict_b`, and `expected_merged`. + +Before rerunning `test_basic_functions.py` predict how many distinct test cases will be reported by pytest. + +
+ + + +Finally, you can apply multiple parameterizing decorators to a test so that pytest will run _all combinations of the respective parameter values_. + +```python +# testing all combinations of `x` and `y` +@pytest.mark.parametrize("x", [0, 1, 2]) +@pytest.mark.parametrize("y", [10, 20]) +def test_all_combinations(x, y): + # will run: + # x=0 y=10 + # x=0 y=20 + # x=1 y=10 + # x=1 y=20 + # x=2 y=10 + # x=2 y=20 + pass +``` + + +### Fixtures + +The final major pytest feature that we will discuss are "fixtures". +A fixture, roughly speaking, is a means by which we can share information and functionality across our tests. +Fixtures can be defined within our `conftest.py` file, and pytest will automatically "discover" them and make them available for use throughout our test suite in a convenient way. + +Exploring fixtures will quickly take us beyond our depths for the purposes of this introductory material, so we will only scratch the surface here. +We can read about advanced details of fixtures [here](https://docs.pytest.org/en/latest/fixture.html#fixture). + +Below are examples of two useful fixtures. + + +```python +# contents of conftest.py + +import os +import tempfile + +import pytest + +@pytest.fixture() +def cleandir(): + """ This fixture will use the stdlib `tempfile` module to + change the current working directory to a tmp-dir for the + duration of the test. + + Afterwards, the test session returns to its previous working + directory, and the temporary directory and its contents + will be automatically deleted. + + Yields + ------ + str + The name of the temporary directory.""" + with tempfile.TemporaryDirectory() as tmpdirname: + old_dir = os.getcwd() # get current working directory (cwd) + os.chdir(tmpdirname) # change cwd to the temp-directory + yield tmpdirname # yields control to the test to be run + os.chdir(old_dir) # restore the cwd to the original directory + # Leaving the context manager will prompt the deletion of the + # temporary directory and its contents. This cleanup will be + # triggered even if errors were raised during the test. + + +@pytest.fixture() +def dummy_email(): + """ This fixture will simply have pytest pass the string: + 'dummy.email@plymi.com' + to any test-function that has the parameter name `dummy_email` in + its signature. + """ + return "dummy.email@plymi.com" +``` + + + +The first one, `cleandir`, can be used in conjunction with tests that need to write files. +We don't want our tests to leave behind files on our machines; the `cleandir` fixture will ensure that our tests will write files to a temporary directory that will be deleted once the test is complete. + +Second is a simple fixture called `dummy_email`. +Suppose that our project needs to interact with a specific email address, suppose it's `dummy.email@plymi.com`, and that we have several tests that need access to this address. +This fixture will pass this address to any test function that has the parameter name `dummy_email` in its signature. + +A reference implementation of `conftest.py` in our project can be found [here](https://github.com/rsokl/plymi_mod6/blob/fixtures/tests/conftest.py). +Several reference tests that make use of these fixtures can be found [here](https://github.com/rsokl/plymi_mod6/blob/fixtures/tests/test_using_fixtures.py). + +Let's create a file `tests/test_using_fixtures.py`, and write some tests that put these fixtures to use: + +```python +# contents of test_using_fixtures.py +import pytest + +# When run, this test will be executed within a +# temporary directory that will automatically be +# deleted - along with all of its contents - once +# the test ends. +# +# Thus we can have this test write a file, and we +# need not worry about having it clean up after itself. +@pytest.mark.usefixtures("cleandir") +def test_writing_a_file(): + with open("a_text_file.txt", mode="w") as f: + f.write("hello world") + + with open("a_text_file.txt", mode="r") as f: + file_content = f.read() + + assert file_content == "hello world" + + +# We can use the `dummy_email` fixture to provide +# the same email address to many tests. In this +# way, if we need to change the email address, we +# can simply update the fixture and all of the tests +# will be affected by the update. +# +# Note that we don't need to use a decorator here. +# pytest is smart, and will see that the parameter-name +# `dummy_email` matches the name of our fixture. It will +# thus call these tests using the value returned by our +# fixture + +def test_email1(dummy_email): + assert "dummy" in dummy_email + + +def test_email2(dummy_email): + assert "plymi" in dummy_email + + +def test_email3(dummy_email): + assert ".com" in dummy_email +``` + + +## Links to Official Documentation + +- [pytest](https://docs.pytest.org/en/latest/) +- [pytest's system for test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) +- [Testing in PyCharm](https://www.jetbrains.com/help/pycharm/pytest.html) +- [Testing in VSCode](https://code.visualstudio.com/docs/python/testing) +- [Assertion introspection](https://docs.pytest.org/en/latest/assert.html#assertion-introspection-details) +- [Parameterizing tests](https://docs.pytest.org/en/latest/parametrize.html) +- [Fixtures](https://docs.pytest.org/en/latest/fixture.html#fixture) + + +## Reading Comprehension Solutions + + +**Running a Test Suite: Solution** + +> Let's add the test function `test_broken_function` to our test suite. +> We must include the word "test" in the function's name so that pytest will identify it as a test to run. +> There are limitless ways in which we can make this test fail; we'll introduce a trivial false-assertion: + +```python +def test_broken_function(): + assert [1, 2, 3] == [1, 2] +``` + +> After introducing this broken test into `test_basic_functions.py` , running our tests should result in the following output: + +``` +$ pytest tests/ +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +rootdir: C:\Users\plymi_user\plymi_root_dir +collected 4 items + +tests\test_basic_functions.py ..F [ 75%] +tests\test_basic_numpy.py . [100%] + +================================== FAILURES =================================== +____________________________ test_broken_function _____________________________ + + def test_broken_function(): +> assert [1, 2, 3] == [1, 2] +E assert [1, 2, 3] == [1, 2] +E Left contains one more item: 3 +E Use -v to get the full diff + +tests\test_basic_functions.py:40: AssertionError +========================= 1 failed, 3 passed in 0.07s ========================= +``` + +> Four tests were "discovered" and run by pytest. The pattern `..F` indicates that the first two tests in `test_basic_functions` passed and the third test failed. +> It then indicates which test failed, and specifically that the assertion was false because a length-2 list cannot be equal to a length-3 list. + + + +**Parameterizing Tests: Solution** + +A reference implementation for this solution within the `plymi_mod6` project can be found [here](https://github.com/rsokl/plymi_mod6/blob/parameterized/tests/test_basic_functions.py). + +The contents of `test_basic_functions.py`, rewritten to use pytest-parameterized tests: + +```python +import pytest +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings + + +@pytest.mark.parametrize( + "input_string, include_y, expected_count", + [("aA bB yY", False, 2), ("aA bB yY", True, 4), ("", False, 0), ("", True, 0)], +) +def test_count_vowels_basic(input_string, include_y, expected_count): + assert count_vowels(input_string, include_y) == expected_count + + +@pytest.mark.parametrize( + "dict_a, dict_b, expected_merged", + [ + (dict(a=1, b=2), dict(b=20, c=-1), dict(a=1, b=20, c=-1)), + (dict(), dict(b=20, c=-1), dict(b=20, c=-1)), + (dict(a=1, b=2), dict(), dict(a=1, b=2)), + (dict(), dict(), dict()), + ], +) +def test_merge_max_mappings(dict_a, dict_b, expected_merged): + assert merge_max_mappings(dict_a, dict_b) == expected_merged +``` + +Running these tests via pytest should produce eight distinct test-case: four for `test_count_vowels_basic` and four for `test_merge_max_mappings`. + +``` +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +cachedir: .pytest_cache +rootdir: C:\Users\plymi_user\Learning_Python\plymi_mod6_src +collecting ... collected 8 items + +test_basic_functions.py::test_count_vowels_basic[aA bB yY-False-2] PASSED [ 12%] +test_basic_functions.py::test_count_vowels_basic[aA bB yY-True-4] PASSED [ 25%] +test_basic_functions.py::test_count_vowels_basic[-False-0] PASSED [ 37%] +test_basic_functions.py::test_count_vowels_basic[-True-0] PASSED [ 50%] +test_basic_functions.py::test_merge_max_mappings[dict_a0-dict_b0-expected_merged0] PASSED [ 62%] +test_basic_functions.py::test_merge_max_mappings[dict_a1-dict_b1-expected_merged1] PASSED [ 75%] +test_basic_functions.py::test_merge_max_mappings[dict_a2-dict_b2-expected_merged2] PASSED [ 87%] +test_basic_functions.py::test_merge_max_mappings[dict_a3-dict_b3-expected_merged3] PASSED [100%] + +============================== 8 passed in 0.07s ============================== +``` + + diff --git a/Python/_build/_images/individual_test.png b/Python/_build/_images/individual_test.png new file mode 100644 index 00000000..381fba2d Binary files /dev/null and b/Python/_build/_images/individual_test.png differ diff --git a/Python/_build/_images/test_tree_view.png b/Python/_build/_images/test_tree_view.png new file mode 100644 index 00000000..5b352aa5 Binary files /dev/null and b/Python/_build/_images/test_tree_view.png differ diff --git a/Python/index.rst b/Python/index.rst index f8650de9..3274b75e 100644 --- a/Python/index.rst +++ b/Python/index.rst @@ -64,6 +64,7 @@ I started learning to use Python in graduate school for my physics research, and module_3_problems.rst module_4.rst module_5.rst + module_6.rst changes.rst Indices and tables diff --git a/Python/module_5.rst b/Python/module_5.rst index 0c0bf09f..63c8036d 100644 --- a/Python/module_5.rst +++ b/Python/module_5.rst @@ -1,5 +1,5 @@ Module 5: Odds and Ends -===================================== +======================= This module contains materials that are extraneous to the essentials of Python as a language and of NumPy, but are nonetheless critical to doing day-to-day work using these tools. The first section introduces some general guidelines for writing "good code". Specifically, it points you, the reader, to a style guide that many people in the Python community abide by. It also introduces a relatively new and increasingly-popular feature of Python, called type-hinting, which permits us to enhance our code with type-documentation annotations. The reader will also be introduced to NumPy's and Google's respective specifications for writing good docstrings. diff --git a/Python/module_6.rst b/Python/module_6.rst new file mode 100644 index 00000000..2b113105 --- /dev/null +++ b/Python/module_6.rst @@ -0,0 +1,21 @@ +Module 6: Testing Our Code +========================== +This module will introduce us to the critically-important and often-overlooked process of testing code. +We will begin by considering some general motivations for writing tests. +Next, we will study the basic anatomy of a test-function, including the :code:`assert` statement, which serves as the nucleus of our test functions. +Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework `pytest `_. +This will inform how we structure our tests alongside our Python project; with pytest, we can incisively run our tests with the press of a single button. +Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. +Finally, we will take a step back to consider some strategies for writing effective tests. +Among these is a methodology that is near and dear to my heart: property-based testing. +This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library `Hypothesis `_ waiting to greet us (adorned with the mad Hatter's cap and all). + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + Module6_Testing/Intro_to_Testing.md + Module6_Testing/Pytest.md + Module6_Testing/Hypothesis.md + + diff --git a/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree b/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree index 4ff5d28d..3ed93a2c 100644 Binary files a/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree and b/docs/.doctrees/Module2_EssentialsOfPython/Functions.doctree differ diff --git a/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree b/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree index 0375e784..dd124c77 100644 Binary files a/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree and b/docs/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree b/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree index df4f5a44..45dd3576 100644 Binary files a/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree and b/docs/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/Testing_Your_Code.doctree b/docs/.doctrees/Module5_OddsAndEnds/Testing_Your_Code.doctree deleted file mode 100644 index 2833f151..00000000 Binary files a/docs/.doctrees/Module5_OddsAndEnds/Testing_Your_Code.doctree and /dev/null differ diff --git a/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree b/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree index f513f21d..9e56eca8 100644 Binary files a/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree and b/docs/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree differ diff --git a/docs/.doctrees/Module6_Testing/Hypothesis.doctree b/docs/.doctrees/Module6_Testing/Hypothesis.doctree new file mode 100644 index 00000000..915c93b0 Binary files /dev/null and b/docs/.doctrees/Module6_Testing/Hypothesis.doctree differ diff --git a/docs/.doctrees/Module6_Testing/Intro_to_Testing.doctree b/docs/.doctrees/Module6_Testing/Intro_to_Testing.doctree new file mode 100644 index 00000000..e05ac85b Binary files /dev/null and b/docs/.doctrees/Module6_Testing/Intro_to_Testing.doctree differ diff --git a/docs/.doctrees/Module6_Testing/Pytest.doctree b/docs/.doctrees/Module6_Testing/Pytest.doctree new file mode 100644 index 00000000..2e73d66e Binary files /dev/null and b/docs/.doctrees/Module6_Testing/Pytest.doctree differ diff --git a/docs/.doctrees/environment.pickle b/docs/.doctrees/environment.pickle index 6adf0b07..b3b0b327 100644 Binary files a/docs/.doctrees/environment.pickle and b/docs/.doctrees/environment.pickle differ diff --git a/docs/.doctrees/index.doctree b/docs/.doctrees/index.doctree index 124b0996..b83baaab 100644 Binary files a/docs/.doctrees/index.doctree and b/docs/.doctrees/index.doctree differ diff --git a/docs/.doctrees/module_6.doctree b/docs/.doctrees/module_6.doctree new file mode 100644 index 00000000..a783bac5 Binary files /dev/null and b/docs/.doctrees/module_6.doctree differ diff --git a/docs/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html b/docs/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html index 0093cf28..0f8e9a58 100644 --- a/docs/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html +++ b/docs/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html @@ -97,6 +97,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/GettingStartedWithPython.html b/docs/Module1_GettingStartedWithPython/GettingStartedWithPython.html index d6e0e87c..25adba2a 100644 --- a/docs/Module1_GettingStartedWithPython/GettingStartedWithPython.html +++ b/docs/Module1_GettingStartedWithPython/GettingStartedWithPython.html @@ -116,6 +116,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html b/docs/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html index 462d4d3a..e881b7e5 100644 --- a/docs/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html +++ b/docs/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html @@ -116,6 +116,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/Informal_Intro_Python.html b/docs/Module1_GettingStartedWithPython/Informal_Intro_Python.html index 124649a1..d168f12b 100644 --- a/docs/Module1_GettingStartedWithPython/Informal_Intro_Python.html +++ b/docs/Module1_GettingStartedWithPython/Informal_Intro_Python.html @@ -114,6 +114,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/Installing_Python.html b/docs/Module1_GettingStartedWithPython/Installing_Python.html index 75e705e7..2e3c24d9 100644 --- a/docs/Module1_GettingStartedWithPython/Installing_Python.html +++ b/docs/Module1_GettingStartedWithPython/Installing_Python.html @@ -114,6 +114,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/Jupyter_Notebooks.html b/docs/Module1_GettingStartedWithPython/Jupyter_Notebooks.html index a19840ae..3ce18f47 100644 --- a/docs/Module1_GettingStartedWithPython/Jupyter_Notebooks.html +++ b/docs/Module1_GettingStartedWithPython/Jupyter_Notebooks.html @@ -121,6 +121,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html b/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html index cd00735a..e5311491 100644 --- a/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html +++ b/docs/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html @@ -97,6 +97,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module1_GettingStartedWithPython/SiteFormatting.html b/docs/Module1_GettingStartedWithPython/SiteFormatting.html index e881b672..64fbbcb1 100644 --- a/docs/Module1_GettingStartedWithPython/SiteFormatting.html +++ b/docs/Module1_GettingStartedWithPython/SiteFormatting.html @@ -109,6 +109,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Basic_Objects.html b/docs/Module2_EssentialsOfPython/Basic_Objects.html index 7da982d7..20e13803 100644 --- a/docs/Module2_EssentialsOfPython/Basic_Objects.html +++ b/docs/Module2_EssentialsOfPython/Basic_Objects.html @@ -150,6 +150,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/ConditionalStatements.html b/docs/Module2_EssentialsOfPython/ConditionalStatements.html index 70f5d637..781a1ad1 100644 --- a/docs/Module2_EssentialsOfPython/ConditionalStatements.html +++ b/docs/Module2_EssentialsOfPython/ConditionalStatements.html @@ -128,6 +128,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/DataStructures.html b/docs/Module2_EssentialsOfPython/DataStructures.html index 58596593..976f489c 100644 --- a/docs/Module2_EssentialsOfPython/DataStructures.html +++ b/docs/Module2_EssentialsOfPython/DataStructures.html @@ -125,6 +125,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html b/docs/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html index bcfbb213..227ae5c5 100644 --- a/docs/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html +++ b/docs/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html @@ -133,6 +133,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html b/docs/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html index 15f374d6..7e3a5e41 100644 --- a/docs/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html +++ b/docs/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html @@ -134,6 +134,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/ForLoops.html b/docs/Module2_EssentialsOfPython/ForLoops.html index 427598fe..f4eeb998 100644 --- a/docs/Module2_EssentialsOfPython/ForLoops.html +++ b/docs/Module2_EssentialsOfPython/ForLoops.html @@ -127,6 +127,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Functions.html b/docs/Module2_EssentialsOfPython/Functions.html index af180b17..dc1e1c9b 100644 --- a/docs/Module2_EssentialsOfPython/Functions.html +++ b/docs/Module2_EssentialsOfPython/Functions.html @@ -136,6 +136,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • @@ -322,7 +323,7 @@

    The def<

    The return Statement

    -

    In general, any Python object can follow a function’s return statement. Furthermore, an empty return statement can be specified, or the return statement of a function can be omitted altogether. In both of these cases, the function will return the ``None`` object.

    +

    In general, any Python object can follow a function’s return statement. Furthermore, an empty return statement can be specified, or the return statement of a function can be omitted altogether. In both of these cases, the function will return the None object.

    # this function returns `None`
     # an "empty" return statement
     def f():
    diff --git a/docs/Module2_EssentialsOfPython/Generators_and_Comprehensions.html b/docs/Module2_EssentialsOfPython/Generators_and_Comprehensions.html
    index 5a1c11b9..8df08021 100644
    --- a/docs/Module2_EssentialsOfPython/Generators_and_Comprehensions.html
    +++ b/docs/Module2_EssentialsOfPython/Generators_and_Comprehensions.html
    @@ -140,6 +140,7 @@
     
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Introduction.html b/docs/Module2_EssentialsOfPython/Introduction.html index 50774bbd..22813573 100644 --- a/docs/Module2_EssentialsOfPython/Introduction.html +++ b/docs/Module2_EssentialsOfPython/Introduction.html @@ -120,6 +120,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Iterables.html b/docs/Module2_EssentialsOfPython/Iterables.html index 3f9e5f4c..e2b0856a 100644 --- a/docs/Module2_EssentialsOfPython/Iterables.html +++ b/docs/Module2_EssentialsOfPython/Iterables.html @@ -127,6 +127,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Itertools.html b/docs/Module2_EssentialsOfPython/Itertools.html index 8d46448a..77170ab2 100644 --- a/docs/Module2_EssentialsOfPython/Itertools.html +++ b/docs/Module2_EssentialsOfPython/Itertools.html @@ -121,6 +121,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Problems/DifferenceFanout.html b/docs/Module2_EssentialsOfPython/Problems/DifferenceFanout.html index aba13461..4d012f2f 100644 --- a/docs/Module2_EssentialsOfPython/Problems/DifferenceFanout.html +++ b/docs/Module2_EssentialsOfPython/Problems/DifferenceFanout.html @@ -113,6 +113,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Problems/EncodeAsString.html b/docs/Module2_EssentialsOfPython/Problems/EncodeAsString.html index f93b0e70..0ececc7a 100644 --- a/docs/Module2_EssentialsOfPython/Problems/EncodeAsString.html +++ b/docs/Module2_EssentialsOfPython/Problems/EncodeAsString.html @@ -111,6 +111,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Problems/MarginPercentage.html b/docs/Module2_EssentialsOfPython/Problems/MarginPercentage.html index cbb0dd6c..936c4001 100644 --- a/docs/Module2_EssentialsOfPython/Problems/MarginPercentage.html +++ b/docs/Module2_EssentialsOfPython/Problems/MarginPercentage.html @@ -111,6 +111,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html b/docs/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html index 506ef56e..1c9ef3fc 100644 --- a/docs/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html +++ b/docs/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html @@ -120,6 +120,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Problems/Palindrome.html b/docs/Module2_EssentialsOfPython/Problems/Palindrome.html index d8cf34b8..fc385d90 100644 --- a/docs/Module2_EssentialsOfPython/Problems/Palindrome.html +++ b/docs/Module2_EssentialsOfPython/Problems/Palindrome.html @@ -112,6 +112,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Scope.html b/docs/Module2_EssentialsOfPython/Scope.html index c8166c0c..9e71fc5c 100644 --- a/docs/Module2_EssentialsOfPython/Scope.html +++ b/docs/Module2_EssentialsOfPython/Scope.html @@ -121,6 +121,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/SequenceTypes.html b/docs/Module2_EssentialsOfPython/SequenceTypes.html index 2ca34486..eaee9f65 100644 --- a/docs/Module2_EssentialsOfPython/SequenceTypes.html +++ b/docs/Module2_EssentialsOfPython/SequenceTypes.html @@ -128,6 +128,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module2_EssentialsOfPython/Variables_and_Assignment.html b/docs/Module2_EssentialsOfPython/Variables_and_Assignment.html index 214a9b86..609d582d 100644 --- a/docs/Module2_EssentialsOfPython/Variables_and_Assignment.html +++ b/docs/Module2_EssentialsOfPython/Variables_and_Assignment.html @@ -126,6 +126,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html b/docs/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html index 9fd45a6a..e3e9f094 100644 --- a/docs/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html +++ b/docs/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html @@ -130,6 +130,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/AdvancedIndexing.html b/docs/Module3_IntroducingNumpy/AdvancedIndexing.html index 8ae0efff..32cfd621 100644 --- a/docs/Module3_IntroducingNumpy/AdvancedIndexing.html +++ b/docs/Module3_IntroducingNumpy/AdvancedIndexing.html @@ -124,6 +124,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/ArrayTraversal.html b/docs/Module3_IntroducingNumpy/ArrayTraversal.html index 8760df27..bc800fae 100644 --- a/docs/Module3_IntroducingNumpy/ArrayTraversal.html +++ b/docs/Module3_IntroducingNumpy/ArrayTraversal.html @@ -116,6 +116,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/BasicArrayAttributes.html b/docs/Module3_IntroducingNumpy/BasicArrayAttributes.html index b4b322dc..750c926f 100644 --- a/docs/Module3_IntroducingNumpy/BasicArrayAttributes.html +++ b/docs/Module3_IntroducingNumpy/BasicArrayAttributes.html @@ -115,6 +115,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/BasicIndexing.html b/docs/Module3_IntroducingNumpy/BasicIndexing.html index 18fc5b5d..80af5e7e 100644 --- a/docs/Module3_IntroducingNumpy/BasicIndexing.html +++ b/docs/Module3_IntroducingNumpy/BasicIndexing.html @@ -130,6 +130,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/Broadcasting.html b/docs/Module3_IntroducingNumpy/Broadcasting.html index 1731ff3f..24653361 100644 --- a/docs/Module3_IntroducingNumpy/Broadcasting.html +++ b/docs/Module3_IntroducingNumpy/Broadcasting.html @@ -129,6 +129,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • @@ -603,16 +604,16 @@

    Pairwise Distances Using For-Loops
    def pairwise_dists_looped(x, y):
         """  Computing pairwise distances using for-loops
     
    -         Parameters
    -         ----------
    -         x : numpy.ndarray, shape=(M, D)
    -         y : numpy.ndarray, shape=(N, D)
    +     Parameters
    +     ----------
    +     x : numpy.ndarray, shape=(M, D)
    +     y : numpy.ndarray, shape=(N, D)
     
    -         Returns
    -         -------
    -         numpy.ndarray, shape=(M, N)
    -             The Euclidean distance between each pair of
    -             rows between `x` and `y`."""
    +     Returns
    +     -------
    +     numpy.ndarray, shape=(M, N)
    +         The Euclidean distance between each pair of
    +         rows between `x` and `y`."""
         # `dists[i, j]` will store the Euclidean
         # distance between  `x[i]` and `y[j]`
         dists = np.empty((5, 6))
    @@ -654,18 +655,18 @@ 

    Pairwise Distances Using Broadcasting (Unoptimized)
    def pairwise_dists_crude(x, y):
         """  Computing pairwise distances using vectorization.
     
    -         This method uses memory-inefficient broadcasting.
    +     This method uses memory-inefficient broadcasting.
     
    -         Parameters
    -         ----------
    -         x : numpy.ndarray, shape=(M, D)
    -         y : numpy.ndarray, shape=(N, D)
    +     Parameters
    +     ----------
    +     x : numpy.ndarray, shape=(M, D)
    +     y : numpy.ndarray, shape=(N, D)
     
    -         Returns
    -         -------
    -         numpy.ndarray, shape=(M, N)
    -             The Euclidean distance between each pair of
    -             rows between `x` and `y`."""
    +     Returns
    +     -------
    +     numpy.ndarray, shape=(M, N)
    +         The Euclidean distance between each pair of
    +         rows between `x` and `y`."""
         # The use of `np.newaxis` here is equivalent to our
         # use of the `reshape` function
         return np.sqrt(np.sum((x[:, np.newaxis] - y[np.newaxis])**2, axis=2))
    @@ -724,22 +725,22 @@ 

    Optimized Pairwise Distances\((M, N)\) to do so! This is the memory-efficient, vectorized form - the stuff that dreams are made of. Let’s write the function that performs this computation in full.

    def pairwise_dists(x, y):
         """ Computing pairwise distances using memory-efficient
    -        vectorization.
    -
    -        Parameters
    -        ----------
    -        x : numpy.ndarray, shape=(M, D)
    -        y : numpy.ndarray, shape=(N, D)
    -
    -        Returns
    -        -------
    -        numpy.ndarray, shape=(M, N)
    -            The Euclidean distance between each pair of
    -            rows between `x` and `y`."""
    +    vectorization.
    +
    +    Parameters
    +    ----------
    +    x : numpy.ndarray, shape=(M, D)
    +    y : numpy.ndarray, shape=(N, D)
    +
    +    Returns
    +    -------
    +    numpy.ndarray, shape=(M, N)
    +        The Euclidean distance between each pair of
    +        rows between `x` and `y`."""
         dists = -2 * np.matmul(x, y.T)
    -    dists +=  np.sum(x**2, axis=1)[:, np.newaxis]
    +    dists += np.sum(x**2, axis=1)[:, np.newaxis]
         dists += np.sum(y**2, axis=1)
    -    return  np.sqrt(dists)
    +    return np.sqrt(dists)
     
    diff --git a/docs/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.html b/docs/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.html index deb9ddb8..97ca1abe 100644 --- a/docs/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.html +++ b/docs/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.html @@ -121,6 +121,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/IntroducingTheNDarray.html b/docs/Module3_IntroducingNumpy/IntroducingTheNDarray.html index 8cdc5a03..269f1475 100644 --- a/docs/Module3_IntroducingNumpy/IntroducingTheNDarray.html +++ b/docs/Module3_IntroducingNumpy/IntroducingTheNDarray.html @@ -115,6 +115,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/Problems/Approximating_pi.html b/docs/Module3_IntroducingNumpy/Problems/Approximating_pi.html index 0de96ed8..052ad2d1 100644 --- a/docs/Module3_IntroducingNumpy/Problems/Approximating_pi.html +++ b/docs/Module3_IntroducingNumpy/Problems/Approximating_pi.html @@ -112,6 +112,7 @@
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html b/docs/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html index 524f3cd5..cd5a7b53 100644 --- a/docs/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html +++ b/docs/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html @@ -109,6 +109,7 @@
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module3_IntroducingNumpy/VectorizedOperations.html b/docs/Module3_IntroducingNumpy/VectorizedOperations.html index dfae9183..880676c7 100644 --- a/docs/Module3_IntroducingNumpy/VectorizedOperations.html +++ b/docs/Module3_IntroducingNumpy/VectorizedOperations.html @@ -128,6 +128,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/Applications_of_OOP.html b/docs/Module4_OOP/Applications_of_OOP.html index eec20339..000f78e9 100644 --- a/docs/Module4_OOP/Applications_of_OOP.html +++ b/docs/Module4_OOP/Applications_of_OOP.html @@ -114,6 +114,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/Brief_Review.html b/docs/Module4_OOP/Brief_Review.html index b3af34ce..cc78be4b 100644 --- a/docs/Module4_OOP/Brief_Review.html +++ b/docs/Module4_OOP/Brief_Review.html @@ -111,6 +111,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/ClassDefinition.html b/docs/Module4_OOP/ClassDefinition.html index c9ba9723..d808a2ee 100644 --- a/docs/Module4_OOP/ClassDefinition.html +++ b/docs/Module4_OOP/ClassDefinition.html @@ -117,6 +117,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/ClassInstances.html b/docs/Module4_OOP/ClassInstances.html index 85952f8c..1ee523bb 100644 --- a/docs/Module4_OOP/ClassInstances.html +++ b/docs/Module4_OOP/ClassInstances.html @@ -116,6 +116,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/Inheritance.html b/docs/Module4_OOP/Inheritance.html index 6e7bf62c..ff7c867f 100644 --- a/docs/Module4_OOP/Inheritance.html +++ b/docs/Module4_OOP/Inheritance.html @@ -115,6 +115,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/Introduction_to_OOP.html b/docs/Module4_OOP/Introduction_to_OOP.html index 6d3b806b..2109a29f 100644 --- a/docs/Module4_OOP/Introduction_to_OOP.html +++ b/docs/Module4_OOP/Introduction_to_OOP.html @@ -115,6 +115,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/Methods.html b/docs/Module4_OOP/Methods.html index 36088bd0..6b84cfe2 100644 --- a/docs/Module4_OOP/Methods.html +++ b/docs/Module4_OOP/Methods.html @@ -120,6 +120,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/ObjectOrientedProgramming.html b/docs/Module4_OOP/ObjectOrientedProgramming.html index 0818327b..a9c45563 100644 --- a/docs/Module4_OOP/ObjectOrientedProgramming.html +++ b/docs/Module4_OOP/ObjectOrientedProgramming.html @@ -97,6 +97,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module4_OOP/Special_Methods.html b/docs/Module4_OOP/Special_Methods.html index e50e6d4d..15d9fd59 100644 --- a/docs/Module4_OOP/Special_Methods.html +++ b/docs/Module4_OOP/Special_Methods.html @@ -117,6 +117,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module5_OddsAndEnds/Matplotlib.html b/docs/Module5_OddsAndEnds/Matplotlib.html index 33689426..08fca6b8 100644 --- a/docs/Module5_OddsAndEnds/Matplotlib.html +++ b/docs/Module5_OddsAndEnds/Matplotlib.html @@ -120,6 +120,7 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module5_OddsAndEnds/Modules_and_Packages.html b/docs/Module5_OddsAndEnds/Modules_and_Packages.html index 2eb7def9..e41ea5ab 100644 --- a/docs/Module5_OddsAndEnds/Modules_and_Packages.html +++ b/docs/Module5_OddsAndEnds/Modules_and_Packages.html @@ -42,7 +42,7 @@ - + @@ -125,6 +125,7 @@ +
  • Module 6: Testing Our Code
  • Changelog
  • @@ -509,11 +510,11 @@

    PYTHONPATH and Site-Packages

    Installing Your Own Python Package

    -

    Suppose that we are happy with the work we have done on our face_detector project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter’s working directory. Here we will construct a basic setup script that will allow us to accomplish this.

    +

    Suppose that we are happy with the work we have done on our face_detector project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter’s working directory. Here we will construct a basic setup script that will allow us to accomplish this. For completeness, we will also indicate how one would include a test suite alongside the source code in this directory structure.

    We note outright that the purpose of this section is strictly to provide you with the minimum set of instructions needed to install a package. We will not be diving into what is going on under the hood at all. Please refer to An Introduction to Distutils and Packaging Your Project for a deeper treatment of this topic.

    Carrying on, we will want to create a setup-script, setup.py, in the same directory as our package. That is, our directory structure should look like:

    -
    - setup.py
    -- face_detection/
    +
    - setup.py         # script responsible for installing `face_detection` package
    +- face_detection/  # source code of `face_detection` package
         |-- __init__.py
         |-- utils.py
         |-- database.py
    @@ -522,31 +523,42 @@ 

    Installing Your Own Python Package|-- __init__.py |-- calibration.py |-- config.py +- tests/ # test-suite for `face_detection` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_utils.py + |-- test_database.py + |-- test_model.py + |-- camera/ + |-- test_calibration.py + |-- test_config.py

    +

    A tests/ directory can be included at the same directory level as setup.py and face_detection/. This is the recommended structure for using pytest as our test-runner.

    The bare bones build script for preparing your package for installation, setup.py, is as follows:

    # contents of setup.py
    -import setuptools
    +from setuptools import find_packages, setup
     
    -setuptools.setup(
    +setup(
         name="face_detection",
    -    version="1.0",
    -    packages=setuptools.find_packages(),
    +    version="1.0.0",
    +    packages=find_packages(exclude=["tests", "tests.*"]),
    +    python_requires=">=3.5",
     )
     
    +

    The exclude expression is used to ensure that specific directories or files are not included in the installation of face_detection. We use exclude=["tests", "tests.*"] to avoid installing the test-suite alongside face_detection.

    If you read through the additional materials linked above, you will see that there are many more fields of optional information that can be provided in this setup script, such as the author name, any installation requirements that the package has, and more.

    Armed with this script, we are ready to install our package locally on our machine! In your terminal, navigate to the directory containing this setup script and your package that it being installed. Run

    -
    python setup.py install
    +
    pip install .
     

    and voilà, your package face_detection will have been installed to site-packages. You are now free to import this package from any directory on your machine. In order to uninstall this package from your machine execute the following from your terminal:

    pip uninstall face_detection
     
    -

    One final but important detail. The installed version of your package will no longer “see” the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead you can install your package in develop mode, such that a symbolic link to your source code is placed in your site-packages. Thus any changes that you make to your code will immediately be reflected in your system-wide -installation. Thus, instead of running python setup.py install, execute the following to install a package in develop mode:

    -
    python setup.py develop
    +

    One final but important detail: the installed version of your package will no longer “see” the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead, you can install your package in “development mode”, such that a symbolic link to your source code is placed in your site-packages. Thus, any changes that you make to your code will immediately be reflected in your system-wide +installation. You can add the --editable flag to pip to install a package in development mode:

    +
    pip install --editable .
     
    @@ -637,7 +649,7 @@

    Reading Comprehension Exercise Solutions: - + diff --git a/docs/Module5_OddsAndEnds/WorkingWithFiles.html b/docs/Module5_OddsAndEnds/WorkingWithFiles.html index 1d2f0ce0..f16723a3 100644 --- a/docs/Module5_OddsAndEnds/WorkingWithFiles.html +++ b/docs/Module5_OddsAndEnds/WorkingWithFiles.html @@ -124,6 +124,7 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/Module5_OddsAndEnds/Writing_Good_Code.html b/docs/Module5_OddsAndEnds/Writing_Good_Code.html index 3f5499ce..7097f83b 100644 --- a/docs/Module5_OddsAndEnds/Writing_Good_Code.html +++ b/docs/Module5_OddsAndEnds/Writing_Good_Code.html @@ -128,6 +128,7 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Our Code
  • Changelog
  • @@ -765,7 +766,7 @@

    Writing Good Type-Hints (quack quack)the duck test: if your function is expecting a duck then hint for something that walks like a duck, quacks like a duck, etc. This will help you avoid writing type-hints that are overly narrow, and which are ultimately non-Pythonic in their strictness.

    To be more concrete, let’s revisit our count_vowels function:

    def count_vowels(x: str, include_y: bool = False) -> int:
    -    """Returns the number of vowels contained in `in_string`"""
    +    """Returns the number of vowels contained in `x`"""
         vowels = set("aeiouAEIOU")
         if include_y:
             vowels.update("yY")
    @@ -871,14 +872,16 @@ 

    The NumPy Documentation Style Parameters ---------- x : numpy.ndarray, shape=(M, D) - An optional description of ``x`` + An array of M, D-dimensional vectors. + y : numpy.ndarray, shape=(N, D) - An optional description of ``y`` + An array of N, D-dimensional vectors. Returns ------- numpy.ndarray, shape=(M, N) - The pairwise distances + The pairwise distances between the M rows of ``x`` and the N + rows of ``y``. Notes ----- @@ -922,7 +925,7 @@

    The NumPy Documentation Style Parameters ---------- - grade_book : Dict[str, List[float]] + grade_book : Dict[str, Iterable[float]] The dictionary (name -> grades) of all of the students' grades. diff --git a/docs/Module6_Testing/Hypothesis.html b/docs/Module6_Testing/Hypothesis.html new file mode 100644 index 00000000..e33e642a --- /dev/null +++ b/docs/Module6_Testing/Hypothesis.html @@ -0,0 +1,327 @@ + + + + + + + + + + + + + Describing Data with Hypothesis — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    Describing Data with Hypothesis

    +

    It is often the case that the process of describing our data is by far the heaviest burden that we must bear when writing tests. This process of assessing “what variety of values should I test?”, “have I thought of all the important edge-cases?”, and “how much is ‘enough’?” will crop up with nearly every test that we write. Indeed, these are questions that you may have been asking yourself when writing test_count_vowels_basic and test_merge_max_mappings in the previous sections of this +module.

    +

    Hypothesis is a powerful Python library that empowers us to write a description (specification, to be more precise) of the data that we want to use to exercise our test. It will then generate test cases that satisfy this description and will run our test on these cases.

    +

    Let’s look at a simple example of Hypothesis in action. In the preceding section, we learned to use pytest’s parameterization mechanism to test properties of code over a set of values. For example, we wrote the following trivial test:

    +
    import pytest
    +
    +# A simple parameterized test that only tests a few, conservative inputs.
    +# Note that this test must be run by pytest to work properly
    +@pytest.mark.parametrize("size", [0, 1, 2, 3])
    +def test_range_length(size):
    +    assert len(range(size)) == size
    +
    +
    +

    which tests the property that range(n) has a length of n for any non-negative integer value of n. Well, it isn’t really testing this property for all non-negative integers; clearly it is only testing the values 0-3. We should probably also check much larger numbers and perhaps traverse various orders of magnitude (i.e. factors of ten) in our parameterization scheme. No matter what set of values we land on, it seems like we will have to eventually throw our hands up and say “okay, +that seems good enough.”

    +

    Instead of manually specifying the data to pass to test_range_length, let’s use Hypothesis to simply describe the data:

    +
    from hypothesis import given
    +
    +# Hypothesis provides so-called "strategies" for us
    +# to describe our data
    +import hypothesis.strategies as st
    +
    +# Using hypothesis to test any integer value in [0, 10 ** 10]
    +@given(size=st.integers(min_value=0, max_value=1E10))
    +def test_range_length(size):
    +    assert len(range(size)) == size
    +
    +
    +

    Here we have specified that the size value in our test should take on any integer value within \([0, 10^{10}]\). We did this by using the integers “strategy” that is provided by Hypothesis: st.integers(min_value=0, max_value=1E10). When we execute the resulting test (which can simply be run within a Jupyter cell or via pytest), this will trigger Hypothesis to generate test cases based on this specification; by default, Hypothesis will generate 100 test cases - an amount that we +can configure - and will evaluate our test for each one of them.

    +
    # Running this test once will trigger Hypothesis to
    +# generate 100 values based on the description of our data,
    +# and it will execute the test using each one of those values
    +>>> test_range_length()
    +
    +
    +

    With great ease, we were able to replace our pytest-parameterized test, which only very sparsely tested the property at hand, with a much more robust, hypothesis-driven test. This will be a recurring trend: we will generally produce much more robust tests by describing our data with Hypothesis, rather than manually specifying test values.

    +

    The rest of this section will be dedicated to learning about the Hypothesis library and how we can leverage it to write powerful tests.

    +
    +

    Hypothesis is *very* effective…:

    +

    You may be wondering why, in the preceding example, I arbitrarily picked \(10^{10}\) as the upper bound to the integer-values to feed to the test. I actually didn’t write the test that way initially. Instead, I wrote the more general test:

    +
    @given(size=st.integers(min_value=0))
    +def test_range_length(size):
    +    assert len(range(size)) == size
    +
    +
    +

    which places no formal upper bound on the integers that Hypothesis will generate. However, this test immediately found an issue (I hesitate to call it an outright bug):

    +
    Falsifying example: test_range_length(
    +    size=9223372036854775808,
    +)
    +
    +----> 3     assert len(range(size)) == size
    +
    +OverflowError: Python int too large to convert to C ssize_t
    +
    +
    +

    This reveals that the implementation of the built-in len function is such that it can only handle non-negative integers smaller than \(2^{63}\) (i.e. it will only allocate 64 bits to represent a signed integer - one bit is used to store the sign of the number). Hypothesis revealed this by generating the failing test case size=9223372036854775808, which is exactly \(2^{63}\). I did not want this error to distract from what is otherwise merely a simple example, but it is very +important to point out.

    +

    Hypothesis has a knack for catching these sorts of unexpected edge cases. Now we know that len(range(size)) == size does not hold for “arbitrary” non-negative integers! (I wonder how many of the Python core developers know about this 😄).

    +
    + +
    +

    Reading Comprehension Solutions

    +
    +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Module6_Testing/Intro_to_Testing.html b/docs/Module6_Testing/Intro_to_Testing.html new file mode 100644 index 00000000..17ebcc9e --- /dev/null +++ b/docs/Module6_Testing/Intro_to_Testing.html @@ -0,0 +1,640 @@ + + + + + + + + + + + + + Introduction to Testing — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    Introduction to Testing

    +

    This section will show us just how simple it is to write rudimentary tests. We need only recall some of Python’s basic scoping rules and introduce ourselves to the assert statement to write a genuine test function. That being said, we will quickly encounter some important questions to ponder. How do we know that our tests work? And, how do we know that our tests are effective? These questions will drive us deeper into the world of testing.

    +

    Before we hit the ground running, let’s take a moment to consider some motivations for testing out code.

    +
    +

    Why Should We Write Tests?

    +

    The fact of the matter is that it is intuitive for most people to test their code to some extent. After writing, say, a new function, it is only natural to contrive an input to feed it, and to check that the function returns the output that we expected. To the extent that one would want to see evidence that their code works, we need not motivate the importance of testing.

    +

    Less obvious are the massive benefits that we stand to gain from automating this testing process. By “automating”, we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. We will accumulate these test functions into a “test suite” that we can run quickly and repeatedly.

    +

    There are plenty of practical details ahead for us to learn, so let’s expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite:

    +

    It saves us lots of time:

    +
    +

    After you have devised a test scenario for your code, it may only take us a second or so to run it; perhaps we need only run a couple of Jupyter notebook cells to verify the output of our code. This, however, will quickly become unwieldy as we write more code and devise more test scenarios. Soon we will be dissuaded from running our tests, except for on rare occasions.

    +

    With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x’s…) will summarize the health of our project (insofar as our tests serve as good diagnostics). This, of course, also means that we will find and fix bugs much faster! In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost.

    +
    +

    It increases the “shelf life” of our code:

    +
    +
    If you’ve ever dusted off a project that you haven’t used for years (or perhaps only months or weeks…), you might know the tribulations of getting old code to work. Perhaps, in the interim, new versions of our project’s dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project’s code. And perhaps we can’t even remember all of the ways in which our project is supposed to work. Our test suite provides us with a simple and incisive way to dive back +into our work. It will point us to any potential incompatibilities that have accumulated over time. It also provides us with a large collection of detailed use-cases of our code; we can read through our tests and remind ourselves of the inner-workings of our project.
    +

    It will inform the design and usability of our project for the better:

    +
    +
    Although it may not be obvious from the outset, writing testable code leads to writing better code. This is, in part, because the process of writing tests gives us the opportunity to actually use our code under varied circumstances. The process of writing tests will help us suss out bad design decisions and redundancies in our code. Ultimately, if we find it frustrating to use our code within our tests, then surely others will find the code frustrating to use in applied settings.
    +

    It makes it easier for others to contribute to a project:

    +
    +
    Having a healthy test suite lowers the barrier to entry for a project. A contributor can rely on our project’s tests to quickly check to see if their changes to our code have broken the project or changed any of its behavior in unexpected ways.
    +

    This all sounds great, but where do we even start the process of writing a test suite? Let’s begin by seeing what constitutes a basic test function.

    +
    +
    +

    Writing Our First Tests

    +
    +

    Our “Source Code”

    +

    We need some code to test. For the sake of this introduction, let’s borrow a couple of functions that may look familiar from previous modules. These will serve as our “source code”; i.e. these are functions that we have written for our project and that need to be tested.

    +
    # Defining functions that we will be testing
    +
    +def count_vowels(x, include_y=False):
    +    """Returns the number of vowels contained in `x`.
    +
    +    The vowel 'y' is included optionally.
    +
    +    Parameters
    +    ----------
    +    x : str
    +        The input string
    +
    +    include_y : bool, optional (default=False)
    +        If `True` count y's as vowels
    +
    +    Returns
    +    -------
    +    vowel_count: int
    +
    +    Examples
    +    --------
    +    >>> count_vowels("happy")
    +    1
    +    >>> count_vowels("happy", include_y=True)
    +    2
    +    """
    +    vowels = set("aeiouAEIOU")
    +    if include_y:
    +        vowels.update("yY")
    +    return sum(1 for char in x if char in vowels)
    +
    +
    +def merge_max_mappings(dict1, dict2):
    +    """ Merges two dictionaries based on the largest value
    +    in a given mapping.
    +
    +    Parameters
    +    ----------
    +    dict1 : Dict[str, float]
    +    dict2 : Dict[str, float]
    +
    +    Returns
    +    -------
    +    merged : Dict[str, float]
    +        The dictionary containing all of the keys common
    +        between `dict1` and `dict2`, retaining the largest
    +        value from common mappings.
    +
    +    Examples
    +    --------
    +    >>> x = {"a": 1, "b": 2}
    +    >>> y = {"b": 100, "c": -1}
    +    >>> merge_max_mappings(x, y)
    +    {'a': 1, 'b': 100, 'c': -1}
    +    """
    +    # `dict(dict1)` makes a copy of `dict1`. We do this
    +    # so that updating `merged` doesn't also update `dict1`
    +    merged = dict(dict1)
    +    for key, value in dict2.items():
    +        if key not in merged or value > merged[key]:
    +            merged[key] = value
    +    return merged
    +
    +
    +

    As always, it is useful for us to follow along with this material in a Jupyter notebook. We ought to take time to define these functions and run inputs through them to make sure that we understand what they are doing. Testing code that we don’t understand is a lost cause!

    +
    +
    +

    The Basic Anatomy of a Test

    +

    Let’s write a test for count_vowels. For our most basic test, we can simply call count_vowels under various contrived inputs and assert that it returns the expected output. The desired behavior for this test function, upon being run, is to:

    +
      +
    • Raise an error if any of our assertions failed to hold true.
    • +
    • Complete “silently” if all of our assertions hold true (i.e. our test function will simply return None)
    • +
    +

    Here, we will be making use of Python’s assert statements, whose behavior will be easy to deduce from the context of this test alone. We will be formally introduced to the assert statement soon.

    +
    # Writing a rudimentary test function for `count_vowels`
    +
    +def test_count_vowels_basic():
    +    assert count_vowels("aA bB yY", include_y=False) == 2
    +    assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +
    +

    To run this test, we simply call the function:

    +
    # running our test function
    +>>> test_count_vowels_basic()  # passes: returns None | fails: raises error
    +
    +
    +

    As described above, the fact our function runs and simply returns None (i.e. we see no output when we run this test in a console or notebook cell) means that our code has passed this test. We’ve written and run our very first test! It certainly isn’t the most robust test, but it is a good start.

    +

    Let’s look more carefully at the structure of test_count_vowels_basic. Note that this function doesn’t take in any inputs; thanks to Python’s scoping rules, we can reference our count_vowels function within our test as long as it is defined in the same “namespace” as test_count_vowels_basic. That is, we can either define count_vowels in the same .py file (or Jupyter notebook, if you are following +along with this material in a notebook) as test_count_vowels_basic, or we can import count_vowels, from wherever it is defined, into the file containing our test. The latter scenario is by far the most common one in practice. More on this later.

    +
    +

    Takeaway:

    +

    A “test function” is designed to provide an encapsulated “environment” (namespace to be more precise) in which we can exercise parts of our source code and assert that the code behaves as expected. The basic anatomy of a test function is such that it:

    +
      +
    • contains one or more assert statements, each of which will raise an error if our source code misbehaves
    • +
    • simply returns None if all of the aforementioned assertions held true
    • +
    • can be run end-to-end simply by calling the test function without passing it any parameters; we rely on Python’s scoping rules to call our source code within the body of the test function without explicitly passing anything to said test function
    • +
    +
    +
    +

    Reading Comprehension: Adding Assertions to a Test

    +

    Add an additional assertion to the body of test_count_vowels_basic, which tests that count_vowels handles empty-string ("") input appropriately. Make sure to run your updated test to see if it passes.

    +
    +
    +

    Reading Comprehension: The Basic Anatomy of a Test

    +

    Write a rudimentary test function for merge_max_mappings. This should adhere to the basic structure of a test function that we just laid out. See if you can think of some “edge cases” to test, which we may have overlooked when writing merge_max_mappings.

    +
    +
    +
    +
    +

    The assert Statement

    +

    With our first test functions under our belt, it is time for us to clearly understand how assert statements work and how they should be used.

    +

    Similar to return, def, or if, the term assert is a reserved term in the Python language. It has the following specialized behavior:

    +
    # demonstrating the rudimentary behavior of the `assert` statement
    +
    +# asserting an expression whose boolean-value is `True` will complete "silently"
    +>>> assert 1 < 2
    +
    +# asserting an expression whose boolean-value is `False` raises an error
    +>>> assert 2 < 1
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-5-c82711d5fe4d> in <module>
    +----> 1 assert 2 < 1
    +
    +AssertionError:
    +
    +# we can include an error message with our assertion
    +>>> assert 0 in [1, 2, 3], "0 is not in the list"
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-8-e72fb36dc785> in <module>
    +----> 1 assert 0 in [1, 2, 3], "0 is not in the list"
    +
    +AssertionError: 0 is not in the list
    +
    +
    +

    The general form of an assertion statement is:

    +
    assert <expression> [, <error-message>]
    +
    +
    +

    When an assertion statement is executed, the built-in bool function is called on the object that is returned by <expression>; if bool(<expression>) returns False, then an AssertionError is raised. If you included a string in the assertion statement - separated from <expression> by a comma - then this string will be printed as the error message.

    +

    See that the assertion statement:

    +
    assert expression, error_message
    +
    +
    +

    is effectively shorthand for the following code (barring some additional details):

    +
    # long-form equivalent of: `assert expression, error_message`
    +if bool(expression) is False:
    +    raise AssertionError(error_message)
    +
    +
    +
    +

    Reading Comprehension: Assertions

    +

    Given the following objects:

    +
    a_list = []
    +a_number = 22
    +a_string = "abcdef"
    +
    +
    +

    Write two assertion statements with the respective behaviors:

    +
      +
    • asserts that a_list is not empty
    • +
    • asserts that the number of vowels in a_string is less than a_number; include an error message that prints the actual number of vowels
    • +
    +
    +

    In our code, an assertion should be used as a statement that is true unless there is a bug in our code. It is plain to see that the assertions in test_count_vowels_basic fit this description. However, it can also be useful to include assertions within our source code itself. For instance, we know that count_vowels should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string. We can +explicitly assert that this is the case:

    +
    # an example of including an assertion within our source code
    +
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    vowels = set("aeiouAEIOU")
    +    if include_y:
    +        vowels.update("yY")
    +    count = sum(1 for char in x if char in vowels)
    +
    +    # This assertion should always be true: it is asserting that
    +    # the internal logic of our function is correct
    +    assert isinstance(count, int) and 0 <= count <= len(x)
    +    return count
    +
    +
    +

    Note that this assertion is not meant to check if the user passed bad inputs for x and include_y. Rather, it is meant to assert that our own internal logic holds true.

    +

    Admittedly, the count_vowels function is simple enough that the inclusion of this assertion is rather pedantic. That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base. We will also see that keen use of assertions can make it much easier for us to write good tests.

    +
    +

    Disabling Assertions:

    +

    Python code can be run in an “optimized” mode such that all assertions are skipped by the Python interpreter during execution. This can be achieved by specifying the command line option -O (the letter “O”, not zero), e.g.:

    +
    python -O my_code.py
    +
    +
    +

    or by setting the PYTHONOPTIMIZE environment variable.

    +

    The idea here is that we may want assertions within our source code to perform expensive checks to guarantee internal consistency within our code, and that we want the ability to forgo these checks when we are no longer debugging our code. Because they can be skipped in this way, assertions should never be used for practical error handling.

    +
    +
    +
    +

    Testing Our Tests

    +

    It is surprisingly easy to unwittingly write a broken test: a test that always passes, or a test that simply doesn’t exercise our code in the way that we had intended. Broken tests are insidious; they are alarms that fail to sound when they are supposed to. They create misdirection in the bug-finding process and can mask problems with our code. Thus, a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior so that we can verify +that our test works. Once we confirm that our test does indeed raise an error as expected, we restore the function to its original form and re-run the test to see that it passes.

    +

    A practical note: we ought to mutate our function in a way that is trivial to undo. We can make use of code-comments towards this end. All IDEs have the ability to “block-comment” selected code. In order to block-comment code in a Jupyter notebook code cell, highlight the lines of code and press CTRL + /. The same key-combination will also un-comment a highlighted block of +commented code.

    +
    +

    Reading Comprehension: Testing Your Test via Manual Mutation

    +

    Temporarily change the body of count_vowels such that the second assertion in test_count_vowels_basic raises an error. Run the test to confirm that the second assertion raises, and then restore count_vowels to its original form. Finally, rerun the test to see that count_vowels once again passes all of the assertions.

    +

    Repeat this process given the test that you wrote for merge_max_mappings. Try breaking the function such that it always merges in values from dict2, even if those values are smaller.

    +
    +
    +

    Mutation Testing:

    +

    There is an entire subfield of automated testing known as “mutation testing”, where tools like Cosmic Ray are used to make temporary, incisive mutations to your source code - like change a + to a - or change a 1 to a -1 - and then run your test suite. The idea here is that such mutations ought to cause one or more of your tests to fail. A mutation that does not +trigger at least one test failure is likely an indicator that your tests could stand to be more robust.

    +

    Automated mutation testing tools might be a bit too “heavy duty” at this point in our testing journey, but they are great to keep in mind.

    +
    +
    +
    +

    Our Work, Cut Out

    +

    We see now that the concept of a “test function” isn’t all that fancy. Compared to other code that we have written, writing a function that simply runs a handful of assertions is far from a heavy lift for us. Of course, we must be diligent and take care to test our tests, but we can certainly manage this as well. With this in hand, we should take stock of the work and challenges that lie in our path ahead.

    +

    It is necessary that we evolve beyond manual testing. There are multiple facets to this observation. First, we must learn how to organize our test functions into a test suite that can be run in one fell swoop. Next, it will become increasingly apparent that a test function often contains large amounts of redundant code shared across its litany of assertions. We will want to “parametrize” our tests to distill them down to their most concise and functional forms. Finally, and most importantly, it +may already be evident that the process of contriving known inputs and outputs to use in our tests is a highly manual and tedious process; furthermore, it is a process that will become increasingly cumbersome as our source code becomes more sophisticated. To combat this, we will seek out alternative, powerful testing methodologies, including property-based testing.

    +
    + +
    +

    Reading Comprehension Solutions

    +

    Adding Assertions to a Test: Solution

    +

    Add an additional assertion to the body of test_count_vowels_basic, which tests whether count_vowels handles the empty-string ("") case appropriately. Make sure to run your updated test to see if it passes.

    +
    def test_count_vowels_basic():
    +    # test basic strings with uppercase and lowercase letters
    +    assert count_vowels("aA bB yY", include_y=False) == 2
    +    assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +    # test empty strings
    +    assert count_vowels("", include_y=False) == 0
    +    assert count_vowels("", include_y=True) == 0
    +
    +
    +
    # running the test in a notebook-cell: the function should simply return
    +# `None` if all assertions hold true
    +>>> test_count_vowels_basic()
    +
    +
    +

    The Basic Anatomy of a Test: Solution

    +

    Write a rudimentary test function for merge_max_mappings.

    +
    +
    Let’s test the use case that is explicitly documented in the Examples section of the function’s docstring. We can also test cases where one or both of the inputs are empty dictionaries. These can often be problematic edge cases that we didn’t consider when writing our code.
    +
    def test_merge_max_mappings():
    +    # test documented behavior
    +    dict1 = {"a": 1, "b": 2}
    +    dict2 = {"b": 20, "c": -1}
    +    expected = {'a': 1, 'b': 20, 'c': -1}
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +    # test empty dict1
    +    dict1 = {}
    +    dict2 = {"a": 10.2, "f": -1.0}
    +    expected = dict2
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +    # test empty dict2
    +    dict1 = {"a": 10.2, "f": -1.0}
    +    dict2 = {}
    +    expected = dict1
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +    # test both empty
    +    dict1 = {}
    +    dict2 = {}
    +    expected = {}
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +
    +
    # running the test (seeing no errors means the tests all passed)
    +>>> test_merge_max_mappings()
    +
    +
    +

    Assertions: Solution

    +
    a_list = []
    +a_number = 22
    +a_string = "abcdef"
    +
    +
    +

    Assert that a_list is not empty:

    +
    >>> assert a_list
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-10-2eba8294859e> in <module>
    +----> 1 assert a_list
    +
    +AssertionError:
    +
    +
    +
    +
    You may have written assert len(a_list) > 0 - this is also correct. However, recall that calling bool on any sequence (list, tuple, string, etc.) will return False if the sequence is empty. This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - bool will be called on whatever the provided expression is.
    +

    Assert that the number of vowels in a_string is fewer than a_number; include an error message that prints the actual number of vowels:

    +
    >>> assert count_vowels(a_string) < a_number, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}"
    +
    +
    +
    +
    Note that we make use of an f-string as a convenient means for writing an informative error message.
    +

    Testing Your Test via Manual Mutation: Solution

    +

    Temporarily change the body of count_vowels such that the second assertion in test_count_vowels_basic raises an error. > Let’s comment out the if include_y block in our code. This should prevent us from counting y’s, and thus should violate the second assertion in our test.

    +
    # Breaking the behavior of `include_y=True`
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    vowels = set("aeiouAEIOU")
    +    # if include_y:
    +    #    vowels.update("yY")
    +    return sum(1 for char in x if char in vowels)
    +
    +
    +
    # the second assertion should raise an error
    +>>> test_count_vowels_basic()
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-5-32301ff829e9> in <module>
    +----> 1 test_count_vowels_basic()
    +
    +<ipython-input-4-99ef0ca3d859> in test_count_vowels_basic()
    +      1 def test_count_vowels_basic():
    +      2     assert count_vowels("aA bB yY", include_y=False) == 2
    +----> 3     assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +AssertionError:
    +
    +
    +
    +
    See that the error output, which is called a “stack trace”, indicates with an ASCII-arrow that our second assertion is the one that is failing. Thus, we can be confident that that assertion really does help to ensure that we are counting y’s correctly.
    +

    Restore count_vowels to its original form and rerun the test to see that count_vowels once again passes all of the assertions.

    +
    +
    We simply un-comment the block of code and rerun our test.
    +
    # Restore the behavior of `include_y=True`
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    vowels = set("aeiouAEIOU")
    +    if include_y:
    +        vowels.update("yY")
    +    return sum(1 for char in x if char in vowels)
    +
    +
    +
    # confirming that we restored the proper behavior in `count_vowels`
    +>>> test_count_vowels_basic()
    +
    +
    +
    +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Module6_Testing/Pytest.html b/docs/Module6_Testing/Pytest.html new file mode 100644 index 00000000..9def2dc4 --- /dev/null +++ b/docs/Module6_Testing/Pytest.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + + The pytest Framework — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    The pytest Framework

    +

    Thus far, our process for running tests has been an entirely manual one. It is time for us to arrange our test functions into a proper “test suite” and to learn to leverage the pytest framework to run them. We will begin by reorganizing our source code to create an installable Python package. We will then learn how to structure and run a test suite for this +Python package, using pytest.

    +

    The pytest framework does much more than just run tests; for instance, it will enrich the assertions in our tests to produce verbose, informative error messages. Furthermore it provides valuable means for enhancing our tests via mechanisms like fixtures and parameterizing decorators. Ultimately, all of this functionality helps to eliminate manual and redundant aspects of the testing process.

    +
    +

    Note

    +

    It can be useful to create a separate conda environment for the sake of this lesson, so that we can work through this material starting from a blank slate. If you do create a new conda environment, be sure to activate that environment and install NumPy and Jupyter notebook: conda install numpy notebook

    +
    +

    Let’s install pytest. Installing from the conda-forge channel will install the most up-to-date version of pytest. In a terminal where conda can be accessed, run:

    +
    conda install -c conda-forge pytest
    +
    +
    +

    Or, pytest is installable via pip:

    +
    pip install pytest
    +
    +
    +
    +

    Regarding Alternative Testing Frameworks (a note from the author of PLYMI):

    +

    When sifting through tutorials, blogs, and videos about testing in Python, it is common to see pytest presented alongside, and on an equal footing with, the alternative testing frameworks: nose and unittest. This strikes me as… bizarre.

    +

    unittest is the testing framework that comes with the Python standard library. As a test runner, its design is clunky, archaic, and, ironically, un-pythonic. While unittest.mock provides extremely valuable functionality for advanced testing, all of its functionality can be leveraged while using pytest as your testing framework.

    +

    nose, which simply extends the functionality of unittest, is no longer being maintained. There is a project, “Nose2”, which is carrying the torch of nose. However, this is a fledgling project in comparison with pytest. As of writing this, pytest was downloaded 12 million times last month versus nose2’s 150 thousand downloads.

    +

    The takeaway here is that, when it comes to picking a testing framework for Python, pytest is the clear choice. Any discussion that you come across to the contrary is likely outdated.

    +
    +
    +

    Creating a Python Package with Tests

    +

    It’s time to create a proper test suite. Before proceeding any further, we should reread the material presented in Module 5 - Import: Modules and Packages and recall the essentials of import statements, modules, and Python packages. This material serves as the foundation for this section.

    +
    +

    Organizing our Source Code

    +

    Let’s create a Python package, which we will call plymi_mod6, with the following directory structure:

    +
    project_dir/     # the "parent directory" houses our source code, tests, and all other relevant files
    +  - setup.py     # script responsible for installing `plymi_mod6` package
    +  - plymi_mod6/  # directory containing source code of `plymi_mod6` package
    +      |-- __init__.py
    +      |-- basic_functions.py
    +      |-- numpy_functions.py
    +  - tests/        # test-suite for `plymi_mod6` package (to be run using pytest)
    +      |-- conftest.py # optional configuration file for pytest
    +      |-- test_basic_functions.py
    +      |-- test_numpy_functions.py
    +
    +
    +

    A reference implementation of this package can be found in this GitHub repository. Populate the basic_functions.py file with the two functions that we were using as our source code in the previous section: count_vowels and merge_max_mappings. In the numpy_functions.py module, add the pairwise_dists function that appears in Module 3’s discussion of optimized pairwise +distances. Don’t forget to include import numpy as np in your script in accordance with how pairwise_dists calls NumPy functions.

    +

    We have arranged these functions so that they can be imported from the basic_functions module and the numpy_functions module, respectively, which reside in our plymi_mod6 package. Let’s fill out our setup.py script and install this package so that we can import it regardless of our current working directory. The content of setup.py will be:

    +
    from setuptools import find_packages, setup
    +
    +setup(
    +    name="plymi_mod6",
    +    packages=find_packages(exclude=["tests", "tests.*"]),
    +    version="1.0.0",
    +    author="Your Name",
    +    description="A template Python package for learning about testing",
    +    install_requires=["numpy >= 1.10.0"],
    +    tests_require=["pytest>=5.3", "hypothesis>=5.0"],
    +    python_requires=">=3.6",
    +)
    +
    +
    +

    This setup file dictates that a user must have Python 3.6+ installed - we will bar Python 3.5 and below so that we are free to make use of f-strings in our code, which were introduced in Python 3.6. Additionally, we will require pytest and hypothesis for running tests; the Hypothesis library will be introduced in a later section.

    +

    Finally, let’s install our package locally in development mode. Navigate to the directory containing setup.py and run:

    +
    pip install --editable .
    +
    +
    +

    Now, we should be able to start a python console, IPython console, or Jupyter notebook in any directory and import our package:

    +
    # checking that we can import our `plymi_mod6` package
    +>>> from plymi_mod6.basic_functions import count_vowels
    +>>> count_vowels("Happy birthday", include_y=True)
    +5
    +
    +
    +
    +
    +
    +

    Populating and Running Our Test Suite

    +

    pytest’s system for “test discovery” is quite simple: pytest need only be pointed to a directory with files named test_*.py in it, and it will find all of the functions in these files whose names start with the word “test” and will run all such functions.

    +

    Thus, let’s populate the file test_basic_functions.py with the functions test_count_vowels_basic and test_merge_max_mappings, which we wrote in the previous section of this module:

    +
    # The contents of test_basic_functions.py
    +
    +# we must import the functions we are testing
    +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings
    +
    +
    +def test_count_vowels_basic():
    +    # test basic strings with uppercase and lowercase letters
    +    assert count_vowels("aA bB yY", include_y=False) == 2
    +    assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +    # test empty strings
    +    assert count_vowels("", include_y=False) == 0
    +    assert count_vowels("", include_y=True) == 0
    +
    +
    +def test_merge_max_mappings():
    +    # test documented behavior
    +    dict1 = {"a": 1, "b": 2}
    +    dict2 = {"b": 20, "c": -1}
    +    expected = {'a': 1, 'b': 20, 'c': -1}
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +    # test empty dict1
    +    dict1 = {}
    +    dict2 = {"a": 10.2, "f": -1.0}
    +    expected = dict2
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +    # test empty dict2
    +    dict1 = {"a": 10.2, "f": -1.0}
    +    dict2 = {}
    +    expected = dict1
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +    # test both empty
    +    dict1 = {}
    +    dict2 = {}
    +    expected = {}
    +    assert merge_max_mappings(dict1, dict2) == expected
    +
    +
    +

    As described before, count_vowels and merge_max_mappings must both be imported from our plymi_mod6 package, so that our functions are in the same namespace as our tests. A reference implementation of test_basic_functions.py can be viewed here. Finally, add a dummy test - a test function that will always pass - to test_basic_numpy.py. We will replace this with a useful test later.

    +

    Without further ado, let’s run our test suite! In our terminal, with the appropriate conda environment active, we navigate to the root directory of the project, which contains the tests/ directory, and run pytest tests/. The following output should appear:

    +
    $ pytest tests/
    +============================= test session starts =============================
    +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0
    +rootdir: C:\Users\plymi_user\plymi_root_dir
    +collected 3 items
    +
    +tests\test_basic_functions.py ..                                         [ 66%]
    +tests\test_basic_numpy.py .                                              [100%]
    +
    +============================== 3 passed in 0.04s ==============================
    +
    +
    +

    This output indicates that three test-functions were found across two files and that all of the tests “passed”; i.e. the functions ran without raising any errors. The first two tests are located in tests/test_basic_functions.py; the two dots indicate that two functions were run, and the [66%] indicator simply denotes that the test-suite is 66% (two-thirds) complete. The following reading comprehension problem will lead us to see what it looks like for pytest to report a failing test.

    +
    +

    Reading Comprehension: Running a Test Suite

    +

    Temporarily add a new “broken” test to tests/test_basic_functions.py. The name that you give this test should adhere to pytest’s simple rules for test-discovery. Design the test function so that is sure to fail when it is run.

    +

    Rerun your test suite and compare its output to what you saw before - is it easy to identify which test failed and what caused it to fail? Make sure to remove this function from your test suite once you are finished answering this question.

    +
    +

    We can also direct pytest to run the tests in a specific .py file. For example, executing:

    +
    pytest tests/test_basic_functions.py
    +
    +
    +

    will cue pytest to only run the tests in test_basic_functions.py.

    +

    A key component to leveraging tests effectively is the ability to exercise one’s tests repeatedly and rapidly with little manual overhead. Clearly, pytest is instrumental toward this end - this framework makes the process of organizing and running our test suite exceedingly simple! That being said, there will certainly be occasions when we want to run a specific test function. Suppose, for instance, that we are writing a new function, and repeatedly want to run one of our tests that is +pointing to a bug in our work-in-progress. We can leverage pytest in conjunction with an IDE to run our tests in such incisive ways.

    +
    +

    Utilizing pytest within an IDE

    +

    Both PyCharm and VSCode can be configured to make keen use of pytest. The following images show a couple of the enhancements afforded to us by PyCharm; comparable features are available in VSCode. The IDEs will “discover” tests, and provide us with the ability to run individual tests. For example, in the following image, the green “play button” allows us to run +test_count_vowels_basic.

    +
    +

    +Running an individual test in PyCharm +

    +

    Furthermore, IDEs can provide a rich tree view of all the tests that are being run. This is especially useful as our test suite grows to contain a considerable number of tests. In the following image, we see that test_version is failing - we can click on the failing test in this tree-view, and our IDE will navigate us directly to the failing test.

    +
    +

    +Viewing an enhanced tree-view of your test suite +

    +

    The first step for leveraging these features in your IDE is to enable the pytest framework in the IDE. The following links point to detailed instructions for configuring pytest with PyCharm and VSCode, respectively:

    + +

    These linked materials also include advanced details, like instructions for running tests in parallel, which are beyond the scope of this material but are useful nonetheless.

    +
    +
    +
    +

    Enhanced Testing with pytest

    +

    In addition to providing us with a simple means for organizing and running our test suite, pytest has powerful features that will both simplify and enhance our tests. We will now leverage these features in our test suite.

    +
    +

    Enriched Assertions

    +

    A failing “bare” assertion - an assert statement without an error message - can be a frustrating thing. Suppose, for instance, that one of our test-assertions about count_vowels fails:

    +
    # a failing assertion without an error message is not informative
    +
    +assert count_vowels("aA bB yY", include_y=True) == 4
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-2-f89f8b6a7213> in <module>
    +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +AssertionError:
    +
    +
    +

    The problem with this bare assertion is that we don’t know what count_vowels("aA bB yY", include_y=True) actually returned! We now have to go through the trouble of starting a python console, importing this function, and calling it with this specific input in order to see what our function was actually returning. An obvious remedy to this is for us to write our own error message, but this too is quite cumbersome when we consider the large number of assertions that we are destined to write.

    +

    Fortunately, pytest comes to the rescue: it will “hijack” any failing bare assertion and will insert a useful error message for us. This is known as “assertion introspection”. For example, if the aforementioned assertion failed when being run by pytest, we would see the following output:

    +
    # pytest will write informative error messages for us
    +
    +assert count_vowels("aA bB yY", include_y=True) == 4
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +~\Learning_Python\Python\Module6_Testing\Untitled1.ipynb in <module>
    +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +AssertionError: assert 2 == 4
    + +  where 2 = <function count_vowels at 0x000001B91B913708>('aA bB yY', include_y=True
    +
    +
    +

    See that the error message that pytest included for us indicates that count_vowels("aA bB yY", include_y=True) returned 2, when we expected it to return 4. From this we might suspect that count_vowels is not counting y’s correctly.

    +

    Here are some more examples of “enriched assertions”, as provided by pytest. See that these error messages even provide useful “diffs”, which specify specifically how two similar objects differ, where possible.

    +
    # comparing unequal lists
    +assert [1, 2, 3] == [1, 2]
    +E         Left contains one more item: 3
    +E         Full diff:
    +E         - [1, 2, 3]
    +E         ?      ---
    +E         + [1, 2]
    +
    +
    +
    # comparing unequal dictionaries
    +assert {"a": 1, "b": 2} == {"a": 1, "b": 3}
    +E       AssertionError: assert {'a': 1, 'b': 2} == {'a': 1, 'b': 3}
    +E         Omitting 1 identical items, use -vv to show
    +E         Differing items:
    +E         {'b': 2} != {'b': 3}
    +E         Full diff:
    +E         - {'a': 1, 'b': 2}
    +E         ?               ^
    +E         + {'a': 1, 'b': 3}...
    +
    +
    +
    # comparing unequal strings
    +assert "moo" == "moon"
    +E       AssertionError: assert 'moo' == 'moon'
    +E         - moo
    +E         + moon
    +E         ?    +
    +
    +
    +
    +
    +

    Parameterized Tests

    +

    Looking back to both test_count_vowels_basic and test_merge_max_mappings, we see that there is a lot of redundancy within the bodies of these test functions. The assertions that we make within a given test-function share identical forms - they differ only in the parameters that we feed into our functions and their expected output. Another shortcoming of this test-structure is that a failing assertion will block subsequent assertions from being evaluated. That is, if the second assertion +in test_count_vowels_basic fails, the third and fourth assertions will not be evaluated in that run. This precludes us from potentially seeing useful patterns among the failing assertions.

    +

    pytest provides a useful tool that will allow us to eliminate these structural shortcomings by transforming our test-functions into so-called parameterized tests. Let’s parametrize the following test:

    +
    # a simple test with redundant assertions
    +
    +def test_range_length_unparameterized():
    +    assert len(range(0)) == 0
    +    assert len(range(1)) == 1
    +    assert len(range(2)) == 2
    +    assert len(range(3)) == 3
    +
    +
    +

    This test is checking the property len(range(n)) == n, where n is any non-negative integer. Thus, the parameter to be varied here is the “size” of the range-object being created. Let’s treat it as such by using pytest to write a parameterized test:

    +
    # parameterizing a test
    +import pytest
    +
    +# note that this test must be run by pytest to work properly
    +@pytest.mark.parametrize("size", [0, 1, 2, 3])
    +def test_range_length(size):
    +    assert len(range(size)) == size
    +
    +
    +

    Make note that a pytest-parameterized test must be run using pytest; an error will raise if we manually call test_range_length(). When executed, pytest will treat this parameterized test as four separate tests - one for each parameter value:

    +
    test_basic_functions.py::test_range_length[0] PASSED                     [ 25%]
    +test_basic_functions.py::test_range_length[1] PASSED                     [ 50%]
    +test_basic_functions.py::test_range_length[2] PASSED                     [ 75%]
    +test_basic_functions.py::test_range_length[3] PASSED                     [100%]
    +
    +
    +

    See that we have successfully eliminated the redundancy from test_range_length; the body of the function now contains only a single assertion, making obvious the property that is being tested. Furthermore, the four assertions are now being run independently from one another and thus we can potentially see patterns across multiple fail cases in concert.

    +
    +

    Decorators

    +

    The syntax used to parameterize this test may look alien to us, as we have yet to encounter this construct thus far. pytest.mark.parameterize(...) is a decorator - an object that is used to “wrap” a function in order to transform its behavior. The pytest.mark.parameterize(...) decorator wraps our test function so that pytest can call it multiple times, once for each parameter value. The @ character, in this context, denotes the application of a decorator:

    +
    # general syntax for applying a decorator to a function
    +
    +@the_decorator
    +def the_function_being_decorated(<arguments_for_function>):
    +    pass
    +
    +
    +

    For an in-depth discussion of decorators, please refer to Real Python’s Primer on decorators.

    +
    +
    +

    Parameterization Syntax

    +

    The general form for creating a parameterizing decorator with a single parameter, as we formed above, is:

    +
    @pytest.mark.parametrize("<param-name>", [<val-1>, <val-2>, ...])
    +def test_function(<param-name>):
    +    ...
    +
    +
    +

    We will often have tests that require multiple parameters. The general form for creating the parameterization decorator for \(N\) parameters, each of which assume \(J\) values, is:

    +
    @pytest.mark.parametrize("<param-name1>, <param-name2>, [...], <param-nameN>",
    +                         [(<param1-val1>, <param2-val1>, [...], <paramN-val1>),
    +                          (<param1-val2>, <param2-val2>, [...], <paramN-val2>),
    +                          ...
    +                          (<param1-valJ>, <param2-valJ>, [...], <paramN-valJ>),
    +                         ])
    +def test_function(<param-name1>, <param-name2>, [...], <param-nameN>):
    +    ...
    +
    +
    +

    For example, let’s take the following trivial test:

    +
    def test_inequality_unparameterized():
    +    assert 1 < 2 < 3
    +    assert 4 < 5 < 6
    +    assert 7 < 8 < 9
    +    assert 10 < 11 < 12
    +
    +
    +

    and rewrite it in parameterized form. The decorator will have three distinct parameters, and each parameter, let’s simply call them a, b, and c, will take on four values.

    +
    # the parameterized form of `test_inequality_unparameterized`
    +@pytest.mark.parametrize("a, b, c", [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)])
    +def test_inequality(a, b, c):
    +    assert a < b < c
    +
    +
    +
    +

    Note

    +

    The formatting for multi-parameter tests can quickly become unwieldy. It isn’t always obvious where one should introduce line breaks and indentations to improve readability. This is a place where the “black” auto-formatter really shines! Black will make all of these formatting decisions for us - we can write our parameterized tests as haphazardly as we like and simply run black to format our code.

    +
    +
    +

    Reading Comprehension: Parameterizing Tests

    +

    Rewrite test_count_vowels_basic as a parameterized test with the parameters: input_string, include_y, and expected_count.

    +

    Rewrite test_merge_max_mappings as a parameterized test with the parameters: dict_a, dict_b, and expected_merged.

    +

    Before rerunning test_basic_functions.py predict how many distinct test cases will be reported by pytest.

    +
    +

    Finally, you can apply multiple parameterizing decorators to a test so that pytest will run all combinations of the respective parameter values.

    +
    # testing all combinations of `x` and `y`
    +@pytest.mark.parametrize("x", [0, 1, 2])
    +@pytest.mark.parametrize("y", [10, 20])
    +def test_all_combinations(x, y):
    +    # will run:
    +    # x=0 y=10
    +    # x=0 y=20
    +    # x=1 y=10
    +    # x=1 y=20
    +    # x=2 y=10
    +    # x=2 y=20
    +    pass
    +
    +
    +
    +
    +
    +

    Fixtures

    +

    The final major pytest feature that we will discuss are “fixtures”. A fixture, roughly speaking, is a means by which we can share information and functionality across our tests. Fixtures can be defined within our conftest.py file, and pytest will automatically “discover” them and make them available for use throughout our test suite in a convenient way.

    +

    Exploring fixtures will quickly take us beyond our depths for the purposes of this introductory material, so we will only scratch the surface here. We can read about advanced details of fixtures here.

    +

    Below are examples of two useful fixtures.

    +
    # contents of conftest.py
    +
    +import os
    +import tempfile
    +
    +import pytest
    +
    +@pytest.fixture()
    +def cleandir():
    +    """ This fixture will use the stdlib `tempfile` module to
    +    change the current working directory to a tmp-dir for the
    +    duration of the test.
    +
    +    Afterwards, the test session returns to its previous working
    +    directory, and the temporary directory and its contents
    +    will be automatically deleted.
    +
    +    Yields
    +    ------
    +    str
    +        The name of the temporary directory."""
    +    with tempfile.TemporaryDirectory() as tmpdirname:
    +        old_dir = os.getcwd()  # get current working directory (cwd)
    +        os.chdir(tmpdirname)   # change cwd to the temp-directory
    +        yield tmpdirname       # yields control to the test to be run
    +        os.chdir(old_dir)      # restore the cwd to the original directory
    +    # Leaving the context manager will prompt the deletion of the
    +    # temporary directory and its contents. This cleanup will be
    +    # triggered even if errors were raised during the test.
    +
    +
    +@pytest.fixture()
    +def dummy_email():
    +    """ This fixture will simply have pytest pass the string:
    +                   'dummy.email@plymi.com'
    +    to any test-function that has the parameter name `dummy_email` in
    +    its signature.
    +    """
    +    return "dummy.email@plymi.com"
    +
    +
    +

    The first one, cleandir, can be used in conjunction with tests that need to write files. We don’t want our tests to leave behind files on our machines; the cleandir fixture will ensure that our tests will write files to a temporary directory that will be deleted once the test is complete.

    +

    Second is a simple fixture called dummy_email. Suppose that our project needs to interact with a specific email address, suppose it’s dummy.email@plymi.com, and that we have several tests that need access to this address. This fixture will pass this address to any test function that has the parameter name dummy_email in its signature.

    +

    A reference implementation of conftest.py in our project can be found here. Several reference tests that make use of these fixtures can be found here.

    +

    Let’s create a file tests/test_using_fixtures.py, and write some tests that put these fixtures to use:

    +
    # contents of test_using_fixtures.py
    +import pytest
    +
    +# When run, this test will be executed within a
    +# temporary directory that will automatically be
    +# deleted - along with all of its contents - once
    +# the test ends.
    +#
    +# Thus we can have this test write a file, and we
    +# need not worry about having it clean up after itself.
    +@pytest.mark.usefixtures("cleandir")
    +def test_writing_a_file():
    +    with open("a_text_file.txt", mode="w") as f:
    +        f.write("hello world")
    +
    +    with open("a_text_file.txt", mode="r") as f:
    +        file_content = f.read()
    +
    +    assert file_content == "hello world"
    +
    +
    +# We can use the `dummy_email` fixture to provide
    +# the same email address to many tests. In this
    +# way, if we need to change the email address, we
    +# can simply update the fixture and all of the tests
    +# will be affected by the update.
    +#
    +# Note that we don't need to use a decorator here.
    +# pytest is smart, and will see that the parameter-name
    +# `dummy_email` matches the name of our fixture. It will
    +# thus call these tests using the value returned by our
    +# fixture
    +
    +def test_email1(dummy_email):
    +    assert "dummy" in dummy_email
    +
    +
    +def test_email2(dummy_email):
    +    assert "plymi" in dummy_email
    +
    +
    +def test_email3(dummy_email):
    +    assert ".com" in dummy_email
    +
    +
    +
    +
    + +
    +

    Reading Comprehension Solutions

    +

    Running a Test Suite: Solution

    +
    +
    Let’s add the test function test_broken_function to our test suite. We must include the word “test” in the function’s name so that pytest will identify it as a test to run. There are limitless ways in which we can make this test fail; we’ll introduce a trivial false-assertion:
    +
    def test_broken_function():
    +    assert [1, 2, 3] == [1, 2]
    +
    +
    +
    +
    After introducing this broken test into test_basic_functions.py , running our tests should result in the following output:
    +
    $ pytest tests/
    +============================= test session starts =============================
    +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0
    +rootdir: C:\Users\plymi_user\plymi_root_dir
    +collected 4 items
    +
    +tests\test_basic_functions.py ..F                                        [ 75%]
    +tests\test_basic_numpy.py .                                              [100%]
    +
    +================================== FAILURES ===================================
    +____________________________ test_broken_function _____________________________
    +
    +    def test_broken_function():
    +>       assert [1, 2, 3] == [1, 2]
    +E       assert [1, 2, 3] == [1, 2]
    +E         Left contains one more item: 3
    +E         Use -v to get the full diff
    +
    +tests\test_basic_functions.py:40: AssertionError
    +========================= 1 failed, 3 passed in 0.07s =========================
    +
    +
    +
    +
    Four tests were “discovered” and run by pytest. The pattern ..F indicates that the first two tests in test_basic_functions passed and the third test failed. It then indicates which test failed, and specifically that the assertion was false because a length-2 list cannot be equal to a length-3 list.
    +

    Parameterizing Tests: Solution

    +

    A reference implementation for this solution within the plymi_mod6 project can be found here.

    +

    The contents of test_basic_functions.py, rewritten to use pytest-parameterized tests:

    +
    import pytest
    +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings
    +
    +
    +@pytest.mark.parametrize(
    +    "input_string, include_y, expected_count",
    +    [("aA bB yY", False, 2), ("aA bB yY", True, 4), ("", False, 0), ("", True, 0)],
    +)
    +def test_count_vowels_basic(input_string, include_y, expected_count):
    +    assert count_vowels(input_string, include_y) == expected_count
    +
    +
    +@pytest.mark.parametrize(
    +    "dict_a, dict_b, expected_merged",
    +    [
    +        (dict(a=1, b=2), dict(b=20, c=-1), dict(a=1, b=20, c=-1)),
    +        (dict(), dict(b=20, c=-1), dict(b=20, c=-1)),
    +        (dict(a=1, b=2), dict(), dict(a=1, b=2)),
    +        (dict(), dict(), dict()),
    +    ],
    +)
    +def test_merge_max_mappings(dict_a, dict_b, expected_merged):
    +    assert merge_max_mappings(dict_a, dict_b) == expected_merged
    +
    +
    +

    Running these tests via pytest should produce eight distinct test-case: four for test_count_vowels_basic and four for test_merge_max_mappings.

    +
    ============================= test session starts =============================
    +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0
    +cachedir: .pytest_cache
    +rootdir: C:\Users\plymi_user\Learning_Python\plymi_mod6_src
    +collecting ... collected 8 items
    +
    +test_basic_functions.py::test_count_vowels_basic[aA bB yY-False-2] PASSED [ 12%]
    +test_basic_functions.py::test_count_vowels_basic[aA bB yY-True-4] PASSED [ 25%]
    +test_basic_functions.py::test_count_vowels_basic[-False-0] PASSED        [ 37%]
    +test_basic_functions.py::test_count_vowels_basic[-True-0] PASSED         [ 50%]
    +test_basic_functions.py::test_merge_max_mappings[dict_a0-dict_b0-expected_merged0] PASSED [ 62%]
    +test_basic_functions.py::test_merge_max_mappings[dict_a1-dict_b1-expected_merged1] PASSED [ 75%]
    +test_basic_functions.py::test_merge_max_mappings[dict_a2-dict_b2-expected_merged2] PASSED [ 87%]
    +test_basic_functions.py::test_merge_max_mappings[dict_a3-dict_b3-expected_merged3] PASSED [100%]
    +
    +============================== 8 passed in 0.07s ==============================
    +
    +
    +
    +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_images/individual_test.png b/docs/_images/individual_test.png new file mode 100644 index 00000000..381fba2d Binary files /dev/null and b/docs/_images/individual_test.png differ diff --git a/docs/_images/test_tree_view.png b/docs/_images/test_tree_view.png new file mode 100644 index 00000000..5b352aa5 Binary files /dev/null and b/docs/_images/test_tree_view.png differ diff --git a/docs/_sources/Module2_EssentialsOfPython/Functions.md.txt b/docs/_sources/Module2_EssentialsOfPython/Functions.md.txt index 2ad15dda..2d670f3d 100644 --- a/docs/_sources/Module2_EssentialsOfPython/Functions.md.txt +++ b/docs/_sources/Module2_EssentialsOfPython/Functions.md.txt @@ -137,7 +137,7 @@ Write a function named `count_even`. It should accept one input argument, named ## The `return` Statement -In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the `None` object*. +In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the* `None` *object*. ```python # this function returns `None` diff --git a/docs/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt b/docs/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt index 5c8a96fc..cd83934a 100644 --- a/docs/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt +++ b/docs/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.3.0 kernelspec: display_name: Python 3 language: python @@ -486,16 +486,16 @@ Performing this computation using for-loops proceeds as follows: def pairwise_dists_looped(x, y): """ Computing pairwise distances using for-loops - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # `dists[i, j]` will store the Euclidean # distance between `x[i]` and `y[j]` dists = np.empty((5, 6)) @@ -545,18 +545,18 @@ Voilà! We have produced the distances in a vectorized way. Let's write this out def pairwise_dists_crude(x, y): """ Computing pairwise distances using vectorization. - This method uses memory-inefficient broadcasting. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + This method uses memory-inefficient broadcasting. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # The use of `np.newaxis` here is equivalent to our # use of the `reshape` function return np.sqrt(np.sum((x[:, np.newaxis] - y[np.newaxis])**2, axis=2)) @@ -628,23 +628,23 @@ In total, we have successfully used vectorization to compute the all pairs of di ```python def pairwise_dists(x, y): - """ Computing pairwise distances using memory-efficient - vectorization. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + """ Computing pairwise distances using memory-efficient + vectorization. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" dists = -2 * np.matmul(x, y.T) - dists += np.sum(x**2, axis=1)[:, np.newaxis] + dists += np.sum(x**2, axis=1)[:, np.newaxis] dists += np.sum(y**2, axis=1) - return np.sqrt(dists) + return np.sqrt(dists) ``` diff --git a/docs/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt b/docs/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt index 3324669e..471e1a4e 100644 --- a/docs/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt +++ b/docs/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt @@ -5,7 +5,7 @@ jupyter: extension: .md format_name: markdown format_version: '1.2' - jupytext_version: 1.3.0rc1 + jupytext_version: 1.3.0 kernelspec: display_name: Python 3 language: python @@ -406,15 +406,15 @@ It must be mentioned that we are sweeping some details under the rug here. Insta ### Installing Your Own Python Package -Suppose that we are happy with the work we have done on our `face_detector` project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter's working directory. Here we will construct a basic setup script that will allow us to accomplish this. +Suppose that we are happy with the work we have done on our `face_detector` project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter's working directory. Here we will construct a basic setup script that will allow us to accomplish this. For completeness, we will also indicate how one would include a test suite alongside the source code in this directory structure. We note outright that the purpose of this section is strictly to provide you with the minimum set of instructions needed to install a package. We will not be diving into what is going on under the hood at all. Please refer to [An Introduction to Distutils](https://docs.python.org/3/distutils/introduction.html#an-introduction-to-distutils) and [Packaging Your Project](https://packaging.python.org/tutorials/packaging-projects/#packaging-your-project) for a deeper treatment of this topic. Carrying on, we will want to create a setup-script, `setup.py`, *in the same directory as our package*. That is, our directory structure should look like: ``` -- setup.py -- face_detection/ +- setup.py # script responsible for installing `face_detection` package +- face_detection/ # source code of `face_detection` package |-- __init__.py |-- utils.py |-- database.py @@ -423,23 +423,34 @@ Carrying on, we will want to create a setup-script, `setup.py`, *in the same dir |-- __init__.py |-- calibration.py |-- config.py +- tests/ # test-suite for `face_detection` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_utils.py + |-- test_database.py + |-- test_model.py + |-- camera/ + |-- test_calibration.py + |-- test_config.py ``` +A `tests/` directory can be included at the same directory level as `setup.py` and `face_detection/`. +This is the recommended structure for using [pytest](https://docs.pytest.org/en/latest/) as our test-runner. + The bare bones build script for preparing your package for installation, `setup.py`, is as follows: ```python # contents of setup.py -import setuptools +from setuptools import find_packages, setup -setuptools.setup( +setup( name="face_detection", - version="1.0", - packages=setuptools.find_packages(), + version="1.0.0", + packages=find_packages(exclude=["tests", "tests.*"]), + python_requires=">=3.5", ) ``` - - +The `exclude` expression is used to ensure that specific directories or files are not included in the installation of `face_detection`. We use `exclude=["tests", "tests.*"]` to avoid installing the test-suite alongside `face_detection`. If you read through the additional materials linked above, you will see that there are many more fields of optional information that can be provided in this setup script, such as the author name, any installation requirements that the package has, and more. @@ -447,7 +458,7 @@ If you read through the additional materials linked above, you will see that the Armed with this script, we are ready to install our package locally on our machine! In your terminal, navigate to the directory containing this setup script and your package that it being installed. Run ```shell -python setup.py install +pip install . ``` and voilà, your package `face_detection` will have been installed to site-packages. You are now free to import this package from any directory on your machine. In order to uninstall this package from your machine execute the following from your terminal: @@ -456,10 +467,10 @@ and voilà, your package `face_detection` will have been installed to site-packa pip uninstall face_detection ``` -One final but important detail. The installed version of your package will no longer "see" the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead you can install your package in develop mode, such that a symbolic link to your source code is placed in your site-packages. Thus any changes that you make to your code will immediately be reflected in your system-wide installation. Thus, instead of running `python setup.py install`, execute the following to install a package in develop mode: +One final but important detail: the installed version of your package will no longer "see" the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead, you can install your package in "development mode", such that a symbolic link to your source code is placed in your site-packages. Thus, any changes that you make to your code will immediately be reflected in your system-wide installation. You can add the `--editable` flag to pip to install a package in development mode: ```shell -python setup.py develop +pip install --editable . ``` diff --git a/docs/_sources/Module5_OddsAndEnds/Testing_Your_Code.ipynb.txt b/docs/_sources/Module5_OddsAndEnds/Testing_Your_Code.ipynb.txt deleted file mode 100644 index 9e2f28b1..00000000 --- a/docs/_sources/Module5_OddsAndEnds/Testing_Your_Code.ipynb.txt +++ /dev/null @@ -1,157 +0,0 @@ -{ - "cells": [ - { - "cell_type": "raw", - "metadata": { - "raw_mimetype": "text/restructuredtext" - }, - "source": [ - ".. meta::\n", - " :description: Topic: Writing tests for your code, Difficulty: Medium, Category: Section\n", - " :keywords: test, pytest, automated, unit, integration, property-based, hypothesis " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Testing Your Code\n", - "\n", - "This section will introduce us to the critically-important and often-overlooked process of testing code. \n", - "We will begin by considering the basic motivations behind writing tests.\n", - "Next, we will study the basic anatomy of a test-function, including its nucleus: the `assert` statement.\n", - "Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework [pytest](https://docs.pytest.org/).\n", - "This will inform how to structure our tests alongside our Python project that we are developing, and will allow us to incisively run our tests with the press of a single button.\n", - "Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests.\n", - "Finally, we will take a step back to consider some strategies for writing effective tests.\n", - "Among these is a methodology that is near and dear to my heart: property-based testing.\n", - "This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library [Hypothesis](https://hypothesis.readthedocs.io/) waiting to greet us (adorned with the mad Hatter's cap and all).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Why Should We Write Tests?\n", - "With great power comes great responsibility: tests help us be responsible for the code that we create and that others will (hopefully) use.\n", - "\n", - "The fact of the matter is that everyone already tests their code to some extent.\n", - "After coding, say, a new function, it is only natural to contrive an input to feed it, and to check that it returns the output that you expected.\n", - "To the extent that anyone would want to see evidence that their code works, we need not motivate the importance of testing.\n", - "\n", - "Less obvious is the massive benefits that we stand to gain from formalizing this testing process.\n", - "And by \"formalizing\", we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end.\n", - "We will accumulate these functions into a \"test suite\" that we can run quickly and repeatedly.\n", - "\n", - "There are plenty of practical details ahead for us to learn, so let's expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite:\n", - "\n", - "- It saves us lots of time:\n", - " > After you have devised a test scenario for your code, it may only take us a second or so to run it - perhaps we need only run a couple of Jupyter notebook cells to check the output.\n", - " > However, this will quickly become unwieldy as we write more code and devise more test scenarios.\n", - " > Soon we will be dissuaded from running our tests except for on rare occasions.\n", - " > With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x's...) will summarize the health of our project (insofar as our tests serve as good diagnostics).\n", - " > This, of course, also means that we will find and fix bugs much faster!\n", - " > In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost.\n", - "- It increases the \"shelf life\" of our code:\n", - " > If you've ever dusted off a project that you haven't used for years (or perhaps only months or weeks...), you might know the tribulations of getting old code to work.\n", - " > Perhaps, in the interim, new versions of your project's dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project.\n", - " > And perhaps we can't even _remember_ all of the ways in which our project is supposed to work.\n", - " > Our test suite provides us with a simple and incisive way to dive back into our work.\n", - " > It will point us to any potential incompatibilities that have accumulated over time.\n", - " > It also provides us with a large collection of detailed use-cases of our code;\n", - " > we can read through our tests remind ourselves of the inner-workings of our project.\n", - "- It will inform the design and usability of our project for the better:\n", - " > Although it may not be obvious from the outset, writing testable code leads to writing better code.\n", - " > This is, in part, because the process of writing tests gives us the opportunity to actually _use_ our code under varied circumstances.\n", - " > The process of writing tests will help us suss out cumbersome function interfaces, brittle statefulness, and redundant capabilities in our code. If _we_ find it frustrating to use our code within our tests, then surely others will find it frustrating to use in applied settings.\n", - "- It makes it easier for others to contribute to a project:\n", - " > Having a healthy test suite lowers the barrier to entry for a project. \n", - " > A contributor can make improvements to the project and quickly check to see if they have broken it or changed any of its behavior.\n", - "\n", - "This all sounds great, but where do we even begin to kick off the process of writing a test suite? \n", - "Let's start by seeing what constitutes a basic test function." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The Basic Anatomy of a Test Function\n", - "\n", - "```python\n", - "def count_vowels(x: str, include_y: bool = False) -> int:\n", - " \"\"\"Returns the number of vowels contained in `x`\n", - "\n", - " Examples\n", - " --------\n", - " >>> count_vowels(\"happy\")\n", - " 1\n", - " >>> count_vowels(\"happy\", include_y=True)\n", - " 2\n", - " \"\"\"\n", - " vowels = set(\"aeiouAEIOU\")\n", - " if include_y:\n", - " vowels.update(\"yY\")\n", - " return sum(1 for char in x if char in vowels)\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## SCRATCH\n", - "As we become capable Python users, we will naturally find ourselves moving away from writing short, trivial programs in favor of creating useful and increasingly-sophisticated projects. It is only naturally try using your code to verify its behavior. You may even devise several scenarios to exercise your project. Clearly this sort of testing need no justification; it is a ubiquitous practice among coders. Less obvious are the major pitfalls associated with this highly-manual means of testing. \n", - "\n", - "Let's consider some of the pitfalls of casual, manual tests. To do so, consider the following unfortunate scenario: you carefully run your code through several test scenarios and see that \n", - "\n", - "- \n", - "Fortunately, it is exceedingly easy to convert this casual and flawed testing workflow to one that is far more powerful and efficient.\n", - "\n", - "\n", - "```python\n", - "x += 2\n", - "\n", - "x+= 4\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "jupytext": { - "formats": "ipynb,md", - "text_representation": { - "extension": ".md", - "format_name": "markdown", - "format_version": "1.2", - "jupytext_version": "1.3.0" - } - }, - "kernelspec": { - "display_name": "Python 3", - "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.7.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/docs/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt b/docs/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt index 1fb91532..43be9158 100644 --- a/docs/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt +++ b/docs/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt @@ -636,7 +636,7 @@ To be more concrete, let's revisit our `count_vowels` function: ```python def count_vowels(x: str, include_y: bool = False) -> int: - """Returns the number of vowels contained in `in_string`""" + """Returns the number of vowels contained in `x`""" vowels = set("aeiouAEIOU") if include_y: vowels.update("yY") @@ -774,14 +774,16 @@ def pairwise_dists(x: np.ndarray, y: np.ndarray) -> np.ndarray: Parameters ---------- x : numpy.ndarray, shape=(M, D) - An optional description of ``x`` + An array of M, D-dimensional vectors. + y : numpy.ndarray, shape=(N, D) - An optional description of ``y`` + An array of N, D-dimensional vectors. Returns ------- numpy.ndarray, shape=(M, N) - The pairwise distances + The pairwise distances between the M rows of ``x`` and the N + rows of ``y``. Notes ----- @@ -829,7 +831,7 @@ def compute_student_stats(grade_book: Dict[str, Iterable[float]], Parameters ---------- - grade_book : Dict[str, List[float]] + grade_book : Dict[str, Iterable[float]] The dictionary (name -> grades) of all of the students' grades. diff --git a/docs/_sources/Module6_Testing/Hypothesis.md.txt b/docs/_sources/Module6_Testing/Hypothesis.md.txt new file mode 100644 index 00000000..119f6b31 --- /dev/null +++ b/docs/_sources/Module6_Testing/Hypothesis.md.txt @@ -0,0 +1,131 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python [conda env:.conda-jupy] * + language: python + name: conda-env-.conda-jupy-py +--- + + +.. meta:: + :description: Topic: Writing tests for your code, Difficulty: Easy, Category: Section + :keywords: test, automated, pytest, parametrize, fixture, suite, decorator, clean directory + + + +# Describing Data with Hypothesis + +It is often the case that the process of *describing our data* is by far the heaviest burden that we must bear when writing tests. This process of assessing "what variety of values should I test?", "have I thought of all the important edge-cases?", and "how much is 'enough'?" will crop up with nearly every test that we write. +Indeed, these are questions that you may have been asking yourself when writing `test_count_vowels_basic` and `test_merge_max_mappings` in the previous sections of this module. + +[Hypothesis](https://hypothesis.readthedocs.io/) is a powerful Python library that empowers us to write a _description_ (specification, to be more precise) of the data that we want to use to exercise our test. +It will then *generate* test cases that satisfy this description and will run our test on these cases. + +Let's look at a simple example of Hypothesis in action. +In the preceding section, we learned to use pytest's parameterization mechanism to test properties of code over a set of values. +For example, we wrote the following trivial test: + +```python +import pytest + +# A simple parameterized test that only tests a few, conservative inputs. +# Note that this test must be run by pytest to work properly +@pytest.mark.parametrize("size", [0, 1, 2, 3]) +def test_range_length(size): + assert len(range(size)) == size +``` + +which tests the property that `range(n)` has a length of `n` for any non-negative integer value of `n`. +Well, it isn't *really* testing this property for all non-negative integers; clearly it is only testing the values 0-3. +We should probably also check much larger numbers and perhaps traverse various orders of magnitude (i.e. factors of ten) in our parameterization scheme. +No matter what set of values we land on, it seems like we will have to eventually throw our hands up and say "okay, that seems good enough." + +Instead of manually specifying the data to pass to `test_range_length`, let's use Hypothesis to simply describe the data: + + + +```python +from hypothesis import given + +# Hypothesis provides so-called "strategies" for us +# to describe our data +import hypothesis.strategies as st + +# Using hypothesis to test any integer value in [0, 10 ** 10] +@given(size=st.integers(min_value=0, max_value=1E10)) +def test_range_length(size): + assert len(range(size)) == size +``` + + + +Here we have specified that the `size` value in our test should take on any integer value within $[0, 10^{10}]$. +We did this by using the `integers` "strategy" that is provided by Hypothesis: `st.integers(min_value=0, max_value=1E10)`. +When we execute the resulting test (which can simply be run within a Jupyter cell or via pytest), this will trigger Hypothesis to generate test cases based on this specification; +by default, Hypothesis will generate 100 test cases - an amount that we can configure - and will evaluate our test for each one of them. + +```python +# Running this test once will trigger Hypothesis to +# generate 100 values based on the description of our data, +# and it will execute the test using each one of those values +>>> test_range_length() +``` + +With great ease, we were able to replace our pytest-parameterized test, which only very sparsely tested the property at hand, with a much more robust, hypothesis-driven test. +This will be a recurring trend: we will generally produce much more robust tests by _describing_ our data with Hypothesis, rather than manually specifying test values. + +The rest of this section will be dedicated to learning about the Hypothesis library and how we can leverage it to write powerful tests. + + + +
    + +**Hypothesis is _very_ effective...**: + +You may be wondering why, in the preceding example, I arbitrarily picked $10^{10}$ as the upper bound to the integer-values to feed to the test. +I actually didn't write the test that way initially. +Instead, I wrote the more general test: + +```python +@given(size=st.integers(min_value=0)) +def test_range_length(size): + assert len(range(size)) == size +``` + +which places no formal upper bound on the integers that Hypothesis will generate. +However, this test immediately found an issue (I hesitate to call it an outright bug): + +```python +Falsifying example: test_range_length( + size=9223372036854775808, +) + +----> 3 assert len(range(size)) == size + +OverflowError: Python int too large to convert to C ssize_t +``` + +This reveals that the implementation of the built-in `len` function is such that it can only handle non-negative integers smaller than $2^{63}$ (i.e. it will only allocate 64 bits to represent a signed integer - one bit is used to store the sign of the number). +Hypothesis revealed this by generating the failing test case `size=9223372036854775808`, which is exactly $2^{63}$. +I did not want this error to distract from what is otherwise merely a simple example, but it is very important to point out. + +Hypothesis has a knack for catching these sorts of unexpected edge cases. +Now we know that `len(range(size)) == size` _does not_ hold for "arbitrary" non-negative integers! +(I wonder how many of the Python core developers know about this 😄). + + +
    + + +## Links to Official Documentation + +- [Hypothesis](https://hypothesis.readthedocs.io/) + + +## Reading Comprehension Solutions diff --git a/docs/_sources/Module6_Testing/Intro_to_Testing.md.txt b/docs/_sources/Module6_Testing/Intro_to_Testing.md.txt new file mode 100644 index 00000000..35231320 --- /dev/null +++ b/docs/_sources/Module6_Testing/Intro_to_Testing.md.txt @@ -0,0 +1,565 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +.. meta:: + :description: Topic: Writing tests for your code, Difficulty: Easy, Category: Section + :keywords: test, automated, unit, assert + + +# Introduction to Testing + +This section will show us just how simple it is to write rudimentary tests. We need only recall some of Python's basic scoping rules and introduce ourselves to the `assert` statement to write a genuine test function. That being said, we will quickly encounter some important questions to ponder. How do we know that our tests work? And, how do we know that our tests are effective? These questions will drive us deeper into the world of testing. + +Before we hit the ground running, let's take a moment to consider some motivations for testing out code. + + +## Why Should We Write Tests? + +The fact of the matter is that it is intuitive for most people to test their code to some extent. +After writing, say, a new function, it is only natural to contrive an input to feed it, and to check that the function returns the output that we expected. +To the extent that one would want to see evidence that their code works, we need not motivate the importance of testing. + +Less obvious are the massive benefits that we stand to gain from automating this testing process. +By "automating", we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. +We will accumulate these test functions into a "test suite" that we can run quickly and repeatedly. + +There are plenty of practical details ahead for us to learn, so let's expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite: + +**It saves us lots of time**: + +> After you have devised a test scenario for your code, it may only take us a second or so to run it; perhaps we need only run a couple of Jupyter notebook cells to verify the output of our code. +> This, however, will quickly become unwieldy as we write more code and devise more test scenarios. +> Soon we will be dissuaded from running our tests, except for on rare occasions. +> +> With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x's...) will summarize the health of our project (insofar as our tests serve as good diagnostics). +> This, of course, also means that we will find and fix bugs much faster! +> In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost. + +**It increases the "shelf life" of our code:** + +> If you've ever dusted off a project that you haven't used for years (or perhaps only months or weeks...), you might know the tribulations of getting old code to work. +> Perhaps, in the interim, new versions of our project's dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project's code. +> And perhaps _we can't even remember_ all of the ways in which our project is supposed to work. +> Our test suite provides us with a simple and incisive way to dive back into our work. +> It will point us to any potential incompatibilities that have accumulated over time. +> It also provides us with a large collection of detailed use-cases of our code; +> we can read through our tests and remind ourselves of the inner-workings of our project. + + +**It will inform the design and usability of our project for the better:** + +> Although it may not be obvious from the outset, writing testable code leads to writing better code. +> This is, in part, because the process of writing tests gives us the opportunity to actually _use_ our code under varied circumstances. +> The process of writing tests will help us suss out bad design decisions and redundancies in our code. Ultimately, if _we_ find it frustrating to use our code within our tests, then surely others will find the code frustrating to use in applied settings. + +**It makes it easier for others to contribute to a project:** + +> Having a healthy test suite lowers the barrier to entry for a project. +> A contributor can rely on our project's tests to quickly check to see if their changes to our code have broken the project or changed any of its behavior in unexpected ways. + +This all sounds great, but where do we even start the process of writing a test suite? +Let's begin by seeing what constitutes a basic test function. + + + +## Writing Our First Tests + +### Our "Source Code" +We need some code to test. For the sake of this introduction, let's borrow a couple of functions that may look familiar from previous modules. +These will serve as our "source code"; i.e. these are functions that we have written for our project and that need to be tested. + +```python +# Defining functions that we will be testing + +def count_vowels(x, include_y=False): + """Returns the number of vowels contained in `x`. + + The vowel 'y' is included optionally. + + Parameters + ---------- + x : str + The input string + + include_y : bool, optional (default=False) + If `True` count y's as vowels + + Returns + ------- + vowel_count: int + + Examples + -------- + >>> count_vowels("happy") + 1 + >>> count_vowels("happy", include_y=True) + 2 + """ + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + return sum(1 for char in x if char in vowels) + + +def merge_max_mappings(dict1, dict2): + """ Merges two dictionaries based on the largest value + in a given mapping. + + Parameters + ---------- + dict1 : Dict[str, float] + dict2 : Dict[str, float] + + Returns + ------- + merged : Dict[str, float] + The dictionary containing all of the keys common + between `dict1` and `dict2`, retaining the largest + value from common mappings. + + Examples + -------- + >>> x = {"a": 1, "b": 2} + >>> y = {"b": 100, "c": -1} + >>> merge_max_mappings(x, y) + {'a': 1, 'b': 100, 'c': -1} + """ + # `dict(dict1)` makes a copy of `dict1`. We do this + # so that updating `merged` doesn't also update `dict1` + merged = dict(dict1) + for key, value in dict2.items(): + if key not in merged or value > merged[key]: + merged[key] = value + return merged +``` + +As always, it is useful for us to follow along with this material in a Jupyter notebook. +We ought to take time to define these functions and run inputs through them to make sure that we understand what they are doing. +Testing code that we don't understand is a lost cause! + + +### The Basic Anatomy of a Test + +Let's write a test for `count_vowels`. For our most basic test, we can simply call `count_vowels` under various contrived inputs and *assert* that it returns the expected output. +The desired behavior for this test function, upon being run, is to: + +- Raise an error if any of our assertions *failed* to hold true. +- Complete "silently" if all of our assertions hold true (i.e. our test function will simply [return None](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Functions.html#The-return-Statement)) + +Here, we will be making use of Python's `assert` statements, whose behavior will be easy to deduce from the context of this test alone. +We will be formally introduced to the `assert` statement soon. + +```python +# Writing a rudimentary test function for `count_vowels` + +def test_count_vowels_basic(): + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 +``` + +To run this test, we simply call the function: + +```python +# running our test function +>>> test_count_vowels_basic() # passes: returns None | fails: raises error +``` + +As described above, the fact our function runs and simply returns `None` (i.e. we see no output when we run this test in a console or notebook cell) means that our code has passed this test. We've written and run our very first test! It certainly isn't the most robust test, but it is a good start. + +Let's look more carefully at the structure of `test_count_vowels_basic`. +Note that this function doesn't take in any inputs; +thanks to [Python's scoping rules](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Scope.html), we can reference our `count_vowels` function within our test as long as it is defined in the same "namespace" as `test_count_vowels_basic`. +That is, we can either define `count_vowels` in the same .py file (or Jupyter notebook, if you are following along with this material in a notebook) as `test_count_vowels_basic`, or we can [import](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Import-Statements) `count_vowels`, from wherever it is defined, into the file containing our test. +The latter scenario is by far the most common one in practice. +More on this later. + + + +
    + +**Takeaway**: + +A "test function" is designed to provide an encapsulated "environment" (namespace to be more precise) in which we can exercise parts of our source code and assert that the code behaves as expected. The basic anatomy of a test function is such that it: + +- contains one or more `assert` statements, each of which will raise an error if our source code misbehaves +- simply returns `None` if all of the aforementioned assertions held true +- can be run end-to-end simply by calling the test function without passing it any parameters; we rely on Python's scoping rules to call our source code within the body of the test function without explicitly passing anything to said test function + +
    + + +
    + +**Reading Comprehension: Adding Assertions to a Test** + +Add an additional assertion to the body of `test_count_vowels_basic`, which tests that `count_vowels` handles empty-string (`""`) input appropriately. +Make sure to run your updated test to see if it passes. + +
    + + +
    + +**Reading Comprehension: The Basic Anatomy of a Test** + +Write a rudimentary test function for `merge_max_mappings`. This should adhere to the basic structure of a test function that we just laid out. See if you can think of some "edge cases" to test, which we may have overlooked when writing `merge_max_mappings`. + +
    + + +## The `assert` Statement +With our first test functions under our belt, it is time for us to clearly understand how `assert` statements work and how they should be used. + +Similar to `return`, `def`, or `if`, the term `assert` is a reserved term in the Python language. +It has the following specialized behavior: + +```python +# demonstrating the rudimentary behavior of the `assert` statement + +# asserting an expression whose boolean-value is `True` will complete "silently" +>>> assert 1 < 2 + +# asserting an expression whose boolean-value is `False` raises an error +>>> assert 2 < 1 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert 2 < 1 + +AssertionError: + +# we can include an error message with our assertion +>>> assert 0 in [1, 2, 3], "0 is not in the list" +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert 0 in [1, 2, 3], "0 is not in the list" + +AssertionError: 0 is not in the list +``` + +The general form of an assertion statement is: + +```python +assert [, ] +``` + +When an assertion statement is executed, the built-in `bool` function is called on the object that is returned by ``; if `bool()` returns `False`, then an `AssertionError` is raised. +If you included a string in the assertion statement - separated from `` by a comma - then this string will be printed as the error message. + +See that the assertion statement: +```python +assert expression, error_message +``` + +is effectively shorthand for the following code (barring some additional details): + +```python +# long-form equivalent of: `assert expression, error_message` +if bool(expression) is False: + raise AssertionError(error_message) +``` + + + +
    + +**Reading Comprehension: Assertions** + +Given the following objects: + +```python +a_list = [] +a_number = 22 +a_string = "abcdef" +``` + +Write two assertion statements with the respective behaviors: + +- asserts that `a_list` is _not_ empty +- asserts that the number of vowels in `a_string` is less than `a_number`; include an error message that prints the actual number of vowels + +
    + + + +#### What is the Purpose of an Assertion? +In our code, an assertion should be used as _a statement that is true unless there is a bug in our code_. +It is plain to see that the assertions in `test_count_vowels_basic` fit this description. +However, it can also be useful to include assertions within our source code itself. +For instance, we know that `count_vowels` should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string. +We can explicitly assert that this is the case: + +```python +# an example of including an assertion within our source code + +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + count = sum(1 for char in x if char in vowels) + + # This assertion should always be true: it is asserting that + # the internal logic of our function is correct + assert isinstance(count, int) and 0 <= count <= len(x) + return count +``` + +Note that this assertion *is not meant to check if the user passed bad inputs for* `x` *and* `include_y`. +Rather, it is meant to assert that our own internal logic holds true. + +Admittedly, the `count_vowels` function is simple enough that the inclusion of this assertion is rather pedantic. +That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base. +We will also see that keen use of assertions can make it much easier for us to write good tests. + +
    + +**Disabling Assertions**: + +Python code can be run in an "optimized" mode such that *all assertions are skipped by the Python interpreter during execution*. +This can be achieved by specifying the command line option `-O` (the letter "O", not zero), e.g.: + +```shell +python -O my_code.py +``` + +or by setting the `PYTHONOPTIMIZE` [environment variable](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE). + +The idea here is that we may want assertions within our source code to perform expensive checks to guarantee internal consistency within our code, and that we want the ability to forgo these checks when we are no longer debugging our code. +Because they can be skipped in this way, *assertions should never be used for practical error handling*. + +
    + + + +## Testing Our Tests + +It is surprisingly easy to unwittingly write a broken test: a test that always passes, or a test that simply doesn't exercise our code in the way that we had intended. +Broken tests are insidious; they are alarms that fail to sound when they are supposed to. +They create misdirection in the bug-finding process and can mask problems with our code. +**Thus, a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior so that we can verify that our test works.** +Once we confirm that our test does indeed raise an error as expected, we restore the function to its original form and re-run the test to see that it passes. + +A practical note: we ought to mutate our function in a way that is trivial to undo. We can make use of code-comments towards this end. +All [IDEs](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) have the ability to "block-comment" selected code. +In order to block-comment code in a Jupyter notebook code cell, highlight the lines of code and press `CTRL + /`. +The same key-combination will also un-comment a highlighted block of commented code. + + + +
    + +**Reading Comprehension: Testing Your Test via Manual Mutation** + +Temporarily change the body of `count_vowels` such that the second assertion in `test_count_vowels_basic` raises an error. +Run the test to confirm that the second assertion raises, +and then restore `count_vowels` to its original form. +Finally, rerun the test to see that `count_vowels` once again passes all of the assertions. + +Repeat this process given the test that you wrote for `merge_max_mappings`. +Try breaking the function such that it always merges in values from `dict2`, even if those values are smaller. + +
    + + + +
    + +**Mutation Testing**: + +There is an entire subfield of automated testing known as ["mutation testing"](https://en.wikipedia.org/wiki/Mutation_testing), where tools like [Cosmic Ray](https://cosmic-ray.readthedocs.io/en/latest/index.html) are used to make temporary, incisive mutations to your source code - like change a `+` to a `-` or change a `1` to a `-1` - and then run your test suite. +The idea here is that such mutations *ought to cause one or more of your tests to fail*. +A mutation that does not trigger at least one test failure is likely an indicator that your tests could stand to be more robust. + +Automated mutation testing tools might be a bit too "heavy duty" at this point in our testing journey, but they are great to keep in mind. + +
    + + +## Our Work, Cut Out + +We see now that the concept of a "test function" isn't all that fancy. +Compared to other code that we have written, writing a function that simply runs a handful of assertions is far from a heavy lift for us. +Of course, we must be diligent and take care to test our tests, but we can certainly manage this as well. +With this in hand, we should take stock of the work and challenges that lie in our path ahead. + +It is necessary that we evolve beyond manual testing. +There are multiple facets to this observation. +First, we must learn how to organize our test functions into a test suite that can be run in one fell swoop. +Next, it will become increasingly apparent that a test function often contains large amounts of redundant code shared across its litany of assertions. +We will want to "parametrize" our tests to distill them down to their most concise and functional forms. +Finally, and most importantly, it may already be evident that the process of contriving known inputs and outputs to use in our tests is a highly manual and tedious process; furthermore, it is a process that will become increasingly cumbersome as our source code becomes more sophisticated. +To combat this, we will seek out alternative, powerful testing methodologies, including property-based testing. + + +## Links to Official Documentation + +- [The assert statement](https://docs.python.org/3/reference/simple_stmts.html?highlight=assert#the-assert-statement) +- [PYTHONOPTIMIZE environment variable](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE) + + +## Reading Comprehension Solutions + + +**Adding Assertions to a Test: Solution** + +Add an additional assertion to the body of `test_count_vowels_basic`, which tests whether `count_vowels` handles the empty-string (`""`) case appropriately. +Make sure to run your updated test to see if it passes. + +```python +def test_count_vowels_basic(): + # test basic strings with uppercase and lowercase letters + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 + + # test empty strings + assert count_vowels("", include_y=False) == 0 + assert count_vowels("", include_y=True) == 0 +``` + +```python +# running the test in a notebook-cell: the function should simply return +# `None` if all assertions hold true +>>> test_count_vowels_basic() +``` + + + +**The Basic Anatomy of a Test: Solution** + +Write a rudimentary test function for `merge_max_mappings`. + +> Let's test the use case that is explicitly documented in the Examples section of the function's docstring. +> We can also test cases where one or both of the inputs are empty dictionaries. +> These can often be problematic edge cases that we didn't consider when writing our code. + +```python +def test_merge_max_mappings(): + # test documented behavior + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 20, "c": -1} + expected = {'a': 1, 'b': 20, 'c': -1} + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict1 + dict1 = {} + dict2 = {"a": 10.2, "f": -1.0} + expected = dict2 + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict2 + dict1 = {"a": 10.2, "f": -1.0} + dict2 = {} + expected = dict1 + assert merge_max_mappings(dict1, dict2) == expected + + # test both empty + dict1 = {} + dict2 = {} + expected = {} + assert merge_max_mappings(dict1, dict2) == expected +``` + +```python +# running the test (seeing no errors means the tests all passed) +>>> test_merge_max_mappings() +``` + + + +**Assertions: Solution** +```python +a_list = [] +a_number = 22 +a_string = "abcdef" +``` + +Assert that `a_list` is _not_ empty: + +```python +>>> assert a_list +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert a_list + +AssertionError: +``` + +> You may have written `assert len(a_list) > 0` - this is also correct. +> However, recall that calling `bool` on any sequence (list, tuple, string, etc.) will return `False` if the sequence is empty. +> This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - `bool` will be called on whatever the provided expression is. + +Assert that the number of vowels in `a_string` is fewer than `a_number`; include an error message that prints the actual number of vowels: + +```python +>>> assert count_vowels(a_string) < a_number, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}" +``` + +> Note that we make use of an [f-string](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) as a convenient means for writing an informative error message. + + + +**Testing Your Test via Manual Mutation: Solution** + +Temporarily change the body of `count_vowels` such that the _second_ assertion in `test_count_vowels_basic` raises an error. +> Let's comment out the `if include_y` block in our code. This should prevent us from counting y's, and thus should violate the second assertion in our test. + +```python +# Breaking the behavior of `include_y=True` +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + # if include_y: + # vowels.update("yY") + return sum(1 for char in x if char in vowels) +``` + +```python +# the second assertion should raise an error +>>> test_count_vowels_basic() +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 test_count_vowels_basic() + + in test_count_vowels_basic() + 1 def test_count_vowels_basic(): + 2 assert count_vowels("aA bB yY", include_y=False) == 2 +----> 3 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: +``` + +> See that the error output, which is called a "stack trace", indicates with an ASCII-arrow that our second assertion is the one that is failing. +> Thus, we can be confident that that assertion really does help to ensure that we are counting y's correctly. + +Restore `count_vowels` to its original form and rerun the test to see that `count_vowels` once again passes all of the assertions. + +> We simply un-comment the block of code and rerun our test. + +```python +# Restore the behavior of `include_y=True` +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + return sum(1 for char in x if char in vowels) +``` + +```python +# confirming that we restored the proper behavior in `count_vowels` +>>> test_count_vowels_basic() +``` + diff --git a/docs/_sources/Module6_Testing/Pytest.md.txt b/docs/_sources/Module6_Testing/Pytest.md.txt new file mode 100644 index 00000000..cf71bd70 --- /dev/null +++ b/docs/_sources/Module6_Testing/Pytest.md.txt @@ -0,0 +1,753 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +.. meta:: + :description: Topic: Introducing the pytest framework, Difficulty: Easy, Category: Section + :keywords: test, automated, pytest, parametrize, fixture, suite, decorator, clean directory + + +# The pytest Framework + +Thus far, our process for running tests has been an entirely manual one. It is time for us to arrange our test functions into a proper "test suite" and to learn to leverage [the pytest framework](https://docs.pytest.org/en/latest/) to run them. +We will begin by reorganizing our source code to create an installable [Python package](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Packages). +We will then learn how to structure and run a test suite for this Python package, using pytest. + +The pytest framework does much more than just run tests; +for instance, it will enrich the assertions in our tests to produce verbose, informative error messages. +Furthermore it provides valuable means for enhancing our tests via mechanisms like fixtures and parameterizing decorators. +Ultimately, all of this functionality helps to eliminate manual and redundant aspects of the testing process. + + + +
    + +**Note** + +It can be useful to [create a separate conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) for the sake of this lesson, so that we can work through this material starting from a blank slate. +If you do create a new conda environment, be sure to activate that environment and install NumPy and Jupyter notebook: `conda install numpy notebook` +
    + + + +Let's install pytest. Installing from [the conda-forge channel](https://conda-forge.org/) will install the most up-to-date version of pytest. In a terminal where conda can be accessed, run: + +```shell +conda install -c conda-forge pytest +``` + +Or, pytest is installable via pip: + +```shell +pip install pytest +``` + + +
    + +**Regarding Alternative Testing Frameworks** (a note from the author of PLYMI): + +When sifting through tutorials, blogs, and videos about testing in Python, it is common to see `pytest` presented alongside, and on an equal footing with, the alternative testing frameworks: `nose` and `unittest`. +This strikes me as... bizarre. + +`unittest` is the testing framework that comes with the Python standard library. +As a test runner, its design is clunky, archaic, and, ironically, un-pythonic. +While [unittest.mock](https://docs.python.org/3/library/unittest.mock.html) provides extremely valuable functionality for advanced testing, all of its functionality can be leveraged while using pytest as your testing framework. + +`nose`, which simply extends the functionality of `unittest`, **is no longer being maintained**. +There is a project, "Nose2", which is carrying the torch of `nose`. However, this is a fledgling project in comparison with `pytest`. +As of writing this, `pytest` was downloaded 12 million times last month versus `nose2`'s 150 thousand downloads. + +The takeaway here is that, when it comes to picking a testing framework for Python, `pytest` is the clear choice. +Any discussion that you come across to the contrary is likely outdated. +
    + + +## Creating a Python Package with Tests + +It's time to create a proper test suite. +Before proceeding any further, we should reread the material presented in [Module 5 - Import: Modules and Packages](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html) and recall the essentials of import statements, modules, and Python packages. +This material serves as the foundation for this section. + +### Organizing our Source Code +Let's create a Python package, which we will call `plymi_mod6`, with the following directory structure: + +``` +project_dir/ # the "parent directory" houses our source code, tests, and all other relevant files + - setup.py # script responsible for installing `plymi_mod6` package + - plymi_mod6/ # directory containing source code of `plymi_mod6` package + |-- __init__.py + |-- basic_functions.py + |-- numpy_functions.py + - tests/ # test-suite for `plymi_mod6` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_basic_functions.py + |-- test_numpy_functions.py +``` + +A reference implementation of this package can be found [in this GitHub repository](https://github.com/rsokl/plymi_mod6). +Populate the `basic_functions.py` file with the two functions that we were using as our source code in the previous section: `count_vowels` and `merge_max_mappings`. +In the `numpy_functions.py` module, add the `pairwise_dists` function that appears in [Module 3's discussion of optimized pairwise distances](https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/Broadcasting.html#Optimized-Pairwise-Distances). +Don't forget to include `import numpy as np` in your script in accordance with how `pairwise_dists` calls NumPy functions. + +We have arranged these functions so that they can be imported from the `basic_functions` module and the `numpy_functions` module, respectively, which reside in our `plymi_mod6` package. +Let's fill out our `setup.py` script and install this package so that we can import it regardless of our current working directory. The content of `setup.py` will be: + +```python +from setuptools import find_packages, setup + +setup( + name="plymi_mod6", + packages=find_packages(exclude=["tests", "tests.*"]), + version="1.0.0", + author="Your Name", + description="A template Python package for learning about testing", + install_requires=["numpy >= 1.10.0"], + tests_require=["pytest>=5.3", "hypothesis>=5.0"], + python_requires=">=3.6", +) +``` + +This setup file dictates that a user must have Python 3.6+ installed - we will bar Python 3.5 and below so that we are free to make use of [f-strings](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) in our code, which were introduced in Python 3.6. Additionally, we will require pytest and hypothesis for running tests; the Hypothesis library will be introduced in a later section. + +Finally, let's install our package locally [in development mode](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Installing-Your-Own-Python-Package). +Navigate to the directory containing `setup.py` and run: + +```shell +pip install --editable . +``` + +Now, we should be able to start a python console, IPython console, or Jupyter notebook in any directory and import our package: + +```python +# checking that we can import our `plymi_mod6` package +>>> from plymi_mod6.basic_functions import count_vowels +>>> count_vowels("Happy birthday", include_y=True) +5 +``` + + + +## Populating and Running Our Test Suite + +pytest's [system for "test discovery"](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) is quite simple: +pytest need only be pointed to a directory with files named `test_*.py` in it, and it will find all of the functions in these files _whose names start with the word "test"_ and will run all such functions. + +Thus, let's populate the file ``test_basic_functions.py`` with the functions `test_count_vowels_basic` and `test_merge_max_mappings`, which we wrote in the previous section of this module: + +```python +# The contents of test_basic_functions.py + +# we must import the functions we are testing +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings + + +def test_count_vowels_basic(): + # test basic strings with uppercase and lowercase letters + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 + + # test empty strings + assert count_vowels("", include_y=False) == 0 + assert count_vowels("", include_y=True) == 0 + + +def test_merge_max_mappings(): + # test documented behavior + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 20, "c": -1} + expected = {'a': 1, 'b': 20, 'c': -1} + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict1 + dict1 = {} + dict2 = {"a": 10.2, "f": -1.0} + expected = dict2 + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict2 + dict1 = {"a": 10.2, "f": -1.0} + dict2 = {} + expected = dict1 + assert merge_max_mappings(dict1, dict2) == expected + + # test both empty + dict1 = {} + dict2 = {} + expected = {} + assert merge_max_mappings(dict1, dict2) == expected + +``` + +As described before, `count_vowels` and `merge_max_mappings` must both be imported from our `plymi_mod6` package, so that our functions are in the same namespace as our tests. +A reference implementation of `test_basic_functions.py` can be viewed [here](https://github.com/rsokl/plymi_mod6/blob/master/tests/test_basic_functions.py). +Finally, add a dummy test - a test function that will always pass - to `test_basic_numpy.py`. +We will replace this with a useful test later. + +Without further ado, let's run our test suite! In our terminal, with the appropriate conda environment active, we navigate to the root directory of the project, which contains the `tests/` directory, and run `pytest tests/`. +The following output should appear: + + +``` +$ pytest tests/ +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +rootdir: C:\Users\plymi_user\plymi_root_dir +collected 3 items + +tests\test_basic_functions.py .. [ 66%] +tests\test_basic_numpy.py . [100%] + +============================== 3 passed in 0.04s ============================== +``` + + +This output indicates that three test-functions were found across two files and that all of the tests "passed"; i.e. the functions ran without raising any errors. +The first two tests are located in `tests/test_basic_functions.py`; the two dots indicate that two functions were run, and the `[66%]` indicator simply denotes that the test-suite is 66% (two-thirds) complete. +The following reading comprehension problem will lead us to see what it looks like for pytest to report a failing test. + + +
    + +**Reading Comprehension: Running a Test Suite** + +Temporarily add a new "broken" test to `tests/test_basic_functions.py`. +The name that you give this test should adhere to pytest's simple rules for test-discovery. +Design the test function so that is sure to fail when it is run. + +Rerun your test suite and compare its output to what you saw before - is it easy to identify which test failed and what caused it to fail? +Make sure to remove this function from your test suite once you are finished answering this question. + +
    + + + +We can also direct pytest to run the tests in a specific .py file. For example, executing: + +```shell +pytest tests/test_basic_functions.py +``` + +will cue pytest to only run the tests in `test_basic_functions.py`. + +A key component to leveraging tests effectively is the ability to exercise one's tests repeatedly and rapidly with little manual overhead. +Clearly, pytest is instrumental toward this end - this framework makes the process of organizing and running our test suite exceedingly simple! +That being said, there will certainly be occasions when we want to run a _specific_ test function. +Suppose, for instance, that we are writing a new function, and repeatedly want to run one of our tests that is pointing to a bug in our work-in-progress. +We can leverage pytest in conjunction with [an IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) to run our tests in such incisive ways. + + +### Utilizing pytest within an IDE + +Both [PyCharm and VSCode](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) can be configured to make keen use of pytest. +The following images show a couple of the enhancements afforded to us by PyCharm; comparable features are available in VSCode. +The IDEs will "discover" tests, and provide us with the ability to run individual tests. +For example, in the following image, the green "play button" allows us to run `test_count_vowels_basic`. + + +
    +

    +Running an individual test in PyCharm +

    +
    + + +Furthermore, IDEs can provide a rich tree view of all the tests that are being run. +This is especially useful as our test suite grows to contain a considerable number of tests. +In the following image, we see that `test_version` is failing - we can click on the failing test in this tree-view, and our IDE will navigate us directly to the failing test. + + +
    +

    +Viewing an enhanced tree-view of your test suite +

    +
    + + +The first step for leveraging these features in your IDE is to enable the pytest framework in the IDE. +The following links point to detailed instructions for configuring pytest with PyCharm and VSCode, respectively: + +- [Running tests in PyCharm](https://www.jetbrains.com/help/pycharm/pytest.html) +- [Running tests in VSCode](https://code.visualstudio.com/docs/python/testing) + +These linked materials also include advanced details, like instructions for running tests in parallel, which are beyond the scope of this material but are useful nonetheless. + + +## Enhanced Testing with pytest + +In addition to providing us with a simple means for organizing and running our test suite, pytest has powerful features that will both simplify and enhance our tests. +We will now leverage these features in our test suite. + + +### Enriched Assertions + +A failing "bare" assertion - an `assert` statement without an error message - can be a frustrating thing. +Suppose, for instance, that one of our test-assertions about `count_vowels` fails: + +```python +# a failing assertion without an error message is not informative + +assert count_vowels("aA bB yY", include_y=True) == 4 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: +``` + +The problem with this bare assertion is that we don't know what `count_vowels("aA bB yY", include_y=True)` actually returned! +We now have to go through the trouble of starting a python console, importing this function, and calling it with this specific input in order to see what our function was actually returning. An obvious remedy to this is for us to write our own error message, but this too is quite cumbersome when we consider the large number of assertions that we are destined to write. + +Fortunately, pytest comes to the rescue: it will "hijack" any failing bare assertion and will _insert a useful error message for us_. +This is known as ["assertion introspection"](https://docs.pytest.org/en/latest/assert.html#assertion-introspection-details). +For example, if the aforementioned assertion failed when being run by pytest, we would see the following output: + +```python +# pytest will write informative error messages for us + +assert count_vowels("aA bB yY", include_y=True) == 4 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) +~\Learning_Python\Python\Module6_Testing\Untitled1.ipynb in +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: assert 2 == 4 + + where 2 = ('aA bB yY', include_y=True +``` + +See that the error message that pytest included for us indicates that `count_vowels("aA bB yY", include_y=True)` returned `2`, when we expected it to return `4`. +From this we might suspect that `count_vowels` is not counting y's correctly. + +Here are some more examples of "enriched assertions", as provided by pytest. +See that these error messages even provide useful "diffs", which specify specifically _how_ two similar objects differ, where possible. + +```python +# comparing unequal lists +assert [1, 2, 3] == [1, 2] +E Left contains one more item: 3 +E Full diff: +E - [1, 2, 3] +E ? --- +E + [1, 2] +``` + +```python +# comparing unequal dictionaries +assert {"a": 1, "b": 2} == {"a": 1, "b": 3} +E AssertionError: assert {'a': 1, 'b': 2} == {'a': 1, 'b': 3} +E Omitting 1 identical items, use -vv to show +E Differing items: +E {'b': 2} != {'b': 3} +E Full diff: +E - {'a': 1, 'b': 2} +E ? ^ +E + {'a': 1, 'b': 3}... +``` + +```python +# comparing unequal strings +assert "moo" == "moon" +E AssertionError: assert 'moo' == 'moon' +E - moo +E + moon +E ? + +``` + + + + +### Parameterized Tests + +Looking back to both `test_count_vowels_basic` and `test_merge_max_mappings`, we see that there is a lot of redundancy within the bodies of these test functions. +The assertions that we make within a given test-function share identical forms - they differ only in the parameters that we feed into our functions and their expected output. +Another shortcoming of this test-structure is that a failing assertion will block subsequent assertions from being evaluated. +That is, if the second assertion in `test_count_vowels_basic` fails, the third and fourth assertions will not be evaluated in that run. +This precludes us from potentially seeing useful patterns among the failing assertions. + +pytest provides a useful tool that will allow us to eliminate these structural shortcomings by transforming our test-functions into so-called _parameterized tests_. Let's parametrize the following test: + +```python +# a simple test with redundant assertions + +def test_range_length_unparameterized(): + assert len(range(0)) == 0 + assert len(range(1)) == 1 + assert len(range(2)) == 2 + assert len(range(3)) == 3 +``` + +This test is checking the property `len(range(n)) == n`, where `n` is any non-negative integer. +Thus, the parameter to be varied here is the "size" of the range-object being created. +Let's treat it as such by using pytest to write a parameterized test: + +```python +# parameterizing a test +import pytest + +# note that this test must be run by pytest to work properly +@pytest.mark.parametrize("size", [0, 1, 2, 3]) +def test_range_length(size): + assert len(range(size)) == size +``` + +Make note that a pytest-parameterized test must be run using pytest; an error will raise if we manually call `test_range_length()`. +When executed, pytest will treat this parameterized test as _four separate tests_ - one for each parameter value: + +``` +test_basic_functions.py::test_range_length[0] PASSED [ 25%] +test_basic_functions.py::test_range_length[1] PASSED [ 50%] +test_basic_functions.py::test_range_length[2] PASSED [ 75%] +test_basic_functions.py::test_range_length[3] PASSED [100%] +``` + +See that we have successfully eliminated the redundancy from `test_range_length`; +the body of the function now contains only a single assertion, making obvious the property that is being tested. +Furthermore, the four assertions are now being run independently from one another and thus we can potentially see patterns across multiple fail cases in concert. + + + +#### Decorators + +The syntax used to parameterize this test may look alien to us, as we have yet to encounter this construct thus far. +`pytest.mark.parameterize(...)` is a _decorator_ - an object that is used to "wrap" a function in order to transform its behavior. +The `pytest.mark.parameterize(...)` decorator wraps our test function so that pytest can call it multiple times, once for each parameter value. +The `@` character, in this context, denotes the application of a decorator: + +```python +# general syntax for applying a decorator to a function + +@the_decorator +def the_function_being_decorated(): + pass +``` + +For an in-depth discussion of decorators, please refer to [Real Python's Primer on decorators](https://realpython.com/primer-on-python-decorators/#simple-decorators). + + + +#### Parameterization Syntax + +The general form for creating a parameterizing decorator with *a single parameter*, as we formed above, is: + +```python +@pytest.mark.parametrize("", [, , ...]) +def test_function(): + ... +``` + +We will often have tests that require multiple parameters. +The general form for creating the parameterization decorator for $N$ parameters, +each of which assume $J$ values, is: + +```python +@pytest.mark.parametrize(", , [...], ", + [(, , [...], ), + (, , [...], ), + ... + (, , [...], ), + ]) +def test_function(, , [...], ): + ... +``` + +For example, let's take the following trivial test: + +```python +def test_inequality_unparameterized(): + assert 1 < 2 < 3 + assert 4 < 5 < 6 + assert 7 < 8 < 9 + assert 10 < 11 < 12 +``` + +and rewrite it in parameterized form. +The decorator will have three distinct parameters, and each parameter, let's simply call them `a`, `b`, and `c`, will take on four values. + +```python +# the parameterized form of `test_inequality_unparameterized` +@pytest.mark.parametrize("a, b, c", [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]) +def test_inequality(a, b, c): + assert a < b < c +``` + + +
    + +**Note** + +The formatting for multi-parameter tests can quickly become unwieldy. +It isn't always obvious where one should introduce line breaks and indentations to improve readability. +This is a place where the ["black" auto-formatter](https://black.readthedocs.io/en/stable/) really shines! +Black will make all of these formatting decisions for us - we can write our parameterized tests as haphazardly as we like and simply run black to format our code. +
    + + + +
    + +**Reading Comprehension: Parameterizing Tests** + +Rewrite `test_count_vowels_basic` as a parameterized test with the parameters: `input_string`, `include_y`, and `expected_count`. + +Rewrite `test_merge_max_mappings` as a parameterized test with the parameters: `dict_a`, `dict_b`, and `expected_merged`. + +Before rerunning `test_basic_functions.py` predict how many distinct test cases will be reported by pytest. + +
    + + + +Finally, you can apply multiple parameterizing decorators to a test so that pytest will run _all combinations of the respective parameter values_. + +```python +# testing all combinations of `x` and `y` +@pytest.mark.parametrize("x", [0, 1, 2]) +@pytest.mark.parametrize("y", [10, 20]) +def test_all_combinations(x, y): + # will run: + # x=0 y=10 + # x=0 y=20 + # x=1 y=10 + # x=1 y=20 + # x=2 y=10 + # x=2 y=20 + pass +``` + + +### Fixtures + +The final major pytest feature that we will discuss are "fixtures". +A fixture, roughly speaking, is a means by which we can share information and functionality across our tests. +Fixtures can be defined within our `conftest.py` file, and pytest will automatically "discover" them and make them available for use throughout our test suite in a convenient way. + +Exploring fixtures will quickly take us beyond our depths for the purposes of this introductory material, so we will only scratch the surface here. +We can read about advanced details of fixtures [here](https://docs.pytest.org/en/latest/fixture.html#fixture). + +Below are examples of two useful fixtures. + + +```python +# contents of conftest.py + +import os +import tempfile + +import pytest + +@pytest.fixture() +def cleandir(): + """ This fixture will use the stdlib `tempfile` module to + change the current working directory to a tmp-dir for the + duration of the test. + + Afterwards, the test session returns to its previous working + directory, and the temporary directory and its contents + will be automatically deleted. + + Yields + ------ + str + The name of the temporary directory.""" + with tempfile.TemporaryDirectory() as tmpdirname: + old_dir = os.getcwd() # get current working directory (cwd) + os.chdir(tmpdirname) # change cwd to the temp-directory + yield tmpdirname # yields control to the test to be run + os.chdir(old_dir) # restore the cwd to the original directory + # Leaving the context manager will prompt the deletion of the + # temporary directory and its contents. This cleanup will be + # triggered even if errors were raised during the test. + + +@pytest.fixture() +def dummy_email(): + """ This fixture will simply have pytest pass the string: + 'dummy.email@plymi.com' + to any test-function that has the parameter name `dummy_email` in + its signature. + """ + return "dummy.email@plymi.com" +``` + + + +The first one, `cleandir`, can be used in conjunction with tests that need to write files. +We don't want our tests to leave behind files on our machines; the `cleandir` fixture will ensure that our tests will write files to a temporary directory that will be deleted once the test is complete. + +Second is a simple fixture called `dummy_email`. +Suppose that our project needs to interact with a specific email address, suppose it's `dummy.email@plymi.com`, and that we have several tests that need access to this address. +This fixture will pass this address to any test function that has the parameter name `dummy_email` in its signature. + +A reference implementation of `conftest.py` in our project can be found [here](https://github.com/rsokl/plymi_mod6/blob/fixtures/tests/conftest.py). +Several reference tests that make use of these fixtures can be found [here](https://github.com/rsokl/plymi_mod6/blob/fixtures/tests/test_using_fixtures.py). + +Let's create a file `tests/test_using_fixtures.py`, and write some tests that put these fixtures to use: + +```python +# contents of test_using_fixtures.py +import pytest + +# When run, this test will be executed within a +# temporary directory that will automatically be +# deleted - along with all of its contents - once +# the test ends. +# +# Thus we can have this test write a file, and we +# need not worry about having it clean up after itself. +@pytest.mark.usefixtures("cleandir") +def test_writing_a_file(): + with open("a_text_file.txt", mode="w") as f: + f.write("hello world") + + with open("a_text_file.txt", mode="r") as f: + file_content = f.read() + + assert file_content == "hello world" + + +# We can use the `dummy_email` fixture to provide +# the same email address to many tests. In this +# way, if we need to change the email address, we +# can simply update the fixture and all of the tests +# will be affected by the update. +# +# Note that we don't need to use a decorator here. +# pytest is smart, and will see that the parameter-name +# `dummy_email` matches the name of our fixture. It will +# thus call these tests using the value returned by our +# fixture + +def test_email1(dummy_email): + assert "dummy" in dummy_email + + +def test_email2(dummy_email): + assert "plymi" in dummy_email + + +def test_email3(dummy_email): + assert ".com" in dummy_email +``` + + +## Links to Official Documentation + +- [pytest](https://docs.pytest.org/en/latest/) +- [pytest's system for test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) +- [Testing in PyCharm](https://www.jetbrains.com/help/pycharm/pytest.html) +- [Testing in VSCode](https://code.visualstudio.com/docs/python/testing) +- [Assertion introspection](https://docs.pytest.org/en/latest/assert.html#assertion-introspection-details) +- [Parameterizing tests](https://docs.pytest.org/en/latest/parametrize.html) +- [Fixtures](https://docs.pytest.org/en/latest/fixture.html#fixture) + + +## Reading Comprehension Solutions + + +**Running a Test Suite: Solution** + +> Let's add the test function `test_broken_function` to our test suite. +> We must include the word "test" in the function's name so that pytest will identify it as a test to run. +> There are limitless ways in which we can make this test fail; we'll introduce a trivial false-assertion: + +```python +def test_broken_function(): + assert [1, 2, 3] == [1, 2] +``` + +> After introducing this broken test into `test_basic_functions.py` , running our tests should result in the following output: + +``` +$ pytest tests/ +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +rootdir: C:\Users\plymi_user\plymi_root_dir +collected 4 items + +tests\test_basic_functions.py ..F [ 75%] +tests\test_basic_numpy.py . [100%] + +================================== FAILURES =================================== +____________________________ test_broken_function _____________________________ + + def test_broken_function(): +> assert [1, 2, 3] == [1, 2] +E assert [1, 2, 3] == [1, 2] +E Left contains one more item: 3 +E Use -v to get the full diff + +tests\test_basic_functions.py:40: AssertionError +========================= 1 failed, 3 passed in 0.07s ========================= +``` + +> Four tests were "discovered" and run by pytest. The pattern `..F` indicates that the first two tests in `test_basic_functions` passed and the third test failed. +> It then indicates which test failed, and specifically that the assertion was false because a length-2 list cannot be equal to a length-3 list. + + + +**Parameterizing Tests: Solution** + +A reference implementation for this solution within the `plymi_mod6` project can be found [here](https://github.com/rsokl/plymi_mod6/blob/parameterized/tests/test_basic_functions.py). + +The contents of `test_basic_functions.py`, rewritten to use pytest-parameterized tests: + +```python +import pytest +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings + + +@pytest.mark.parametrize( + "input_string, include_y, expected_count", + [("aA bB yY", False, 2), ("aA bB yY", True, 4), ("", False, 0), ("", True, 0)], +) +def test_count_vowels_basic(input_string, include_y, expected_count): + assert count_vowels(input_string, include_y) == expected_count + + +@pytest.mark.parametrize( + "dict_a, dict_b, expected_merged", + [ + (dict(a=1, b=2), dict(b=20, c=-1), dict(a=1, b=20, c=-1)), + (dict(), dict(b=20, c=-1), dict(b=20, c=-1)), + (dict(a=1, b=2), dict(), dict(a=1, b=2)), + (dict(), dict(), dict()), + ], +) +def test_merge_max_mappings(dict_a, dict_b, expected_merged): + assert merge_max_mappings(dict_a, dict_b) == expected_merged +``` + +Running these tests via pytest should produce eight distinct test-case: four for `test_count_vowels_basic` and four for `test_merge_max_mappings`. + +``` +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +cachedir: .pytest_cache +rootdir: C:\Users\plymi_user\Learning_Python\plymi_mod6_src +collecting ... collected 8 items + +test_basic_functions.py::test_count_vowels_basic[aA bB yY-False-2] PASSED [ 12%] +test_basic_functions.py::test_count_vowels_basic[aA bB yY-True-4] PASSED [ 25%] +test_basic_functions.py::test_count_vowels_basic[-False-0] PASSED [ 37%] +test_basic_functions.py::test_count_vowels_basic[-True-0] PASSED [ 50%] +test_basic_functions.py::test_merge_max_mappings[dict_a0-dict_b0-expected_merged0] PASSED [ 62%] +test_basic_functions.py::test_merge_max_mappings[dict_a1-dict_b1-expected_merged1] PASSED [ 75%] +test_basic_functions.py::test_merge_max_mappings[dict_a2-dict_b2-expected_merged2] PASSED [ 87%] +test_basic_functions.py::test_merge_max_mappings[dict_a3-dict_b3-expected_merged3] PASSED [100%] + +============================== 8 passed in 0.07s ============================== +``` + + diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt index f8650de9..3274b75e 100644 --- a/docs/_sources/index.rst.txt +++ b/docs/_sources/index.rst.txt @@ -64,6 +64,7 @@ I started learning to use Python in graduate school for my physics research, and module_3_problems.rst module_4.rst module_5.rst + module_6.rst changes.rst Indices and tables diff --git a/docs/_sources/module_5.rst.txt b/docs/_sources/module_5.rst.txt index 0c0bf09f..63c8036d 100644 --- a/docs/_sources/module_5.rst.txt +++ b/docs/_sources/module_5.rst.txt @@ -1,5 +1,5 @@ Module 5: Odds and Ends -===================================== +======================= This module contains materials that are extraneous to the essentials of Python as a language and of NumPy, but are nonetheless critical to doing day-to-day work using these tools. The first section introduces some general guidelines for writing "good code". Specifically, it points you, the reader, to a style guide that many people in the Python community abide by. It also introduces a relatively new and increasingly-popular feature of Python, called type-hinting, which permits us to enhance our code with type-documentation annotations. The reader will also be introduced to NumPy's and Google's respective specifications for writing good docstrings. diff --git a/docs/_sources/module_6.rst.txt b/docs/_sources/module_6.rst.txt new file mode 100644 index 00000000..2b113105 --- /dev/null +++ b/docs/_sources/module_6.rst.txt @@ -0,0 +1,21 @@ +Module 6: Testing Our Code +========================== +This module will introduce us to the critically-important and often-overlooked process of testing code. +We will begin by considering some general motivations for writing tests. +Next, we will study the basic anatomy of a test-function, including the :code:`assert` statement, which serves as the nucleus of our test functions. +Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework `pytest `_. +This will inform how we structure our tests alongside our Python project; with pytest, we can incisively run our tests with the press of a single button. +Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. +Finally, we will take a step back to consider some strategies for writing effective tests. +Among these is a methodology that is near and dear to my heart: property-based testing. +This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library `Hypothesis `_ waiting to greet us (adorned with the mad Hatter's cap and all). + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + Module6_Testing/Intro_to_Testing.md + Module6_Testing/Pytest.md + Module6_Testing/Hypothesis.md + + diff --git a/docs/changes.html b/docs/changes.html index bc4b764e..15195aee 100644 --- a/docs/changes.html +++ b/docs/changes.html @@ -40,7 +40,7 @@ - + @@ -98,6 +98,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/genindex.html b/docs/genindex.html index 1d2df97d..15d63e22 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -98,6 +98,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/index.html b/docs/index.html index dab8cc9c..defa8131 100644 --- a/docs/index.html +++ b/docs/index.html @@ -98,6 +98,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • @@ -312,6 +313,12 @@

    About MeImport: Modules and Packages +
  • Module 6: Testing Our Code +
  • Changelog diff --git a/docs/intro.html b/docs/intro.html index f33a8537..5e35f826 100644 --- a/docs/intro.html +++ b/docs/intro.html @@ -108,6 +108,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_1.html b/docs/module_1.html index 1427c4ad..901f1773 100644 --- a/docs/module_1.html +++ b/docs/module_1.html @@ -107,6 +107,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_2.html b/docs/module_2.html index c292815a..90b65c2d 100644 --- a/docs/module_2.html +++ b/docs/module_2.html @@ -115,6 +115,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_2_problems.html b/docs/module_2_problems.html index 1496c86c..6f732efb 100644 --- a/docs/module_2_problems.html +++ b/docs/module_2_problems.html @@ -106,6 +106,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_3.html b/docs/module_3.html index 03c6551c..faf179ab 100644 --- a/docs/module_3.html +++ b/docs/module_3.html @@ -110,6 +110,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_3_problems.html b/docs/module_3_problems.html index 13c54072..39835d9b 100644 --- a/docs/module_3_problems.html +++ b/docs/module_3_problems.html @@ -103,6 +103,7 @@
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_4.html b/docs/module_4.html index 916588d1..c9ca37b3 100644 --- a/docs/module_4.html +++ b/docs/module_4.html @@ -109,6 +109,7 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_5.html b/docs/module_5.html index 93224ad7..2b1a791c 100644 --- a/docs/module_5.html +++ b/docs/module_5.html @@ -105,6 +105,7 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/module_6.html b/docs/module_6.html new file mode 100644 index 00000000..34f910fb --- /dev/null +++ b/docs/module_6.html @@ -0,0 +1,287 @@ + + + + + + + + + + + Module 6: Testing Our Code — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    Module 6: Testing Our Code

    +

    This module will introduce us to the critically-important and often-overlooked process of testing code. +We will begin by considering some general motivations for writing tests. +Next, we will study the basic anatomy of a test-function, including the assert statement, which serves as the nucleus of our test functions. +Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework pytest. +This will inform how we structure our tests alongside our Python project; with pytest, we can incisively run our tests with the press of a single button. +Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. +Finally, we will take a step back to consider some strategies for writing effective tests. +Among these is a methodology that is near and dear to my heart: property-based testing. +This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library Hypothesis waiting to greet us (adorned with the mad Hatter’s cap and all).

    + +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/objects.inv b/docs/objects.inv index 1ec8b8fa..f8b23291 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/search.html b/docs/search.html index 77d97609..34f3ce45 100644 --- a/docs/search.html +++ b/docs/search.html @@ -98,6 +98,7 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Our Code
  • Changelog
  • diff --git a/docs/searchindex.js b/docs/searchindex.js index f776415e..5711b681 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python","Module1_GettingStartedWithPython/GettingStartedWithPython","Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks","Module1_GettingStartedWithPython/Informal_Intro_Python","Module1_GettingStartedWithPython/Installing_Python","Module1_GettingStartedWithPython/Jupyter_Notebooks","Module1_GettingStartedWithPython/Numerical_Work_In_Python","Module1_GettingStartedWithPython/SiteFormatting","Module2_EssentialsOfPython/Basic_Objects","Module2_EssentialsOfPython/ConditionalStatements","Module2_EssentialsOfPython/DataStructures","Module2_EssentialsOfPython/DataStructures_III_Sets_and_More","Module2_EssentialsOfPython/DataStructures_II_Dictionaries","Module2_EssentialsOfPython/ForLoops","Module2_EssentialsOfPython/Functions","Module2_EssentialsOfPython/Generators_and_Comprehensions","Module2_EssentialsOfPython/Introduction","Module2_EssentialsOfPython/Iterables","Module2_EssentialsOfPython/Itertools","Module2_EssentialsOfPython/Problems/DifferenceFanout","Module2_EssentialsOfPython/Problems/EncodeAsString","Module2_EssentialsOfPython/Problems/MarginPercentage","Module2_EssentialsOfPython/Problems/MergeMaxDicts","Module2_EssentialsOfPython/Problems/Palindrome","Module2_EssentialsOfPython/Scope","Module2_EssentialsOfPython/SequenceTypes","Module2_EssentialsOfPython/Variables_and_Assignment","Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions","Module3_IntroducingNumpy/AdvancedIndexing","Module3_IntroducingNumpy/ArrayTraversal","Module3_IntroducingNumpy/BasicArrayAttributes","Module3_IntroducingNumpy/BasicIndexing","Module3_IntroducingNumpy/Broadcasting","Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays","Module3_IntroducingNumpy/IntroducingTheNDarray","Module3_IntroducingNumpy/Problems/Approximating_pi","Module3_IntroducingNumpy/Problems/ComputeAccuracy","Module3_IntroducingNumpy/VectorizedOperations","Module4_OOP/Applications_of_OOP","Module4_OOP/Brief_Review","Module4_OOP/ClassDefinition","Module4_OOP/ClassInstances","Module4_OOP/Inheritance","Module4_OOP/Introduction_to_OOP","Module4_OOP/Methods","Module4_OOP/ObjectOrientedProgramming","Module4_OOP/Special_Methods","Module5_OddsAndEnds/Matplotlib","Module5_OddsAndEnds/Modules_and_Packages","Module5_OddsAndEnds/Testing_Your_Code","Module5_OddsAndEnds/WorkingWithFiles","Module5_OddsAndEnds/Writing_Good_Code","changes","index","intro","module_1","module_2","module_2_problems","module_3","module_3_problems","module_4","module_5"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,nbsphinx:1,sphinx:55},filenames:["Module1_GettingStartedWithPython\\Exercises\\Informal_Intro_Python.ipynb","Module1_GettingStartedWithPython\\GettingStartedWithPython.md","Module1_GettingStartedWithPython\\Getting_Started_With_IDEs_and_Notebooks.md","Module1_GettingStartedWithPython\\Informal_Intro_Python.md","Module1_GettingStartedWithPython\\Installing_Python.md","Module1_GettingStartedWithPython\\Jupyter_Notebooks.md","Module1_GettingStartedWithPython\\Numerical_Work_In_Python.md","Module1_GettingStartedWithPython\\SiteFormatting.md","Module2_EssentialsOfPython\\Basic_Objects.md","Module2_EssentialsOfPython\\ConditionalStatements.md","Module2_EssentialsOfPython\\DataStructures.md","Module2_EssentialsOfPython\\DataStructures_III_Sets_and_More.md","Module2_EssentialsOfPython\\DataStructures_II_Dictionaries.md","Module2_EssentialsOfPython\\ForLoops.md","Module2_EssentialsOfPython\\Functions.md","Module2_EssentialsOfPython\\Generators_and_Comprehensions.md","Module2_EssentialsOfPython\\Introduction.md","Module2_EssentialsOfPython\\Iterables.md","Module2_EssentialsOfPython\\Itertools.md","Module2_EssentialsOfPython\\Problems\\DifferenceFanout.md","Module2_EssentialsOfPython\\Problems\\EncodeAsString.md","Module2_EssentialsOfPython\\Problems\\MarginPercentage.md","Module2_EssentialsOfPython\\Problems\\MergeMaxDicts.md","Module2_EssentialsOfPython\\Problems\\Palindrome.md","Module2_EssentialsOfPython\\Scope.md","Module2_EssentialsOfPython\\SequenceTypes.md","Module2_EssentialsOfPython\\Variables_and_Assignment.md","Module3_IntroducingNumpy\\AccessingDataAlongMultipleDimensions.md","Module3_IntroducingNumpy\\AdvancedIndexing.md","Module3_IntroducingNumpy\\ArrayTraversal.md","Module3_IntroducingNumpy\\BasicArrayAttributes.md","Module3_IntroducingNumpy\\BasicIndexing.md","Module3_IntroducingNumpy\\Broadcasting.md","Module3_IntroducingNumpy\\FunctionsForCreatingNumpyArrays.md","Module3_IntroducingNumpy\\IntroducingTheNDarray.md","Module3_IntroducingNumpy\\Problems\\Approximating_pi.ipynb","Module3_IntroducingNumpy\\Problems\\ComputeAccuracy.md","Module3_IntroducingNumpy\\VectorizedOperations.md","Module4_OOP\\Applications_of_OOP.md","Module4_OOP\\Brief_Review.md","Module4_OOP\\ClassDefinition.md","Module4_OOP\\ClassInstances.md","Module4_OOP\\Inheritance.md","Module4_OOP\\Introduction_to_OOP.md","Module4_OOP\\Methods.md","Module4_OOP\\ObjectOrientedProgramming.md","Module4_OOP\\Special_Methods.md","Module5_OddsAndEnds\\Matplotlib.ipynb","Module5_OddsAndEnds\\Modules_and_Packages.md","Module5_OddsAndEnds\\Testing_Your_Code.ipynb","Module5_OddsAndEnds\\WorkingWithFiles.md","Module5_OddsAndEnds\\Writing_Good_Code.md","changes.rst","index.rst","intro.rst","module_1.rst","module_2.rst","module_2_problems.rst","module_3.rst","module_3_problems.rst","module_4.rst","module_5.rst"],objects:{},objnames:{},objtypes:{},terms:{"**kwarg":14,"*arg":14,"0th":[8,29],"0x00000146ce118620":50,"0x000001e768fe8a40":15,"0x000002a32898c6a8":14,"0x1d50de887b8":41,"0x1d50de896d8":41,"0x1d50de897b8":41,"0x1d50de89940":41,"0x1d50de899e8":41,"0x1d50de89a20":41,"0x1d50de89a58":41,"0x1d50de89a90":41,"0x1d50de89ac8":41,"0x1d50de89b00":41,"0x1d50de89b38":41,"0x20de1082608":18,"0x20de109ec18":18,"0x20de10a7728":18,"0x23e3557b3f0":18,"0x284f0008da0":44,"0x2ae8f65fcf8":41,"0x2ae8f666f60":41,"0x2ae8f68f2e8":41,"10000j":8,"10_000j":8,"10x10":47,"111111111111111e":8,"15x25":47,"16j":48,"1_000_000":8,"1e12":8,"1e3":8,"1e34":51,"1e9":8,"1st":[25,37],"1x10":8,"1x4":36,"207d18d18af2":27,"2246467991473532e":48,"2_3_4":8,"2cool":26,"2e10":8,"2f755f117ac9":27,"2mb":32,"2nd":12,"2x2":27,"2x3":[37,47],"2x3x4":33,"32x32":[32,37],"3471672109ee":9,"38e":8,"3rd":[4,37,50,51,55],"3x4":[15,33],"48x48":32,"4th":31,"50x75x3":47,"551115123125783e":8,"5_6_7":8,"662_607_004":8,"6gb":32,"74c002a67890":12,"7th":25,"\u0113z":27,"\u4e2d\u6587\u7248":[53,54],"\u4f60\u597d":8,"absolute import":48,"abstract method":44,"abstract":[27,28,42,45,51],"array iter":29,"basic index":31,"basic program":13,"best practic":51,"big-o":10,"binary fil":50,"boolean array index":28,"boolean":[12,20,26,35,36,37,51,56,58],"break":[3,4,8,17,23,24,26,51,56],"byte":[8,30,50],"c order":29,"c routin":37,"case":[1,3,4,5,9,10,12,13,14,15,17,19,20,21,22,23,25,27,31,32,36,37,40,45,47,49,50,51,56],"catch":[8,9,12,20,51],"char":[11,14,23,49,51],"class creat":41,"class definit":[39,40],"class funt":44,"class method":44,"class object":40,"class":[8,11,17,22,26,36,38,39,42,45,48,50,51,53,60,61],"close fil":50,"code block":7,"code styl":51,"column-major ord":29,"comparison oper":9,"console styl":7,"context manag":50,"control flow":[13,16,21],"copy index":28,"create arrai":33,"custom packag":48,"custom syntax":46,"data sci":[4,5],"default paramet":14,"default":[4,5,8,15,25,27,29,31,33,37,43,44,46,47,48,50,51,58],"dunder method":46,"export":4,"f order":29,"final":[5,8,19,20,26,31,32,35,42,47,48,49,51,52,56,58,61],"float":[3,12,15,20,21,26,27,28,31,33,36,37,43,44,46,47,51],"floating point precis":8,"for loop":19,"for-loop":[13,16],"function":[0,1,2,3,5,6,7,8,9,10,11,15,16,18,19,20,21,22,23,24,28,29,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,50,51,53,56,58,60,61],"generator comprehens":15,"get item":[12,25],"import":[0,3,4,5,6,8,10,11,12,14,15,17,18,19,20,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,41,44,47,49,50,51,53,54,56,60,61],"inline for-loop":15,"inline if":9,"int":[1,8,9,16,19,20,28,31,33,36,40,41,43,45,49,51,60],"integer array index":28,"interview prepar":[10,11,12],"is oper":9,"join directori":50,"jupyter lab":5,"linear algebra":37,"list comprehens":[15,19],"long":[2,4,8,10,12,15,19,20,23,31,37,43,47,48,49,51,56],"machine learn":36,"mismatched shap":32,"multidimensional arrai":31,"nd arrai":31,"negative index":[25,27],"nested comprehens":15,"new":[1,2,3,4,5,8,10,12,15,17,19,22,23,25,26,27,31,32,37,38,41,42,43,44,49,50,51,53,54,60,61],"no copy index":31,"null":8,"numpy arrai":[27,28,34],"object ori":[38,42,47],"ol\u00e1":8,"open fil":50,"operator overload":46,"practice problem":[19,20,21,22,23],"property-bas":49,"public":47,"python shopping list":38,"quick introduct":3,"read fil":50,"read lin":50,"relative import":48,"return":[3,4,5,6,7,8,9,10,11,12,13,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,32,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,56],"row-major ord":29,"short":[3,8,13,15,37,49,56],"special method":46,"static method":44,"static":[41,51,52,60],"sub class":42,"super":[42,45],"switch stat":9,"switch":4,"throw":[27,35],"true":[3,5,8,9,10,11,12,13,14,15,16,17,20,22,23,24,25,26,28,29,31,32,34,35,36,37,39,40,41,42,44,45,46,47,49,50,51],"try":[0,3,8,11,12,13,15,19,22,25,26,32,35,38,44,45,48,49,51,58],"type hint":51,"utf-8":50,"valid nam":26,"var":[13,14,15,26,37,41,50],"variable nam":26,"voil\u00e0":[1,32,48],"vowel count":14,"while":[0,3,4,5,16,17,19,22,24,26,27,30,31,32,47,51,53,56],"while-loop":13,Added:52,And:[4,5,11,14,20,36,49],Are:[8,15,32],Axes:[58,61],Being:25,But:[16,53,54],Doing:[26,32,38],For:[0,1,3,4,5,7,8,9,10,11,12,14,15,16,17,19,25,26,27,28,29,30,31,33,35,36,37,41,43,44,45,46,47,48,50,53,56],IDE:[1,2,5,48,51,52],IDEs:[1,16,48,51,55],IDs:36,Its:[5,8,16,37,41,45,47],Not:[5,27,36],One:[8,15,16,29,37,45,47,48,50,58],Such:[7,14],That:[1,2,4,5,8,9,10,11,12,13,14,15,17,19,20,24,25,26,27,29,31,32,35,36,40,41,42,43,44,45,46,48,50,51,53,54,60],The:[1,2,3,4,5,6,7,9,10,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,39,41,42,43,45,46,48,50,53,54,57,59,60,61],Their:[14,25],Then:[1,8,10,12,18,19,26,27,28,32,38,41],There:[1,2,3,4,5,8,9,10,13,14,15,18,19,22,25,26,31,32,33,34,36,37,43,44,47,48,49,50,51],These:[1,4,5,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,37,41,43,46,48,50,51,56,57,58,59],Tis:23,Use:[0,5,8,9,11,13,14,15,16,17,28,32,35,46,47,50,51],Uses:56,Using:[0,6,8,9,13,14,18,22,25,26,27,28,35,38,41,45,47,50,56,58],Will:[9,25,36,55],With:[4,11,41,49,50],Yes:4,__add__:[44,45,46],__all__:48,__contains__:46,__div__:46,__eq__:45,__ge__:45,__getitem__:[17,46,51],__gt__:45,__init__:[38,39,42,43,44,45,46,48,51,60],__iter__:[17,46],__le__:45,__len__:[46,51],__lt__:45,__main__:[39,40,41,44],__mul__:[45,46],__ne__:45,__next__:46,__pow__:[45,46],__radd__:45,__repr__:[42,43,45,46],__rmul__:45,__rsub__:45,__rtruediv__:45,__setitem__:46,__str__:[45,46],__sub__:[45,46],__truediv__:[45,46],_data:46,_need:[38,46],_purchas:[38,46],_use_gpu:51,_var2:26,a858573fdc63:26,a_dir:48,a_long_list_nam:51,a_poem:50,abacus:32,abbrevi:[8,34,47],abc:[3,9,25,50,51],abcabcabc:9,abcd:[17,25,44],abcdef:29,abcdefg:25,abcdefghij:13,abid:[22,51,61],abil:[2,8,9,14,16,25,26,27,29,41,43,44,46,49,51,56,61],abl:[1,3,4,5,8,12,14,22,25,26,27,29,31,32,37,44,45,47,48,53,54,58],about:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,19,22,29,32,33,35,37,38,41,43,44,45,46,47,50,51,56,60,61],abov:[4,5,8,14,22,27,31,32,35,36,39,41,48,51],abs:[8,15,21],abs_tol:8,absolut:[8,15,32,37,50],acceler:51,accept:[11,12,14,15,17,22,25,36,37,38,42,44,46,47,50,51],access:[1,3,8,9,10,11,15,17,18,19,20,22,24,25,28,29,31,32,33,34,40,41,43,44,48,50,53,58,60],accident:[4,5,48],accommod:[8,9,11,12,16,22,32,38,48,51],accomod:50,accompani:[57,59],accomplish:[0,1,3,12,14,48],accord:[1,8,9,10,12,14,20,27,29,30,31,32,35,37,41,44,47,50,51],accordingli:[1,35,46],account:[8,9,23,32,53,54],accru:51,accumul:[1,49,51],accuraci:[35,53,59],accustom:51,ace:25,aceg:25,achiev:[17,32,58],acquaint:[3,56],acquir:[53,54],across:[5,8,16,18,22,35,36,50,51],act:[37,56],action:[3,7,8,37,42,50,51],activ:[4,5,48],actual:[4,6,8,9,14,15,19,21,25,27,31,32,33,35,41,49,51,55,56,61],adam:8,add:[1,2,4,8,10,11,12,14,16,17,28,32,35,37,38,44,46,47,51,60],add_2:14,add_3:31,add_new_item:[38,46],added:[5,10,12,13,15,22,28,38,40,46,51,61],adding:[11,12,13,26,50,51,53,54,56],addit:[4,8,9,11,12,14,16,33,35,37,40,44,45,47,48,51],addition:[1,5,22,28,38,41,43,47,48],address:[14,15,22,32,41,44],adher:[16,29,51],adjust:[5,27,29],ado:4,adopt:[44,51],adorn:49,advanc:[2,4,6,12,15,27,29,34,53,58],advantag:[10,11,37,45],advis:[4,16,50],aeiou:[13,50],aeiouaeiou:[14,49,51],aesthet:51,affect:[3,16,26,31,41,43,46,47],afford:[27,49],afoot:22,aforement:[1,4,16],after:[3,4,8,11,12,13,14,15,19,22,24,27,32,40,49,51,57,59],afterward:31,again:[3,10,15,24,31,32,43,51],against:[10,19,22,36],age:8,aggress:49,agre:27,aha:20,ahead:[19,49],aid:51,aim:[28,47],air:51,aka:51,akaclass:51,akin:[8,40],aks:27,albeit:32,albert:50,alert:51,alex:53,alexding123:[53,54],alfr:8,algebra:[10,11,58],algorithm:[12,17,21,22,51,56],alia:[4,41,48,51],alias:[48,51],alias_nam:48,alic:22,alien:8,align:[8,32,47,51],alik:[5,7,15,55],all:[1,2,3,4,5,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,60,61],all_cap:51,all_fanout:19,allclos:[32,37],allevi:32,alloc:[8,31],allot:8,allow:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,19,21,23,25,27,28,29,31,32,33,34,36,38,40,41,42,45,46,47,48,49,50,51,55,56,61],almost:[8,10,12,27,32,51],alon:50,along:[3,8,11,13,15,17,20,22,23,24,28,29,30,31,32,33,34,35,37,47,48,51,53,54,56,58],alongsid:[49,51,52],alpha:[35,47],alphabet:[8,27,38,51],alphanumer:[23,26],alreadi:[4,5,6,8,9,10,12,15,25,31,38,40,41,42,44,45,48,49,50,51],also:[2,3,4,6,8,9,10,11,12,14,15,17,20,21,22,23,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,57,58,59,61],altern:[5,8,9],although:[1,5,8,12,15,17,19,23,25,27,28,29,37,40,43,47,49,50,51,56],altogeth:14,alwai:[3,5,8,9,12,13,16,20,22,27,28,29,32,37,38,42,44,47,48,51],alyosha:51,ambigu:[27,58],amend:[26,33],among:[1,5,8,12,22,25,27,37,44,49,51,58],amort:10,amount:[8,29,33,37,38,45,47,50,56],amp:47,amplitud:47,anaconda3:4,anaconda:[3,5,6,47,48,55],analog:37,analysi:[8,10,35,43,52,53,54],analyt:48,analyz:[5,10,50,51,58],anchor:51,anew:50,angi:18,angl:48,ani:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,22,24,25,26,29,30,31,32,35,37,40,41,43,44,45,46,48,49,50,55],anim:47,annabel:[53,54],annabellelew:[53,54],annot:[14,47,51,61],anoth:[1,5,8,9,11,12,15,22,25,28,29,31,32,35,41,42,43,46,47,48,51,60],another_long_nam:51,answer:[1,5,8,28,37,50],anticip:[21,44],anyon:[1,21,49,61],anyth:[1,8,9,12,14,44,45,47,50,51],anywher:[8,9,14,24,48,51],apart:5,api:[47,61],appear:[1,3,5,7,8,15,19,25,26,45,47,48],append:[0,3,8,10,11,13,15,17,19,20,25,26,35,36,41,44,45,46,50,51],appendix:46,appendleft:11,appl:[3,8,11,12,14,15,18,22,25,38,39,40,46,51],applepie_yum_yum:26,appli:[19,27,28,32,35,37,41,49,51],applic:[4,5,6,11,27,29,37,47,53,54,56,58,60],apply_fanout:19,appreci:[15,22,35,46],approach:[32,36],appropri:[0,14,21,22,26,28,29,32,38,41,50,51],approv:51,approx:35,approxim:[8,14,35,37],arang:[6,27,28,29,35,37,47,58],arbitrari:[25,28,32,40,46,51,57],arbitrarili:[8,15,28],archiv:50,area:[35,43],area_:35,aren:22,arg1:51,arg2:51,arg3:51,arg4:51,arg5:51,arg6:51,arg:[14,22,24,46],argmax:[36,37],argmin:37,arguabl:[1,21],argument:[9,12,15,17,22,24,31,33,36,39,40,41,46,47,50,51,56],aris:56,arithmet:[3,8,9,31,32,37],arm:[9,19,28,30,48,49,55,56,58],around:[8,34,41,43,51],arr:[27,31],arrai:[6,9,25,26,35,36,43,47,48,51,53,58,61],arriv:[12,58],arrow:51,articl:6,artifact:46,as_integer_ratio:8,ascrib:[9,25,27],ashlei:[12,17,26,27],asid:2,ask:25,aspect:[8,19,24,28,46,47],assert:[45,49],assess:23,assign:[0,1,3,5,7,9,13,14,17,22,25,27,39,40,41,48,53,56,58],associ:[4,8,9,10,12,36,37,45,47,48,49,51],assort:[27,32],assum:[1,4,8,9,10,12,19,21,24,25,35,36,44,50,51],assumpt:[47,51],assur:50,asterisk:14,astrophys:58,astropi:58,astyp:47,atrophi:51,attempt:[4,8,13,19,25,26,40,44,45,48],attent:[17,43,51,56,60],attr:[40,42],attract:6,attribut:[38,39,42,43,44,45,46,48,53,58,60],attribute_nam:40,attributeerror:[39,40,45],augment:[38,58],author:48,auto:[43,48],autocomplet:[2,3,5],autom:[49,51],automat:[8,16,19,27,31,38,39,41,43,44,47,50,51],autoreload:48,avail:[3,5,7,8,10,11,12,25,27,33,37,40,45,47,48,50,51,52,53,54],averag:[32,35,37,56],avoid:[3,8,15,17,32,33,37,51],awai:[3,14,49,51,53,54],awar:[2,5,8,47,50],ax1:47,ax2:47,ax3:47,ax4:47,ax5:47,ax6:47,axes:[27,30,31,32,35,37,47],axi:[27,28,29,30,31,32,34,35,36,47],axs:47,b9d20096048c:15,b_attr:42,back:[4,5,13,29,49,51,53,54],background:[7,47],backtick:7,bad:[16,22,35,40,44,51,53,54],bad_dict:12,bad_f:14,bad_func1:14,bad_func2:14,bad_func3:14,bad_func4:14,bad_merge_max_map:22,bagel:50,balanc:56,banana:[12,18,22,51],bar:[16,47],bare:[48,58],barrier:49,base:[1,5,8,9,14,19,20,22,25,26,27,28,32,33,45,47,48,49,51],base_fanout:19,base_numb:19,bashrc:4,basic:[1,5,7,9,13,15,17,25,27,32,34,40,41,43,47,48,50,53,54,56,58],basic_math:48,basic_modul:48,basket:8,batch:36,batman:8,bcd:25,beauti:47,becaus:[1,4,8,9,10,11,12,13,14,15,17,22,25,27,28,29,31,33,35,36,37,44,45,48,49,50,53,54],becom:[1,5,6,9,11,13,15,17,18,27,33,37,40,48,49,51,53,54,55,56],bedrock:50,been:[1,4,5,8,10,12,15,20,25,27,31,32,35,37,38,40,43,45,48,51,53,54,56],beet:46,befor:[4,10,12,13,15,16,22,23,27,32,38,43,45,48,50],begin:[1,3,4,7,8,9,10,11,16,22,25,26,27,28,31,32,35,38,40,44,49,50,51,53,54,55,56],beginn:[4,5],behav:[8,11,12,13,14,19,20,22,25,28,31,35,36,37,41,43,44,45,46,51,60],behavior:[8,9,11,14,19,20,21,22,23,25,26,28,37,44,46,47,49],behind:[6,15,26,31,32,45,49],being:[1,2,4,5,7,8,9,12,13,14,15,17,20,22,26,27,28,29,31,32,35,37,38,39,40,41,42,43,44,45,46,47,48,50,51,53,54,60],belong:[8,9,18,34,39,43],below:[4,5,11,35,40,50,56],beneath:[5,13],benefit:[5,33,37,47,48,49,51],best:[6,8,22,26,28,37,47,50,53,54,61],better:[12,22,29,49,50],between:[1,3,4,5,7,8,15,16,19,25,27,31,32,35,37,41,42,47,51,58,60],beyond:[3,8,12,14,15,19,27,31,32,44,46,48,61],biff:51,big:[2,4,10,12,28,31],biggest:51,billion:8,bin:[4,47,48],binari:[4,19,50,51],bind:40,bit:[8,14,15,18,29,30,33,37,47,49,50],black:[51,56],blank:[14,16,47,51],blazingli:6,bloat:32,block:[5,7,8,9,13,16,24,36,50,56],blog:[53,54],blogospher:25,blue:[5,32,37,47],board:35,bob:[3,8,22],bodi:[9,11,13,14,16,20,40,41,44],bogus_path:50,bohm:11,bohr:11,boil:1,boiling_point:51,bokeh:47,bolster:[44,56],bone:48,bonu:0,book:[11,32,50,51,53,54],bookkeep:[27,29],bool:[8,12,13,14,15,17,20,23,28,37,41,49,51,56],bool_ind:28,bool_index:28,boope:25,boopeeboopeeboopeeboopeeboope:25,border:5,both:[5,6,8,9,10,11,13,14,25,26,27,28,29,31,32,37,39,42,43,44,45,47,48,50,51],bottleneck:[22,23,32],bottom:[1,5,8,9,13,14,15,25,26,37,47,48],bound:[19,27,35,40,43,47,48],box:[2,56],brace:[10,12,16],bracket:[8,10,12,16,25,46,50,51],brad:[17,27],branch:[9,16,56],brand:44,bread:38,brian:[18,26],brief:[7,37,48,51,52,53,55,60],briefli:[4,9,11,18,24,27,43,47,50],bring:[5,44],brittl:49,broadcast:[28,29,31,34,35,37,47,51,53,58],broadcast_to:[32,47],broadli:41,broken:[20,49],brought:60,browser:[5,47],bruce:[8,51],bud:51,bug:[8,9,12,17,22,31,49,51],buggi:57,buggy_merge_max_map:22,build:[3,4,16,27,29,32,37,42,48,55],built:[0,3,8,9,10,11,12,14,15,17,18,21,25,29,31,35,38,40,41,42,43,44,48,50,51,56],builtin:40,bullet:[6,46],bunch:[32,56],bundl:45,button:[4,49],bye:[8,14],calcul:[0,6,19,32,34,37],calibr:48,call:[1,3,4,5,7,8,9,11,12,13,14,15,19,20,22,23,26,27,31,32,33,34,36,37,40,41,44,45,46,47,50,51,56,61],callabl:19,came:[4,6,12],camel:40,camelcas:51,camera:48,can:[0,1,2,3,4,5,6,7,9,10,11,13,14,15,16,17,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,54,56,60,61],cannot:[5,8,10,11,12,13,14,15,24,25,26,27,31,32,41,45,50,51,58],cap:49,capabl:[1,5,17,20,37,43,47,48,49,51,58],capit:[8,43,44,51],capsul:14,caption:7,captur:51,capword:51,care:[10,12,14,19,20,22,32,38,48,50,51,55],carefulli:[37,49,51],carpent:[53,54],carri:[1,29,38,43,48],carrot:12,cassi:[17,18,27],cast:[14,20],casual:[40,49],cat:[3,8,11,14,18,24,25,36,40,41,43],cat_dog_goose_oth:36,catcatcat:25,categori:[27,51],catwoman:8,caught:[53,54],caus:[1,13,16,22,26,31,48,50],caution:[8,38],caveat:4,cavemen:32,cavewomen:32,cba:9,cdot4:32,cdot5:32,cdot6:32,cdot7:32,cdot:[32,37],ceaselessli:13,celin:51,cell:[22,36,49,55],celsiu:51,center:[8,32,35,42,43],center_of_mass:32,certain:[3,32,50],certainli:12,chain:[9,18],challeng:57,chanc:5,chang:[1,3,4,5,8,12,19,22,25,26,27,31,32,35,41,48,49,51,53,54],changelog:53,channel:[32,47,48],charact:[0,1,2,3,8,9,11,13,16,23,26,43,46,50,51,56],characterist:51,charli:40,chart:47,cheat:47,check:[2,3,8,9,10,11,12,15,20,22,25,27,31,32,37,40,41,46,48,49,50,51,56],chees:12,chines:[53,54],chocol:51,choic:[20,51],choos:[22,27,33,47,51],chosen:[51,53,54],chronolog:52,chunk:5,cindi:22,circl:[35,47],circuit:[13,56],circumst:[6,24,26,49],cite:51,civil:[33,40],clariti:16,class_:51,class_func:44,classa:11,classb:11,classif:[53,59],classifi:[36,51],classification_accuraci:36,classification_scor:36,classmethod:44,classnam:40,claus:[9,15,20,56],clean:[11,17,51,56],cleaner:[8,36,51],clear:[9,14,15,20,27,32,34,35,37,44,50,51,56],clearli:[19,49,51],clever:[20,22,25,32],click:[0,4,5],clockwis:43,close:[0,5,8,35,37,50,51,53,54],closur:51,cloth:46,cloud:48,cls:[44,51],cmap:47,cmath:8,cmd:[1,3,4],cnt:[7,40],cnt_div_by_3:16,code:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,31,32,34,35,36,37,38,39,40,41,42,45,47,48,50,52,53,54,55,56,57,58,59,61],coder:49,coerc:32,coexist:43,coffe:46,coher:[37,51],col:[15,28,47],collabor:51,collect:[1,4,8,9,10,12,13,17,25,27,32,37,40,43,48,49,50,51,53,56],colon:[9,11,13,14,25,51],color:[2,5,7,32,37,47],colormap:47,column:[27,28,30,31,32,34,35,36,37,47,58],com:51,comb_l:18,combin:[14,18,24,31,32,37,41,46,58],come:[1,3,4,6,7,8,10,14,17,25,37,49,50,51,56,60],comfort:[18,21,37],comma:[8,14,15,25,51],command:[1,4,5,9,15,22,36,47,48,51],commensur:47,comment:7,common:[3,4,5,8,10,11,12,15,16,22,25,26,27,28,34,37,41,44,45,50,51,56],commonli:[8,9,14,29],commun:[2,5,51,61],commut:45,comp_var:24,compact:12,compani:51,compar:[5,6,8,9,10,11,12,15,22,23,24,27,32,36,37,51],comparison:[1,8,11,21,22,23,35,37,51,56],compat:[4,6,8,32,38,45,46,51],compet:[5,53,54],compil:[34,37,51],complac:[53,54],complain:44,complet:[2,4,5,6,8,9,10,11,12,13,20,21,27,29,33,35,36,46,48,50,51,53,54],complex32:30,complex64:33,complex:[11,26,33,48,51,56],complic:[12,15,35],compon:[6,31,48],compound:9,comprehens:[0,5,20,21,23,24,36,46,53,56,57,58,60,61],compris:[32,33],comput:[1,2,3,5,6,7,8,10,14,15,16,19,21,24,25,27,32,35,36,41,43,48,50,51,53,55,56,58],compute_area:[42,43],compute_corn:43,compute_exp:14,compute_student_stat:51,con:2,concat_to_str:20,concaten:[3,19,20,25,33,44],concept:[12,13,16,27,29,42,43,45,53,60],concern:[15,19,23,48,51,56],concis:[9,17,19,23,32,35,47,51,56,58],conclud:[10,14,26,28,32,44,48,51,60],conclus:58,concret:[13,29,32,41,51],conda:[55,61],condens:9,condit:[0,8,12,13,15,16,20,22,28,32,51,53,56],condition:16,conduc:1,conduct:[5,13],config:48,configur:[1,2,48,51],confirm:[0,44],conflict:[4,26,48,51],conform:1,confus:[1,8,15],conjunct:[17,28,50],connect:[5,47],consecut:9,consid:[6,9,10,13,15,16,19,20,21,22,23,25,27,28,29,31,32,37,41,42,44,48,49,51,57,59,61],consider:[6,38,56],consist:[9,14,16,25,26,27,35,41,46,48,51],consol:[3,4,5,7,8,16,22,26,36,43,45,46,47,48,51],constant:[10,48,51,58],constitut:49,constraint:[22,36,51],construct:[8,10,11,15,16,17,23,25,27,28,33,44,47,48,50,56,60],constructor:[8,12,15],consult:[8,11,46,47,51],consum:[11,12,23,25,32],consumpt:[15,32],contact:60,contain:[0,1,2,3,4,5,8,9,10,11,12,14,15,16,17,18,22,24,25,26,27,28,30,31,32,33,34,35,37,38,40,41,45,47,48,49,50,51,56,60,61],content:[1,3,5,8,9,10,11,12,13,14,15,17,24,25,26,27,28,31,32,33,34,36,37,41,46,48,50,51,53,54,55,56,57,58,59,60,61],context:[2,3,13,14,17,24,28,30,31,37,41,45,46,50,61],context_manag:50,context_vari:50,continu:[22,26,27,56],continuum:48,contour:47,contract:[22,40],contrast:[24,37,40,44,51],contribut:[49,51,53,54],contributor:49,contriv:[18,49],control:[2,8,13,17,20,21,29,46,47,53,56],convei:[10,17,32,42,47,51],conveni:[1,3,8,9,10,15,27,32,37,44,46,47,48,50],convent:[40,44],convers:20,convert:[8,15,20,25,48,49,50],convinc:[22,28],convolut:[19,51],cook:[22,32],cool:12,coord:32,coordin:[11,12,32,35,38,47],copi:[22,23,26,27,28,31,32,41,46,48,53,54],core:[3,10,18,51,53,54,58],corner:[5,43],cornerston:[53,54,56],correct:[25,36,51,57],correctli:[9,22,36,51],correspond:[1,8,11,12,14,15,17,18,20,21,24,25,27,28,29,31,32,33,35,36,37,47],corrupt:50,cos:[5,37,47],cost:49,costli:5,could:[3,5,8,9,12,18,22,27,29,32,34,37,44,47,51,53,54],count:[3,8,10,11,12,14,16,17,18,21,25,35,36,41,45,51],count_even:14,count_vowel:[14,49,51],counterpart:31,coupl:[8,20,49],cours:[1,2,3,4,5,6,14,16,26,27,49,50],courtnei:51,cout:1,cover:[8,12,14,17,37,50],cow:[12,14,17,18,24],cpython:[1,3,4,5,10,12,51],craft:61,creat:[0,1,2,3,4,8,9,12,17,18,20,22,23,25,26,27,28,29,31,32,34,35,37,38,39,40,42,43,44,45,48,49,50,51,53,54,55,56,58,60,61],creation:[11,32,33,40,41,43,50],creativ:25,creator:[48,51],credit:19,criterion:22,critic:[4,5,10,16,25,29,31,41,43,48,49,51,53,54,55,58,61],cross:[4,46],crowd:51,crucial:6,crude:35,crust:50,cryptic:8,ctrl:[0,5],cube:[9,48],cue:[3,27,37],cumbersom:49,cumsum:35,cumul:35,curat:[36,48],curi:11,curli:[8,10,12,16],current:[5,8,15,35,44,48,51,53,54],current_num:17,cursor:5,curv:[2,5,35,47],custom:[6,8,43,47,48,50,51,60],custom_dot_product:51,custom_inherit:51,customiz:2,cut:5,cute:20,cycl:47,d3_arrai:27,d5_arrai:27,d_sinc:5,dabbl:55,dai:[4,61],danger:[9,53,54],dangl:32,dart:[53,59],dart_posit:35,dash:[35,47,51],data1:50,data2:50,data:[2,3,4,5,15,22,25,28,29,30,32,34,36,37,43,45,47,48,50,51,53,54,55,56,58,60,61],databas:[48,51],datafram:43,dataset:[27,47],datatyp:33,date:[1,8,51,53,54],datum:36,davi:51,david:[11,12,18,50,53,54],deactiv:4,dead:[4,9],deal:[3,8,10,12,19,28,36,37,48],dear:49,debat:21,debug:[2,5,22,51],debugg:2,decid:35,decim:[3,8,12,32],decis:51,decod:50,decor:44,dedic:[2,17,31],deduc:35,deem:27,deep:[25,53,54],deepen:43,deeper:[15,47,48],deepli:[48,53,54],def:[5,6,7,10,12,16,19,20,21,22,23,24,26,31,32,36,38,39,40,41,42,43,44,45,46,48,49,51,56],defacto:44,defaultdict:[11,48],defin:[1,3,5,7,8,11,13,14,15,16,20,22,24,26,27,31,33,34,37,38,39,42,43,44,46,48,50,51,53,56,58,60],definit:[2,10,12,13,14,15,16,17,24,27,29,31,32,37,38,39,41,42,43,44,48,51,60],deg_to_rad:48,degre:[35,48,58],deleg:37,delet:5,deliev:48,delimit:[8,9,13,14,46,50,51,56],deliv:48,deliveri:48,delv:[26,28,31,37],demand:[15,56],demarc:14,demo:3,demonin:45,demonstr:[7,8,9,11,12,13,18,19,22,24,25,26,28,29,31,32,33,37,40,41,44,46,47,48,50,51],denom:45,denot:[5,8,9,10,14,27,37,40,50],depend:[2,4,10,12,13,21,26,29,45,48,49,50,58],depict:[27,35],deriv:5,describ:[1,11,20,30,37,41,42,43,48,51,56],descript:[8,10,11,14,22,28,29,48,51],deserv:17,design:[1,3,8,11,21,27,36,37,40,43,44,46,47,49,50,51,56,57,58,59],desir:[5,21,22,27,29,32,44,46],desktop:[48,50],despit:[22,48],detail:[4,5,7,8,12,14,17,25,26,27,28,29,32,37,44,45,47,48,49,50,51,56],detect:[12,48],determin:[1,8,9,10,19,23,28,31,32,33,35,42,46,51],dev:[22,33,35,36],develop:[1,5,23,32,38,47,48,49,51,52,53,54,55,58],deviat:[21,35,37],devic:[8,53,54],devis:[22,49],diagnost:49,diagon:28,diagram:[25,27,32],dict1:22,dict2:22,dict:[11,12,17,22,41,44,60],dictat:[12,40],dictionari:[9,10,14,15,17,20,26,43,44,46,50,51,53,56,57],did:[3,8,10,13,19,20,22,35,38,44,55],didn:[29,35,44],diff:32,differ:[2,3,5,6,8,9,10,11,12,14,15,16,20,22,23,24,25,29,31,32,34,43,44,45,47,48,51,53,56,57,58,60],difference_fanout:57,difference_upd:[38,46],differenti:[1,2,43],difficult:[28,51],digit:[8,20,32,37,53,54],dilig:[8,48],dimens:[28,29,30,31,33,34,35,37,53,58],dimension:[6,29,30,32,33,34,43,47,58],ding:53,direct:[32,37,48],directli:[1,2,4,6,8,15,25,31,36,48,50],directori:[1,4,5,47,48,50],discard:8,discern:[12,30,51],discourag:23,discov:40,discret:47,discuss:[2,4,8,9,12,13,14,15,22,25,26,27,28,29,30,31,32,37,39,42,43,44,46,48,49,50,51,52,53,54,55,56,58,60],disk:50,dismai:8,dispatch:58,displai:[3,7,8,25,26,35,43,46,61],dispos:8,dissuad:49,dist:32,dist_from_origin:35,distanc:[35,51,58],distil:[47,53,54,56],distinct:[7,9,11,14,17,25,26,28,31,34,37,41,42,43,47],distinctli:7,distinguish:[2,7,11,34,43,44,50,56,60],distribut:[3,4,11,33,37,47,48,55],distutil:48,div:37,dive:[4,15,25,46,48,49,58],divers:[47,51],divid:[8,32,33,35,36,37,46,51],divide_func:48,divis:[8,9,16,32,37,46],divorc:31,dlib:51,doc2:9,doc:[14,35,51],docstr:[14,22,40,51,61],document:[1,2,3,5,45,53,54,56,58,60,61],doe:[3,5,8,9,10,11,12,14,15,20,22,23,25,26,27,28,31,33,37,41,42,44,45,47,48,51,55,56],doesn:[5,11,12,17,22,25,32,44,45,53,54],dog:[3,11,14,18,24,25,36,40,51],doing:[1,3,4,5,6,8,33,34,47,48,52,55,56,58,61],domain:[5,28,33,36,47],don:[5,8,9,12,19,27,31,45,50,51,53,54],done:[5,29,37,40,48],doom:32,dos:51,dot:[8,32,37,40,47,48],dot_index:9,doubl:[3,8,10,41,46,51],down:[1,20,27,37,48,49,50,53,54,61],downgrad:48,download:[1,2,4,48],downsid:[11,12,23],downstream:22,dpi:47,draw:[33,43,47,60],drawn:[10,18],dream:32,drill:48,dropbox:51,dropdown:5,dtype:[28,30,33,34,37],duck:51,dude:3,due:[12,37,48],dummi:[40,41,44,48],dummy_inst:41,dump:50,dunder:[41,46],dure:[1,15,35,48,51],dust:49,dynam:47,dynload:48,e7cf39509d06:12,each:[9,10,11,12,13,14,15,16,17,18,19,20,22,23,25,27,28,29,30,31,32,33,34,35,36,37,40,41,43,47,48,50,51,56,57,58,59],earli:[5,13],earlier:[8,12,15,19,27,35,41,51],easi:[2,4,17,22,37,45,48,49,50,51,56],easier:[29,35,38,46,49,51],easiest:48,easili:[2,5,7,14,19,22,32,35,53,54],echo:46,econom:15,ed60a54ccf0b:15,edg:[14,20,21,27],edit:[2,5,51,53,54,55],editor:[1,2,5,48,51],educ:55,edward:12,effect:[4,5,8,11,12,16,22,29,32,35,37,40,47,48,49,51,56,58],effici:[3,6,10,11,12,15,16,17,18,23,31,32,37,49,51,56,58],effort:5,egg:46,eigenvalu:37,eight:[9,16,20],einstein:11,either:[8,9,11,13,14,22,27,29,32,37,38,40,44,45,50,51],electr:8,electron:47,eleg:[2,6,9,17,28,35,42,46,47,61],elegantli:8,element:[10,11,12,15,18,19,25,26,27,28,29,30,31,32,34,35,37,38,44,45,46,51,56],elementwis:[35,37],elif:[14,16,17,20,22,26,56],elimin:36,elppa:25,els:[14,15,16,17,20,21,22,24,26,35,36,44,45,46,50,51,56],elsewher:[16,26],elucid:48,email:56,emb:[5,47],embark:[16,55],embed:47,embellish:51,embodi:[40,48],embrac:47,emerg:5,emit:23,emmi:[41,50],emphas:[8,20,32,53,54,57,59],emphasi:[51,53,54],empow:60,empti:[0,8,9,11,12,13,14,19,21,22,25,27,29,32,33,41,51],emul:[46,47],enabl:[2,4,5,19,43,46,47,48,50,51,56,58],encapsul:[14,16,24,31,39,41,43,45,49,51,56,60],enclos:13,encod:[36,50,53,57],encount:[4,8,11,13,15,17,24,25,27,41,43,44,50,51],encourag:[4,51],end:[1,3,4,5,8,9,10,11,13,14,15,16,17,18,19,25,26,28,29,32,34,35,37,40,49,50,51,53],endear:37,endeavor:56,endl:1,endors:2,endswith:8,enforc:51,engin:[1,8],english:[1,8,20,51],enhanc:[51,61],enjoi:35,enough:[5,8,29,53,54],enrol:11,ensur:[1,4,8,22,25,38,50,51],entail:[1,12,26,40,48],enter:[3,5,7,11,13,14,16,38,50],entertain:35,entir:[3,8,10,15,17,20,24,25,26,31,36,37,46,48,50],entireti:[10,37,57,59],entri:[3,8,10,11,14,17,25,26,27,28,29,31,32,33,34,37,38,41,47,48,49,51],enumer:[18,19,22,29,32,35,48],env:4,envelop:14,environ:[1,5,46,47,48,52,53,55],envis:32,eps:47,equal:[5,8,9,11,12,28,30,32,33,37,42],equat:[0,3,5,8,28,32,35,47],equip:56,equival:[8,9,11,13,14,15,19,20,21,22,23,25,27,28,31,32,33,37,41,42,44,46,51],eras:[5,50],err_low:47,err_upp:47,error:[1,2,5,8,9,12,13,14,19,21,25,26,27,36,44,45,47,50,51],errorbar:47,esc:5,especi:[1,2,5,19,20,27,28,30,45,48,51],essenti:[1,5,11,12,13,15,17,18,28,37,42,43,47,48,53,54,55,57,59,60,61],establish:[32,60],estim:[8,53,59],etc:[2,4,22,25,31,35,37,40,51,53,54,60],euclidean:[32,51],euler:[11,41,48],evalu:[0,5,9,12,13,14,17,20,22,33,40,47,51],even:[5,6,7,8,9,10,12,13,14,15,16,17,19,20,24,28,32,34,38,40,41,44,48,49,50,51,53,54],even_gen:15,evenli:[5,8,33,47],event:[11,50],eventu:[50,51],ever:[3,5,9,13,14,15,17,32,49],everi:[4,5,13,15,16,22,25,31,35,37,41,50,51],everyon:49,everyth:5,everywher:[36,37],evid:49,evil:23,evolv:35,exact:[8,15,28,32,41,51],exactli:[8,11,12,15,16,28,32,37,45],exagger:51,exam:[12,22,26,27,32],exam_1:22,exam_1_scor:18,exam_2:22,exam_2_scor:18,examin:45,exampl:[1,3,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,36,37,39,41,42,43,44,45,46,47,48,49,51,55,56,61],example_arrai:30,example_default_dict:11,example_dict:12,example_gen:15,example_scop:24,exce:[8,13],exceedingli:[14,49,51],excel:[2,3,5,11,46,51],except:[8,14,15,26,49,51],exception:1,excit:5,exclud:[14,15,25,33,46],exclus:[5,15,33,37],exe:[1,3,4],execut:[1,2,3,4,5,6,8,9,13,14,16,20,24,39,40,41,43,44,45,47,48,56],exemplifi:51,exercis:[20,49,56,57,59,61],exhaust:[8,11,15,28,37,45,46,53,54],exhibit:28,exist:[1,4,8,10,11,12,22,24,26,32,40,42,46,50,51,60],exit:[13,14,19,22],exorcis:49,exp:[8,31,37,47],expand:[9,16,43],expect:[1,4,7,10,14,15,35,37,40,44,45,47,48,49,50,51],expedit:49,expel:20,experi:[2,35,51],experienc:[53,54],experiment:8,explain:[5,8,25,44,48],explan:[10,46,50,57,59],explicit:[1,12,14,23,27,31,32,35,37],explicitli:[9,11,15,18,25,29,32,37,41,44],explor:[3,5,25,50],expon:8,exponenti:37,expos:[8,27,51],express:[0,8,10,12,13,14,19,20,22,23,31,36,37,40,46,51,53,56],expression_1:9,expression_2:9,expression_n:9,extend:[8,9,29,35,47,51,57],extens:[2,8,17,35,37,47,50,51,57],extent:[19,43,49],extern:44,extra:[19,32,57],extract:[9,11,15],extran:61,extraordinarili:50,extrapol:[20,27],extrem:[2,12,15,17,22,28,31,35,44,46,50,56],f8487d9d0863:[8,9],face:[44,48],face_detect:48,face_detector:48,facial:48,facilit:[2,5,10,11,17,28,29,47,48,51,58],fact:[1,5,8,9,12,14,15,26,37,43,46,49,51,60],factor:[10,45,47],factori:[3,8,14,21],fail:[9,11,26,45,50],failur:19,faithfulli:51,fall:[16,21,27,28,35,47],fallen:35,fals:[0,3,8,9,10,11,12,13,14,15,17,20,23,25,26,28,31,35,36,37,40,41,45,46,49,50,51],familiar:[1,2,3,4,8,9,10,11,17,20,21,31,34,35,37,45,47,51,55,56],fanci:[14,20],fancier:15,fanout:[53,57],fantast:[6,8,50,55],far:[6,8,17,25,27,29,31,39,41,43,46,47,48,49,51,56],farmer:8,fashion:[22,27,37],fast:[6,12,18,37],faster:[4,6,10,36,37,48,49],favor:[8,49],featur:[1,2,3,5,11,15,16,17,33,34,43,47,48,51,52,53,54,58,61],fed:[3,11,12,15,22,37,47],federici:[53,54],feed:[11,14,15,33,36,37,41,49],feedback:[53,54],feel:[5,15,25,35,46,55,56],fell:[12,17,35],fermi:[11,41],few:[3,8,10,14,15,16,18,38,45,46,51,60],fewer:[19,31],feynman:11,fidel:51,field:[8,48],fig:[5,35,47],figsiz:47,figur:61,file12345:50,file1:50,file2:50,file3:50,file4:50,file:[1,2,4,5,9,24,26,45,47,48,53,61],file_var:24,filefilefil:50,filenam:[2,9,47],fill:[29,31,32,33,37,47],fill_between:[35,47],filter:[9,11,15,21,23],filtered_str:23,find:[1,4,5,8,9,10,11,13,15,18,19,22,25,29,31,32,35,36,46,48,49,50,51,60],find_alpha:51,find_packag:48,fine:[8,33],finish:41,finit:[8,15,25],first:[1,2,3,4,5,8,9,11,12,13,14,15,16,17,19,20,22,23,25,27,29,31,32,35,36,37,41,43,44,45,46,48,50,51,52,58,60,61],first_item:9,fit:50,five:[8,20,25,33,36,51],fix:[49,51,52],flag:51,flake8:51,flaw:[22,49],flesh:48,flexibl:[6,12,14,16,26,28,31,40,47,48,51],flip:[22,27],float16:33,float32:33,float64:30,float_kei:12,floor:8,flour:46,flow:[5,13,17,20,21,53,54,56],fly:51,focu:51,focus:47,folder:[1,5],folli:12,follow:[0,1,3,4,5,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,36,37,39,40,41,44,45,46,47,48,49,50,51,53,54],food:[12,46],footprint:32,for_block:24,forai:43,forc:50,forego:3,foregon:18,foremost:[1,2,48,51],forese:14,forev:0,forget:50,forgiv:16,form:[3,8,9,11,15,17,18,20,23,25,26,28,31,32,33,37,41,44,46,48,50,51,60],formal:[5,8,9,10,13,16,27,28,32,36,40,49,51,52,56],format:[1,2,3,5,14,20,26,40,42,43,45,46,47,50,51,53,55],formatt:51,former:[3,9,46,57,59],formul:32,formula:[0,35,48,51],forth:4,fortran:29,fortun:[6,15,19,32,49,50,51,53,54],forward:[13,28,32,43,61],found:[5,8,9,11,22,27,33,46,47,50,51],foundat:[1,53,54,58],four:[11,16,20,27,33,36,37,40,51],frac:[5,8,14,15,30,32,35,45],frac_correct:36,fraction:[8,21,35,36,47],framework:[48,49],free:[1,2,15,17,22,32,42,48,51,53,54],freeli:[4,31],frequent:[3,8,10,15,51],fresh:55,friend:35,friendli:[44,50],from:[1,2,3,5,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,35,36,37,38,40,41,43,44,45,46,47,48,49,50,51,53,54,56,58,60,61],fromkei:44,front:20,frozen:[11,12,26],frozenset:[11,12],fruit:12,fruit_or_veggi:12,frustrat:49,fulfil:48,full:[3,9,15,27,29,32,37,46,47,48,51],fuller:60,fulli:[2,35,43,60],fun:[19,35,53,54],func:[14,24,44,51],func_a:51,func_b:51,func_block:24,func_c:51,func_d:51,func_nam:51,func_var:24,fundament:[6,8,31,51,58],funni:27,further:[4,6,9,22,27,43,60],furthermor:[5,8,9,10,14,17,25,28,29,31,32,35,41,47,49,51,53,54],fyi:27,gain:49,game:[9,37],gather:38,gaug:51,gauss:11,gaussian:[33,47],gcd:45,gen:15,gen_1:[15,18],gen_2:[15,18],gener:[3,5,8,9,11,12,13,14,17,18,19,20,21,23,25,26,27,29,32,33,35,36,37,42,43,46,47,48,50,51,53,55,56,57,58,60,61],genesi:[53,54],genexpr:15,get:[1,2,4,5,6,8,10,11,12,14,19,25,27,28,31,32,36,37,40,41,44,46,48,49,50,51,53,54],get_area:[42,45],get_first_and_last:51,get_max:12,get_zip:48,getattr:40,getitem:46,getsitepackag:48,gfedcba:25,gheliabci:17,git:2,give:[0,4,6,16,24,25,27,35,36,41,45,46,48,49,58,61],given:[0,1,5,7,8,9,10,11,13,14,15,16,17,18,19,21,22,23,25,27,28,29,31,32,35,36,37,41,42,43,44,47,50,51,56],glad:56,glanc:[17,19,29,32,44,47],glare:32,glimps:3,glob:61,global:22,goal:[43,47],goe:[8,26,51],going:[3,41,45,48],good:[2,5,9,16,17,20,22,25,34,48,49,50,52,53,54,57,59,61],good_f:14,goodby:15,googl:[5,46,61],goos:[32,36],goosei:40,got:[53,54],gracefulli:38,grade:[11,12,17,26,27,32,50,51,56],grade_book:51,grade_lookup:51,gradebook:[11,27,51],graduat:[48,53,54],grai:47,grammar:[1,51,52],grammat:1,grape:[12,22,38,40,46],graph:[15,47],graphic:47,grasp:[25,41],grayscal:47,great:[3,5,8,11,12,14,15,17,25,37,49,51,53,54],greater:[0,8,9,15,22,28],greatest:[22,45],greatli:[17,36,43,44,46,49,51,56,61],green:[5,32,37,47,49],greet:49,grid:[5,32,33,35,37,47],grigg:[53,54],groceri:12,grocery_list:51,gross:[8,16],gross_merge_max_map:22,group:[8,50,51],grow:[5,15,51,56],grumpi:1,guarante:[1,8,9,12,20,35],guess:[22,28,37],gui:14,guid:[47,53,54,55,61],guidelin:[51,61],gush:5,had:[5,8,12,19,20,21,24,32,35,37,48,53,54,58],half:47,hand:[5,8,12,15,29,51],handi:[25,50],handl:[4,5,9,14,20,21,29,38,46,50,51],hang:[37,51],haphazardli:31,happen:[0,5,8,9,13,15,17,24,27,44,45,55],happi:[14,48,49],happili:51,hard:[8,16,18,20,22,31,51,53,54,58],hardboiled800:[53,54],harmon:15,has:[1,2,4,5,8,9,11,12,13,14,15,16,18,22,23,24,25,27,29,30,31,32,33,34,35,36,37,39,40,41,44,45,46,47,48,50,51,53,54,55,56,58],hasattr:[40,46],hash:[11,12],hashabl:[12,44,51],haskel:5,hasn:12,hat:[3,8,11,25],hatter:49,have:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,24,25,26,27,28,29,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,53,54,56,57,58,59,60],haven:49,header:[5,51],health:[9,49],healthi:49,hear:0,heart:49,heavi:[2,22],heavili:[1,43],heed:8,height:[42,43,45,47],heisenberg:11,hello:[1,3,8,13,14,15,17,20,25,40,41,43,46,51],hello_world:9,help:[1,2,5,8,9,13,14,15,17,19,22,25,26,32,35,38,41,48,49,50,51,53,54,58],helper:20,henc:45,her:[9,11,41],here:[1,2,5,6,7,8,10,11,12,13,17,18,20,21,22,23,24,26,27,28,29,31,32,35,36,37,40,41,42,43,44,45,46,47,48,50,51,53,54,56,57,59,61],herein:44,heterogen:[10,12],high:[5,6,27,33,36,37,46,47,51],higher:[8,27,29,32,47,51],highest:[10,36],highli:[2,4,8,9,12,17,37,47,49,50,58],highlight:[2,3,51],hill:50,him:18,hint:[3,8,25,52,61],his:[9,41],hist:47,histogram:[47,61],histor:43,historgram:47,histori:35,hit:[0,3,5,35,44,50,51],hline:35,hold:[3,8,11,13,14,51,56],hole:49,home:[4,48],homogen:[30,37],hood:[10,17,19,38,41,44,45,46,48,50,56],hope:56,hopefulli:[10,16,35,49,53,54],hopper:11,horizont:[32,33,35,37,51],horrai:36,host:48,hour:6,hous:[48,51],how:[1,3,4,5,8,10,12,14,15,16,21,22,25,26,27,32,35,37,41,43,44,46,47,48,49,50,51,53,54,56,58,61],howev:[6,8,9,10,12,14,15,17,20,22,25,27,31,33,36,37,38,40,43,45,48,49,50],hstack:33,html:51,http:51,huge:[1,2,5,6,31,51,53,54],human:[1,51],hundr:[6,15,35,53,54],hyperbol:37,hypothesi:49,hypothet:[35,36],idea:2,ideal:[12,27,47],ident:[5,8,9,26,47,48,60],identifi:[13,22,25,27,41,51],idiomat:51,if_block:24,ignor:[11,23,32,38],iii:[32,53,56],ill:25,illustr:28,ilovepython:23,imag:[5,8,32,36,37,50,51,58,61],imagin:35,imaginari:8,imbal:22,immedi:[3,8,11,13,14,17,18,19,20,22,27,32,33,42,48,51],immut:[8,10,11,12,25,56],imort:48,impact:[12,22,32,51,58],implement:[1,10,12,16,17,22,25,32,37,38,43,44,45,46,50,51,58],impolit:3,impos:27,imposs:[14,25],imprecis:8,improv:[1,17,35,43,46,49,51,52,53,54,56,61],imread:47,imsav:47,imshow:47,in_arg1:24,in_arg2:24,in_circl:35,in_str:[14,51],inaccess:[2,46],inadmiss:32,inadvert:22,inch:47,incis:49,includ:[1,3,4,7,8,9,11,12,13,14,15,16,17,22,25,26,27,33,35,37,38,40,41,42,43,47,48,49,50,51,52,55,56,57,58,59,61],include_i:[14,49,51],inclus:[11,15,33,51],incompat:[8,12,32,49],inconsequenti:17,inconsist:[16,51],incorrect:16,increas:[8,10,16,29,49],increasingli:[49,51,61],incred:[6,27,37,45],increment:[3,8,17],ind0:28,ind1:28,ind2:28,ind3:28,ind4:28,ind:28,ind_0:28,ind_1:28,ind_2:28,inde:[5,31,44,51],indel:58,indent:[9,13,14,16,40,50],indentationerror:16,independ:[4,5,9,15,17,22,28,33,35,36,41,61],index:[3,8,9,10,11,12,15,17,19,20,21,29,32,34,35,36,37,43,46,48,51,53,58],index_2d:28,indexerror:[9,25,27],indic:[0,3,7,8,11,14,15,19,28,30,31,32,37,44,47,48,50,51],individu:[3,8,11,25,27,31,34,35,37,41,43,46,48,50],ineffici:32,inequ:[8,22],inevit:[8,31],infer:[2,51],influenc:[53,54],info:8,inform:[1,8,10,14,26,31,37,43,44,47,48,49,51,53,55],inher:[12,29],inherit:[43,51,53,60],init:[35,39,41,45],initi:[4,11,15,17,19,22,26,27,32,33,39,41,44,45,48,51,56],inject:8,inlin:[15,20,21,22,47,56],inner:[19,33,49],innermost:19,input:[3,5,7,8,9,10,12,14,15,17,19,20,23,24,26,27,29,31,37,38,40,44,46,47,49,51],input_str:[23,40],insert:[8,27,29,31],insid:[12,16,24,45,50],insidi:22,insight:[28,48,58,61],insofar:49,inspect:[2,5,8,15,25,30,35,40,43,46,50,51,61],inst:44,instal:[2,3,5,6,51,53,54,55,61],instanc:[0,1,2,4,5,7,8,9,10,11,12,15,17,18,20,25,26,27,28,29,31,32,37,38,39,40,42,43,46,47,48,50,51,53,60],instanti:[39,41],instead:[2,3,4,5,8,9,10,11,15,19,25,27,29,33,34,35,36,37,38,42,44,47,48,50,51],instruct:[1,4,5,15,16,25,28,31,32,33,36,37,41,47,48,50,51],instrument:6,instuct:1,int32:[30,33,34],int64:28,int_to_str:20,integ:[1,3,7,9,10,12,13,14,15,18,20,22,25,26,29,30,33,36,37,40,41,45,46,47,51,58],integer_flag:51,integr:[1,45,49,51,55],intellisens:2,intend:[31,51],intens:[47,51],inter:[17,48],interact:[4,41,43,44,46,47,48,60],interchang:[8,27,51],interest:[6,15,32,43,53,54,61],interfac:[2,3,5,8,10,25,27,28,34,47,49,50,56,58,60],interim:49,intermedi:[19,31,32],intermediari:29,intern:51,internet:5,interpet:1,interpret:[3,4,5,8,10,17,24,28,32,33,35,47,48,51,55],interrupt:[0,13],intersect:[10,11],interv:[10,16,33,35],intra:61,intro:43,introduc:[9,10,11,13,17,20,32,33,37,40,43,45,47,49,50,51,52,53,55,56,58,60,61],introduct:[2,16,34,41,42,48,53,55,56,60],introductori:1,intuit:[1,8,15,17,23,27,28,29,32,37,38,55,58],invalid:[11,14,26],invalu:58,inventori:56,invers:[29,37,47,50],invert:[12,37],inverted_x:12,investig:26,invok:[4,11,14,15,28,31,32,37,39,41,44,45,46,47,50,56],involv:[8,10,12,15,17,29,31,50,56],iostream:1,ipynb:[5,50],ipython:[0,2,3,4,5,7,8,9,12,15,22,26,27,36,47,48],irrat:[35,48],irrespect:[28,42,48],is_bound:14,is_equ:23,is_in:10,is_in_circl:35,is_in_slow:10,is_palindrom:23,isalnum:23,isalpha:11,isclos:[8,28],isdigit:8,isinst:[8,9,20,25,34,38,39,41,42,45,46,51],islow:15,isn:[1,5,6,8,11,14,24,25,51],isort:51,issu:[4,6,8,32,44,53,54,61],issubclass:[42,43],isupp:9,it_var:24,item1:[8,11],item2:[8,10,11],item3:8,item:[3,7,8,9,10,11,12,13,14,15,17,18,20,21,25,26,27,28,29,31,37,38,41,46,47,51],item_to_transcript:20,item_to_transcript_alt:20,itemn:8,items:30,items_to_pric:12,iter:[8,10,11,12,13,14,16,18,19,20,22,23,25,31,32,37,38,40,41,44,46,50,51,53,56,58,60],iter_3:18,iter_4:18,iter_cnt:17,itertool:[17,24,36,41,53,56],ith:10,its:[1,3,4,5,8,9,10,11,12,13,14,15,17,19,20,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,53,54,56,57,58,59,61],itself:[8,12,14,19,29,39,43,44,48,51],jack:8,jackenzi:8,jan:51,jane:8,jargon:8,java:[1,16],javascript:47,job:[10,20],join:[3,8,15,20,23,25,46,47,53,54,58],jpg:47,judici:[9,19,27],julia:[5,58],jupyt:[0,2,4,7,13,16,22,36,46,48,49,50,52,53,55,61],just:[5,8,9,10,11,12,15,18,19,20,22,25,32,35,37,38,43,44,45,48,50,51,53,54,55],justif:49,jython:1,kamasi:41,keen:[4,22,32,36,51,58],keep:[2,8,11,12,15,17,19,20,22,27,31,32,35,38,45,46,51,52],kei:[3,10,11,14,22,37,44,46,47,56,60],kept:[53,54],kernel:[0,5,13,48],key1:12,key2:12,key3:12,keyboard:[5,46],keyerror:[11,12,22],keyword:[31,33,36,47,50],kick:49,kid:8,kill:5,kind:15,king:51,kit:[53,54],know:[1,4,5,10,13,14,15,17,19,25,28,33,35,36,37,40,41,43,44,45,48,49,51,53,54],knowledg:[19,38,48],known:[1,3,8,12,15,17,19,24,25,29,31,36,37,40,43,46,48,50,51,58],kwarg:[14,51],l_2:32,lab:[52,55],label:[5,27,35,36,47],labmat:[5,53,54],labor:51,lack:[25,53,54],ladi:50,laid:[5,29,37,47],lame:8,land:[4,35],landscap:58,languag:[2,3,4,6,8,10,14,16,24,25,26,29,37,43,51,53,54,55,56,58,60,61],laptop:2,larg:[1,2,5,6,8,15,20,21,32,43,47,48,49,51],large_int:8,large_num:8,larger:[8,10,22,32,48],largest:[12,17,22,27,32,36],lassi:51,last:[0,3,8,9,12,13,15,23,25,26,27,28,29,31,32,35,40,45,48,51],lastli:[7,8,12,31,37,38,43,47,48,50,51,55],late:50,later:[0,1,3,5,8,14,27,32,37,48,50],latest:[1,4,27,53,54],latex:[5,47],latter:[3,9,20,51],laundri:33,layout:[27,28,32,37,43,47,48],ldot:32,lead:[8,16,17,31,32,33,37,43,48,49,51,61],lean:[53,54],learn:[0,1,3,6,8,9,10,14,15,29,32,38,41,43,46,47,48,49,50,51,53,54,55,56,58,61],learning_python:48,least:[8,13,25,27,28,31,51,53,54],leav:[8,9,14,19,22,31,32,40,41,50],left:[9,14,17,23,26,28,29,32,37,45,47],legend:[5,35,47],legibl:51,leisur:27,len:[0,3,8,9,10,12,14,15,18,19,21,22,23,25,36,46,51],length:[3,8,10,15,18,25,27,30,32,33,37,42,46,51],leq:37,less:[1,8,9,12,22,25,27,36,37,40,47,49],lesson:[8,17,22],let:[3,4,5,8,10,12,13,15,16,20,22,24,27,29,32,33,34,35,37,38,39,41,42,43,44,45,46,47,48,49,50,51],letter:[8,11,13,15,17,25,40,50],level:[4,10,16,37,39,46,47,48,51,60],leverag:[4,8,9,35,36,37,41,42,43,46,47,48,50,51,58,61],lew:[53,54],lexicon:43,lib:[4,48],liber:[24,51],librari:[1,3,4,5,8,27,33,34,37,43,47,48,49,50,51,53,54,55,58,61],lies:[9,44,53,54],lieu:[38,48,50],life:49,lifetim:51,light:[8,32,37,42,44],lightweight:[2,51],like:[1,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,22,23,24,26,27,29,31,32,33,34,35,36,37,40,41,43,44,45,47,48,49,50,51,55,56,57,59,60,61],likewis:[9,43],limit:[6,8,12,19,37,45,48,50],limitless:19,linalg:35,line:[3,5,7,8,9,14,15,16,20,32,35,36,45,47,50,51,61],linear:[10,47,58],linearli:[10,15,16,47],linestyl:[35,47],link:[35,56,57,58,59,60,61],linspac:[5,47,58],lint:51,linter:51,linux:[1,3,4,50],list1:26,list2:26,list:[4,5,9,11,12,13,14,17,18,20,21,22,23,24,25,26,27,28,29,31,33,34,35,37,40,41,43,44,45,46,47,48,49,50,52,55,56,57,60],list_famous_dog:51,list_of_ag:51,list_of_dummi:41,list_of_nam:51,list_of_peopl:41,list_of_stud:51,list_of_temperatur:51,list_purchased_item:38,list_unpurchased_item:38,listofstud:51,liter:[8,52],littl:[45,49,50],live:[4,23,47,51],load:[47,61],load_databas:48,load_ext:48,loc:47,local:[5,48,51],locat:[4,25,31,43,47,48,50],log10:[8,37],log2:37,log:[8,17,26,31,33,35,37,47],log_:37,logarithm:[8,37,47],logic:[12,16,20,22,26,28,35,36,38,44,56,58],logical_and:28,logical_or:28,long_variable_nam:51,longer:[13,15,22,31,48,51],longev:51,look:[1,2,3,5,8,9,12,14,16,20,25,27,30,31,32,36,37,41,43,44,45,47,48,50,51,55],lookup:[11,12],loop:[0,7,12,14,15,16,17,20,21,22,23,34,35,36,37,40,41,51,53,56,57],loosei:40,lost:[8,27],lot:[14,49,53,54],love:[23,53,54],low:[36,37],lower:[8,10,11,12,14,15,23,32,35,40,47,49],lowercas:[3,8,11,15,50,51],luckili:50,luxuri:8,mac:[1,3,4],machin:[1,3,4,5,6,8,10,43,48,50,51,53,54,58,61],machineri:15,maco:50,mad:[9,49],made:[1,8,18,20,22,31,32,35,45,48,51,53,54],magic:[6,22,47,48],magnitud:47,mai:[1,2,7,8,9,10,14,15,17,19,20,22,23,26,27,28,29,31,32,37,40,44,45,46,49,50,51],mail:48,main:[1,38],maintain:[1,4,12,48,51],major:[4,5,6,8,16,18,25,28,32,33,34,36,37,49,50,51,53,54,58],make:[2,3,4,5,6,8,9,11,12,14,15,16,17,19,20,22,23,25,27,28,29,31,32,34,35,36,37,38,41,43,44,45,46,47,48,49,50,51,53,54,56,57,59],manag:[4,5,12,19,44,50,51,61],mangl:23,mani:[1,2,3,4,5,6,8,10,11,14,15,16,18,19,25,27,29,31,33,35,37,47,48,50,51,53,54,56,58,61],manifest:[3,29,56],manifestli:[8,27],manipul:[3,41,43,47,56,58,60],manner:51,manual:[4,15,17,22,49,50],manufactur:21,map:[1,10,11,14,20,22,37,44,51],march:51,margin:[53,57],mari:50,mark:[1,3,5,8,38,46,47,49,51,58],mark_purchased_item:[38,46],marker:47,mascharka:[53,54],mass:32,massiv:[5,32,37,47,49,50],master:41,match:[14,22,27,28,32,36,37,47,50,51],materi:[12,15,31,37,48,51,53,54,57,59,61],math:[3,5,14,37,48],mathcal:[10,11,12],mathemat:[3,5,6,8,9,10,31,32,33,34,51,58,60],matlab:[37,58],matmul:32,matplotib:47,matplotlib:[4,5,35,49,53,55,58,61],matric:[37,47],matrix:[6,15,32,37,47],matter:[3,5,8,12,14,20,25,27,29,32,44,49,56],matur:[5,43,51,61],max:[12,14,17,22,32,36,37],max_kei:12,max_key_optim:12,max_num:51,max_or_min:14,max_red_quad:37,max_val:[12,32],maximum:[12,22,37],mean:[2,3,4,5,8,9,10,12,13,14,15,17,19,22,23,24,25,26,27,31,32,33,34,35,36,37,39,42,43,45,46,48,49,50,51,55,56,57,58,59,60,61],mean_exam_scor:32,mean_i:32,mean_imag:37,mean_in_circl:35,mean_x:32,meaning:24,meaningfulli:10,meant:[7,8,9,13,14,15,20,25,26,44,46,51,57,59],measur:[8,53,59],meaur:47,mechan:[8,11,19,25,26,31,32,41,51,58,60],median:[37,51],melon:46,member:[8,10,11,13,14,15,17,19,25,48,51],membership:[9,10,11,12,15,25,46,51,56],memor:[10,37],memori:[1,8,12,14,15,17,18,23,25,26,30,31,32,41,44,51,56],mention:48,menu:[3,5],mere:[3,7,10,20,22,32,40,41,43,47,48,51],merg:[20,46,51,53,57],merge_max_map:22,mess:[48,55],messag:[44,45],messi:9,met:[16,20,28,56],method:[0,8,10,15,17,20,28,29,30,31,32,33,34,38,39,40,42,43,45,47,48,50,51,53,60],methodolog:[29,49],metric:21,microsecond:37,microsoft:[1,2,48,51],middl:[3,11,47],might:[3,17,22,27,32,45,48,49,51],milk:[12,38,46],mill:1,min:[14,17,19,37],min_blu:37,mind:[8,11,19,22,26,31,32,35,51],mine:[57,59],miniconda3:48,minimalist:47,minimum:[37,48],minor:[44,57],minut:4,mirror:[10,12,15],mis:[46,50],misapprehens:51,mislead:15,miss:[11,14,32,53,54],misspel:2,mistak:[1,2,22,31,51,53,54],mistakenli:[14,38,51],mix:[3,7,14,25,37],mkdir:50,mkl:[6,37,48],mobil:[53,54],mod:[8,37],mode:[5,14,26,48,51],model:[24,32,48,53,59],moder:2,modern:[16,43,47,55,60],modif:50,modifi:[2,8,41,44,48,50,51],modul:[2,3,4,9,12,14,15,16,17,18,26,27,34,37,41,42,43,45,50,52,53],modular:[16,56],module5_oddsandend:[48,50],module_nam:48,modulo:[8,37],moment:[1,4,16,38],momentarili:41,monitor:[32,37],montalcini:11,month:[5,49],moo:[3,8,10,11,12,14,18,25,44],more:[1,2,3,4,5,6,8,9,10,11,13,14,15,16,17,20,21,22,23,25,27,28,29,31,32,33,35,36,37,38,39,40,41,43,46,47,48,49,50,51,53,54,55,56,58,60,61],moreov:[36,53,54],most:[1,5,8,9,11,12,15,16,17,24,26,27,32,45,46,47,48,50,51,55,58],most_common:11,motiv:[4,10,49,50],move:[13,19,32,41,43,49,61],moveabl:5,movi:8,much:[0,1,2,3,5,8,12,16,22,32,33,35,36,45,46,49,50,53,54,56,60],muli:9,multi:[8,27,33,34,50,51],multidimension:[27,29,30,33,37],multipl:[3,5,8,12,18,19,20,25,31,32,34,37,38,43,46,47,48,50,53,56,58],multipli:[32,34,35,37,46],must:[3,8,9,10,11,12,13,14,15,16,22,23,25,26,27,28,29,31,32,36,37,41,44,48,50,51],mutabl:[8,10,11,12,22,25,56],mutat:[10,11,22,25,26],mxnet:43,my_arch:50,my_archive_fil:50,my_arrai:50,my_cod:1,my_cub:48,my_dequ:11,my_dict:12,my_dir:48,my_fil:[9,50],my_fold:50,my_func:[7,16,24],my_imag:47,my_list:[3,9,10,14,17,24,38],my_loaded_grad:50,my_modul:48,my_open_fil:50,my_script:1,my_squar:[42,45],my_text:1,mygrad:[43,52,58],mygui:40,mylist:46,mypi:[51,52],n_circl:35,n_total:35,naiv:44,name:[2,3,4,5,8,9,12,17,18,22,24,25,27,37,38,40,41,44,45,46,48,50,56,60],name_to_scor:12,namedtupl:11,nameerror:[8,13,24],namespac:[5,24],nano:1,nanosecond:10,napolean:51,narrow:51,nativ:[2,4,5,37,47,51],natur:[3,8,19,25,27,32,37,49,50,61],navig:[4,5,48,51],ncircl:35,ncol:47,ndarrai:[25,28,30,31,32,33,34,36,51,60],ndenumer:29,ndim:[30,43],nearest:25,nearli:[5,13,25,37,47,56],necessari:[9,10,16,17,28,32,48,50,51],necessarili:[12,15,32,47],necromanc:4,need:[1,2,4,5,8,10,14,15,17,18,19,20,22,27,29,32,34,35,36,41,42,44,47,48,49,50,51,53,54,56],neg:[0,3,8,9,20,23,25,28,31,37],neg_index:25,negat:[8,9,51],neighbor:19,neither:14,nest:[9,10,19,32,33,48],nestl:9,network:43,neural:43,never:[0,5,8,9,10,11,13,14,22,29,37,51],new_dict:44,new_fold:50,new_kei:12,new_list:46,new_subarrai:31,new_valu:[12,44],newaxi:[28,58],newcom:2,newfound:[3,9,56],newlin:8,next:[3,5,8,12,13,19,23,29,31,33,36,38,41,42,43,44,46,48,49,50,51,55,56,58,60,61],ngrid:47,nice:[2,3,5,8,10,11,12,14,20,25,31,35,47,48,51],nicer:2,niceti:[17,56],nick:12,niel:41,nimbl:[4,5],nine:20,njit:6,nlog:10,noether:[11,41],noisi:35,non:[6,8,11,15,17,19,23,27,32,37,45,48,51,56],none:[9,10,11,14,17,20,22,24,25,31,32,41,44,46,48,56],none_indic:17,nonetheless:61,nonetyp:8,nonsens:46,nontrivi:28,nonzero:[9,13],nor:[9,11,14,22,24,47],norm:35,normal:[11,12,23,32,33,37],normed_imag:32,notat:[10,28,31,37],note:[0,1,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,27,29,31,32,35,37,41,44,45,46,47,48,50,51,60],notebook:[0,2,4,7,13,16,22,35,36,46,48,49,50,52,53,55,61],notepad:1,noth:[1,2,8,15,24,44,50],notic:[5,20,23,37,38,45,51],notifi:8,notimpl:45,novic:31,now:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,17,19,22,25,26,27,30,31,32,35,37,41,42,45,46,47,48,50,52,53,54,56],npy:50,npz:50,nrow:47,nthi:50,nuanc:[10,27,31,44,56],nucleu:49,num:[9,13,14,16,17,45],num_correct:36,num_health:9,num_in_circl:35,num_loop:13,num_thrown:35,num_vowel:14,numba_result:6,number:[0,1,2,4,5,6,9,10,11,12,13,15,16,17,19,25,26,27,28,29,30,31,32,33,34,35,36,37,41,43,44,45,46,47,48,49,50,51,55,56,57,58],number_of_arg:14,numer:[1,5,9,14,26,27,32,34,35,37,43,46,53,54,58],numpi:[1,4,5,9,25,26,27,28,29,30,32,34,35,36,43,47,48,53,54,55,59,60,61],numpy_result:6,numpydoc:51,nwai:50,nwhat:3,obei:[1,8],obj1:12,obj2:12,obj:[10,11,12,25,40],object:[3,10,11,12,13,15,17,19,20,22,25,28,30,33,34,37,39,42,44,48,51,53,56,58,61],obscur:[8,19,33,51],observ:[37,45],obtain:[6,20,46],obviou:[8,44,46,49],obvious:50,occas:[49,50],occur:[3,4,8,25,44,45,47],occurr:[10,25,28],odd:[8,13,15,16,50,53],odd_numb:51,off:[3,5,11,13,32,42,49,51,56],office_suppli:46,offici:[1,56,58,60,61],offload:6,offset:32,often:[2,8,16,27,32,33,41,45,49],ok_func:14,okai:[5,9,16,32],old:[5,8,49],omit:[14,25],onc:[1,3,4,5,8,9,12,13,14,15,17,22,24,25,26,28,32,35,38,39,40,41,47,50,51],one:[0,1,2,3,5,6,8,9,11,12,14,15,16,17,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,38,41,42,43,44,46,47,48,49,50,51,53,54,58,60,61],ones:[8,58],onion:12,onli:[2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,24,25,27,28,29,30,31,32,33,36,37,38,41,42,43,44,46,47,48,49,50,51,56,61],onlin:47,onto:1,oop:45,opaqu:[47,51],open:[1,2,3,4,5,8,26,47,48,49,51,61],opencv:58,opened_fil:[26,50],oper:[1,4,5,6,10,12,15,19,21,22,26,27,29,32,34,35,36,41,43,44,50,51,53,56,58,60],operand:[32,37,45],opportun:[35,49,56],oppos:61,opt_merge_max_map:22,optim:[1,4,6,10,11,12,14,23,36,48,53,57,58],option:[4,5,8,14,15,29,31,43,44,48],orang:[3,18,47],orchestr:20,order:[5,8,9,10,11,14,15,16,17,18,22,23,25,26,27,28,31,32,35,36,37,38,48,51,52,53,54,58],ordereddict:12,org:[1,48],organ:[3,35,48,51],orient:[5,8,17,41,42,47,53,61],origin:[8,17,21,22,26,27,29,31,35],other:[0,1,2,3,4,6,8,10,11,12,14,15,16,17,19,20,22,24,25,26,28,29,31,33,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,53,54,56,58],otherwis:[8,9,11,13,19,32,33,35,46,51,58],ought:[9,12,37,38,42,45],ould:3,our:[1,2,3,5,8,9,10,11,12,14,15,17,19,20,22,23,24,25,26,27,28,30,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,60,61],ourselv:[3,34,44,48,49,56,60],out0:50,out1:50,out2:50,out:[0,1,2,3,5,8,9,11,12,13,15,17,20,21,23,26,27,28,29,32,35,36,37,38,44,46,47,48,49,50,51,53,54,58],outcom:[8,37,51],outer:[19,25],outermost:19,output:[0,3,5,7,14,15,19,22,27,28,29,37,47,49,50],outright:[12,13,15,48],outset:49,outsid:[13,16,19,21,24,35,40,48],over:[1,4,8,10,11,12,13,14,16,17,18,19,20,21,22,32,34,35,36,37,41,45,46,47,49,50,51,53,56,58],overal:[22,32],overli:[10,51],overload:46,overlook:[32,49],overrid:[14,24,50],overridden:[14,24],oversight:[19,51],overst:[18,51,58],overview:[7,8,16,34,37,39,43,48],overwhelm:[2,53,54],overwrit:[31,42,50],overwritten:37,overwrot:42,own:[4,6,8,10,14,16,17,26,29,38,40,41,42,43,45,46,49,50,51,56,61],pack:[12,14,22,31,51],packag:[1,3,4,6,34,47,53,61],package_nam:48,pad:8,page:[4,5,8,9,13,14,15,25,26,51,53,54],pai:[48,51,56],painstakingli:37,pair:[11,12,14,17,18,19,21,32,37,41,47,51],pairwis:[37,51,58],pairwise_dist:[32,51],pairwise_dists_crud:32,pairwise_dists_loop:32,palindrom:[53,57],paltri:15,pan:47,panda:[43,53,54,58],pane:5,paradigm:[5,13,37,56],paramet:[12,14,15,19,20,21,22,23,32,35,36,38,43,44,45,46,51],parameterless:51,paramount:[51,56],parent:[28,31,42,45],parenthes:[8,14,15,25,51],parenthesi:[14,51],parenthet:15,pars:[1,51],part:[1,3,4,8,19,20,21,22,24,26,43,48,49,50,51,53,56,58],parti:[4,50,51,55,58],particip:1,particular:[4,11,22,28,36,40,41,43,44,51,56],particularli:[6,17,28,53,54,56],pass:[1,12,13,14,15,16,19,21,22,24,26,27,31,33,36,39,41,42,43,44,45,46,50,51],past:[5,13,46,52],path:[4,27,48,61],path_to_data1:50,path_to_fil:50,pathet:35,pathlib:61,pattern:[9,17,20,34,47,48,50,51],pdf:[9,47],peach:38,pear:[18,22],peculiar:[20,41,46],peek:[16,34,43],pen:46,pencil:46,peopl:[1,4,14,43,51,53,54,61],pep8:61,pep:51,per:[22,36,47],percentag:[53,57],perceptu:47,perfect:[4,5,8,11],perfectli:8,perform:[1,3,4,5,6,8,9,10,13,15,17,19,22,23,27,28,29,32,34,35,36,37,45,47,48,51],perhap:[8,9,35,47,49,51],period:[3,8,9,47],permiss:28,permit:[5,8,9,10,17,19,20,25,26,27,28,29,31,32,40,42,43,47,48,50,51,56,60,61],persist:[3,7,12,13],person:[41,53,54],pertin:51,perus:[5,8,11],pessimist:10,pet:23,petar:[53,54],petarmhg:[53,54],phone:3,phrase:[37,40],phrase_of_the_dai:48,physic:[27,53,54],pick:[3,32,51,53,54],pickl:61,pictur:[36,48],pie:[15,47],piec:[3,13,16,25,36,45,53,54,57,59],pillow:14,pineappl:38,pip:[4,52,61],pitfal:49,pixel:[32,37,47],pixel_std_dev:37,pizza:[12,40],pizzashop:40,pkl:50,place:[1,4,8,12,14,20,25,27,32,37,38,40,46,48,51,53,54,58],placehold:[8,26,32,37],plai:[19,20,32,53,55,59],plain:[1,7],plan:51,platform:[4,61],player:47,pleas:[3,8,9,11,33,37,48,50,53,54],pleasantli:37,plenti:[3,49],plot:[5,35,58,61],plotli:47,plt:[5,35,47],plu:50,plug:43,plymi:[35,50,51,57,59],png:[47,50],point:[3,4,5,9,12,15,16,19,20,22,23,26,27,28,29,32,33,35,36,37,46,47,49,50,51,53,54,61],point_to_region:12,pointer:26,polish:[2,5],polyglot:2,pop:[8,10,25],popul:[22,28,33,41,46,47,50],popular:[1,4,5,15,43,48,51,55,58,61],portabl:[38,50],portion:[5,9,37],pos_index:25,pose:25,posit:[0,3,8,9,10,11,13,17,19,25,27,28,32,35,37,43,44,48,51],posixpath:50,poss:30,possess:[8,10,31,32,37,39,40,43,47,48,60],possibl:[8,13,17,19,21,26,27,28,32,38,40,50,51],post:[53,54],poster:12,potenti:[19,23,29,49,51],potpourri:47,power:[2,4,5,6,8,9,19,25,28,31,34,35,37,42,45,46,47,48,49,50,51,55,56,58,61],practic:[1,5,8,9,13,14,15,25,26,28,36,37,43,49,50,53,54,57,59,61],pre:[1,10,37],prece:46,preced:[1,8,9,11,12,17,20,24,25,28,29,30,31,32,33,37,46,51],preceed:25,precis:[1,27,31,37],pred_label:36,predict:[0,26,28,36],prefer:[9,15,20,22,38,51],prefix:3,prematur:[13,23],premier:[5,34,53,54],premium:2,prepar:[32,47,48],prepend:4,prescrib:[34,37,58],prescript:20,presenc:3,present:[5,12,22,33,46,47,48,50,53,54,55,57,58,59,61],preserv:29,press:[5,32,49,50],pressur:51,presum:50,presumpt:22,pretti:45,prev_num:17,prevent:[15,51],previou:[4,8,14,19,22,27,32,35,47,52],previous:[13,51],price:12,primari:51,print:[0,1,3,7,8,9,12,13,14,15,16,17,24,26,35,41,45,46,48,50],print_kwarg:14,printabl:[43,46],prior:[5,12,19,51],priorit:[4,47],pro:2,probabl:[18,35,51],problem:[4,10,19,20,21,23,32,36,37,53,54],problemat:[9,12,31,51],proce:[5,15,19,25,29,32,40,42,44,47,48,50,56],proceed:[8,27,43],process:[1,2,3,4,5,9,11,13,26,29,32,34,35,36,37,41,44,46,48,49,50,51,53,54,55,56,58],produc:[8,9,11,12,13,15,17,21,22,23,24,25,26,27,28,29,32,33,35,36,37,39,41,44,46,47,48,50,51,58],product:[8,19,30,32,37,41],profession:2,program:[5,6,8,16,17,41,42,49,53,54,55,56],programm:[2,6,8],programmat:[8,30],progress:48,project:[4,5,36,48,49,51,53,54,61],prolif:51,promin:[5,61],promis:[22,51],prompt:[46,50],prone:[36,50],pronounc:[27,41],proper:[14,49],properli:[5,22,50],properti:[42,43,44,49],propos:51,protocol:[50,51,60],prototyp:[1,2,4,5],proud:35,provid:[1,2,3,4,5,6,7,8,10,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,35,37,38,41,42,43,45,46,47,48,49,50,51,53,54,56,58],prudent:51,pseudo:[9,15],pts:32,publish:[47,51],punctuat:[11,15],purchas:[38,46],purchased_item:46,pure:[6,7,23,37,43],purpl:[40,47],purpos:[7,8,14,19,32,41,45,48,51],push:49,put:[3,8,9,13,14,15,16,25,26,37,43],py27:4,pycharm:[2,51,55],pyformat:8,pypi:48,pyplot:[5,35,61],pyright:[51,52],pytest:49,python36:48,python3:48,python:[2,5,7,9,10,11,12,13,14,15,17,19,20,23,24,25,26,27,29,31,34,37,38,39,40,41,42,43,44,45,46,47,49,52,57,58,59,60,61],pythonlikeyoumeanit:51,pytorch:[43,48,49,53,54],quadrant:37,quadrat:[0,3,10],qualiti:[5,47,51],queri:15,question:[3,5,8,25,51,53,54],quick:[3,39,47,53,55],quickli:[4,11,12,27,49,51],quintessenti:16,quirk:[8,50],quit:[1,6,8,9,12,15,16,17,24,25,27,51,53,54],quot:[3,8,50],quotat:[1,3,8],quotient:8,rabbit:49,racecar:23,radian:[5,47,48],radiu:35,rais:[1,8,9,11,12,13,14,15,16,19,21,22,24,25,26,34,40,44,50,51],raiton:45,ram:32,ramp:47,ran:5,rand:[32,33,35,36,37,47],randint:36,randn:[33,47],random:[11,32,35,36,37,47,58],randomli:[10,18,33,35],rang:[6,7,11,12,14,16,18,21,22,23,25,28,33,36,40,41,47,48,50],rank:58,rapidli:[1,5,34],rare:[1,49,51],rat:45,rather:[1,3,8,10,15,20,22,26,28,31,35,37,41,44,46,47,48],ratio:35,ration:[8,45],rationa:45,rbg:[32,37],reach:[9,13,14,19,29,35,46],read:[1,4,5,6,21,22,23,33,49,53,54,56,57,58,59,60,61],readabl:[1,9,11,15,17,22,23,46,51],reader:[8,11,23,32,46,53,54,55,56,57,59,61],readi:[48,55],readili:[15,56],readlin:50,real:[8,11,27,32,37,48],realiz:35,realli:[5,16,22,32,33,44,45,51],reap:49,reason:[12,14,15,20,22,27,31,43,47,56,58],recal:[3,5,8,9,10,12,14,15,16,17,19,20,22,23,27,28,29,30,31,33,35,36,37,40,41,44,45,46,48,50,51],recast:32,receiv:[22,33,38,44],recent:[5,8,9,12,15,26,27,45,52],recogn:[27,32,42],recognit:48,recoil:32,recommend:[4,5,8,11,12,17,18,35,38,46,47,50,51],recomput:5,record:[17,21,52],recreat:12,rect1:43,rect:45,rectangl:[41,42,43,45],red:[5,32,37,40,47,49],redefin:[5,15,46],redraw:5,reduc:[38,40],redund:[11,20,28,38,44,49,51],redundantli:32,refactor:[21,32,44],refer:[2,3,5,8,9,11,12,13,14,19,22,24,25,26,27,28,29,31,33,34,35,37,40,41,42,43,45,46,48,50,51,56],referenc:[5,7,10,11,31,41,51,56],refin:47,reflect:[22,26,31,32,48,51,52],refresh:37,regard:22,regardless:[12,29,32,51],region:[12,28,35,40,47],regrett:32,regular:[4,28,48],regularli:[48,51],reimplement:12,reiniti:31,reinstal:48,reiter:[22,50],rel:[1,3,8,10,14,16,20,22,25,32,33,37,44,50,53,54,61],relat:[4,11,48,50,53,54,55,58,61],relationship:[8,25,31,41,42,45],relative_po:32,releas:[49,52],relev:[37,57,59],reli:[1,7,8,12,37,43,51,56],reliabl:[2,8,35],relic:[8,43],reload:48,remain:[9,17,31,48],remaind:[8,16,37],remaining_item:46,remedi:31,rememb:[8,22,29,41,49],remind:[8,49,50],remov:[4,8,10,11,19,26,37,38],renam:5,render:[5,8,46,47,48,51],repeat:[11,13,20,25,27,28,33,37],repeatedli:[3,13,14,28,49,56],repertoir:56,replac:[3,8,10,17,26,27,28,31,37,46],replic:[15,32],report:5,repr:[45,46],repres:[6,8,9,10,12,14,21,24,26,30,31,32,37,41,46,47,48],represent:[8,20,43,50,60],reproduc:[1,47,51],repurpos:26,request:[13,15,38],requir:[2,4,5,6,8,9,12,15,21,23,25,27,28,29,31,32,37,46,48,51,53,54],rerun:35,research:[1,5,53,54,55,58],resembl:32,reserv:[8,14,15,25,26,32,43,44,46,47,51,60],reset:29,reshap:[28,29,31,32,33,34,37],resid:[27,41,47,48],resolut:[32,47],resolv:[9,24,27,28,41,45,56],resourc:[2,8,15,46,47,51,53,54],respect:[5,8,9,13,14,17,20,24,27,28,29,32,33,35,37,40,44,47,50,61],respons:[20,38,47,49,51],rest:[5,7,17],restart:[5,13,48],restore_default:48,restrict:[6,8,9,24,37,48,51],result:[1,3,5,6,7,8,11,12,15,20,22,26,27,28,29,31,32,33,35,36,37,40,41,45,47,48,50,51,60],resum:50,retain:[8,22],retriev:[10,11,15,25,27,47,51],reus:56,reveal:[5,14,47],reveres:25,revers:[9,23,25,26,27,31,41,52],review:[5,8,16,25,27,31,51,61],revisit:[5,13,42,50,51],revolutionari:55,revolv:34,rewit:44,rewrit:[0,19,22,32,44,51],rewritten:[8,14,31],rgb:[32,37,47],rgba:47,rich:[2,5,46,51],richer:51,rid:28,right:[3,5,9,12,19,22,23,26,28,29,32,37,43,45,47,56],rightarrow:[8,9,11,12,19,20,25,28,32],rigor:[32,46,51,53,54],rival:37,road:[53,54,61],roadblock:6,roar:0,robot:3,robust:[2,5,49],roll:[19,50],root:[0,3,4,32,35,37,50],root_dir:50,roster:11,rotate_imag:51,rotateimag:51,roughli:[12,36],round:[12,20,32],rout:5,routin:[27,29,32,37,48],row:[8,15,25,27,28,30,31,32,33,35,36,37,47,51,58],row_i:32,row_x:32,rsokl:[53,54],rubi:5,rudimentari:[49,51],rug:48,rule:[1,8,12,15,16,24,27,28,29,31,37,41,47,51,58],run:[0,1,2,4,10,12,13,15,22,34,35,36,48,49,50,51,55],rundown:[10,11,12,25,31,39,50],running_estim:35,runtim:51,ryan:[8,11,12,14,48,51,53,54],safe:[32,50],safeti:21,sai:[5,6,8,10,15,26,27,37,45,49,51],said:[2,4,5,8,9,13,20,24,27,29,31,32,35,40,41,42,43,48,51,53,54],sake:[1,12,16,23,32,37,46,51],salient:[17,41,51],salt:46,sam:[53,54],same:[1,5,6,8,9,10,12,15,16,19,20,22,23,24,25,26,27,28,29,31,32,35,37,40,41,43,45,47,48,51,56,60],sampl:58,sane:4,sash:3,satisfactori:20,satisfi:[8,28,31,32,48],save:[1,5,15,49,51,61],savefig:47,savez:50,saw:[5,8,15,25,31,41,51],scalar:[27,37],scale:[10,33,35,47,48,51],scatter:[47,61],scenario:[9,10,21,32,45,49],scene:[6,15,31,32],schema:27,scheme:[11,12,25,27,31,50,58],school:[53,54],sci:[53,54],scienc:[4,5,29,47,53,54,56,58],scientif:6,scientist:[1,55],scikit:58,scipi:4,scope:[8,12,22,40,41,51,53,56],score:[12,22,26,27,32,36,56],score_offset:32,scores_per_stud:32,scratch:[8,33,42,44,53,54],scratchwork:3,screen:[1,3],script:[2,3,4,8,17,24,48,55],search:[4,50,51,53,54,61],second:[5,6,8,10,15,17,20,22,25,27,29,36,44,47,49,50,51,61],secretli:6,section:[1,2,4,5,7,8,9,10,13,14,15,16,17,25,27,28,29,31,32,33,37,38,40,41,42,45,46,47,48,49,50,51,57,59,61],see:[3,4,5,7,8,9,11,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,31,32,33,34,35,37,38,40,41,42,43,44,45,46,47,48,49,50,51,60],seem:[15,17,29,32,40,44],seen:[8,15,16,24,25,31,37,47,48,51,60],segment:[14,35,47],sel:27,seldom:[33,41],select:[5,27,28,30],self:[27,38,39,41,42,43,45,46,51],selina:8,semant:17,semi:[35,47],semicolon:47,send:[1,5],send_mail:48,sens:[8,15,34,38,44,53,54],sensibl:[25,29,44,46],sensit:23,sentenc:[3,8,11],separ:[3,5,8,10,14,15,16,17,20,22,25,26,47,50,51],seq1:25,seq2:25,seq3:25,seq:[10,14,23,25],sequenc:[3,9,10,12,13,14,15,16,17,18,19,20,23,26,27,28,29,34,35,37,41,43,50,51,53,56,58,60],sequenti:[3,8,11,17,25,32,36,56,58],seri:[14,15,36,49],serial:50,seriou:[6,8],serv:[7,16,26,41,48,49,50,51,53,54],server:55,servic:4,session:[3,4,48],set:[1,5,8,9,10,12,14,15,17,18,22,26,27,28,36,37,38,40,41,43,44,46,47,48,49,50,52,53,55,56,60],set_1:11,set_2:11,set_titl:[5,47],set_xlabel:[5,35,47],set_xscal:35,set_ylabel:[35,47],set_yscal:47,setattr:[40,46],setup:48,setuptool:48,seven:[8,20],sever:[3,5,6,8,14,16,18,25,33,35,38,41,45,48,49,50,51],shade:[35,47],shadow:[51,56],shallow:22,shameless:43,shampoo:51,shape:[27,28,29,30,31,32,33,35,36,37,43,46,47,51,58],share:[5,16,24,25,31,41,48],shares_memori:[28,31],sheet:[27,28,29,30,32,37,47],shelf:49,shell:[0,2,47],shift:5,shine:[9,10,12,32,37],shirt:46,shmangela:51,shmonathan:51,shock:8,shockingli:40,shop:[40,46,60],shoppinglist:[38,46,51],short_gen:15,shortcut:[5,8],shorten:14,shorthand:[25,26,27,31,34],shortli:[47,51],should:[3,4,5,7,8,9,10,12,13,14,15,16,17,19,20,22,23,25,26,28,31,32,33,34,35,36,37,38,40,41,42,44,45,46,47,48,50,51,52,53,54],shouldn:38,show:[5,11,16,26,27,32,34,45,47],showcas:18,shown:[22,51],shrewdli:32,side:[3,4,9,42,45,47],sidewai:47,sigh:14,sight:32,sign:[9,20],signal:[13,14,15,16,31,42],signatur:[14,22,44,46,51],signifi:[10,14,16,50],signific:[8,31,44,53,54],significantli:[4,6,28],silent:[1,12],silli:[46,51],sillyclass:46,similar:[1,5,14,15,22,25,27,32,33,37,40,41,44,47,51],similarli:[8,9,22,24,25,27,28,29,32,37,40,44,46,50],simpl:[1,2,3,4,5,8,9,12,14,15,16,17,20,25,26,27,29,35,36,37,38,39,40,43,45,46,48,49,50,51,57,58],simple_arrai:27,simple_merge_max_map:22,simpler:[0,36,47],simplest:[9,23,28,51],simpli:[1,2,3,4,5,8,10,12,14,15,16,19,21,22,25,26,27,29,31,32,34,35,36,37,40,44,45,46,47,48,49,50,51,53,54],simplic:[1,35,51],simplifi:[8,15,17,19,36],simul:35,simultan:[14,19,28,37],sin:[5,37,47],sinc:[5,8,12,15,16,19,20,25,27,36,37,40,43,45,48,50],sine:[33,47],sine_wav:47,sinewave_plt:47,sing:47,singl:[3,5,8,9,11,12,14,15,16,18,20,22,23,25,27,28,31,32,33,35,36,37,38,41,42,47,48,49,50,51,56],singular:[40,41],site:[53,54],situat:24,six:[9,20,37,53,54],size:[10,12,15,22,25,27,30,31,33,35,36,37,42,47,58],skill:60,skip:[9,13,15,35],sky:8,sleek:[15,17,28,46,47],slice:[3,8,9,10,11,19,23,26,28,34,37,46,51],slick:[20,35],slightli:[15,41,47,50],slot:29,slow:[6,32,37],slower:6,small:[3,5,6,8,22],smaller:[22,47],smallest:[17,27],snake:40,snake_cas:51,sneak:[16,34,43],snippet:[3,5,34,51,53,54],sock:46,softwar:[1,2,48],soil:50,soklaski:[48,51,53,54],sole:[8,10,14,15,38,41,44],solid:[47,53,54,58],solut:[0,4,53,54,56,57,58,59,60,61],solv:[4,19,21,37,44],solver:48,some:[3,4,5,7,8,10,11,12,17,18,19,20,26,27,29,35,36,37,38,39,41,45,47,48,49,50,51,53,54,55,56,58,60,61],some_dict:14,some_iterable_of_str:20,some_list:[14,48],some_long_function_nam:51,some_text:50,some_util_func:48,someon:[38,53,54,61],someth:[5,9,14,16,22,33,36,44,51],sometim:[20,50,51],somewhat:[19,27,28,46],soon:[9,15,40,43,49,51],sophist:[1,2,4,31,46,49,60],sort:[2,8,9,10,11,17,25,38,41,45,49,50,51,53,54],sound:[49,53,54],sourc:[1,2,8,25,48,51],space:[5,8,11,12,16,27,33,40,47,50],space_time_coord:11,span:14,sparingli:[14,15,20,51],speak:40,spec:51,special:[1,3,8,9,15,17,19,20,22,29,32,34,38,39,41,42,43,44,45,48,50,51,53,60],specif:[1,4,8,10,12,15,21,25,27,28,31,32,36,37,39,40,41,43,44,47,48,50,51,55,61],specifi:[1,3,4,8,9,11,12,15,16,18,25,27,28,29,32,35,36,39,40,41,42,44,47,48,51,56,58],speed:6,speedup:[10,22,37],spell:[1,20,26],spend:[7,51],spent:38,sphinx:51,split:[8,11,15,33,47],spot:[53,54],spreadsheet:[32,43],spuriou:32,sqrt:[3,8,32,35,37,47],squar:[0,3,8,9,10,12,15,25,31,32,34,35,37,42,45,46,47,48,50],stack:[27,29,32,33,36,51,56],stagnat:[53,54],stand:[5,8,41,49,51,58],standalon:[27,51],standard:[1,3,4,8,11,12,14,16,33,35,37,47,48,50,51,58],stapl:46,star:[8,12,34],stark:[22,37,51],starkli:60,start:[3,4,5,8,12,13,15,16,18,25,26,27,29,31,32,33,34,35,43,45,49,50,53,54],startswith:[8,50],stat:51,stat_func:51,stat_funct:51,state:[8,14,15,22,26,31,46,48,49],statement:[13,15,16,17,20,21,22,24,40,49,51,53,56,61],static_func:44,staticmethod:44,statist:[17,33,35,37,51],statment:[13,14],statu:[9,26],std:[1,22,33,35,36,37],std_in_circl:35,stdin:45,stem:[43,53,54,55,56,58],step:[10,13,15,23,25,27,29,32,33,37,49,51,55],stew:8,stick:[6,10,51],still:[5,8,13,14,26,28,31,32,38,40,41,44,45,48,51,52,56],stomp:22,stop:[15,19,25,27,33,53,54],stopiter:[13,15],store:[3,4,6,8,9,11,14,17,18,19,22,25,26,27,30,31,32,34,35,36,37,38,41,43,46,47,48,50,51,56,58],str:[8,9,14,15,20,23,25,38,40,41,43,44,45,46,49,50,51,60],strage:45,straight:[14,28,32],straightforward:[22,27,32,37],strang:44,strategi:49,stream:47,streamlin:49,strength:47,stretch:47,strict:[1,51],strictli:[9,48,50,51],strike:46,string:[2,5,9,11,12,13,14,15,17,19,22,23,25,26,27,37,38,40,41,43,44,45,48,50,51,53,55,56,57,60],string_of_num:15,stringent:6,strip:[8,47],strive:[35,50,51],strongli:[16,18,35,46,50,51],struck:56,structur:[27,30,32,33,48,49,50,53,56],struggl:[5,51],student:[11,12,17,22,26,27,32,51,55,56,57,59],student_grad:26,student_list:51,studi:[11,16,32,35,37,43,49,51,55,56,60,61],studio:[2,51,55],stuff:32,style:[5,7,16,40,47,48,53,54,61],stylist:[20,22],styliz:5,sub:[25,27,34,48],subarrai:31,subclass:42,subdirectori:[5,48,50],subject:28,sublist:51,submit:[51,57,59],submodul:47,subpackag:48,subplot:[5,35,61],subscript:15,subsect:[5,9,15,25,26,28,31,32,51],subsequ:[8,10,13,14,15,16,20,22,24,25,26,27,28,34,37,50,60],subset:[6,11,50],substanti:[32,35,37,48,53,54],subtl:[20,22],subtract:[19,32,35,37,45,46],succe:46,success:[19,51],successfulli:32,succinct:[22,36,51],succinctli:31,suffic:[13,44],suffici:[8,10,16,37,51,53,54],suffix:[1,2,5,48,50],suggest:[9,51],suit:[1,11,20,28,32,37,47,49,51],sum:[1,6,8,13,14,15,17,19,21,32,35,36,37,43,44,49,51],sum_:[15,32],sum_func:[6,48],summar:[7,8,10,25,32,43,48,49,50],summari:[10,12,16,38,47,51,53,55,56,60],summed_row:32,superior:[21,46],superset:11,suppli:[25,28,31,33,37,50],support:[1,2,8,9,11,12,25,26,27,47,48,51],suppos:[8,9,10,11,14,17,19,22,26,27,28,29,32,36,37,38,41,42,48,49,50,51],suppress:47,suprem:[8,15,17],sure:[9,14,32,34,45,49,51],surfac:[8,33,42],surpris:[15,27,31,37,40,51],surround:[5,51],survei:[10,24,37,44,55],susan:11,suss:49,swap:[4,27],sweep:48,swept:48,symbol:[7,8,11,14,26,46,48],symmetr:11,symmetric_differ:11,synonym:[41,43],syntact:[16,17],syntax:[1,2,5,6,8,9,11,12,13,14,15,16,17,19,20,21,22,25,26,27,31,38,40,41,48,50,51,55,60],syntaxerror:14,sys:[0,48],system:[4,25,26,31,43,48,50,51,61],tab:[3,5,8,16,51],tabl:[27,29,37],tabular:58,tac:25,tackl:19,tag:44,tailor:[6,32],take:[0,1,4,6,7,8,10,11,12,14,15,16,17,18,19,20,22,25,27,28,29,31,32,34,35,36,37,38,40,44,45,46,47,48,49,50,51,53,54,55,56,60],takeawai:[2,4,9,10,11,12,15,17,22,24,25,27,28,31,32,37,40,43,48,50,51,56],taken:[12,20,27,32,50,51,53,54],talent:51,talk:[3,7],talli:[3,11,13,21,35,36,37],tan:37,target:[10,47,48],task:[1,8,20,25,28,37,56],taylor:14,teach:[50,53,54],technic:[16,48,51,61],techniqu:[12,28,58],technolog:47,tediou:[27,29,44,50,51],tell:[1,5,14,50,51,53,54],temperatur:51,templat:9,temporarili:32,ten:[10,35,37,41],tend:43,tensor:[37,43],tensorflow:[43,48,53,54],term:[3,8,10,16,17,19,22,25,32,37,43,47,48,50,51,53,58,60],termin:[0,1,2,3,4,5,48],terminolog:[15,41,60],terrancewasabi:[48,50],terribl:[10,53,54],terrif:5,ters:28,tertiari:51,test:[1,2,5,9,10,11,12,14,21,22,25,36,41,50,51],test_0:50,test_1:50,test_appl:50,testabl:49,text:[1,2,3,5,7,8,9,11,13,14,15,25,26,46,48,51,53,54,56,61],text_1:11,text_2:11,textbook:8,textedit:1,than:[0,1,4,6,8,9,10,11,12,13,14,15,19,20,21,22,25,28,29,31,32,35,36,37,41,44,46,47,48,50,51,56],thefollow:47,thei:[1,4,5,6,8,10,12,13,15,16,17,18,20,22,24,25,26,27,29,30,31,32,37,41,43,44,45,47,48,49,50,51,53,54,57,58,59],them:[2,3,4,5,8,11,15,18,19,20,22,26,29,32,35,37,38,43,44,45,46,47,48,49,50,51,52,56],themselv:51,theoret:11,theori:51,therefor:[30,32,37],therein:[5,9,53,54],thi:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,55,56,57,58,59,60,61],thing1:48,thing2:48,thing:[3,8,14,15,27,37,43,45,50,51,60],thingth:51,think:[1,16,25,27,37,45,51,53,54],third:[5,15,26,32,50,51,58],thorough:[28,37],those:[4,8,11,14,15,21,24,25,26,28,31,35,37,42,48,51,53,54,58],though:[32,41,51],thought:[3,22,51],thousand:[6,8,10,35],three:[3,8,9,14,17,18,20,25,27,28,31,32,33,34,36,37,41,44,46,47,50],threshold:28,through:[4,5,15,17,22,27,31,32,45,46,47,48,49,50,51,55,57,59,60],throughout:[1,2,6,7,8,9,13,14,15,25,26,34,51,53,54],thrown:35,thu:[1,2,4,5,6,8,9,10,11,12,13,14,15,17,18,19,20,22,23,25,26,27,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,50,51,58],thusli:8,tick:[47,51],tightli:35,time:[3,4,5,6,7,8,10,11,13,15,17,18,22,23,25,28,29,31,32,34,35,36,37,38,41,45,47,49,50,51,55,60],timeit:[22,36],times10:8,tinker:5,tip:[20,36,57,59],titl:47,tmp:41,togeth:[3,8,12,15,18,20,22,32,36,44,45,56,58],token:11,toler:8,too:[8,12,14,15,20,23,27,37,51],took:48,tool:[1,2,3,5,6,8,11,12,15,16,17,18,29,37,47,51,52,53,54,55,56,58,61],toolkit:56,toothpast:51,top:[0,1,5,11,13,37,43,47,48,51],topic:[28,37,42,48,58],topmost:[22,36,48],total:[3,10,13,14,15,19,20,21,27,30,32,35,36,37],total_even:14,touch:[8,31,51],tough:12,tour:[48,60],tover:8,toward:[5,8,37,51],town:47,toyplot:47,trace:51,traceback:[8,9,12,15,26,27,45],track:[2,8,11,12,15,17,27,38,45,46,48,51],trade:56,tradit:[8,37,56],tradition:[1,8,37],trail:[3,8,25,27,31,32,50,51],train:43,trait:51,transcript:20,transit:[29,46],translat:[1,6,15],transpar:[35,47],transpir:[26,32],transpos:[27,32],travers:[25,28,36,37,51,53,58],treacher:31,treat:[3,8,27,28,32,37,40,43,44,48,50,51],treatment:[8,28,29,46,47,48,53,54,56],tree:11,tremend:[1,5,6,34,37,58],tri:[22,36,45],trial:[8,35],triangl:47,triangular:47,tribul:49,trick:[20,56],trigger:[14,31],trigonometr:[8,37],trillion:8,tripl:[8,50],triplet:29,triu:47,trivial:[28,32,35,41,44,49],troubl:51,troubleshoot:61,true_label:36,truli:[10,31],truth:[36,56],tupl:[8,9,12,13,14,17,18,22,26,27,28,30,33,37,38,41,43,47,56,60],tuple_of_dummi:41,turn:[31,47],tutori:[2,4,8,11,12,15,38,40,42,43,47,48,50],twelv:32,twice:[10,12,17,20,38],twitter:[53,54],two:[0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,18,19,20,25,26,28,29,31,32,33,34,35,37,38,40,41,43,44,45,46,47,48,51,53,55,57,58,61],txt:[1,26,50],type:[1,2,3,5,9,10,11,12,13,15,17,20,22,24,28,30,31,34,37,38,39,40,41,42,44,45,46,47,48,50,52,53,56,58,60,61],typeerror:[12,14,15,25,26,44,45],typic:[2,7,8,11,14,28,37,47],typo:[2,52],u0336:46,ubiquit:[25,49],uint8:47,ultim:[8,20,27,50,51,60],umbrella:14,unabl:[37,45],unachiev:58,unaffect:[26,31],unambigu:[1,9,37],unanticip:22,unchang:[22,27,31,35,44],uncommon:[4,56],uncompromis:51,undefin:[2,40],under:[10,17,19,38,41,44,45,46,48,49,51,56],undergo:32,underli:[9,27,28,34,58],underneath:50,underscor:[8,26,40,41,46,51],underst:13,understand:[1,3,7,9,10,15,16,17,20,22,25,26,27,28,29,30,31,32,41,43,44,47,48,51,53,54,56,57,59],understat:56,understood:[7,8,14,60],undo:29,unequ:[32,33],unevalu:9,unexpect:44,unfortun:[45,49,53,54],unhash:12,unicod:[8,26,46,50],unifi:43,uniform:[16,30,33,47],uninstal:[4,48],union:[10,11,38],uniqu:[11,12,25,27,28,29,38,46,47],unit:49,univers:[1,8],unknown:27,unless:[12,31,33,48],unlik:[11,12,25,28,37],unnecessari:[27,51],unnecessarili:[15,32],unord:[10,11,12],unpack:[14,22,28,47],unpattern:28,unpickl:50,unpopul:22,unpurchas:[38,46],unrecogn:45,unrestrict:37,unruli:51,unsign:47,unsorted_index:17,unsuccessfulli:45,unsupport:45,until:[0,12,13,15,16,24,29,45],untitl:5,unus:51,unusu:48,unvector:59,unvectorized_accuraci:36,unwieldi:[27,49],unwittingli:[22,31],updat:[3,4,7,8,9,10,11,12,22,26,28,31,34,35,38,41,46,48,49,50,51,52,58],upgrad:48,upload:48,upon:[15,17,39],upper:[8,14,35,47],uppercas:9,upward:47,usabl:49,usag:[11,15,17,32],use:[0,1,2,3,4,5,6,8,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,53,54,56,58],use_gpu:51,used:[1,3,5,6,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,31,32,33,34,37,39,40,41,43,44,45,46,47,48,49,50,51,56],useful:[1,2,3,4,5,8,10,11,12,14,15,16,17,18,27,28,31,32,35,36,37,38,45,46,47,48,49,50,51,56],usefulness:27,useless:9,user:[2,3,4,5,7,8,11,12,14,25,27,31,33,37,43,44,47,48,49,50,51,53,54,56,57,58,59,60,61],uses:[4,8,10,11,16,20,25,27,29,32,35,37,47,51],using:[0,1,2,4,5,6,8,9,10,11,12,14,17,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,37,40,41,42,43,46,47,48,49,50,51,53,54,56,57,58,61],usr:48,utf:[8,50],util:[1,3,4,8,9,10,11,13,14,16,17,18,26,28,29,31,34,37,38,42,43,44,46,47,48,50,51,61],val:14,valid:[1,3,9,12,13,14,15,23,25,27,29,31,37,44,47,51,56],valu:[0,1,3,5,8,10,11,13,15,17,18,19,20,21,22,24,25,26,27,28,31,32,33,34,35,36,37,40,41,43,44,46,47,56],valuabl:[11,17,18,22,24,27,29,53,54],value1:12,value2:12,value3:12,valueerror:[25,27,32],vanilla:[4,6,11,48],var_nam:14,vari:[27,31,33,49],variabl:[0,1,2,3,4,5,7,8,9,13,14,17,22,25,31,37,38,39,40,41,43,48,50,51,53,56],varianc:[33,37],variant:4,variat:48,varieti:[8,12,25,28,33,37,41,44,46,47,51],variou:[3,5,9,10,11,12,16,24,27,28,31,37,40,43,46,47,48,51,52,56,60],vast:50,vastli:16,vector:[1,32,34,51,53,58,59],veget:12,veggi:12,vein:[37,48],venu:48,verbos:[12,51],veri:[2,4,5,6,8,9,12,14,15,16,20,22,25,27,32,33,34,35,37,41,44,47,51],verifi:[8,15,32,37,41,42,44,47,49,50],versa:[3,22,51],versatil:[12,47,58],version:[2,4,6,8,9,10,11,12,20,24,32,43,44,48,49,51,53,54],versu:[26,31,35,47],vert:37,vertic:[32,33,37,47,51],via:[0,4,5,7,8,9,11,12,13,15,20,22,25,27,31,32,35,37,39,42,47,48,50,51,58],vice:[3,22,51],video:[5,9,58],view:[5,12,27,28,32,38,51,53,54,58],violat:[1,51],viridi:47,visibl:24,visit:[14,20,29,53,54],visual:[2,8,35,47,51,55,61],vogu:8,vowel:[13,14,49,50,51],vscode:[2,51,52],vstack:33,vulner:50,wai:[0,1,3,4,5,8,9,11,12,14,15,16,20,25,27,28,29,31,32,33,35,37,38,40,43,44,45,46,47,48,49,50,51,58,61],wait:49,walk:[45,51,53,54],want:[1,2,3,5,8,9,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,32,33,35,36,37,38,40,41,42,44,48,49,50,51,53,54],warn:[0,1,8,13,14,25,33,51,56],warrant:[8,25,29],wasi:47,wasn:[14,51],wast:32,watch:[8,50],wave:47,wayn:8,weak:47,wealth:10,web:[5,47],websit:[5,53,54],week:49,weirdo:8,welcom:49,well:[1,2,5,8,12,14,17,19,22,23,25,31,32,33,37,46,47,48,51,55,58],went:52,were:[3,5,8,9,12,16,20,31,37,38,44,48,49,50,51,52,53,54,57,59],weren:38,what:[3,5,7,8,9,11,14,15,16,17,18,20,21,22,24,25,26,27,28,29,30,31,32,33,34,37,41,44,45,48,49,50,52,55,56,58,61],whatev:[4,5,10,11,22,47,51],when:[1,3,5,6,8,9,10,11,12,13,14,15,16,17,21,22,24,25,26,27,28,29,31,32,33,37,38,41,44,45,46,47,48,50,51,55,56],whenev:[4,8,11,15,17,28,29,31,37,39,40,44,46,50],where:[1,6,8,9,10,13,14,15,16,17,21,22,23,25,27,28,29,31,32,35,38,40,41,43,45,46,47,48,49,50,51,55],wherea:[3,5,8,9,10,11,14,15,23,24,25,26,28,32,33,44,46,48,51],whereas:9,wherein:39,wherev:[7,8,15,28,36,48],whether:[1,12,21,23,26,32,35,36,45,58],which:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,55,56,57,58,59,60,61],while_block:24,white:16,whitespac:[8,9,13,14,23,51,56],who:[3,4,15,21,32,51,53,54,61],whole:[1,8,15,34,37,48,56],wholesal:48,whom:[32,51],whose:[8,10,11,12,15,25,26,28,35,36,42,43,44,46,47,48,50,51],why:[0,3,6,8,9,15,20,25,26,27,29,31,32,34,44,46,48,51,55,58],wide:[8,12,33,37,44,47,48,50,51],wider:48,width:[42,43,45,47],wildcard:50,wildli:10,win:1,window:[1,3,4,5,47,50],windowspath:50,wisdom:51,wise:[32,37],withhold:27,within:[3,5,7,8,9,10,13,14,15,16,19,22,24,25,27,28,29,31,32,33,35,36,37,40,42,43,44,47,48,49,50,51,53,56,57,61],within_margin_percentag:21,without:[0,4,5,7,8,9,13,14,15,16,19,22,28,31,32,34,35,47,48,50,51,56,58],won:[45,51],wonder:[3,8,46],wont:46,woof:40,word:[1,2,8,11,14,15,20,43,48],word_collect:15,word_distr:11,words_with_o:15,work:[2,3,4,5,8,10,12,14,15,23,24,26,27,28,31,32,34,36,37,38,42,44,45,46,47,48,49,51,53,54,55,56,57,58,59,60,61],workflow:[49,51],world:[1,8,32,41,43,46,48],worldwid:48,worri:[4,8,11,12,19,29,37,41,50],worst:[10,12],worth:51,worthwhil:[6,26,43,47,51],would:[3,5,6,8,9,10,11,12,13,14,17,18,19,20,21,22,24,25,29,31,32,35,36,37,40,44,45,46,47,48,49,50,51,53,54,57,59],wow:25,wrap:[3,51],write:[1,2,3,5,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,25,26,29,32,34,35,36,38,41,42,43,45,48,52,53,54,55,56,58,61],writelin:50,written:[1,3,4,5,6,8,9,10,15,16,22,37,45,48,50,51,53,54,57,59],wrong:[1,9,12,14,22],wrote:[10,22,42,45,46],www:51,x_0:32,x_1:32,x_1d:32,x_i:37,x_it:15,x_left:47,x_norm:32,x_right:47,x_sqrd_sum:32,x_val:18,x_y_prod:32,x_y_sqrd:32,xarrai:[27,58],xmax:35,xmin:35,y_0:32,y_1:32,y_gen:18,y_sqrd_sum:32,year:[5,8,49,53,54],yerr:47,yes:51,yet:[1,8,10,22,25,41],yield:[12,15,18,26,36,50,51],you:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47,48,49,50,51,55,56,57,58,59,61],your:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,16,17,19,20,21,22,25,26,27,31,35,36,38,40,41,43,45,46,47,50,51,55,56,61],your_usernam:4,yourself:[1,2,4,6,8,22,28,35,47,50,51,55],zero:[8,9,14,15,20,25,45,47,51,58],zerodivisionerror:[8,9,21],zeros_lik:32,zip:[12,18,22,36,48],zoe:12,zone:[53,54],zoom:47,zordon:8},titles:["Exercises","Introducing the Python Programming Language","Setting Up a Development Environment","An Informal Introduction to Python","Installing Python","Jupyter Notebooks","Doing Numerical Work in Python","A Quick Guide to Formatting","Basic Object Types","Conditional Statements","Data Structures (Part I): Introduction","Data Structures (Part III): Sets & the Collections Module","Data Structures (Part II): Dictionaries","For-Loops and While-Loops","Basics of Functions","Generators & Comprehension Expressions","Introducing Control Flow","Iterables","Python\u2019s \u201cItertools\u201d","Difference Fanout","Encode as String","Within Margin Percentage","Merging Two Dictionaries","Is Palindrome","Scope","Sequence Types","Variables & Assignment","Accessing Data Along Multiple Dimensions in an Array","Advanced Indexing","Iterating Over Arrays & Array-Traversal Order","Basic Array Attributes","Introducing Basic and Advanced Indexing","Array Broadcasting","Functions for Creating NumPy Arrays","Introducing the ND-array","Playing Darts and Estimating Pi","Measuring the Accuracy of a Classification Model","\u201cVectorized\u201d Operations: Optimized Computations on NumPy Arrays","Applications of Object Oriented Programming","A Brief Summary of Terms and Concepts","Defining a New Class of Object","Instances of a Class","Inheritance","Introduction to Object Oriented Programming","Methods","Object Oriented Programming","Special Methods","Matplotlib","Import: Modules and Packages","Testing Your Code","Working with Files","Writing Good Code","Changelog","Python Like You Mean It","Python Like You Mean It","Module 1: Getting Started with Python","Module 2: The Essentials of Python","Module 2: Problems","Module 3: The Essentials of NumPy","Module 3: Problems","Module 4: Object Oriented Programming","Module 5: Odds and Ends"],titleterms:{"boolean":[8,9,28],"break":13,"class":[40,41,43,44,46],"default":[11,14],"float":8,"function":[12,14,17,27,33,37,49],"import":[43,48],"new":[40,52],"return":14,"short":9,"static":44,"while":13,Adding:12,Are:12,Axes:[32,47],Being:51,Doing:[0,6],For:[13,32,51],IDEs:2,One:[22,27],The:[8,11,14,15,32,40,44,47,49,51,56,58],Uses:16,Using:[5,15,31,32,33,37,51],Will:2,__init__:41,about:[53,54],absolut:[48,51],access:27,accommod:14,accuraci:36,act:17,add:45,advanc:[28,31,32],algebra:37,algorithm:10,along:27,anaconda:4,anatomi:49,ani:51,applic:[32,38],arang:33,arbitrari:[14,22],arg:51,argument:[14,37,44],arithmet:0,arrai:[27,28,29,30,31,32,33,34,37,50],assign:[8,26,28,31],attribut:[30,40,41],augment:[8,28,31],axi:37,basic:[8,12,14,28,30,31,37,49],benefit:31,beyond:47,binari:37,bool:9,bound:25,brief:[4,39],broadcast:32,buggi:22,callabl:51,can:[8,12],cell:5,chain:15,challeng:22,changelog:52,check:0,circuit:9,classif:36,claus:13,code:[5,49,51],collect:11,column:29,combin:28,comparison:9,complex:[8,10,12],comprehens:[8,9,11,12,13,14,15,17,18,19,25,26,27,28,31,32,37,40,41,44,45,47,48,50,51],comput:[4,37],concept:39,conclus:37,conda:[4,48],condit:9,constant:33,construct:[0,12],consum:15,contain:46,content:52,continu:13,contributor:[53,54],control:16,convent:51,correct:22,counter:11,creat:[5,11,15,33,41,46,47],dabbl:3,dart:35,data:[0,10,11,12,27,31,33],def:14,defin:[40,41,45],definit:40,delimit:16,dequ:11,describ:10,develop:2,dict:51,dictionari:[11,12,22],did:4,differ:19,difference_fanout:19,dimens:[27,32],dimension:[27,28,31,37],displai:47,distanc:32,document:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,50,51],doe:1,easi:[53,54],elif:9,ellipsi:31,els:[9,13],encod:20,end:[6,61],enumer:17,environ:[2,4],essenti:[8,56,58],estim:35,exampl:[5,50],exercis:[0,8,9,13,14,15,17,25,26,47,48],express:[9,15],extend:22,extens:19,extra:22,familiar:5,fanout:19,fewer:27,figur:47,file:50,flow:16,fly:15,form:40,format:[7,8],from:33,gener:[15,22,40],get:55,github:[53,54],given:12,glob:50,good:51,googl:51,grade:0,guid:[7,51],handl:[22,25],hint:51,how:29,ident:41,iii:11,imag:47,immut:26,improv:8,indent:51,index:[25,27,28,31],indic:[25,27,53],inform:3,inherit:[42,45],inlin:[9,14],input:22,insert:32,inspect:12,instal:[1,4,48],instanc:[41,44],integ:[8,27,28,31],integr:2,interfac:46,interpret:1,intra:48,introduc:[1,8,15,16,25,27,31,34],introduct:[3,4,10,43],isn:[53,54],iter:[15,17,29],itertool:18,join:33,jupyt:[5,47],just:4,kei:[12,51],keyword:[14,37],lab:5,languag:[1,5],learn:2,level:41,like:[46,53,54],linear:37,link:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,50,51],linspac:33,list:[0,3,8,10,15,19,38,51],liter:51,load:50,logic:[8,9,37],loop:[13,19,32],major:29,manag:48,manipul:27,map:12,margin:21,markdown:5,math:8,mathemat:[37,46],matplotlib:47,mean:[1,53,54],measur:36,merg:22,mess:3,method:[41,44,46],minor:22,mode:50,model:36,modul:[8,11,48,51,55,56,57,58,59,60,61],more:12,multi:37,multipl:[14,26,27],mutabl:26,mutat:8,name:[11,14,26,51],neg:27,nest:15,newaxi:[31,32],next:15,non:9,none:[8,51],notat:8,note:43,notebook:[5,47],noth:51,numba:6,number:[3,8,14,22],numer:[6,8,12],numpi:[6,31,33,37,50,51,58],object:[8,9,14,26,31,32,38,40,41,43,45,46,47,50,60],odd:61,offici:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,50,51],ones:33,open:50,oper:[0,8,9,11,31,37,45,46],optim:[22,32,37],option:51,order:[12,29],orient:[38,43,45,60],other:5,out:[25,31],output:51,over:[15,29],overload:45,own:[15,48],packag:48,pairwis:32,palindrom:23,part:[10,11,12],path:50,pathlib:50,pep8:51,percentag:21,perform:31,pickl:50,pip:48,pitfal:13,place:[28,31],plai:[3,35],plot:47,plymi:[53,54],point:8,posit:14,potenti:13,precis:[8,12],problem:[22,35,57,59],produc:31,program:[1,38,43,45,60],pyplot:47,python:[0,1,3,4,6,8,16,18,33,48,50,51,53,54,55,56],pythonpath:48,quack:51,quick:7,radd:45,random:33,rang:15,read:[8,9,11,12,13,14,15,17,18,25,26,27,28,31,32,35,37,40,41,44,45,47,48,50,51],readabl:8,recommend:2,referenc:26,rel:48,relev:35,remark:6,represent:46,reshap:27,retriev:12,risk:31,row:29,rule:32,run:5,sampl:33,save:[47,50],scheme:28,scientif:8,scope:[16,24],scratch:49,script:1,self:44,sequenc:[8,25,33],sequenti:[10,33,37],server:5,set:[2,11,51],shadow:24,shop:38,should:49,shouldn:[53,54],simpl:[0,22,32],site:48,size:32,slice:[0,25,27,31],solut:[8,9,11,12,13,14,15,17,18,19,20,21,22,23,25,26,27,28,31,32,35,36,37,40,41,44,45,47,48,50,51],space:51,special:46,specifi:[14,31,33,37,50],start:55,statement:[8,9,14,48],store:[12,15],string:[0,3,8,20,46],structur:[10,11,12],studio:5,style:51,subplot:47,summari:[1,6,8,39,42],suppli:27,support:5,tabl:53,term:39,terminolog:43,test:49,text:50,textbook:[53,54],than:27,thi:[4,53,54],time:12,tip:[23,35],togeth:33,too:[53,54],travers:29,trick:17,truth:9,tupl:[10,11,15,25,31,51],two:[22,27],type:[0,8,25,26,33,43,51],unari:37,underli:31,understand:[8,37],union:51,unoptim:32,unpack:17,unvector:[35,36],using:[15,19],util:32,valid:26,valu:[9,12,14,51],variabl:[24,26],variou:0,vector:[35,36,37],version:0,via:28,view:31,visual:5,warn:12,what:[1,2,4,12,51,53,54],whitespac:16,why:[1,49],within:21,word:12,work:[6,17,25,40,50],write:[49,50,51],you:[2,53,54],your:[15,48,49],yourself:5,zero:[22,27,33]}}) \ No newline at end of file +Search.setIndex({docnames:["Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python","Module1_GettingStartedWithPython/GettingStartedWithPython","Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks","Module1_GettingStartedWithPython/Informal_Intro_Python","Module1_GettingStartedWithPython/Installing_Python","Module1_GettingStartedWithPython/Jupyter_Notebooks","Module1_GettingStartedWithPython/Numerical_Work_In_Python","Module1_GettingStartedWithPython/SiteFormatting","Module2_EssentialsOfPython/Basic_Objects","Module2_EssentialsOfPython/ConditionalStatements","Module2_EssentialsOfPython/DataStructures","Module2_EssentialsOfPython/DataStructures_III_Sets_and_More","Module2_EssentialsOfPython/DataStructures_II_Dictionaries","Module2_EssentialsOfPython/ForLoops","Module2_EssentialsOfPython/Functions","Module2_EssentialsOfPython/Generators_and_Comprehensions","Module2_EssentialsOfPython/Introduction","Module2_EssentialsOfPython/Iterables","Module2_EssentialsOfPython/Itertools","Module2_EssentialsOfPython/Problems/DifferenceFanout","Module2_EssentialsOfPython/Problems/EncodeAsString","Module2_EssentialsOfPython/Problems/MarginPercentage","Module2_EssentialsOfPython/Problems/MergeMaxDicts","Module2_EssentialsOfPython/Problems/Palindrome","Module2_EssentialsOfPython/Scope","Module2_EssentialsOfPython/SequenceTypes","Module2_EssentialsOfPython/Variables_and_Assignment","Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions","Module3_IntroducingNumpy/AdvancedIndexing","Module3_IntroducingNumpy/ArrayTraversal","Module3_IntroducingNumpy/BasicArrayAttributes","Module3_IntroducingNumpy/BasicIndexing","Module3_IntroducingNumpy/Broadcasting","Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays","Module3_IntroducingNumpy/IntroducingTheNDarray","Module3_IntroducingNumpy/Problems/Approximating_pi","Module3_IntroducingNumpy/Problems/ComputeAccuracy","Module3_IntroducingNumpy/VectorizedOperations","Module4_OOP/Applications_of_OOP","Module4_OOP/Brief_Review","Module4_OOP/ClassDefinition","Module4_OOP/ClassInstances","Module4_OOP/Inheritance","Module4_OOP/Introduction_to_OOP","Module4_OOP/Methods","Module4_OOP/ObjectOrientedProgramming","Module4_OOP/Special_Methods","Module5_OddsAndEnds/Matplotlib","Module5_OddsAndEnds/Modules_and_Packages","Module5_OddsAndEnds/WorkingWithFiles","Module5_OddsAndEnds/Writing_Good_Code","Module6_Testing/Hypothesis","Module6_Testing/Intro_to_Testing","Module6_Testing/Pytest","changes","index","intro","module_1","module_2","module_2_problems","module_3","module_3_problems","module_4","module_5","module_6"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,nbsphinx:1,sphinx:55},filenames:["Module1_GettingStartedWithPython\\Exercises\\Informal_Intro_Python.ipynb","Module1_GettingStartedWithPython\\GettingStartedWithPython.md","Module1_GettingStartedWithPython\\Getting_Started_With_IDEs_and_Notebooks.md","Module1_GettingStartedWithPython\\Informal_Intro_Python.md","Module1_GettingStartedWithPython\\Installing_Python.md","Module1_GettingStartedWithPython\\Jupyter_Notebooks.md","Module1_GettingStartedWithPython\\Numerical_Work_In_Python.md","Module1_GettingStartedWithPython\\SiteFormatting.md","Module2_EssentialsOfPython\\Basic_Objects.md","Module2_EssentialsOfPython\\ConditionalStatements.md","Module2_EssentialsOfPython\\DataStructures.md","Module2_EssentialsOfPython\\DataStructures_III_Sets_and_More.md","Module2_EssentialsOfPython\\DataStructures_II_Dictionaries.md","Module2_EssentialsOfPython\\ForLoops.md","Module2_EssentialsOfPython\\Functions.md","Module2_EssentialsOfPython\\Generators_and_Comprehensions.md","Module2_EssentialsOfPython\\Introduction.md","Module2_EssentialsOfPython\\Iterables.md","Module2_EssentialsOfPython\\Itertools.md","Module2_EssentialsOfPython\\Problems\\DifferenceFanout.md","Module2_EssentialsOfPython\\Problems\\EncodeAsString.md","Module2_EssentialsOfPython\\Problems\\MarginPercentage.md","Module2_EssentialsOfPython\\Problems\\MergeMaxDicts.md","Module2_EssentialsOfPython\\Problems\\Palindrome.md","Module2_EssentialsOfPython\\Scope.md","Module2_EssentialsOfPython\\SequenceTypes.md","Module2_EssentialsOfPython\\Variables_and_Assignment.md","Module3_IntroducingNumpy\\AccessingDataAlongMultipleDimensions.md","Module3_IntroducingNumpy\\AdvancedIndexing.md","Module3_IntroducingNumpy\\ArrayTraversal.md","Module3_IntroducingNumpy\\BasicArrayAttributes.md","Module3_IntroducingNumpy\\BasicIndexing.md","Module3_IntroducingNumpy\\Broadcasting.md","Module3_IntroducingNumpy\\FunctionsForCreatingNumpyArrays.md","Module3_IntroducingNumpy\\IntroducingTheNDarray.md","Module3_IntroducingNumpy\\Problems\\Approximating_pi.ipynb","Module3_IntroducingNumpy\\Problems\\ComputeAccuracy.md","Module3_IntroducingNumpy\\VectorizedOperations.md","Module4_OOP\\Applications_of_OOP.md","Module4_OOP\\Brief_Review.md","Module4_OOP\\ClassDefinition.md","Module4_OOP\\ClassInstances.md","Module4_OOP\\Inheritance.md","Module4_OOP\\Introduction_to_OOP.md","Module4_OOP\\Methods.md","Module4_OOP\\ObjectOrientedProgramming.md","Module4_OOP\\Special_Methods.md","Module5_OddsAndEnds\\Matplotlib.ipynb","Module5_OddsAndEnds\\Modules_and_Packages.md","Module5_OddsAndEnds\\WorkingWithFiles.md","Module5_OddsAndEnds\\Writing_Good_Code.md","Module6_Testing\\Hypothesis.md","Module6_Testing\\Intro_to_Testing.md","Module6_Testing\\Pytest.md","changes.rst","index.rst","intro.rst","module_1.rst","module_2.rst","module_2_problems.rst","module_3.rst","module_3_problems.rst","module_4.rst","module_5.rst","module_6.rst"],objects:{},objnames:{},objtypes:{},terms:{"**kwarg":14,"*arg":14,"04s":53,"07s":53,"0th":[8,29],"0x00000146ce118620":49,"0x000001b91b913708":53,"0x000001e768fe8a40":15,"0x000002a32898c6a8":14,"0x1d50de887b8":41,"0x1d50de896d8":41,"0x1d50de897b8":41,"0x1d50de89940":41,"0x1d50de899e8":41,"0x1d50de89a20":41,"0x1d50de89a58":41,"0x1d50de89a90":41,"0x1d50de89ac8":41,"0x1d50de89b00":41,"0x1d50de89b38":41,"0x20de1082608":18,"0x20de109ec18":18,"0x20de10a7728":18,"0x23e3557b3f0":18,"0x284f0008da0":44,"0x2ae8f65fcf8":41,"0x2ae8f666f60":41,"0x2ae8f68f2e8":41,"10000j":8,"10_000j":8,"10x10":47,"111111111111111e":8,"15x25":47,"16j":48,"1_000_000":8,"1e10":51,"1e12":8,"1e3":8,"1e34":50,"1e9":8,"1st":[25,37],"1x10":8,"1x4":36,"207d18d18af2":27,"2246467991473532e":48,"2_3_4":8,"2cool":26,"2e10":8,"2eba8294859":52,"2f755f117ac9":27,"2mb":32,"2nd":12,"2x2":27,"2x3":[37,47],"2x3x4":33,"32301ff829e9":52,"32x32":[32,37],"3471672109ee":9,"38e":8,"3rd":[4,37,49,50,57],"3x4":[15,33],"48x48":32,"4th":31,"50x75x3":47,"551115123125783e":8,"5_6_7":8,"662_607_004":8,"6gb":32,"74c002a67890":12,"7th":25,"99ef0ca3d859":52,"\u0113z":27,"\u4e2d\u6587\u7248":[55,56],"\u4f60\u597d":8,"absolute import":48,"abstract method":44,"abstract":[27,28,42,45,50],"array iter":29,"basic index":31,"basic program":13,"best practic":50,"big-o":10,"binary fil":49,"boolean array index":28,"boolean":[12,20,26,35,36,37,50,52,58,60],"break":[3,4,8,17,23,24,26,50,52,53,58],"byte":[8,30,49],"c order":29,"c routin":37,"case":[1,3,4,5,9,10,12,13,14,15,17,19,20,21,22,23,25,27,31,32,36,37,40,45,47,49,50,51,52,53,58],"catch":[8,9,12,20,50,51,52],"char":[11,14,23,50,52],"class creat":41,"class definit":[39,40],"class funt":44,"class method":44,"class object":40,"class":[8,11,17,22,26,36,38,39,42,45,48,49,50,55,62,63],"clean directori":[51,53],"close fil":49,"code block":7,"code styl":50,"column-major ord":29,"comparison oper":9,"console styl":7,"context manag":49,"control flow":[13,16,21],"copy index":28,"create arrai":33,"custom packag":48,"custom syntax":46,"data sci":[4,5],"default paramet":14,"default":[4,5,8,15,25,27,29,31,33,37,43,44,46,47,48,49,50,51,52,60],"dunder method":46,"export":4,"f order":29,"final":[5,8,19,20,26,31,32,35,42,47,48,50,52,53,54,58,60,63,64],"float":[3,12,15,20,21,26,27,28,31,33,36,37,43,44,46,47,50,52],"floating point precis":8,"for loop":19,"for-loop":[13,16],"function":[0,1,2,3,5,6,7,8,9,10,11,15,16,18,19,20,21,22,23,24,28,29,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,55,58,60,62,63,64],"generator comprehens":15,"get item":[12,25],"import":[0,3,4,5,6,8,10,11,12,14,15,17,18,19,20,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,41,44,47,49,50,51,52,53,55,56,58,62,63,64],"inline for-loop":15,"inline if":9,"int":[1,8,9,16,19,20,28,31,33,36,40,41,43,45,50,51,52,62],"integer array index":28,"interview prepar":[10,11,12],"is oper":9,"join directori":49,"jupyter lab":5,"linear algebra":37,"list comprehens":[15,19],"long":[2,4,8,10,12,15,19,20,23,31,37,43,47,48,50,52,58],"machine learn":36,"mismatched shap":32,"multidimensional arrai":31,"nd arrai":31,"negative index":[25,27],"nested comprehens":15,"new":[1,2,3,4,5,8,10,12,15,17,19,22,23,25,26,27,31,32,37,38,41,42,43,44,49,50,52,53,55,56,62,63],"no copy index":31,"null":8,"numpy arrai":[27,28,34],"object ori":[38,42,47],"ol\u00e1":8,"open fil":49,"operator overload":46,"practice problem":[19,20,21,22,23],"public":47,"python shopping list":38,"quick introduct":3,"read fil":49,"read lin":49,"relative import":48,"return":[3,4,5,6,7,8,9,10,11,12,13,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,32,36,37,38,40,41,42,43,44,45,46,47,48,49,50,52,53,58],"row-major ord":29,"short":[3,8,13,15,37,58],"special method":46,"static method":44,"static":[41,50,54,62],"sub class":42,"super":[42,45],"switch stat":9,"switch":4,"throw":[27,35,51],"true":[3,5,8,9,10,11,12,13,14,15,16,17,20,22,23,24,25,26,28,29,31,32,34,35,36,37,39,40,41,42,44,45,46,47,49,50,52,53],"try":[0,3,8,11,12,13,15,19,22,25,26,32,35,38,44,45,48,50,52,60],"type hint":50,"utf-8":49,"valid nam":26,"var":[13,14,15,26,37,41,49],"variable nam":26,"voil\u00e0":[1,32,48],"vowel count":14,"while":[0,3,4,5,16,17,19,22,24,26,27,30,31,32,47,50,53,55,58],"while-loop":13,Added:54,Adding:52,And:[4,5,11,14,20,36,52],Are:[8,15,32],Axes:[60,63],Being:25,But:[16,55,56],Doing:[26,32,38],For:[0,1,3,4,5,7,8,9,10,11,12,14,15,16,17,19,25,26,27,28,29,30,31,33,35,36,37,41,43,44,45,46,47,48,49,51,52,53,55,58],IDE:[1,2,5,48,50,54],IDEs:[1,16,48,50,52,53,57],IDs:36,Its:[5,8,16,37,41,45,47],Not:[5,27,36],One:[8,15,16,29,37,45,47,48,49,60],Such:[7,14],That:[1,2,4,5,8,9,10,11,12,13,14,15,17,19,20,24,25,26,27,29,31,32,35,36,40,41,42,43,44,45,46,48,49,50,52,53,55,56,62],The:[1,2,3,4,5,6,7,9,10,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,39,41,42,43,45,46,48,49,51,55,56,59,61,62,63,64],Their:[14,25],Then:[1,8,10,12,18,19,26,27,28,32,38,41],There:[1,2,3,4,5,8,9,10,13,14,15,18,19,22,25,26,31,32,33,34,36,37,43,44,47,48,49,50,52,53],These:[1,4,5,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,37,41,43,46,48,49,50,52,53,58,59,60,61],Tis:23,Use:[0,5,8,9,11,13,14,15,16,17,28,32,35,46,47,49,50,53],Uses:58,Using:[0,6,8,9,13,14,18,22,25,26,27,28,35,38,41,45,47,49,51,58,60],Will:[9,25,36,57],With:[4,11,41,49,51,52],Yes:4,____________________________:53,_____________________________:53,__add__:[44,45,46],__all__:48,__contains__:46,__div__:46,__eq__:45,__ge__:45,__getitem__:[17,46,50],__gt__:45,__init__:[38,39,42,43,44,45,46,48,50,53,62],__iter__:[17,46],__le__:45,__len__:[46,50],__lt__:45,__main__:[39,40,41,44],__mul__:[45,46],__ne__:45,__next__:46,__pow__:[45,46],__radd__:45,__repr__:[42,43,45,46],__rmul__:45,__rsub__:45,__rtruediv__:45,__setitem__:46,__str__:[45,46],__sub__:[45,46],__truediv__:[45,46],_data:46,_need:[38,46],_purchas:[38,46],_use_gpu:50,_var2:26,a858573fdc63:26,a_dir:48,a_list:52,a_long_list_nam:50,a_numb:52,a_poem:49,a_str:52,a_text_fil:53,abacus:32,abbrevi:[8,34,47],abc:[3,9,25,49,50],abcabcabc:9,abcd:[17,25,44],abcdef:[29,52],abcdefg:25,abcdefghij:13,abid:[22,50,63],abil:[2,8,9,14,16,25,26,27,29,41,43,44,46,50,52,53,58,63,64],abl:[1,3,4,5,8,12,14,22,25,26,27,29,31,32,37,44,45,47,48,51,53,55,56,60],about:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,19,22,29,32,33,35,37,38,41,43,44,45,46,47,49,50,51,53,58,62,63],abov:[4,5,8,14,22,27,31,32,35,36,39,41,48,50,52,53],abs:[8,15,21],abs_tol:8,absolut:[8,15,32,37,49],acceler:50,accept:[11,12,14,15,17,22,25,36,37,38,42,44,46,47,49,50],access:[1,3,8,9,10,11,15,17,18,19,20,22,24,25,28,29,31,32,33,34,40,41,43,44,48,49,53,55,60,62],accident:[4,5,48],accommod:[8,9,11,12,16,22,32,38,48,50],accomod:49,accompani:[59,61],accomplish:[0,1,3,12,14,48],accord:[1,8,9,10,12,14,20,27,29,30,31,32,35,37,41,44,47,49,50,53],accordingli:[1,35,46],account:[8,9,23,32,55,56],accru:50,accumul:[1,50,52],accuraci:[35,55,61],accustom:50,ace:25,aceg:25,achiev:[17,32,52,60],acquaint:[3,58],acquir:[55,56],across:[5,8,16,18,22,35,36,49,50,52,53],act:[37,58],action:[3,7,8,37,42,49,50,51],activ:[4,5,48,53],actual:[4,6,8,9,14,15,19,21,25,27,31,32,33,35,41,50,51,52,53,57,58,63],adam:8,add:[1,2,4,8,10,11,12,14,16,17,28,32,35,37,38,44,46,47,48,50,52,53,62],add_2:14,add_3:31,add_new_item:[38,46],added:[5,10,12,13,15,22,28,38,40,46,50,63],adding:[11,12,13,26,49,50,55,56,58],addit:[4,8,9,11,12,14,16,33,35,37,40,44,45,47,48,50,52,53],addition:[1,5,22,28,38,41,43,47,48,53],address:[14,15,22,32,41,44,53],adher:[16,29,50,52,53],adjust:[5,27,29],admittedli:52,ado:[4,53],adopt:[44,50],adorn:64,advanc:[2,4,6,12,15,27,29,34,53,55,60],advantag:[10,11,37,45],advis:[4,16,49],aeiou:[13,49],aeiouaeiou:[14,50,52],aesthet:50,affect:[3,16,26,31,41,43,46,47,53],afford:[27,52,53],afoot:22,aforement:[1,4,16,52,53],after:[3,4,8,11,12,13,14,15,19,22,24,27,32,40,50,52,53,59,61],afterward:[31,53],again:[3,10,15,24,31,32,43,50,52],against:[10,19,22,36],age:8,aggress:52,agre:27,aha:20,ahead:[19,52],aid:50,aim:[28,47],air:50,aka:50,akaclass:50,akin:[8,40],aks:27,alarm:52,albeit:32,albert:49,alert:50,alex:55,alexding123:[55,56],alfr:8,algebra:[10,11,60],algorithm:[12,17,21,22,50,58],alia:[4,41,48,50],alias:[48,50],alias_nam:48,alic:22,alien:[8,53],align:[8,32,47,50],alik:[5,7,15,57],all:[1,2,3,4,5,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,62,63,64],all_cap:50,all_fanout:19,allclos:[32,37],allevi:32,alloc:[8,31,51],allot:8,allow:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,19,21,23,25,27,28,29,31,32,33,34,36,38,40,41,42,45,46,47,48,49,50,53,57,58,63,64],almost:[8,10,12,27,32,50],alon:[49,52],along:[3,8,11,13,15,17,20,22,23,24,28,29,30,31,32,33,34,35,37,47,48,50,52,53,55,56,58,60],alongsid:[48,50,53,54,64],alpha:[35,47],alphabet:[8,27,38,50],alphanumer:[23,26],alreadi:[4,5,6,8,9,10,12,15,25,31,38,40,41,42,44,45,48,49,50,52],also:[2,3,4,6,8,9,10,11,12,14,15,17,20,21,22,23,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,59,60,61,63],altern:[5,8,9,52,53],although:[1,5,8,12,15,17,19,23,25,27,28,29,37,40,43,47,49,50,52,58],altogeth:14,alwai:[3,5,8,9,12,13,16,20,22,27,28,29,32,37,38,42,44,47,48,50,52,53],alyosha:50,ambigu:[27,60],amend:[26,33],among:[1,5,8,12,22,25,27,37,44,50,53,60,64],amort:10,amount:[8,29,33,37,38,45,47,49,51,52,58],amp:47,amplitud:47,anaconda3:4,anaconda:[3,5,6,47,48,57],analog:37,analysi:[8,10,35,43,54,55,56],analyt:48,analyz:[5,10,49,50,60],anatomi:64,anchor:50,anew:49,angi:18,angl:48,ani:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,22,24,25,26,29,30,31,32,35,37,40,41,43,44,45,46,48,49,51,52,53,57],anim:47,annabel:[55,56],annabellelew:[55,56],annot:[14,47,50,63],anoth:[1,5,8,9,11,12,15,22,25,28,29,31,32,35,41,42,43,46,47,48,50,53,62],another_long_nam:50,answer:[1,5,8,28,37,49,53],anticip:[21,44],anyon:[1,21,63],anyth:[1,8,9,12,14,44,45,47,49,50,52],anywher:[8,9,14,24,48,50],apart:5,api:[47,63],appar:52,appear:[1,3,5,7,8,15,19,25,26,45,47,48,53],append:[0,3,8,10,11,13,15,17,19,20,25,26,35,36,41,44,45,46,49,50],appendix:46,appendleft:11,appl:[3,8,11,12,14,15,18,22,25,38,39,40,46,50],applepie_yum_yum:26,appli:[19,27,28,32,35,37,41,50,52,53],applic:[4,5,6,11,27,29,37,47,53,55,56,58,60,62],apply_fanout:19,appreci:[15,22,35,46],approach:[32,36],appropri:[0,14,21,22,26,28,29,32,38,41,49,50,52,53],approv:50,approx:35,approxim:[8,14,35,37],arang:[6,27,28,29,35,37,47,60],arbitrari:[25,28,32,40,46,50,51,59],arbitrarili:[8,15,28,51],archaic:53,archiv:49,area:[35,43],area_:35,aren:22,arg1:50,arg2:50,arg3:50,arg4:50,arg5:50,arg6:50,arg:[14,22,24,46],argmax:[36,37],argmin:37,arguabl:[1,21],argument:[9,12,15,17,22,24,31,33,36,39,40,41,46,47,49,50,58],arguments_for_funct:53,aris:58,arithmet:[3,8,9,31,32,37],arm:[9,19,28,30,48,57,58,60,64],around:[8,34,41,43,50],arr:[27,31],arrai:[6,9,25,26,35,36,43,47,48,50,55,60,63],arrang:53,arriv:[12,60],arrow:[50,52],articl:6,artifact:46,as_integer_ratio:8,ascii:52,ascrib:[9,25,27],ashlei:[12,17,26,27],asid:2,ask:[25,51],aspect:[8,19,24,28,46,47,53],assert:[45,51,64],assertionerror:[52,53],assess:[23,51],assign:[0,1,3,5,7,9,13,14,17,22,25,27,39,40,41,48,55,58,60],associ:[4,8,9,10,12,36,37,45,47,48,50],assort:[27,32],assum:[1,4,8,9,10,12,19,21,24,25,35,36,44,49,50,53],assumpt:[47,50],assur:49,asterisk:14,astrophys:60,astropi:60,astyp:47,atrophi:50,attempt:[4,8,13,19,25,26,40,44,45,48],attent:[17,43,50,58,62],attr:[40,42],attract:6,attribut:[38,39,42,43,44,45,46,48,55,60,62],attribute_nam:40,attributeerror:[39,40,45],augment:[38,60],author:[48,53],auto:[43,48,53],autocomplet:[2,3,5],autom:[50,51,52,53,64],automat:[8,16,19,27,31,38,39,41,43,44,47,49,50,53],autoreload:48,avail:[3,5,7,8,10,11,12,25,27,33,37,40,45,47,48,49,50,53,54,55,56],averag:[32,35,37,58],avoid:[3,8,15,17,32,33,37,48,50],awai:[3,14,50,55,56],awar:[2,5,8,47,49],ax1:47,ax2:47,ax3:47,ax4:47,ax5:47,ax6:47,axes:[27,30,31,32,35,37,47],axi:[27,28,29,30,31,32,34,35,36,47],axs:47,b9d20096048c:15,b_attr:42,back:[4,5,13,29,50,52,53,55,56,64],background:[7,47],backtick:7,bad:[16,22,35,40,44,50,52,55,56],bad_dict:12,bad_f:14,bad_func1:14,bad_func2:14,bad_func3:14,bad_func4:14,bad_merge_max_map:22,bagel:49,balanc:58,banana:[12,18,22,50],bar:[16,47,52,53],bare:[48,53,60],barrier:52,base:[1,5,8,9,14,19,20,22,25,26,27,28,32,33,45,47,48,50,51,52,64],base_fanout:19,base_numb:19,bashrc:4,basic:[1,5,7,9,13,15,17,25,27,32,34,40,41,43,47,48,49,53,55,56,58,60,64],basic_funct:53,basic_math:48,basic_modul:48,basket:8,batch:36,batman:8,bcd:25,bear:51,beauti:47,becaus:[1,4,8,9,10,11,12,13,14,15,17,22,25,27,28,29,31,33,35,36,37,44,45,48,49,52,53,55,56],becom:[1,5,6,9,11,13,15,17,18,27,33,37,40,48,50,52,53,55,56,57,58],bedrock:49,been:[1,4,5,8,10,12,15,20,25,27,31,32,35,37,38,40,43,45,48,50,51,53,55,56,58],beet:46,befor:[4,10,12,13,15,16,22,23,27,32,38,43,45,48,49,52,53],begin:[1,3,4,7,8,9,10,11,16,22,25,26,27,28,31,32,35,38,40,44,49,50,52,53,55,56,57,58,64],beginn:[4,5],behav:[8,11,12,13,14,19,20,22,25,28,31,35,36,37,41,43,44,45,46,50,52,62],behavior:[8,9,11,14,19,20,21,22,23,25,26,28,37,44,46,47,52,53],behind:[6,15,26,31,32,45,53],being:[1,2,4,5,7,8,9,12,13,14,15,17,20,22,26,27,28,29,31,32,35,37,38,39,40,41,42,43,44,45,46,47,48,49,50,52,53,55,56,62],belong:[8,9,18,34,39,43],below:[4,5,11,35,40,49,53,58],belt:52,beneath:[5,13],benefit:[5,33,37,47,48,50,52],best:[6,8,22,26,28,37,47,49,55,56,63],better:[12,22,29,49,52],between:[1,3,4,5,7,8,15,16,19,25,27,31,32,35,37,41,42,47,50,52,60,62],beyond:[3,8,12,14,15,19,27,31,32,44,46,48,52,53,63],biff:50,big:[2,4,10,12,28,31],biggest:50,billion:8,bin:[4,47,48],binari:[4,19,49,50],bind:40,birthdai:53,bit:[8,14,15,18,29,30,33,37,47,49,51,52,64],bizarr:53,black:[50,53,58],blank:[14,16,47,50,53],blazingli:6,bloat:32,block:[5,7,8,9,13,16,24,36,49,52,53,58],blog:[53,55,56],blogospher:25,blue:[5,32,37,47],board:35,bob:[3,8,22],bodi:[9,11,13,14,16,20,40,41,44,52,53],bogus_path:49,bohm:11,bohr:11,boil:1,boiling_point:50,bokeh:47,bolster:[44,58],bone:48,bonu:0,book:[11,32,49,50,55,56],bookkeep:[27,29],bool:[8,12,13,14,15,17,20,23,28,37,41,50,52,58],bool_ind:28,bool_index:28,boope:25,boopeeboopeeboopeeboopeeboope:25,border:5,borrow:52,both:[5,6,8,9,10,11,13,14,25,26,27,28,29,31,32,37,39,42,43,44,45,47,48,49,50,52,53],bottleneck:[22,23,32],bottom:[1,5,8,9,13,14,15,25,26,37,47,48],bound:[19,27,35,40,43,47,48,51],box:[2,58],brace:[10,12,16],bracket:[8,10,12,16,25,46,49,50],brad:[17,27],branch:[9,16,58],brand:44,bread:38,brian:[18,26],brief:[7,37,48,50,54,55,57,62],briefli:[4,9,11,18,24,27,43,47,49],bring:[5,44],broadcast:[28,29,31,34,35,37,47,50,55,60],broadcast_to:[32,47],broadli:41,broken:[20,52,53],brought:62,browser:[5,47],bruce:[8,50],bud:50,bug:[8,9,12,17,22,31,50,51,52,53],buggi:59,buggy_merge_max_map:22,build:[3,4,16,27,29,32,37,42,48,57],built:[0,3,8,9,10,11,12,14,15,17,18,21,25,29,31,35,38,40,41,42,43,44,48,49,50,51,52,58],builtin:40,bullet:[6,46],bunch:[32,58],bundl:45,burden:51,button:[4,52,53,64],bye:[8,14],c82711d5fe4d:52,cachedir:53,calcul:[0,6,19,32,34,37],calibr:48,call:[1,3,4,5,7,8,9,11,12,13,14,15,19,20,22,23,26,27,31,32,33,34,36,37,40,41,44,45,46,47,49,50,51,52,53,58,63],callabl:19,came:[4,6,12],camel:40,camelcas:50,camera:48,can:[0,1,2,3,4,5,6,7,9,10,11,13,14,15,16,17,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,55,56,58,62,63,64],cannot:[5,8,10,11,12,13,14,15,24,25,26,27,31,32,41,45,49,50,53,60],cap:64,capabl:[1,5,17,20,37,43,47,48,50,60],capit:[8,43,44,50],capsul:14,caption:7,captur:50,capword:50,care:[10,12,14,19,20,22,32,38,48,49,50,52,57],carefulli:[37,50,52],carpent:[55,56],carri:[1,29,38,43,48,53],carrot:12,cassi:[17,18,27],cast:[14,20],casual:40,cat:[3,8,11,14,18,24,25,36,40,41,43],cat_dog_goose_oth:36,catcatcat:25,categori:[27,50],catwoman:8,caught:[55,56],caus:[1,13,16,22,26,31,48,49,52,53],caution:[8,38],caveat:4,cavemen:32,cavewomen:32,cba:9,cdot4:32,cdot5:32,cdot6:32,cdot7:32,cdot:[32,37],ceaselessli:13,celin:50,cell:[22,36,51,52,57],celsiu:50,center:[8,32,35,42,43],center_of_mass:32,certain:[3,32,49],certainli:[12,52,53],chain:[9,18],challeng:[52,59],chanc:5,chang:[1,3,4,5,8,12,19,22,25,26,27,31,32,35,41,48,50,52,53,55,56],changelog:55,channel:[32,47,48,53],charact:[0,1,2,3,8,9,11,13,16,23,26,43,46,49,50,52,53,58],characterist:50,charli:40,chart:47,chdir:53,cheat:47,check:[2,3,8,9,10,11,12,15,20,22,25,27,31,32,37,40,41,46,48,49,50,51,52,53,58],chees:12,chines:[55,56],chocol:50,choic:[20,50,53],choos:[22,27,33,47,50],chosen:[50,55,56],chronolog:54,chunk:5,cindi:22,circl:[35,47],circuit:[13,58],circumst:[6,24,26,52],cite:50,civil:[33,40],clariti:16,class_:50,class_func:44,classa:11,classb:11,classif:[55,61],classifi:[36,50],classification_accuraci:36,classification_scor:36,classmethod:44,classnam:40,claus:[9,15,20,58],clean:[11,17,50,53,58],cleandir:53,cleaner:[8,36,50],cleanup:53,clear:[9,14,15,20,27,32,34,35,37,44,49,50,53,58],clearli:[19,50,51,52,53],clever:[20,22,25,32],click:[0,4,5,53],clockwis:43,close:[0,5,8,35,37,49,50,55,56],closur:50,cloth:46,cloud:48,cls:[44,50],clunki:53,cmap:47,cmath:8,cmd:[1,3,4],cnt:[7,40],cnt_div_by_3:16,code:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,31,32,34,35,36,37,38,39,40,41,42,45,47,48,49,51,54,55,56,57,58,59,60,61,63],coerc:32,coexist:43,coffe:46,coher:[37,50],col:[15,28,47],collabor:50,collect:[1,4,8,9,10,12,13,17,25,27,32,37,40,43,48,49,50,52,53,55,58],colon:[9,11,13,14,25,50],color:[2,5,7,32,37,47],colormap:47,column:[27,28,30,31,32,34,35,36,37,47,60],com:[50,53],comb_l:18,combat:52,combin:[14,18,24,31,32,37,41,46,52,53,60],come:[1,3,4,6,7,8,10,14,17,25,37,49,50,53,58,62],comfort:[18,21,37],comma:[8,14,15,25,50,52],command:[1,4,5,9,15,22,36,47,48,50,52],commensur:47,comment:[7,52],common:[3,4,5,8,10,11,12,15,16,22,25,26,27,28,34,37,41,44,45,49,50,52,53,58],commonli:[8,9,14,29],commun:[2,5,50,63],commut:45,comp_var:24,compact:12,compani:50,compar:[5,6,8,9,10,11,12,15,22,23,24,27,32,36,37,50,52,53],comparison:[1,8,11,21,22,23,35,37,50,53,58],compat:[4,6,8,32,38,45,46,50],compet:[5,55,56],compil:[34,37,50],complac:[55,56],complain:44,complet:[2,4,5,6,8,9,10,11,12,13,20,21,27,29,33,35,36,46,48,49,50,52,53,55,56],complex32:30,complex64:33,complex:[11,26,33,48,50,58],complic:[12,15,35],compon:[6,31,48,53],compound:9,comprehens:[0,5,20,21,23,24,36,46,55,58,59,60,62,63,64],compris:[32,33],comput:[1,2,3,5,6,7,8,10,14,15,16,19,21,24,25,27,32,35,36,41,43,48,49,50,55,57,58,60],compute_area:[42,43],compute_corn:43,compute_exp:14,compute_student_stat:50,con:2,concat_to_str:20,concaten:[3,19,20,25,33,44],concept:[12,13,16,27,29,42,43,45,52,55,62],concern:[15,19,23,48,50,58],concert:53,concis:[9,17,19,23,32,35,47,50,52,58,60],conclud:[10,14,26,28,32,44,48,50,62],conclus:60,concret:[13,29,32,41,50],conda:[53,57,63],condens:9,condit:[0,8,12,13,15,16,20,22,28,32,50,55,58],condition:16,conduc:1,conduct:[5,13],confid:52,config:48,configur:[1,2,48,50,51,53],confirm:[0,44,52],conflict:[4,26,48,50],conform:1,conftest:[48,53],confus:[1,8,15],conjunct:[17,28,49,53],connect:[5,47],consecut:9,conserv:51,consid:[6,9,10,13,15,16,19,20,21,22,23,25,27,28,29,31,32,37,41,42,44,48,50,52,53,59,61,63,64],consider:[6,38,53,58],consist:[9,14,16,25,26,27,35,41,46,48,50,52],consol:[3,4,5,7,8,16,22,26,36,43,45,46,47,48,50,52,53],constant:[10,48,50,60],constitut:52,constraint:[22,36,50],construct:[8,10,11,15,16,17,23,25,27,28,33,44,47,48,49,53,58,62],constructor:[8,12,15],consult:[8,11,46,47,50],consum:[11,12,23,25,32],consumpt:[15,32],contact:62,contain:[0,1,2,3,4,5,8,9,10,11,12,14,15,16,17,18,22,24,25,26,27,28,30,31,32,33,34,35,37,38,40,41,45,47,48,49,50,52,53,58,62,63],content:[1,3,5,8,9,10,11,12,13,14,15,17,24,25,26,27,28,31,32,33,34,36,37,41,46,48,49,50,53,55,56,57,58,59,60,61,62,63,64],context:[2,3,13,14,17,24,28,30,31,37,41,45,46,49,52,53,63],context_manag:49,context_vari:49,continu:[22,26,27,58],continuum:48,contour:47,contract:[22,40],contrari:53,contrast:[24,37,40,44,50],contribut:[50,52,55,56],contributor:52,contriv:[18,52],control:[2,8,13,17,20,21,29,46,47,53,55,58],convei:[10,17,32,42,47,50],conveni:[1,3,8,9,10,15,27,32,37,44,46,47,48,49,52,53],convent:[40,44],convers:20,convert:[8,15,20,25,48,49,51],convinc:[22,28],convolut:[19,50],cook:[22,32],cool:12,coord:32,coordin:[11,12,32,35,38,47],copi:[22,23,26,27,28,31,32,41,46,48,52,55,56],core:[3,10,18,50,51,55,56,60],corner:[5,43],cornerston:[55,56,58],correct:[25,36,50,52,59],correctli:[9,22,36,50,52,53],correspond:[1,8,11,12,14,15,17,18,20,21,24,25,27,28,29,31,32,33,35,36,37,47],corrupt:[49,52],cos:[5,37,47],cosmic:52,cost:52,costli:5,could:[3,5,8,9,12,18,22,27,29,32,34,37,44,47,50,52,55,56],count:[3,8,10,11,12,14,16,17,18,21,25,35,36,41,45,50,52,53],count_even:14,count_valu:[],count_vowel:[14,50,52,53],counterpart:31,coupl:[8,20,52,53],cours:[1,2,3,4,5,6,14,16,26,27,49,52],courtnei:50,cout:1,cover:[8,12,14,17,37,49],cow:[12,14,17,18,24],cpython:[1,3,4,5,10,12,50],craft:63,creat:[0,1,2,3,4,8,9,12,17,18,20,22,23,25,26,27,28,29,31,32,34,35,37,38,39,40,42,43,44,45,48,49,50,52,55,56,57,58,60,62,63,64],creation:[11,32,33,40,41,43,49],creativ:25,creator:[48,50],credit:19,criterion:22,critic:[4,5,10,16,25,29,31,41,43,48,50,52,55,56,57,60,63,64],crop:51,cross:[4,46],crowd:50,crucial:6,crude:35,crust:49,cryptic:8,ctrl:[0,5,52],cube:[9,48],cue:[3,27,37,53],cumbersom:[52,53],cumsum:35,cumul:35,curat:[36,48],curi:11,curli:[8,10,12,16],current:[5,8,15,35,44,48,50,53,55,56],current_num:17,cursor:5,curv:[2,5,35,47],custom:[6,8,43,47,48,49,50,62],custom_dot_product:50,custom_inherit:50,customiz:2,cut:[5,64],cute:20,cwd:53,cycl:47,d3_arrai:27,d5_arrai:27,d_sinc:5,dabbl:57,dai:[4,63],danger:[9,55,56],dangl:32,dart:[55,61],dart_posit:35,dash:[35,47,50],data1:49,data2:49,data:[2,3,4,5,15,22,25,28,29,30,32,34,36,37,43,45,47,48,49,50,55,56,57,58,60,62,63,64],databas:[48,50],datafram:43,dataset:[27,47],datatyp:33,date:[1,8,50,53,55,56],datum:36,davi:50,david:[11,12,18,49,55,56],deactiv:4,dead:[4,9],deal:[3,8,10,12,19,28,36,37,48],dear:64,debat:21,debug:[2,5,22,50,52],debugg:2,decid:35,decim:[3,8,12,32],decis:[50,52,53],decod:49,decor:[44,51],dedic:[2,17,31,51],deduc:[35,52],deem:27,deep:[25,55,56],deepen:43,deeper:[15,47,48,52],deepli:[48,55,56],def:[5,6,7,10,12,16,19,20,21,22,23,24,26,31,32,36,38,39,40,41,42,43,44,45,46,48,50,51,52,53,58],defacto:44,defaultdict:[11,48],defin:[1,3,5,7,8,11,13,14,15,16,20,22,24,26,27,31,33,34,37,38,39,42,43,44,46,48,49,50,52,53,55,58,60,62],definit:[2,10,12,13,14,15,16,17,24,27,29,31,32,37,38,39,41,42,43,44,48,50,62],deg_to_rad:48,degre:[35,48,60],deleg:37,delet:[5,53],deliev:48,delimit:[8,9,13,14,46,49,50,58],deliv:48,deliveri:48,delv:[26,28,31,37],demand:[15,58],demarc:14,demo:3,demonin:45,demonstr:[7,8,9,11,12,13,18,19,22,24,25,26,28,29,31,32,33,37,40,41,44,46,47,48,49,50,52],denom:45,denot:[5,8,9,10,14,27,37,40,49,53],depend:[2,4,10,12,13,21,26,29,45,48,49,52,60],depict:[27,35],depth:53,deriv:5,describ:[1,11,20,30,37,41,42,43,48,50,52,53,55,58,64],descript:[8,10,11,14,22,28,29,48,50,51,52,53],deserv:17,design:[1,3,8,11,21,27,36,37,40,43,44,46,47,49,50,52,53,58,59,60,61],desir:[5,21,22,27,29,32,44,46,52],desktop:[48,49],despit:[22,48],destin:53,detail:[4,5,7,8,12,14,17,25,26,27,28,29,32,37,44,45,47,48,49,50,52,53,58],detect:[12,48],determin:[1,8,9,10,19,23,28,31,32,33,35,42,46,50],dev:[22,33,35,36],develop:[1,5,23,32,38,47,48,50,51,53,54,55,56,57,60],deviat:[21,35,37],devic:[8,55,56],devis:[22,52],diagnost:52,diagon:28,diagram:[25,27,32],dict1:[22,52,53],dict2:[22,52,53],dict:[11,12,17,22,41,44,52,53,62],dict_a0:53,dict_a1:53,dict_a2:53,dict_a3:53,dict_a:53,dict_b0:53,dict_b1:53,dict_b2:53,dict_b3:53,dict_b:53,dictat:[12,40,53],dictionari:[9,10,14,15,17,20,26,43,44,46,49,50,52,53,55,58,59],did:[3,8,10,13,19,20,22,35,38,44,51,57],didn:[29,35,44,51,52],diff:[32,53],differ:[2,3,5,6,8,9,10,11,12,14,15,16,20,22,23,24,25,29,31,32,34,43,44,45,47,48,50,53,55,58,59,60,62],difference_fanout:59,difference_upd:[38,46],differenti:[1,2,43],difficult:[28,50],digit:[8,20,32,37,55,56],dilig:[8,48,52],dimens:[28,29,30,31,33,34,35,37,55,60],dimension:[6,29,30,32,33,34,43,47,50,60],ding:55,dir:53,direct:[32,37,48,53],directli:[1,2,4,6,8,15,25,31,36,48,49,53],directori:[1,4,5,47,48,49,53],disabl:52,discard:8,discern:[12,30,50],discourag:23,discov:[40,53],discoveri:53,discret:47,discuss:[2,4,8,9,12,13,14,15,22,25,26,27,28,29,30,31,32,37,39,42,43,44,46,48,49,50,52,53,54,55,56,57,58,60,62],disk:49,dismai:8,dispatch:60,displai:[3,7,8,25,26,35,43,46,63],dispos:8,dissuad:52,dist:32,dist_from_origin:35,distanc:[35,50,53,60],distil:[47,52,55,56,58],distinct:[7,9,11,14,17,25,26,28,31,34,37,41,42,43,47,53],distinctli:7,distinguish:[2,7,11,34,43,44,49,58,62],distract:51,distribut:[3,4,11,33,37,47,48,57],distutil:48,div:37,dive:[4,15,25,46,48,52,60],divers:[47,50],divid:[8,32,33,35,36,37,46,50],divide_func:48,divis:[8,9,16,32,37,46],divorc:31,dlib:50,doc2:9,doc:[14,35,50],docstr:[14,22,40,50,52,63],document:[1,2,3,5,45,55,56,58,60,62,63,64],doe:[3,5,8,9,10,11,12,14,15,20,22,23,25,26,27,28,31,33,37,41,42,44,45,47,48,50,51,52,53,57,58],doesn:[5,11,12,17,22,25,32,44,45,52,55,56],dog:[3,11,14,18,24,25,36,40,50],doing:[1,3,4,5,6,8,33,34,47,48,52,54,57,58,60,63],domain:[5,28,33,36,47],don:[5,8,9,12,19,27,31,45,49,50,52,53,55,56],done:[5,29,37,40,48],doom:32,dos:50,dot:[8,32,37,40,47,48,53],dot_index:9,doubl:[3,8,10,41,46,50],down:[1,20,27,37,48,49,52,55,56,63,64],downgrad:48,download:[1,2,4,48,53],downsid:[11,12,23],downstream:22,dpi:47,draw:[33,43,47,62],drawn:[10,18],dream:32,drill:48,drive:52,driven:51,dropbox:50,dropdown:5,dtype:[28,30,33,34,37],duck:50,dude:3,due:[12,37,48],dummi:[40,41,44,48,53],dummy_email:53,dummy_inst:41,dump:49,dunder:[41,46],durat:53,dure:[1,15,35,48,50,52,53],dust:52,duti:52,dynam:47,dynload:48,e72fb36dc785:52,e7cf39509d06:12,each:[9,10,11,12,13,14,15,16,17,18,19,20,22,23,25,27,28,29,30,31,32,33,34,35,36,37,40,41,43,47,48,49,50,51,52,53,58,59,60,61],earli:[5,13],earlier:[8,12,15,19,27,35,41,50],eas:51,easi:[2,4,17,22,37,45,48,49,50,52,53,58],easier:[29,35,38,46,50,52],easiest:48,easili:[2,5,7,14,19,22,32,35,55,56],echo:46,econom:15,ed60a54ccf0b:15,edg:[14,20,21,27,51,52],edit:[2,5,48,50,53,55,56,57],editor:[1,2,5,48,50],educ:57,edward:12,effect:[4,5,8,11,12,16,22,29,32,35,37,40,47,48,50,51,52,53,58,60,64],effici:[3,6,10,11,12,15,16,17,18,23,31,32,37,50,58,60],effort:5,egg:46,eigenvalu:37,eight:[9,16,20,53],einstein:11,either:[8,9,11,13,14,22,27,29,32,37,38,40,44,45,49,50,52],electr:8,electron:47,eleg:[2,6,9,17,28,35,42,46,47,63],elegantli:8,element:[10,11,12,15,18,19,25,26,27,28,29,30,31,32,34,35,37,38,44,45,46,50,58],elementwis:[35,37],elif:[14,16,17,20,22,26,58],elimin:[36,53],elppa:25,els:[14,15,16,17,20,21,22,24,26,35,36,44,45,46,49,50,58],elsewher:[16,26],elucid:48,email:[53,58],emb:[5,47],embark:[16,57],embed:47,embellish:50,embodi:[40,48],embrac:47,emerg:5,emit:23,emmi:[41,49],emphas:[8,20,32,55,56,59,61],emphasi:[50,55,56],empow:[51,62],empti:[0,8,9,11,12,13,14,19,21,22,25,27,29,32,33,41,50,52,53],emul:[46,47],enabl:[2,4,5,19,43,46,47,48,49,50,53,58,60],encapsul:[14,16,24,31,39,41,43,45,50,52,58,62],enclos:13,encod:[36,49,55,59],encount:[4,8,11,13,15,17,24,25,27,41,43,44,49,50,52,53],encourag:[4,50],end:[1,3,4,5,8,9,10,11,13,14,15,16,17,18,19,25,26,28,29,32,34,35,37,40,49,50,52,53,55],endear:37,endeavor:58,endl:1,endors:2,endswith:8,enforc:50,engin:[1,8],english:[1,8,20,50],enhanc:[50,63,64],enjoi:35,enough:[5,8,29,51,52,55,56],enrol:11,ensur:[1,4,8,22,25,38,48,49,50,52,53],entail:[1,12,26,40,48],enter:[3,5,7,11,13,14,16,38,49],entertain:35,entir:[3,8,10,15,17,20,24,25,26,31,36,37,46,48,49,52,53],entireti:[10,37,59,61],entri:[3,8,10,11,14,17,25,26,27,28,29,31,32,33,34,37,38,41,47,48,50,52],enumer:[18,19,22,29,32,35,48],env:4,envelop:14,environ:[1,5,46,47,48,52,53,54,55,57],envis:32,eps:47,equal:[5,8,9,11,12,28,30,32,33,37,42,53],equat:[0,3,5,8,28,32,35,47],equip:58,equival:[8,9,11,13,14,15,19,20,21,22,23,25,27,28,31,32,33,37,41,42,44,46,50,52],eras:[5,49],err_low:47,err_upp:47,error:[1,2,5,8,9,12,13,14,19,21,25,26,27,36,44,45,47,49,50,51,52,53],error_messag:52,errorbar:47,esc:5,especi:[1,2,5,19,20,27,28,30,45,48,50,53],essenti:[1,5,11,12,13,15,17,18,28,37,42,43,47,48,53,55,56,57,59,61,62,63],establish:[32,62],estim:[8,55,61],etc:[2,4,22,25,31,35,37,40,50,52,55,56,62],euclidean:[32,50],euler:[11,41,48],evalu:[0,5,9,12,13,14,17,20,22,33,40,47,50,51,53],even:[5,6,7,8,9,10,12,13,14,15,16,17,19,20,24,28,32,34,38,40,41,44,48,49,50,52,53,55,56,64],even_gen:15,evenli:[5,8,33,47],event:[11,49],eventu:[49,50,51],ever:[3,5,9,13,14,15,17,32,52],everi:[4,5,13,15,16,22,25,31,35,37,41,49,50,51],everyth:5,everywher:[36,37],evid:52,evil:23,evolv:[35,52],exact:[8,15,28,32,41,50],exactli:[8,11,12,15,16,28,32,37,45,51],exagger:50,exam:[12,22,26,27,32],exam_1:22,exam_1_scor:18,exam_2:22,exam_2_scor:18,examin:45,exampl:[1,3,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,36,37,39,41,42,43,44,45,46,47,48,50,51,52,53,57,58,63],example_arrai:30,example_default_dict:11,example_dict:12,example_gen:15,example_scop:24,exce:[8,13,52],exceedingli:[14,50,53],excel:[2,3,5,11,46,50],except:[8,14,15,26,50,52],exception:1,excit:5,exclud:[14,15,25,33,46,48,53],exclus:[5,15,33,37],exe:[1,3,4],execut:[1,2,3,4,5,6,8,9,13,14,16,20,24,39,40,41,43,44,45,47,48,51,52,53,58],exemplifi:50,exercis:[20,51,52,53,58,59,61,63],exhaust:[8,11,15,28,37,45,46,55,56],exhibit:28,exist:[1,4,8,10,11,12,22,24,26,32,40,42,46,49,50,62],exit:[13,14,19,22],exorcis:52,exp:[8,31,37,47],expand:[9,16,43],expect:[1,4,7,10,14,15,35,37,40,44,45,47,48,49,50,52,53],expected_count:53,expected_merg:53,expected_merged0:53,expected_merged1:53,expected_merged2:53,expected_merged3:53,expedit:52,expel:20,expens:52,experi:[2,35,50],experienc:[55,56],experiment:8,explain:[5,8,25,44,48],explan:[10,46,49,59,61],explicit:[1,12,14,23,27,31,32,35,37,52],explicitli:[9,11,15,18,25,29,32,37,41,44,52],explor:[3,5,25,49,53],expon:8,exponenti:37,expos:[8,27,50],express:[0,8,10,12,13,14,19,20,22,23,31,36,37,40,46,48,50,52,55,58],expression_1:9,expression_2:9,expression_n:9,extend:[8,9,29,35,47,50,53,59],extens:[2,8,17,35,37,47,49,50,59],extent:[19,43,52],extern:44,extra:[19,32,59],extract:[9,11,15],extran:63,extraordinarili:49,extrapol:[20,27],extrem:[2,12,15,17,22,28,31,35,44,46,49,53,58],f8487d9d0863:[8,9],f89f8b6a7213:53,face:[44,48],face_detect:48,face_detector:48,facet:52,facial:48,facilit:[2,5,10,11,17,28,29,47,48,50,60],fact:[1,5,8,9,12,14,15,26,37,43,46,50,52,62],factor:[10,45,47,51],factori:[3,8,14,21],fail:[9,11,26,45,49,51,52,53],failur:[19,52,53],faithfulli:50,fall:[16,21,27,28,35,47],fallen:35,fals:[0,3,8,9,10,11,12,13,14,15,17,20,23,25,26,28,31,35,36,37,40,41,45,46,49,50,52,53],falsifi:51,familiar:[1,2,3,4,8,9,10,11,17,20,21,31,34,35,37,45,47,50,52,57,58],fanci:[14,20,52],fancier:15,fanout:[55,59],fantast:[6,8,49,57],far:[6,8,17,25,27,29,31,39,41,43,46,47,48,50,51,52,53,58],farmer:8,fashion:[22,27,37],fast:[6,12,18,37],faster:[4,6,10,36,37,48,52],favor:8,featur:[1,2,3,5,11,15,16,17,33,34,43,47,48,50,53,54,55,56,60,63],fed:[3,11,12,15,22,37,47],federici:[55,56],feed:[11,14,15,33,36,37,41,51,52,53],feedback:[55,56],feel:[5,15,25,35,46,57,58],fell:[12,17,35,52],fermi:[11,41],few:[3,8,10,14,15,16,18,38,45,46,50,51,62],fewer:[19,31,52],feynman:11,fidel:50,field:[8,48],fig:[5,35,47],figsiz:47,figur:63,file12345:49,file1:49,file2:49,file3:49,file4:49,file:[1,2,4,5,9,24,26,45,47,48,52,53,55,63],file_cont:53,file_var:24,filefilefil:49,filenam:[2,9,47],fill:[29,31,32,33,37,47,53],fill_between:[35,47],filter:[9,11,15,21,23],filtered_str:23,find:[1,4,5,8,9,10,11,13,15,18,19,22,25,29,31,32,35,36,46,48,49,50,52,53,62,64],find_alpha:50,find_packag:[48,53],fine:[8,33],finish:[41,53],finit:[8,15,25],first:[1,2,3,4,5,8,9,11,12,13,14,15,16,17,19,20,22,23,25,27,29,31,32,35,36,37,41,43,44,45,46,48,49,50,53,54,60,62,63,64],first_item:9,fit:[49,52],five:[8,20,25,33,36,50],fix:[50,52,54],fixtur:51,flag:[48,50],flake8:50,flaw:22,fledgl:53,flesh:48,flexibl:[6,12,14,16,26,28,31,40,47,48,50],flip:[22,27],float16:33,float32:33,float64:30,float_kei:12,floor:8,flour:46,flow:[5,13,17,20,21,55,56,58],fly:50,focu:50,focus:47,folder:[1,5],folli:12,follow:[0,1,3,4,5,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,36,37,39,40,41,44,45,46,47,48,49,50,51,52,53,55,56],food:[12,46],foot:53,footprint:32,for_block:24,forai:43,forc:49,forego:3,foregon:18,foremost:[1,2,48,50],forese:14,forev:0,forg:53,forget:[49,53],forgiv:16,forgo:52,form:[3,8,9,11,15,17,18,20,23,25,26,28,31,32,33,37,41,44,46,48,49,50,52,53,62],formal:[5,8,9,10,13,16,27,28,32,36,40,50,51,52,54,58],format:[1,2,3,5,14,20,26,40,42,43,45,46,47,49,50,53,55,57],formatt:[50,53],former:[3,9,46,59,61],formul:32,formula:[0,35,48,50],forth:4,fortran:29,fortun:[6,15,19,32,49,50,53,55,56],forward:[13,28,32,43,63],found:[5,8,9,11,22,27,33,46,47,49,50,51,53],foundat:[1,53,55,56,60],four:[11,16,20,27,33,36,37,40,50,53],fourth:53,frac:[5,8,14,15,30,32,35,45],frac_correct:36,fraction:[8,21,35,36,47],framework:[48,55,64],free:[1,2,15,17,22,32,42,48,50,53,55,56],freeli:[4,31],frequent:[3,8,10,15,50],fresh:57,friend:35,friendli:[44,49],from:[1,2,3,5,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,35,36,37,38,40,41,43,44,45,46,47,48,49,50,51,52,53,55,56,58,60,62,63],fromkei:44,front:20,frozen:[11,12,26],frozenset:[11,12],fruit:12,fruit_or_veggi:12,frustrat:[52,53],fulfil:48,full:[3,9,15,27,29,32,37,46,47,48,50,53],fuller:62,fulli:[2,35,43,62],fun:[19,35,55,56],func:[14,24,44,50],func_a:50,func_b:50,func_block:24,func_c:50,func_d:50,func_nam:50,func_var:24,fundament:[6,8,31,50,60],funni:27,further:[4,6,9,22,27,43,53,62],furthermor:[5,8,9,10,14,17,25,28,29,31,32,35,41,47,50,52,53,55,56,64],fyi:27,gain:52,game:[9,37],gather:38,gaug:50,gauss:11,gaussian:[33,47],gcd:45,gen:15,gen_1:[15,18],gen_2:[15,18],gener:[3,5,8,9,11,12,13,14,17,18,19,20,21,23,25,26,27,29,32,33,35,36,37,42,43,46,47,48,49,50,51,52,53,55,57,58,59,60,62,63,64],genesi:[55,56],genexpr:15,genuin:52,get:[1,2,4,5,6,8,10,11,12,14,19,25,27,28,31,32,36,37,40,41,44,46,48,49,50,52,53,55,56],get_area:[42,45],get_first_and_last:50,get_max:12,get_zip:48,getattr:40,getcwd:53,getitem:46,getsitepackag:48,gfedcba:25,gheliabci:17,git:2,github:53,give:[0,4,6,16,24,25,27,35,36,41,45,46,48,52,53,60,63],given:[0,1,5,7,8,9,10,11,13,14,15,16,17,18,19,21,22,23,25,27,28,29,31,32,35,36,37,41,42,43,44,47,49,50,51,52,53,58],glad:58,glanc:[17,19,29,32,44,47],glare:32,glimps:3,glob:63,global:22,goal:[43,47],goe:[8,26,50],going:[3,41,45,48],good:[2,5,9,16,17,20,22,25,34,48,49,51,52,54,55,56,59,61,63],good_f:14,goodby:15,googl:[5,46,63],goos:[32,36],goosei:40,got:[55,56],gracefulli:38,grade:[11,12,17,26,27,32,49,50,58],grade_book:50,grade_lookup:50,gradebook:[11,27,50],graduat:[48,55,56],grai:47,grammar:[1,50,54],grammat:1,grape:[12,22,38,40,46],graph:[15,47],graphic:47,grasp:[25,41],grayscal:47,great:[3,5,8,11,12,14,15,17,25,37,50,51,52,55,56],greater:[0,8,9,15,22,28],greatest:[22,45],greatli:[17,36,43,44,46,50,58,63,64],green:[5,32,37,47,52,53],greet:64,grid:[5,32,33,35,37,47],grigg:[55,56],groceri:12,grocery_list:50,gross:[8,16],gross_merge_max_map:22,ground:52,group:[8,49,50],grow:[5,15,50,53,58],grumpi:1,guarante:[1,8,9,12,20,35,52],guess:[22,28,37],gui:14,guid:[47,55,56,57,63],guidelin:[50,63],gush:5,had:[5,8,12,19,20,21,24,32,35,37,48,52,55,56,60],half:47,hand:[5,8,12,15,29,50,51,52],handi:[25,49],handl:[4,5,9,14,20,21,29,38,46,49,50,51,52],hang:[37,50],haphazardli:[31,53],happen:[0,5,8,9,13,15,17,24,27,44,45,57],happi:[14,48,52,53],happili:50,hard:[8,16,18,20,22,31,50,55,56,60],hardboiled800:[55,56],harmon:15,has:[1,2,4,5,8,9,11,12,13,14,15,16,18,22,23,24,25,27,29,30,31,32,33,34,35,36,37,39,40,41,44,45,46,47,48,49,50,51,52,53,55,56,57,58,60],hasattr:[40,46],hash:[11,12],hashabl:[12,44,50],haskel:5,hasn:12,hat:[3,8,11,25],hatter:64,have:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,24,25,26,27,28,29,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,55,56,58,59,60,61,62],haven:52,header:[5,50],health:[9,52],healthi:52,hear:0,heart:64,heavi:[2,22,52],heaviest:51,heavili:[1,43],heed:8,height:[42,43,45,47],heisenberg:11,held:52,hello:[1,3,8,13,14,15,17,20,25,40,41,43,46,50,53],hello_world:9,help:[1,2,5,8,9,13,14,15,17,19,22,25,26,32,35,38,41,48,49,50,52,53,55,56,60],helper:20,henc:45,her:[9,11,41],here:[1,2,5,6,7,8,10,11,12,13,17,18,20,21,22,23,24,26,27,28,29,31,32,35,36,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,55,56,58,59,61,63],herein:44,hesit:51,heterogen:[10,12],high:[5,6,27,33,36,37,46,47,50],higher:[8,27,29,32,47,50],highest:[10,36],highli:[2,4,8,9,12,17,37,47,49,52,60],highlight:[2,3,50,52],hijack:53,hill:49,him:18,hint:[3,8,25,54,63],his:[9,41],hist:47,histogram:[47,63],histor:43,historgram:47,histori:35,hit:[0,3,5,35,44,49,50,52],hline:35,hold:[3,8,11,13,14,50,51,52,58],hole:64,home:[4,48],homogen:[30,37],hood:[10,17,19,38,41,44,45,46,48,49,58],hope:58,hopefulli:[10,16,35,55,56],hopper:11,horizont:[32,33,35,37,50],horrai:36,host:48,hour:6,hous:[48,50,53],how:[1,3,4,5,8,10,12,14,15,16,21,22,25,26,27,32,35,37,41,43,44,46,47,48,49,50,51,52,53,55,56,58,60,63,64],howev:[6,8,9,10,12,14,15,17,20,22,25,27,31,33,36,37,38,40,43,45,48,49,51,52,53],hstack:33,html:50,http:50,huge:[1,2,5,6,31,50,55,56],human:[1,50],hundr:[6,15,35,55,56],hyperbol:37,hypothesi:[53,55,64],hypothet:[35,36],idea:[2,52],ideal:[12,27,47],ident:[5,8,9,26,47,48,53,62],identifi:[13,22,25,27,41,50,53],idiomat:50,if_block:24,ignor:[11,23,32,38],iii:[32,55,58],ill:25,illog:52,illustr:28,ilovepython:23,imag:[5,8,32,36,37,49,50,53,60,63],imagin:35,imaginari:8,imbal:22,immedi:[3,8,11,13,14,17,18,19,20,22,27,32,33,42,48,50,51],immut:[8,10,11,12,25,58],imort:48,impact:[12,22,32,50,60],implement:[1,10,12,16,17,22,25,32,37,38,43,44,45,46,49,50,51,53,60],impolit:3,importantli:52,impos:27,imposs:[14,25],imprecis:8,improv:[1,17,35,43,46,50,53,54,55,56,58,63],imread:47,imsav:47,imshow:47,in_arg1:24,in_arg2:24,in_circl:35,in_str:[14,50],inaccess:[2,46],inadmiss:32,inadvert:22,inch:47,incis:[52,53,64],includ:[1,3,4,7,8,9,11,12,13,14,15,16,17,22,25,26,27,33,35,37,38,40,41,42,43,47,48,49,50,52,53,54,57,58,59,60,61,63,64],include_i:[14,50,52,53],inclus:[11,15,33,50,52],incompat:[8,12,32,52],inconsequenti:17,inconsist:[16,50],incorrect:16,increas:[8,10,16,29,52],increasingli:[50,52,63],incred:[6,27,37,45],increment:[3,8,17],ind0:28,ind1:28,ind2:28,ind3:28,ind4:28,ind:28,ind_0:28,ind_1:28,ind_2:28,inde:[5,31,44,50,51,52],indel:60,indent:[9,13,14,16,40,49,53],indentationerror:16,independ:[4,5,9,15,17,22,28,33,35,36,41,53,63],index:[3,8,9,10,11,12,15,17,19,20,21,29,32,34,35,36,37,43,46,48,50,55,60],index_2d:28,indexerror:[9,25,27],indic:[0,3,7,8,11,14,15,19,28,30,31,32,37,44,47,48,49,50,52,53],individu:[3,8,11,25,27,31,34,35,37,41,43,46,48,49,53],ineffici:32,inequ:[8,22,52],inevit:[8,31],infer:[2,50],influenc:[55,56],info:8,inform:[1,8,10,14,26,31,37,43,44,47,48,50,52,53,55,57,64],inher:[12,29],inherit:[43,50,55,62],init:[35,39,41,45],initi:[4,11,15,17,19,22,26,27,32,33,39,41,44,45,48,50,51,58],inject:8,inlin:[15,20,21,22,47,58],inner:[19,33,52],innermost:19,input:[3,5,7,8,9,10,12,14,15,17,19,20,23,24,26,27,29,31,37,38,40,44,46,47,50,51,52,53],input_str:[23,40,53],insert:[8,27,29,31,53],insid:[12,16,24,45,49],insidi:[22,52],insight:[28,48,60,63],insofar:52,inspect:[2,5,8,15,25,30,35,40,43,46,49,50,63],inst:44,instal:[2,3,5,6,50,53,55,56,57,63],install_requir:53,instanc:[0,1,2,4,5,7,8,9,10,11,12,15,17,18,20,25,26,27,28,29,31,32,37,38,39,40,42,43,46,47,48,49,50,52,53,55,62],instanti:[39,41],instead:[2,3,4,5,8,9,10,11,15,19,25,27,29,33,34,35,36,37,38,42,44,47,48,49,50,51],instruct:[1,4,5,15,16,25,28,31,32,33,36,37,41,47,48,49,50,53],instrument:[6,53],instuct:1,int32:[30,33,34],int64:28,int_to_str:20,integ:[1,3,7,9,10,12,13,14,15,18,20,22,25,26,29,30,33,36,37,40,41,45,46,47,50,51,52,53,60],integer_flag:50,integr:[1,45,50,57],intellisens:2,intend:[31,50,52],intens:[47,50],intention:52,inter:[17,48],interact:[4,41,43,44,46,47,48,53,62],interchang:[8,27,50],interest:[6,15,32,43,52,55,56,63],interfac:[2,3,5,8,10,25,27,28,34,47,49,58,60,62],interim:52,intermedi:[19,31,32],intermediari:29,intern:[50,52],internet:5,interpet:1,interpret:[3,4,5,8,10,17,24,28,32,33,35,47,48,50,52,57],interrupt:[0,13],intersect:[10,11],interv:[10,16,33,35],intra:63,intro:43,introduc:[9,10,11,13,17,20,32,33,37,40,43,45,47,49,50,52,53,54,55,57,58,60,62,63,64],introduct:[2,16,34,41,42,48,55,57,58,62,64],introductori:[1,53],introspect:53,intuit:[1,8,15,17,23,27,28,29,32,37,38,52,57,60],invalid:[11,14,26],invalu:60,inventori:58,invers:[29,37,47,49],invert:[12,37],inverted_x:12,investig:26,invok:[4,11,14,15,28,31,32,37,39,41,44,45,46,47,49,58],involv:[8,10,12,15,17,29,31,49,58],iostream:1,ipynb:[5,49,53],ipython:[0,2,3,4,5,7,8,9,12,15,22,26,27,36,47,48,52,53],iron:53,irrat:[35,48],irrespect:[28,42,48],is_bound:14,is_equ:23,is_in:10,is_in_circl:35,is_in_slow:10,is_palindrom:23,isalnum:23,isalpha:11,isclos:[8,28],isdigit:8,isinst:[8,9,20,25,34,38,39,41,42,45,46,50,52],islow:15,isn:[1,5,6,8,11,14,24,25,50,51,52,53],isort:50,issu:[4,6,8,32,44,51,55,56,63],issubclass:[42,43],isupp:9,it_var:24,item1:[8,11],item2:[8,10,11],item3:8,item:[3,7,8,9,10,11,12,13,14,15,17,18,20,21,25,26,27,28,29,31,37,38,41,46,47,50,52,53],item_to_transcript:20,item_to_transcript_alt:20,itemn:8,items:30,items_to_pric:12,iter:[8,10,11,12,13,14,16,18,19,20,22,23,25,31,32,37,38,40,41,44,46,49,50,55,58,60,62],iter_3:18,iter_4:18,iter_cnt:17,itertool:[17,24,36,41,55,58],ith:10,its:[1,3,4,5,8,9,10,11,12,13,14,15,17,19,20,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,52,53,55,56,58,59,60,61,63],itself:[8,12,14,19,29,39,43,44,48,50,52,53],jack:8,jackenzi:8,jan:50,jane:8,jargon:8,java:[1,16],javascript:47,job:[10,20],join:[3,8,15,20,23,25,46,47,55,56,60],journei:52,jpg:47,judici:[9,19,27],julia:[5,60],jupyt:[0,2,4,7,13,16,22,36,46,48,49,51,52,53,54,55,57,63],just:[5,8,9,10,11,12,15,18,19,20,22,25,32,35,37,38,43,44,45,48,49,50,52,53,55,56,57],jython:1,kamasi:41,keen:[4,22,32,36,50,52,53,60],keep:[2,8,11,12,15,17,19,20,22,27,31,32,35,38,45,46,50,52,54],kei:[3,10,11,14,22,37,44,46,47,52,53,58,62],kept:[55,56],kernel:[0,5,13,48],key1:12,key2:12,key3:12,keyboard:[5,46],keyerror:[11,12,22],keyword:[31,33,36,47,49],kid:8,kill:5,kind:15,king:50,kit:[55,56],knack:51,knew:[],know:[1,4,5,10,13,14,15,17,19,25,28,33,35,36,37,40,41,43,44,45,48,50,51,52,53,55,56],knowledg:[19,38,48],known:[1,3,8,12,15,17,19,24,25,29,31,36,37,40,43,46,48,49,50,52,53,60],kwarg:[14,50],l_2:32,lab:[54,57],label:[5,27,35,36,47],labmat:[5,55,56],labor:50,lack:[25,55,56],ladi:49,laid:[5,29,37,47,52],lame:8,land:[4,35,51],landscap:60,languag:[2,3,4,6,8,10,14,16,24,25,26,29,37,43,50,52,55,56,57,58,60,62,63],laptop:2,larg:[1,2,5,6,8,15,20,21,32,43,47,48,50,51,52,53],large_int:8,large_num:8,larger:[8,10,22,32,48,51],largest:[12,17,22,27,32,36,52],lassi:50,last:[0,3,8,9,12,13,15,23,25,26,27,28,29,31,32,35,40,45,48,50,52,53],lastli:[7,8,12,31,37,38,43,47,48,49,50,57],late:49,later:[0,1,3,5,8,14,27,32,37,48,49,52,53],latest:[1,4,27,55,56],latex:[5,47],latter:[3,9,20,50,52],laundri:33,layout:[27,28,32,37,43,47,48],ldot:32,lead:[8,16,17,31,32,33,37,43,48,50,52,53,63],lean:[55,56],learn:[0,1,3,6,8,9,10,14,15,29,32,38,41,43,46,47,48,49,50,51,52,53,55,56,57,58,60,63],learning_python:[48,53],least:[8,13,25,27,28,31,50,52,55,56],leav:[8,9,14,19,22,31,32,40,41,49,53],left:[9,14,17,23,26,28,29,32,37,45,47,53],legend:[5,35,47],legibl:50,leisur:27,len:[0,3,8,9,10,12,14,15,18,19,21,22,23,25,36,46,50,51,52,53],length:[3,8,10,15,18,25,27,30,32,33,37,42,46,50,51,53],leq:37,less:[1,8,9,12,22,25,27,36,37,40,47,52],lesson:[8,17,22,53],let:[3,4,5,8,10,12,13,15,16,20,22,24,27,29,32,33,34,35,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53],letter:[8,11,13,15,17,25,40,49,52,53],level:[4,10,16,37,39,46,47,48,50,62],leverag:[4,8,9,35,36,37,41,42,43,46,47,48,49,50,51,53,60,63],lew:[55,56],lexicon:43,lib:[4,48],liber:[24,50],librari:[1,3,4,5,8,27,33,34,37,43,47,48,49,50,51,53,55,56,57,60,63,64],lie:52,lies:[9,44,55,56],lieu:[38,48,49],life:52,lifetim:50,lift:52,light:[8,32,37,42,44],lightweight:[2,50],like:[1,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,22,23,24,26,27,29,31,32,33,34,35,36,37,40,41,43,44,45,47,48,49,50,51,52,53,57,58,59,61,62,63],likewis:[9,43],limit:[6,8,12,19,37,45,48,49],limitless:[19,53],linalg:35,line:[3,5,7,8,9,14,15,16,20,32,35,36,45,47,49,50,52,53,63],linear:[10,47,60],linearli:[10,15,16,47],linestyl:[35,47],link:[35,58,59,60,61,62,63,64],linspac:[5,47,60],lint:50,linter:50,linux:[1,3,4,49],list1:26,list2:26,list:[4,5,9,11,12,13,14,17,18,20,21,22,23,24,25,26,27,28,29,31,33,34,35,37,40,41,43,44,45,46,47,48,49,52,53,54,57,58,59,62],list_famous_dog:50,list_of_ag:50,list_of_dummi:41,list_of_nam:50,list_of_peopl:41,list_of_stud:50,list_of_temperatur:50,list_purchased_item:38,list_unpurchased_item:38,listofstud:50,litani:52,liter:[8,54],littl:[45,49,52,53],live:[4,23,47,50],load:[47,63],load_databas:48,load_ext:48,loc:47,local:[5,48,50,53],locat:[4,25,31,43,47,48,49,53],log10:[8,37],log2:37,log:[8,17,26,31,33,35,37,47],log_:37,logarithm:[8,37,47],logic:[12,16,20,22,26,28,35,36,38,44,52,58,60],logical_and:28,logical_or:28,long_variable_nam:50,longer:[13,15,22,31,48,50,52,53],longev:50,look:[1,2,3,5,8,9,12,14,16,20,25,27,30,31,32,36,37,41,43,44,45,47,48,49,50,51,52,53,57],lookup:[11,12],loop:[0,7,12,14,15,16,17,20,21,22,23,34,35,36,37,40,41,50,55,58,59],loosei:40,lost:[8,27,52],lot:[14,52,53,55,56],love:[23,55,56],low:[36,37],lower:[8,10,11,12,14,15,23,32,35,40,47,52],lowercas:[3,8,11,15,49,50,52,53],luckili:49,luxuri:8,mac:[1,3,4],machin:[1,3,4,5,6,8,10,43,48,49,50,53,55,56,60,63],machineri:15,maco:49,mad:[9,64],made:[1,8,18,20,22,31,32,35,45,48,50,55,56],magic:[6,22,47,48],magnitud:[47,51],mai:[1,2,7,8,9,10,14,15,17,19,20,22,23,26,27,28,29,31,32,37,40,44,45,46,49,50,51,52,53],mail:48,main:[1,38],maintain:[1,4,12,48,50,53],major:[4,5,6,8,16,18,25,28,32,33,34,36,37,49,50,53,55,56,60],make:[2,3,4,5,6,8,9,11,12,14,15,16,17,19,20,22,23,25,27,28,29,31,32,34,35,36,37,38,41,43,44,45,46,47,48,49,50,52,53,55,56,58,59,61],manag:[4,5,12,19,44,49,50,52,53,63],mangl:23,mani:[1,2,3,4,5,6,8,10,11,14,15,16,18,19,25,27,29,31,33,35,37,47,48,49,50,51,53,55,56,58,60,63],manifest:[3,29,58],manifestli:[8,27],manipul:[3,41,43,47,58,60,62],manner:50,manual:[4,15,17,22,49,51,52,53],manufactur:21,map:[1,10,11,14,20,22,37,44,50,52],march:50,margin:[55,59],mari:49,mark:[1,3,5,8,38,46,47,50,51,52,53,60],mark_purchased_item:[38,46],marker:47,mascharka:[55,56],mask:52,mass:32,massiv:[5,32,37,47,49,52],master:41,match:[14,22,27,28,32,36,37,47,49,50,53],materi:[12,15,31,37,48,50,52,53,55,56,59,61,63],math:[3,5,14,37,48],mathcal:[10,11,12],mathemat:[3,5,6,8,9,10,31,32,33,34,50,60,62],matlab:[37,60],matmul:32,matplotib:47,matplotlib:[4,5,35,52,55,57,60,63],matric:[37,47],matrix:[6,15,32,37,47],matter:[3,5,8,12,14,20,25,27,29,32,44,51,52,58],matur:[5,43,50,63],max:[12,14,17,22,32,36,37],max_kei:12,max_key_optim:12,max_num:50,max_or_min:14,max_red_quad:37,max_val:[12,32],max_valu:51,maximum:[12,22,37],mean:[2,3,4,5,8,9,10,12,13,14,15,17,19,22,23,24,25,26,27,31,32,33,34,35,36,37,39,42,43,45,46,48,49,50,52,53,57,58,59,60,61,62,63],mean_exam_scor:32,mean_i:32,mean_imag:37,mean_in_circl:35,mean_x:32,meaning:24,meaningfulli:10,meant:[7,8,9,13,14,15,20,25,26,44,46,50,52,59,61],measur:[8,55,61],meaur:47,mechan:[8,11,19,25,26,31,32,41,50,51,53,60,62],median:[37,50],melon:46,member:[8,10,11,13,14,15,17,19,25,48,50],membership:[9,10,11,12,15,25,46,50,58],memor:[10,37],memori:[1,8,12,14,15,17,18,23,25,26,30,31,32,41,44,50,58],mention:48,menu:[3,5],mere:[3,7,10,20,22,32,40,41,43,47,48,50,51],merg:[20,46,50,52,55,59],merge_max_map:[22,52,53],mess:[48,57],messag:[44,45,52,53],messi:9,met:[16,20,28,58],method:[0,8,10,15,17,20,28,29,30,31,32,33,34,38,39,40,42,43,45,47,48,49,50,55,62],methodolog:[29,52,64],metric:21,microsecond:37,microsoft:[1,2,48,50],middl:[3,11,47],might:[3,17,22,27,32,45,48,50,52,53],milk:[12,38,46],mill:1,million:53,min:[14,17,19,37],min_blu:37,min_valu:51,mind:[8,11,19,22,26,31,32,35,50,52],mine:[59,61],miniconda3:48,minimalist:47,minimum:[37,48],minor:[44,59],minut:4,mirror:[10,12,15],mis:[46,49],misapprehens:50,misbehav:52,misdirect:52,mislead:15,miss:[11,14,32,55,56],misspel:2,mistak:[1,2,22,31,50,55,56],mistakenli:[14,38,50],mix:[3,7,14,25,37],mkdir:49,mkl:[6,37,48],mobil:[55,56],mock:53,mod:[8,37],mode:[5,14,26,48,50,52,53],model:[24,32,48,55,61],moder:2,modern:[16,43,47,57,62],modif:49,modifi:[2,8,41,44,48,49,50],modul:[2,3,4,9,12,14,15,16,17,18,26,27,34,37,41,42,43,45,49,51,52,53,54,55],modular:[16,58],module5_oddsandend:[48,49],module6_test:53,module_nam:48,modulo:[8,37],moment:[1,4,16,38,52],momentarili:41,monitor:[32,37],montalcini:11,month:[5,52,53],moo:[3,8,10,11,12,14,18,25,44,53],moon:53,more:[1,2,3,4,5,6,8,9,10,11,13,14,15,16,17,20,21,22,23,25,27,28,29,31,32,33,35,36,37,38,39,40,41,43,46,47,48,49,50,51,52,53,55,56,57,58,60,62,63],moreov:[36,55,56],most:[1,5,8,9,11,12,15,16,17,24,26,27,32,45,46,47,48,49,50,52,53,57,60],most_common:11,motiv:[4,10,49,52,64],move:[13,19,32,41,43,63],moveabl:5,movi:8,much:[0,1,2,3,5,8,12,16,22,32,33,35,36,45,46,49,51,52,53,55,56,58,62],muli:9,multi:[8,27,33,34,49,50,53],multidimension:[27,29,30,33,37],multipl:[3,5,8,12,18,19,20,25,31,32,34,37,38,43,46,47,48,49,52,53,55,58,60],multipli:[32,34,35,37,46],must:[3,8,9,10,11,12,13,14,15,16,22,23,25,26,27,28,29,31,32,36,37,41,44,48,49,50,51,52,53],mutabl:[8,10,11,12,22,25,58],mutat:[10,11,22,25,26,52],mxnet:43,my_arch:49,my_archive_fil:49,my_arrai:49,my_cod:[1,52],my_cub:48,my_dequ:11,my_dict:12,my_dir:48,my_fil:[9,49],my_fold:49,my_func:[7,16,24],my_imag:47,my_list:[3,9,10,14,17,24,38],my_loaded_grad:49,my_modul:48,my_open_fil:49,my_script:1,my_squar:[42,45],my_text:1,mygrad:[43,54,60],mygui:40,mylist:46,mypi:[50,54],n_circl:35,n_total:35,naiv:44,name1:53,name2:53,name:[2,3,4,5,8,9,12,17,18,22,24,25,27,37,38,40,41,44,45,46,48,49,53,58,62],name_to_scor:12,namedtupl:11,nameerror:[8,13,24],namen:53,namespac:[5,24,52,53],nano:1,nanosecond:10,napolean:50,narrow:50,nativ:[2,4,5,37,47,50],natur:[3,8,19,25,27,32,37,49,52,63],navig:[4,5,48,50,53],ncircl:35,ncol:47,ndarrai:[25,28,30,31,32,33,34,36,50,62],ndenumer:29,ndim:[30,43],nearest:25,nearli:[5,13,25,37,47,51,58],necessari:[9,10,16,17,28,32,48,49,50,52],necessarili:[12,15,32,47],necromanc:4,need:[1,2,4,5,8,10,14,15,17,18,19,20,22,27,29,32,34,35,36,41,42,44,47,48,49,50,52,53,55,56,58],neg:[0,3,8,9,20,23,25,28,31,37,51,52,53],neg_index:25,negat:[8,9,50],neighbor:19,neither:14,nest:[9,10,19,32,33,48],nestl:9,network:43,neural:43,never:[0,5,8,9,10,11,13,14,22,29,37,50,52],new_dict:44,new_fold:49,new_kei:12,new_list:46,new_subarrai:31,new_valu:[12,44],newaxi:[28,60],newcom:2,newfound:[3,9,58],newlin:8,next:[3,5,8,12,13,19,23,29,31,33,36,38,41,42,43,44,46,48,49,50,52,57,58,60,62,63,64],ngrid:47,nice:[2,3,5,8,10,11,12,14,20,25,31,35,47,48,50],nicer:2,niceti:[17,58],nick:12,niel:41,nimbl:[4,5],nine:20,njit:6,nlog:10,noether:[11,41],noisi:35,non:[6,8,11,15,17,19,23,27,32,37,45,48,50,51,52,53,58],none:[9,10,11,14,17,20,22,24,25,31,32,41,44,46,48,52,58],none_indic:17,nonetheless:[53,63],nonetyp:8,nonsens:46,nontrivi:28,nonzero:[9,13],nor:[9,11,14,22,24,47],norm:35,normal:[11,12,23,32,33,37],normed_imag:32,nose2:53,nose:53,notat:[10,28,31,37],note:[0,1,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,27,29,31,32,35,37,41,44,45,46,47,48,49,50,51,52,53,62],notebook:[0,2,4,7,13,16,22,35,36,46,48,49,52,53,54,55,57,63],notepad:1,noth:[1,2,8,15,24,44,49],notic:[5,20,23,37,38,45,50],notifi:8,notimpl:45,novic:31,now:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,17,19,22,25,26,27,30,31,32,35,37,41,42,45,46,47,48,49,51,52,53,54,55,56,58],npy:49,npz:49,nrow:47,nthi:49,nuanc:[10,27,31,44,58],nucleu:64,num:[9,13,14,16,17,45],num_correct:36,num_health:9,num_in_circl:35,num_loop:13,num_thrown:35,num_vowel:14,numba_result:6,number:[0,1,2,4,5,6,9,10,11,12,13,15,16,17,19,25,26,27,28,29,30,31,32,33,34,35,36,37,41,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60],number_of_arg:14,numer:[1,5,9,14,26,27,32,34,35,37,43,46,55,56,60],numpi:[1,4,5,9,25,26,27,28,29,30,32,34,35,36,43,47,48,53,55,56,57,61,62,63],numpy_funct:53,numpy_result:6,numpydoc:50,nwai:49,nwhat:3,obei:[1,8],obj1:12,obj2:12,obj:[10,11,12,25,40],object:[3,10,11,12,13,15,17,19,20,22,25,28,30,33,34,37,39,42,44,48,50,52,53,55,58,60,63],obscur:[8,19,33,50],observ:[37,45,52],obtain:[6,20,46],obviou:[8,44,46,52,53],obvious:49,occas:[49,52,53],occur:[3,4,8,25,44,45,47],occurr:[10,25,28],odd:[8,13,15,16,49,55],odd_numb:50,off:[3,5,11,13,32,42,50,52,58],office_suppli:46,offici:[1,58,60,62,63,64],offload:6,offset:32,often:[2,8,16,27,32,33,41,45,51,52,53,64],ok_func:14,okai:[5,9,16,32,51],old:[5,8,52],old_dir:53,omit:[14,25,53],onc:[1,3,4,5,8,9,12,13,14,15,17,22,24,25,26,28,32,35,38,39,40,41,47,49,50,51,52,53],one:[0,1,2,3,5,6,8,9,11,12,14,15,16,17,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,38,41,42,43,44,46,47,48,49,50,51,52,53,55,56,60,62,63],ones:[8,60],onion:12,onli:[2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,24,25,27,28,29,30,31,32,33,36,37,38,41,42,43,44,46,47,48,49,50,51,52,53,58,63],onlin:47,onto:1,oop:45,opaqu:[47,50],open:[1,2,3,4,5,8,26,47,48,50,53,63,64],opencv:60,opened_fil:[26,49],oper:[1,4,5,6,10,12,15,19,21,22,26,27,29,32,34,35,36,41,43,44,49,50,55,58,60,62],operand:[32,37,45],opportun:[35,52,58],oppos:63,opt_merge_max_map:22,optim:[1,4,6,10,11,12,14,23,36,48,52,53,55,59,60],option:[4,5,8,14,15,29,31,43,44,48,52,53],orang:[3,18,47],orchestr:20,order:[5,8,9,10,11,14,15,16,17,18,22,23,25,26,27,28,31,32,35,36,37,38,48,50,51,52,53,54,55,56,60],ordereddict:12,org:[1,48],organ:[3,35,48,50,52],orient:[5,8,17,41,42,47,55,63],origin:[8,17,21,22,26,27,29,31,35,52,53],other:[0,1,2,3,4,6,8,10,11,12,14,15,16,17,19,20,22,24,25,26,28,29,31,33,36,37,38,40,41,42,43,44,45,46,47,48,49,50,52,53,55,56,58,60],otherwis:[8,9,11,13,19,32,33,35,46,50,51,60],ought:[9,12,37,38,42,45,52],ould:3,our:[1,2,3,5,8,9,10,11,12,14,15,17,19,20,22,23,24,25,26,27,28,30,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,51,54,55,56,57,58,62,63],ourselv:[3,34,44,48,52,58,62],out0:49,out1:49,out2:49,out:[0,1,2,3,5,8,9,11,12,13,15,17,20,21,23,26,27,28,29,32,35,36,37,38,44,46,47,48,49,50,51,53,55,56,60,64],outcom:[8,37,50],outdat:53,outer:[19,25],outermost:19,output:[0,3,5,7,14,15,19,22,27,28,29,37,47,49,52,53],outright:[12,13,15,48,51],outset:52,outsid:[13,16,19,21,24,35,40,48],over:[1,4,8,10,11,12,13,14,16,17,18,19,20,21,22,32,34,35,36,37,41,45,46,47,49,50,51,52,55,58,60],overal:[22,32],overflowerror:51,overhead:53,overli:[10,50],overload:46,overlook:[32,52,64],overrid:[14,24,49],overridden:[14,24],oversight:[19,50,52],overst:[18,50,60],overview:[7,8,16,34,37,39,43,48],overwhelm:[2,55,56],overwrit:[31,42,49],overwritten:37,overwrot:42,own:[4,6,8,10,14,16,17,26,29,38,40,41,42,43,45,46,49,50,52,53,58,63],pack:[12,14,22,31,50],packag:[1,3,4,6,34,47,55,63,64],package_nam:48,pad:8,page:[4,5,8,9,13,14,15,25,26,50,55,56],pai:[48,50,58],painstakingli:37,pair:[11,12,14,17,18,19,21,32,37,41,47,50],pairwis:[37,50,53,60],pairwise_dist:[32,50,53],pairwise_dists_crud:32,pairwise_dists_loop:32,palindrom:[55,59],paltri:15,pan:47,panda:[43,55,56,60],pane:5,paradigm:[5,13,37,58],parallel:53,param1:53,param2:53,param:53,paramet:[12,14,15,19,20,21,22,23,32,35,36,38,43,44,45,46,50,52,53],parameter:51,parameterless:50,parametr:[51,52,53],paramn:53,paramount:[50,58],parent:[28,31,42,45,53],parenthes:[8,14,15,25,50],parenthesi:[14,50],parenthet:15,pars:[1,50],part:[1,3,4,8,19,20,21,22,24,26,43,48,49,50,52,55,58,60],parti:[4,49,50,57,60],particip:1,particular:[4,11,22,28,36,40,41,43,44,50,58],particularli:[6,17,28,55,56,58],pass:[1,12,13,14,15,16,19,21,22,24,26,27,31,33,36,39,41,42,43,44,45,46,49,50,51,52,53],past:[5,13,46,54],path:[4,27,48,52,63],path_to_data1:49,path_to_fil:49,pathet:35,pathlib:63,pattern:[9,17,20,34,47,48,49,50,53],pdf:[9,47],peach:38,pear:[18,22],peculiar:[20,41,46],pedant:52,peek:[16,34,43],pen:46,pencil:46,peopl:[1,4,14,43,50,52,55,56,63],pep8:63,pep:50,per:[22,36,47],percentag:[55,59],perceptu:47,perfect:[4,5,8,11],perfectli:8,perform:[1,3,4,5,6,8,9,10,13,15,17,19,22,23,27,28,29,32,34,35,36,37,45,47,48,50,52],perhap:[8,9,35,47,50,51,52],period:[3,8,9,47],permiss:28,permit:[5,8,9,10,17,19,20,25,26,27,28,29,31,32,40,42,43,47,48,49,50,58,62,63],persist:[3,7,12,13],person:[41,55,56],pertin:50,perus:[5,8,11],pessimist:10,pet:23,petar:[55,56],petarmhg:[55,56],phone:3,phrase:[37,40],phrase_of_the_dai:48,physic:[27,55,56],pick:[3,32,50,51,53,55,56],pickl:63,pictur:[36,48],pie:[15,47],piec:[3,13,16,25,36,45,55,56,59,61],pillow:14,pineappl:38,pip:[4,53,54,63],pixel:[32,37,47],pixel_std_dev:37,pizza:[12,40],pizzashop:40,pkl:49,place:[1,4,8,12,14,20,25,27,32,37,38,40,46,48,50,51,53,55,56,60],placehold:[8,26,32,37],plai:[19,20,32,53,55,57,61],plain:[1,7,52],plan:50,platform:[4,53,63],player:47,pleas:[3,8,9,11,33,37,48,49,53,55,56],pleasantli:37,plenti:[3,52],plot:[5,35,60,63],plotli:47,plt:[5,35,47],plu:49,plug:43,pluggi:53,plymi:[35,49,50,53,59,61],plymi_mod6:53,plymi_mod6_src:53,plymi_root_dir:53,plymi_us:53,png:[47,49],point:[3,4,5,9,12,15,16,19,20,22,23,26,27,28,29,32,33,35,36,37,46,47,49,50,51,52,53,55,56,63],point_to_region:12,pointer:26,polish:[2,5],polyglot:2,ponder:52,pop:[8,10,25],popul:[22,28,33,41,46,47,49,64],popular:[1,4,5,15,43,48,50,57,60,63],portabl:[38,49],portion:[5,9,37],pos_index:25,pose:25,posit:[0,3,8,9,10,11,13,17,19,25,27,28,32,35,37,43,44,48,50],posixpath:49,poss:30,possess:[8,10,31,32,37,39,40,43,47,48,62],possibl:[8,13,17,19,21,26,27,28,32,38,40,49,50,53],post:[55,56],poster:12,potenti:[19,23,29,50,52,53],potpourri:47,power:[2,4,5,6,8,9,19,25,28,31,34,35,37,42,45,46,47,48,49,50,51,52,53,57,58,60,63,64],practic:[1,5,8,9,13,14,15,25,26,28,36,37,43,49,52,55,56,59,61,63],pre:[1,10,37],prece:46,preced:[1,8,9,11,12,17,20,24,25,28,29,30,31,32,33,37,46,50,51],preceed:25,precis:[1,27,31,37,51,52],preclud:53,pred_label:36,predict:[0,26,28,36,53],prefer:[9,15,20,22,38,50],prefix:3,prematur:[13,23],premier:[5,34,55,56],premium:2,prepar:[32,47,48],prepend:4,prescrib:[34,37,60],prescript:20,presenc:3,present:[5,12,22,33,46,47,48,49,53,55,56,57,59,60,61,63],preserv:29,press:[5,32,49,52,64],pressur:50,presum:49,presumpt:22,pretti:45,prev_num:17,prevent:[15,50,52],previou:[4,8,14,19,22,27,32,35,47,51,52,53,54],previous:[13,50],price:12,primari:50,primer:53,print:[0,1,3,7,8,9,12,13,14,15,16,17,24,26,35,41,45,46,48,49,52],print_kwarg:14,printabl:[43,46],prior:[5,12,19,50],priorit:[4,47],pro:2,probabl:[18,35,50,51],problem:[4,10,19,20,21,23,32,36,37,52,53,55,56],problemat:[9,12,31,50,52],proce:[5,15,19,25,29,32,40,42,44,47,48,49,58],proceed:[8,27,43,53],process:[1,2,3,4,5,9,11,13,26,29,32,34,35,36,37,41,44,46,48,49,50,51,52,53,55,56,57,58,60,64],produc:[8,9,11,12,13,15,17,21,22,23,24,25,26,27,28,29,32,33,35,36,37,39,41,44,46,47,48,49,50,51,53,60],product:[8,19,30,32,37,41],profession:2,program:[5,6,8,16,17,41,42,55,56,57,58],programm:[2,6,8],programmat:[8,30],progress:[48,53],project:[4,5,36,48,50,52,53,55,56,63,64],project_dir:53,prolif:50,promin:[5,63],promis:[22,50],prompt:[46,49,53],prone:[36,49],pronounc:[27,41],proper:[14,52,53],properli:[5,22,49,51,53],properti:[42,43,44,51,52,53,64],propos:50,protocol:[49,50,62],prototyp:[1,2,4,5],proud:35,provid:[1,2,3,4,5,6,7,8,10,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,35,37,38,41,42,43,45,46,47,48,49,50,51,52,53,55,56,58,60],prudent:50,pseudo:[9,15],pts:32,publish:[47,50],punctuat:[11,15],purchas:[38,46],purchased_item:46,pure:[6,7,23,37,43],purpl:[40,47],purpos:[7,8,14,19,32,41,45,48,50,53],push:52,put:[3,8,9,13,14,15,16,25,26,37,43,53],py27:4,pycharm:[2,50,53,57],pyformat:8,pypi:48,pyplot:[5,35,63],pyright:[50,54],pytest:[48,51,55,64],pytest_cach:53,python36:48,python3:48,python:[2,5,7,9,10,11,12,13,14,15,17,19,20,23,24,25,26,27,29,31,34,37,38,39,40,41,42,43,44,45,46,47,51,52,54,59,60,61,62,63,64],python_requir:[48,53],pythonlikeyoumeanit:50,pythonoptim:52,pytorch:[43,48,52,55,56],quadrant:37,quadrat:[0,3,10],qualiti:[5,47,50],queri:15,question:[3,5,8,25,50,51,52,53,55,56],quick:[3,39,47,55,57],quickli:[4,11,12,27,50,52,53],quintessenti:16,quirk:[8,49],quit:[1,6,8,9,12,15,16,17,24,25,27,50,53,55,56],quot:[3,8,49],quotat:[1,3,8],quotient:8,rabbit:64,racecar:23,radian:[5,47,48],radiu:35,rai:52,rais:[1,8,9,11,12,13,14,15,16,19,21,22,24,25,26,34,40,44,49,50,52,53],raiton:45,ram:32,ramp:47,ran:[5,53],rand:[32,33,35,36,37,47],randint:36,randn:[33,47],random:[11,32,35,36,37,47,60],randomli:[10,18,33,35],rang:[6,7,11,12,14,16,18,21,22,23,25,28,33,36,40,41,47,48,49,51,53],rank:60,rapidli:[1,5,34,53],rare:[1,50,52],rat:45,rather:[1,3,8,10,15,20,22,26,28,31,35,37,41,44,46,47,48,51,52],ratio:35,ration:[8,45],rationa:45,rbg:[32,37],reach:[9,13,14,19,29,35,46],read:[1,4,5,6,21,22,23,33,55,56,58,59,60,61,62,63,64],readabl:[1,9,11,15,17,22,23,46,50,53],reader:[8,11,23,32,46,55,56,57,58,59,61,63],readi:[48,57],readili:[15,58],readlin:49,real:[8,11,27,32,37,48,53],realiz:35,realli:[5,16,22,32,33,44,45,50,51,52,53],reap:52,reason:[12,14,15,20,22,27,31,43,47,58,60],recal:[3,5,8,9,10,12,14,15,16,17,19,20,22,23,27,28,29,30,31,33,35,36,37,40,41,44,45,46,48,49,50,52,53],recast:32,receiv:[22,33,38,44],recent:[5,8,9,12,15,26,27,45,52,53,54],recogn:[27,32,42],recognit:48,recoil:32,recommend:[4,5,8,11,12,17,18,35,38,46,47,48,49,50],recomput:5,record:[17,21,54],recreat:12,rect1:43,rect:45,rectangl:[41,42,43,45],recur:51,red:[5,32,37,40,47,52],redefin:[5,15,46],redraw:5,reduc:[38,40],redund:[11,20,28,38,44,50,52,53],redundantli:32,refactor:[21,32,44],refer:[2,3,5,8,9,11,12,13,14,19,22,24,25,26,27,28,29,31,33,34,35,37,40,41,42,43,45,46,48,49,50,52,53,58],referenc:[5,7,10,11,31,41,50,58],refin:47,reflect:[22,26,31,32,48,50,54],refresh:37,regard:[22,53],regardless:[12,29,32,50,53],region:[12,28,35,40,47],regrett:32,regular:[4,28,48],regularli:[48,50],reimplement:12,reiniti:31,reinstal:48,reiter:[22,49],rel:[1,3,8,10,14,16,20,22,25,32,33,37,44,49,55,56,63],relat:[4,11,48,49,55,56,57,60,63],relationship:[8,25,31,41,42,45],relative_po:32,releas:[52,54],relev:[37,53,59,61],reli:[1,7,8,12,37,43,50,52,58],reliabl:[2,8,35],relic:[8,43],reload:48,remain:[9,17,31,48],remaind:[8,16,37],remaining_item:46,remedi:[31,53],rememb:[8,22,29,41,52],remind:[8,49,52],remov:[4,8,10,11,19,26,37,38,53],renam:5,render:[5,8,46,47,48,50],reorgan:53,repeat:[11,13,20,25,27,28,33,37,52],repeatedli:[3,13,14,28,52,53,58],repertoir:58,replac:[3,8,10,17,26,27,28,31,37,46,51,53],replic:[15,32],report:[5,53],repositori:53,repr:[45,46],repres:[6,8,9,10,12,14,21,24,26,30,31,32,37,41,46,47,48,51],represent:[8,20,43,49,62],reproduc:[1,47,50],repurpos:26,request:[13,15,38],requir:[2,4,5,6,8,9,12,15,21,23,25,27,28,29,31,32,37,46,48,50,53,55,56],reread:53,rerun:[35,52,53],rescu:53,research:[1,5,55,56,57,60],resembl:32,reserv:[8,14,15,25,26,32,43,44,46,47,50,52,62],reset:29,reshap:[28,29,31,32,33,34,37],resid:[27,41,47,48,53],resolut:[32,47],resolv:[9,24,27,28,41,45,58],resourc:[2,8,15,46,47,50,55,56],respect:[5,8,9,13,14,17,20,24,27,28,29,32,33,35,37,40,44,47,49,52,53,63],respons:[20,38,47,48,50,53],rest:[5,7,17,51],restart:[5,13,48],restor:[52,53],restore_default:48,restrict:[6,8,9,24,37,48,50],result:[1,3,5,6,7,8,11,12,15,20,22,26,27,28,29,31,32,33,35,36,37,40,41,45,47,48,49,50,51,53,62],resum:49,retain:[8,22,52],retriev:[10,11,15,25,27,47,50],reus:58,reveal:[5,14,47,51],reveres:25,revers:[9,23,25,26,27,31,41,54],review:[5,8,16,25,27,31,50,63],revisit:[5,13,42,49,50],revolutionari:57,revolv:34,rewit:44,rewrit:[0,19,22,32,44,50,53],rewritten:[8,14,31,53],rgb:[32,37,47],rgba:47,rich:[2,5,46,50,53],richer:50,rid:28,right:[3,5,9,12,19,22,23,26,28,29,32,37,43,45,47,58],rightarrow:[8,9,11,12,19,20,25,28,32],rigor:[32,46,50,55,56],rival:37,road:[55,56,63],roadblock:6,roar:0,robot:3,robust:[2,5,51,52],roll:[19,49],root:[0,3,4,32,35,37,49,53],root_dir:49,rootdir:53,roster:11,rotate_imag:50,rotateimag:50,roughli:[12,36,53],round:[12,20,32],rout:5,routin:[27,29,32,37,48],row:[8,15,25,27,28,30,31,32,33,35,36,37,47,50,60],row_i:32,row_x:32,rsokl:[55,56],rubi:5,rudimentari:[50,52,64],rug:48,rule:[1,8,12,15,16,24,27,28,29,31,37,41,47,50,52,53,60],run:[0,1,2,4,10,12,13,15,22,34,35,36,48,49,50,51,52,57,64],rundown:[10,11,12,25,31,39,49],runner:[48,53],running_estim:35,runtim:50,ryan:[8,11,12,14,48,50,55,56],safe:[32,49],safeti:21,sai:[5,6,8,10,15,26,27,37,45,50,51,52],said:[2,4,5,8,9,13,20,24,27,29,31,32,35,40,41,42,43,48,50,52,53,55,56],sake:[1,12,16,23,32,37,46,50,52,53],salient:[17,41,50],salt:46,sam:[55,56],same:[1,5,6,8,9,10,12,15,16,19,20,22,23,24,25,26,27,28,29,31,32,35,37,40,41,43,45,47,48,50,52,53,58,62],sampl:60,sane:4,sash:3,satisfactori:20,satisfi:[8,28,31,32,48,51],save:[1,5,15,50,52,63],savefig:47,savez:49,saw:[5,8,15,25,31,41,50,53],scalar:[27,37],scale:[10,33,35,47,48,50],scatter:[47,63],scenario:[9,10,21,32,45,52],scene:[6,15,31,32],schema:27,scheme:[11,12,25,27,31,49,51,60],school:[55,56],sci:[55,56],scienc:[4,5,29,47,55,56,58,60],scientif:6,scientist:[1,57],scikit:60,scipi:4,scope:[8,12,22,40,41,50,52,53,55,58],score:[12,22,26,27,32,36,58],score_offset:32,scores_per_stud:32,scratch:[8,33,42,44,53,55,56],scratchwork:3,screen:[1,3],script:[2,3,4,8,17,24,48,53,57],search:[4,49,50,55,56,63],second:[5,6,8,10,15,17,20,22,25,27,29,36,44,47,49,50,52,53,63],secretli:6,section:[1,2,4,5,7,8,9,10,13,14,15,16,17,25,27,28,29,31,32,33,37,38,40,41,42,45,46,47,48,49,50,51,52,53,59,61,63],see:[3,4,5,7,8,9,11,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,31,32,33,34,35,37,38,40,41,42,43,44,45,46,47,48,49,50,52,53,62],seek:52,seem:[15,17,29,32,40,44,51],seen:[8,15,16,24,25,31,37,47,48,50,62],segment:[14,35,47],sel:27,seldom:[33,41],select:[5,27,28,30,52],self:[27,38,39,41,42,43,45,46,50],selina:8,semant:17,semi:[35,47],semicolon:47,send:[1,5],send_mail:48,sens:[8,15,34,38,44,55,56],sensibl:[25,29,44,46],sensit:23,sentenc:[3,8,11],separ:[3,5,8,10,14,15,16,17,20,22,25,26,47,49,50,52,53],seq1:25,seq2:25,seq3:25,seq:[10,14,23,25],sequenc:[3,9,10,12,13,14,15,16,17,18,19,20,23,26,27,28,29,34,35,37,41,43,49,50,52,55,58,60,62],sequenti:[3,8,11,17,25,32,36,58,60],seri:[14,15,36,52],serial:49,seriou:[6,8],serv:[7,16,26,41,48,49,50,52,53,55,56,64],server:57,servic:4,session:[3,4,48,53],set:[1,5,8,9,10,12,14,15,17,18,22,26,27,28,36,37,38,40,41,43,44,46,47,48,49,51,52,54,55,57,58,62],set_1:11,set_2:11,set_titl:[5,47],set_xlabel:[5,35,47],set_xscal:35,set_ylabel:[35,47],set_yscal:47,setattr:[40,46],setup:[48,53],setuptool:[48,53],seven:[8,20],sever:[3,5,6,8,14,16,18,25,33,35,38,41,45,48,49,50,53],shade:[35,47],shadow:[50,58],shallow:22,shameless:43,shampoo:50,shape:[27,28,29,30,31,32,33,35,36,37,43,46,47,50,60],share:[5,16,24,25,31,41,48,52,53],shares_memori:[28,31],sheet:[27,28,29,30,32,37,47],shelf:52,shell:[0,2,47],shift:5,shine:[9,10,12,32,37,53],shirt:46,shmangela:50,shmonathan:50,shock:8,shockingli:40,shop:[40,46,62],shoppinglist:[38,46,50],short_gen:15,shortcom:53,shortcut:[5,8],shorten:14,shorthand:[25,26,27,31,34,52],shortli:[47,50],should:[3,4,5,7,8,9,10,12,13,14,15,16,17,19,20,22,23,25,26,28,31,32,33,34,35,36,37,38,40,41,42,44,45,46,47,48,49,50,51,53,54,55,56,64],shouldn:38,show:[5,11,16,26,27,32,34,45,47,52,53],showcas:18,shown:[22,50],shrewdli:32,side:[3,4,9,42,45,47],sidewai:47,sift:53,sigh:14,sight:32,sign:[9,20,51],signal:[13,14,15,16,31,42],signatur:[14,22,44,46,50,53],signifi:[10,14,16,49],signific:[8,31,44,55,56],significantli:[4,6,28],silent:[1,12,52],silli:[46,50],sillyclass:46,similar:[1,5,14,15,22,25,27,32,33,37,40,41,44,47,50,52,53],similarli:[8,9,22,24,25,27,28,29,32,37,40,44,46,49],simpl:[1,2,3,4,5,8,9,12,14,15,16,17,20,25,26,27,29,35,36,37,38,39,40,43,45,46,48,49,50,51,52,53,59,60],simple_arrai:27,simple_merge_max_map:22,simpler:[0,36,47],simplest:[9,23,28,50],simpli:[1,2,3,4,5,8,10,12,14,15,16,19,21,22,25,26,27,29,31,32,34,35,36,37,40,44,45,46,47,48,49,50,51,52,53,55,56],simplic:[1,35,50],simplifi:[8,15,17,19,36,53],simul:35,simultan:[14,19,28,37],sin:[5,37,47],sinc:[5,8,12,15,16,19,20,25,27,36,37,40,43,45,48,49],sine:[33,47],sine_wav:47,sinewave_plt:47,sing:47,singl:[3,5,8,9,11,12,14,15,16,18,20,22,23,25,27,28,31,32,33,35,36,37,38,41,42,47,48,49,50,53,58,64],singular:[40,41],site:[55,56],situat:24,six:[9,20,37,55,56],size:[10,12,15,22,25,27,30,31,33,35,36,37,42,47,51,53,60],skill:62,skip:[9,13,15,35,52],sky:8,slate:53,sleek:[15,17,28,46,47],slice:[3,8,9,10,11,19,23,26,28,34,37,46,50],slick:[20,35],slightli:[15,41,47,49],slot:29,slow:[6,32,37],slower:6,small:[3,5,6,8,22],smaller:[22,47,51,52],smallest:[17,27],smart:53,snake:40,snake_cas:50,sneak:[16,34,43],snippet:[3,5,34,50,55,56],sock:46,softwar:[1,2,48],soil:49,soklaski:[48,50,55,56],sole:[8,10,14,15,38,41,44],solid:[47,55,56,60],solut:[0,4,55,56,58,59,60,61,62,63,64],solv:[4,19,21,37,44],solver:48,some:[3,4,5,7,8,10,11,12,17,18,19,20,26,27,29,35,36,37,38,39,41,45,47,48,49,50,52,53,55,56,57,58,60,62,63,64],some_dict:14,some_iterable_of_str:20,some_list:[14,48],some_long_function_nam:50,some_text:49,some_util_func:48,someon:[38,55,56,63],someth:[5,9,14,16,22,33,36,44,50],sometim:[20,49,50],somewhat:[19,27,28,46],soon:[9,15,40,43,50,52],sophist:[1,2,4,31,46,52,62],sort:[2,8,9,10,11,17,25,38,41,45,49,50,51,52,55,56],sound:[52,55,56],sourc:[1,2,8,25,48,50],space:[5,8,11,12,16,27,33,40,47,49],space_time_coord:11,span:14,sparingli:[14,15,20,50],spars:51,speak:[40,53],spec:50,special:[1,3,8,9,15,17,19,20,22,29,32,34,38,39,41,42,43,44,45,48,49,50,52,55,62],specif:[1,4,8,10,12,15,21,25,27,28,31,32,36,37,39,40,41,43,44,47,48,49,50,51,53,57,63],specifi:[1,3,4,8,9,11,12,15,16,18,25,27,28,29,32,35,36,39,40,41,42,44,47,48,50,51,52,53,58,60],speed:6,speedup:[10,22,37],spell:[1,20,26],spend:[7,50],spent:38,sphinx:50,split:[8,11,15,33,47],spot:[55,56],spreadsheet:[32,43],spuriou:32,sqrt:[3,8,32,35,37,47],squar:[0,3,8,9,10,12,15,25,31,32,34,35,37,42,45,46,47,48,49],ssize_t:51,stack:[27,29,32,33,36,50,52,58],stagnat:[55,56],stand:[5,8,41,50,52,60],standalon:[27,50],standard:[1,3,4,8,11,12,14,16,33,35,37,47,48,49,50,53,60],stapl:46,star:[8,12,34],stark:[22,37,50],starkli:62,start:[3,4,5,8,12,13,15,16,18,25,26,27,29,31,32,33,34,35,43,45,49,52,53,55,56],startswith:[8,49],stat:50,stat_func:50,stat_funct:50,state:[8,14,15,22,26,31,46,48],statement:[13,15,16,17,20,21,22,24,40,50,53,55,58,63,64],static_func:44,staticmethod:44,statist:[17,33,35,37,50],statment:[13,14],statu:[9,26],std:[1,22,33,35,36,37],std_in_circl:35,stdin:45,stdlib:53,stem:[43,55,56,57,58,60],step:[10,13,15,23,25,27,29,32,33,37,50,52,53,57,64],stew:8,stick:[6,10,50],still:[5,8,13,14,26,28,31,32,38,40,41,44,45,48,50,54,58],stock:52,stomp:22,stop:[15,19,25,27,33,55,56],stopiter:[13,15],store:[3,4,6,8,9,11,14,17,18,19,22,25,26,27,30,31,32,34,35,36,37,38,41,43,46,47,48,49,50,51,58,60],str:[8,9,14,15,20,23,25,38,40,41,43,44,45,46,49,50,52,53,62],strage:45,straight:[14,28,32],straightforward:[22,27,32,37],strang:44,strategi:[51,64],stream:47,streamlin:64,strength:47,stretch:47,strict:[1,50],strictli:[9,48,49,50],strike:[46,53],string:[2,5,9,11,12,13,14,15,17,19,22,23,25,26,27,37,38,40,41,43,44,45,48,49,50,52,53,55,57,58,59,62],string_of_num:15,stringent:6,strip:[8,47],strive:[35,49,50],strongli:[16,18,35,46,49,50],struck:58,structur:[27,30,32,33,48,49,52,53,55,58,64],struggl:[5,50],student:[11,12,17,22,26,27,32,50,57,58,59,61],student_grad:26,student_list:50,studi:[11,16,32,35,37,43,50,57,58,62,63,64],studio:[2,50,57],stuff:32,style:[5,7,16,40,47,48,55,56,63],stylist:[20,22],styliz:5,sub:[25,27,34,48],subarrai:31,subclass:42,subdirectori:[5,48,49],subfield:52,subject:28,sublist:50,submit:[50,59,61],submodul:47,subpackag:48,subplot:[5,35,63],subscript:15,subsect:[5,9,15,25,26,28,31,32,50],subsequ:[8,10,13,14,15,16,20,22,24,25,26,27,28,34,37,49,53,62],subset:[6,11,49],substanti:[32,35,37,48,55,56],subtl:[20,22],subtract:[19,32,35,37,45,46],succe:46,success:[19,50],successfulli:[32,53],succinct:[22,36,50],succinctli:31,suffic:[13,44],suffici:[8,10,16,37,50,55,56],suffix:[1,2,5,48,49],suggest:[9,50],suit:[1,11,20,28,32,37,47,48,50,51,52,64],sum:[1,6,8,13,14,15,17,19,21,32,35,36,37,43,44,50,52],sum_:[15,32],sum_func:[6,48],summar:[7,8,10,25,32,43,48,49,52],summari:[10,12,16,38,47,50,55,57,58,62],summed_row:32,superior:[21,46],superset:11,suppli:[25,28,31,33,37,49],support:[1,2,8,9,11,12,25,26,27,47,48,50],suppos:[8,9,10,11,14,17,19,22,26,27,28,29,32,36,37,38,41,42,48,49,50,52,53],suppress:47,suprem:[8,15,17],sure:[9,14,32,34,45,50,52,53],surfac:[8,33,42,53],surpris:[15,27,31,37,40,50],surprisingli:52,surround:[5,50],survei:[10,24,37,44,57],susan:11,suspect:53,suss:52,swap:[4,27],sweep:48,swept:48,swoop:52,symbol:[7,8,11,14,26,46,48],symmetr:11,symmetric_differ:11,synonym:[41,43],syntact:[16,17],syntax:[1,2,5,6,8,9,11,12,13,14,15,16,17,19,20,21,22,25,26,27,31,38,40,41,48,49,50,57,62],syntaxerror:14,sys:[0,48],system:[4,25,26,31,43,48,49,50,53,63],tab:[3,5,8,16,50],tabl:[27,29,37],tabular:60,tac:25,tackl:19,tag:44,tailor:[6,32],take:[0,1,4,6,7,8,10,11,12,14,15,16,17,18,19,20,22,25,27,28,29,31,32,34,35,36,37,38,40,44,45,46,47,48,49,50,51,52,53,55,56,57,58,62,64],takeawai:[2,4,9,10,11,12,15,17,22,24,25,27,28,31,32,37,40,43,48,49,50,52,53,58],taken:[12,20,27,32,49,50,55,56],talent:50,talk:[3,7],talli:[3,11,13,21,35,36,37],tan:37,target:[10,47,48],task:[1,8,20,25,28,37,58],taylor:14,teach:[49,55,56],technic:[16,48,50,63],techniqu:[12,28,60],technolog:47,tediou:[27,29,44,49,50,52],tell:[1,5,14,49,50,55,56],temp:53,temperatur:50,tempfil:53,templat:[9,53],temporari:[52,53],temporarili:[32,52,53],temporarydirectori:53,ten:[10,35,37,41,51],tend:43,tensor:[37,43],tensorflow:[43,48,55,56],term:[3,8,10,16,17,19,22,25,32,37,43,47,48,49,50,52,55,60,62],termin:[0,1,2,3,4,5,48,53],terminolog:[15,41,62],terrancewasabi:[48,49],terribl:[10,55,56],terrif:5,ters:28,tertiari:50,test:[1,2,5,9,10,11,12,14,21,22,25,36,41,48,49,50,51,55],test_0:49,test_1:49,test_:53,test_all_combin:53,test_appl:49,test_basic_funct:53,test_basic_numpi:53,test_broken_funct:53,test_calibr:48,test_config:48,test_count_vowels_bas:[51,52,53],test_databas:48,test_email1:53,test_email2:53,test_email3:53,test_funct:53,test_inequ:53,test_inequality_unparameter:53,test_merge_max_map:[51,52,53],test_model:48,test_numpy_funct:53,test_range_length:[51,53],test_range_length_unparameter:53,test_using_fixtur:53,test_util:48,test_vers:53,test_writing_a_fil:53,testabl:52,tests_requir:53,text:[1,2,3,5,7,8,9,11,13,14,15,25,26,46,48,50,55,56,58,63],text_1:11,text_2:11,textbook:8,textedit:1,than:[0,1,4,6,8,9,10,11,12,13,14,15,19,20,21,22,25,28,29,31,32,35,36,37,41,44,46,47,48,49,50,51,52,53,58],thank:52,the_decor:53,the_function_being_decor:53,thefollow:47,thei:[1,4,5,6,8,10,12,13,15,16,17,18,20,22,24,25,26,27,29,30,31,32,37,41,43,44,45,47,48,49,50,52,53,55,56,59,60,61],them:[2,3,4,5,8,11,15,18,19,20,22,26,29,32,35,37,38,43,44,45,46,47,48,49,50,51,52,53,54,58],themselv:50,theoret:11,theori:50,therefor:[30,32,37],therein:[5,9,55,56],thi:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64],thing1:48,thing2:48,thing:[3,8,14,15,27,37,43,45,49,50,53,62],thingth:50,think:[1,16,25,27,37,45,50,52,55,56],third:[5,15,26,32,49,50,53,60],thorough:[28,37],those:[4,8,11,14,15,21,24,25,26,28,31,35,37,42,48,50,51,52,55,56,60],though:[32,41,50],thought:[3,22,50,51],thousand:[6,8,10,35,53],three:[3,8,9,14,17,18,20,25,27,28,31,32,33,34,36,37,41,44,46,47,49,53],threshold:28,through:[4,5,15,17,22,27,31,32,45,46,47,48,49,50,52,53,57,59,61,62],throughout:[1,2,6,7,8,9,13,14,15,25,26,34,50,53,55,56],thrown:35,thu:[1,2,4,5,6,8,9,10,11,12,13,14,15,17,18,19,20,22,23,25,26,27,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,52,53,60],thusli:8,tick:[47,50],tightli:35,time:[3,4,5,6,7,8,10,11,13,15,17,18,22,23,25,28,29,31,32,34,35,36,37,38,41,45,47,49,50,52,53,57,62],timeit:[22,36],times10:8,tinker:5,tip:[20,36,59,61],titl:47,tmp:[41,53],tmpdirnam:53,togeth:[3,8,12,15,18,20,22,32,36,44,45,58,60],token:11,toler:8,too:[8,12,14,15,20,23,27,37,50,51,52,53],took:48,tool:[1,2,3,5,6,8,11,12,15,16,17,18,29,37,47,50,52,53,54,55,56,57,58,60,63],toolkit:58,toothpast:50,top:[0,1,5,11,13,37,43,47,48,50],topic:[28,37,42,48,60],topmost:[22,36,48],torch:53,total:[3,10,13,14,15,19,20,21,27,30,32,35,36,37],total_even:14,touch:[8,31,50],tough:12,tour:[48,62],tover:8,toward:[5,8,37,50,52,53],town:47,toyplot:47,trace:[50,52],traceback:[8,9,12,15,26,27,45,52,53],track:[2,8,11,12,15,17,27,38,45,46,48,50],trade:58,tradit:[8,37,58],tradition:[1,8,37],trail:[3,8,25,27,31,32,49,50],train:43,trait:50,transcript:20,transform:53,transit:[29,46],translat:[1,6,15],transpar:[35,47],transpir:[26,32],transpos:[27,32],travers:[25,28,36,37,50,51,55,60],treacher:31,treat:[3,8,27,28,32,37,40,43,44,48,49,50,53],treatment:[8,28,29,46,47,48,55,56,58],tree:[11,53],tremend:[1,5,6,34,37,60],trend:51,tri:[22,36,45],trial:[8,35],triangl:47,triangular:47,tribul:52,trick:[20,58],trigger:[14,31,51,52,53],trigonometr:[8,37],trillion:8,tripl:[8,49],triplet:29,triu:47,trivial:[28,32,35,41,44,51,52,53],troubl:[50,53],troubleshoot:63,true_label:36,truli:[10,31],truth:[36,58],tupl:[8,9,12,13,14,17,18,22,26,27,28,30,33,37,38,41,43,47,52,58,62],tuple_of_dummi:41,turn:[31,47],tutori:[2,4,8,11,12,15,38,40,42,43,47,48,49,53],twelv:32,twice:[10,12,17,20,38],twitter:[55,56],two:[0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,18,19,20,25,26,28,29,31,32,33,34,35,37,38,40,41,43,44,45,46,47,48,50,52,53,55,57,59,60,63],txt:[1,26,49,53],type:[1,2,3,5,9,10,11,12,13,15,17,20,22,24,28,30,31,34,37,38,39,40,41,42,44,45,46,47,48,49,54,55,58,60,62,63],typeerror:[12,14,15,25,26,44,45],typic:[2,7,8,11,14,28,37,47],typo:[2,54],u0336:46,ubiquit:25,uint8:47,ultim:[8,20,27,49,50,52,53,62],umbrella:14,unabl:[37,45],unachiev:60,unaffect:[26,31],unambigu:[1,9,37],unanticip:22,unchang:[22,27,31,35,44],uncommon:[4,58],uncompromis:50,undefin:[2,40],under:[10,17,19,38,41,44,45,46,48,50,52,58],undergo:32,underli:[9,27,28,34,60],underneath:49,underscor:[8,26,40,41,46,50],underst:13,understand:[1,3,7,9,10,15,16,17,20,22,25,26,27,28,29,30,31,32,41,43,44,47,48,50,52,55,56,58,59,61],understat:58,understood:[7,8,14,62],undo:[29,52],unequ:[32,33,53],unevalu:9,unexpect:[44,51,52],unfortun:[45,55,56],unhash:12,unicod:[8,26,46,49],unifi:43,uniform:[16,30,33,47],uninstal:[4,48],union:[10,11,38],uniqu:[11,12,25,27,28,29,38,46,47],unit:52,unittest:53,univers:[1,8],unknown:27,unless:[12,31,33,48,52],unlik:[11,12,25,28,37],unnecessari:[27,50],unnecessarili:[15,32],unord:[10,11,12],unpack:[14,22,28,47],unpattern:28,unpickl:49,unpopul:22,unpurchas:[38,46],unrecogn:45,unrestrict:37,unruli:50,unsign:47,unsorted_index:17,unsuccessfulli:45,unsupport:45,until:[0,12,13,15,16,24,29,45],untitl:5,untitled1:53,unus:50,unusu:48,unvector:61,unvectorized_accuraci:36,unwieldi:[27,52,53],unwittingli:[22,31,52],updat:[3,4,7,8,9,10,11,12,22,26,28,31,34,35,38,41,46,48,49,50,52,53,54,60],upgrad:48,upload:48,upon:[15,17,39,52],upper:[8,14,35,47,51],uppercas:[9,52,53],upward:47,usabl:52,usag:[11,15,17,32],use:[0,1,2,3,4,5,6,8,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,55,56,58,60],use_gpu:50,used:[1,3,5,6,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,31,32,33,34,37,39,40,41,43,44,45,46,47,48,49,50,51,52,53,58],usefixtur:53,useful:[1,2,3,4,5,8,10,11,12,14,15,16,17,18,27,28,31,32,35,36,37,38,45,46,47,48,49,50,52,53,58],usefulness:27,useless:9,user:[2,3,4,5,7,8,11,12,14,25,27,31,33,37,43,44,47,48,49,50,52,53,55,56,58,59,60,61,62,63],uses:[4,8,10,11,16,20,25,27,29,32,35,37,47,50],using:[0,1,2,4,5,6,8,9,10,11,12,14,17,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,37,40,41,42,43,46,47,48,49,50,51,53,55,56,58,59,60,63],usr:48,utf:[8,49],util:[1,3,4,8,9,10,11,13,14,16,17,18,26,28,29,31,34,37,38,42,43,44,46,47,48,49,50,63],val1:53,val2:53,val:[14,53],valid:[1,3,9,12,13,14,15,23,25,27,29,31,37,44,47,50,58],valj:53,valu:[0,1,3,5,8,10,11,13,15,17,18,19,20,21,22,24,25,26,27,28,31,32,33,34,35,36,37,40,41,43,44,46,47,51,52,53,58],valuabl:[11,17,18,22,24,27,29,53,55,56],value1:12,value2:12,value3:12,valueerror:[25,27,32],vanilla:[4,6,11,48],var_nam:14,vari:[27,31,33,52,53],variabl:[0,1,2,3,4,5,7,8,9,13,14,17,22,25,31,37,38,39,40,41,43,48,49,50,52,55,58],varianc:[33,37],variant:4,variat:48,varieti:[8,12,25,28,33,37,41,44,46,47,50,51],variou:[3,5,9,10,11,12,16,24,27,28,31,37,40,43,46,47,48,50,51,52,54,58,62],vast:49,vastli:16,vector:[1,32,34,50,55,60,61],veget:12,veggi:12,vein:[37,48],venu:48,verbos:[12,50,53],veri:[2,4,5,6,8,9,12,14,15,16,20,22,25,27,32,33,34,35,37,41,44,47,50,51,52],verifi:[8,15,32,37,41,42,44,47,49,52],versa:[3,22,50],versatil:[12,47,60],version:[2,4,6,8,9,10,11,12,20,24,32,43,44,48,50,52,53,55,56],versu:[26,31,35,47,53],vert:37,vertic:[32,33,37,47,50],via:[0,4,5,7,8,9,11,12,13,15,20,22,25,27,31,32,35,37,39,42,47,48,49,50,51,52,53,60],vice:[3,22,50],video:[5,9,53,60],view:[5,12,27,28,32,38,50,53,55,56,60],violat:[1,50,52],viridi:47,visibl:24,visit:[14,20,29,55,56],visual:[2,8,35,47,50,57,63],vogu:8,vowel:[13,14,49,50,52],vowel_count:52,vscode:[2,50,53,54],vstack:33,vulner:49,wai:[0,1,3,4,5,8,9,11,12,14,15,16,20,25,27,28,29,31,32,33,35,37,38,40,43,44,45,46,47,48,49,50,51,52,53,60,63],wait:64,walk:[45,50,55,56],want:[1,2,3,5,8,9,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,32,33,35,36,37,38,40,41,42,44,48,49,50,51,52,53,55,56],warn:[0,1,8,13,14,25,33,50,58],warrant:[8,25,29],wasi:47,wasn:[14,50],wast:32,watch:[8,49],wave:47,wayn:8,weak:47,wealth:10,web:[5,47],websit:[5,55,56],week:52,weirdo:8,welcom:64,well:[1,2,5,8,12,14,17,19,22,23,25,31,32,33,37,46,47,48,50,51,52,57,60],went:54,were:[3,5,8,9,12,16,20,31,37,38,44,48,49,50,51,52,53,54,55,56,59,61],weren:38,what:[3,5,7,8,9,11,14,15,16,17,18,20,21,22,24,25,26,27,28,29,30,31,32,33,34,37,41,44,45,48,49,51,52,53,54,57,58,60,63],whatev:[4,5,10,11,22,47,50,52],when:[1,3,5,6,8,9,10,11,12,13,14,15,16,17,21,22,24,25,26,27,28,29,31,32,33,37,38,41,44,45,46,47,48,49,50,51,52,53,57,58],whenev:[4,8,11,15,17,28,29,31,37,39,40,44,46,49],where:[1,6,8,9,10,13,14,15,16,17,21,22,23,25,27,28,29,31,32,35,38,40,41,43,45,46,47,48,49,50,52,53,57,64],wherea:[3,5,8,9,10,11,14,15,23,24,25,26,28,32,33,44,46,48,50],whereas:9,wherein:39,wherev:[7,8,15,28,36,48,52],whether:[1,12,21,23,26,32,35,36,45,52,60],which:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64],while_block:24,white:16,whitespac:[8,9,13,14,23,50,58],who:[3,4,15,21,32,50,55,56,63],whole:[1,8,15,34,37,48,58],wholesal:48,whom:[32,50],whose:[8,10,11,12,15,25,26,28,35,36,42,43,44,46,47,48,49,50,52,53],why:[0,3,6,8,9,15,20,25,26,27,29,31,32,34,44,46,48,50,51,57,60,64],wide:[8,12,33,37,44,47,48,49,50],wider:48,width:[42,43,45,47],wildcard:49,wildli:10,win32:53,win:1,window:[1,3,4,5,47,49],windowspath:49,wisdom:50,wise:[32,37],withhold:27,within:[3,5,7,8,9,10,13,14,15,16,19,22,24,25,27,28,29,31,32,33,35,36,37,40,42,43,44,47,48,49,50,51,52,55,58,59,63],within_margin_percentag:21,without:[0,4,5,7,8,9,13,14,15,16,19,22,28,31,32,34,35,47,48,49,50,52,53,58,60],won:[45,50],wonder:[3,8,46,51],wont:46,woof:40,word:[1,2,8,11,14,15,20,43,48,53],word_collect:15,word_distr:11,words_with_o:15,work:[2,3,4,5,8,10,12,14,15,23,24,26,27,28,31,32,34,36,37,38,42,44,45,46,47,48,50,51,53,55,56,57,58,59,60,61,62,63,64],workflow:50,world:[1,8,32,41,43,46,48,52,53],worldwid:48,worri:[4,8,11,12,19,29,37,41,49,53],worst:[10,12],worth:50,worthwhil:[6,26,43,47,50],would:[3,5,6,8,9,10,11,12,13,14,17,18,19,20,21,22,24,25,29,31,32,35,36,37,40,44,45,46,47,48,49,50,52,53,55,56,59,61],wow:25,wrap:[3,50,53],write:[1,2,3,5,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,25,26,29,32,34,35,36,38,41,42,43,45,48,51,53,54,55,56,57,58,60,63,64],writelin:49,written:[1,3,4,5,6,8,9,10,15,16,22,37,45,48,49,50,52,55,56,59,61],wrong:[1,9,12,14,22],wrote:[10,22,42,45,46,51,52,53],www:50,x_0:32,x_1:32,x_1d:32,x_i:37,x_it:15,x_left:47,x_norm:32,x_right:47,x_sqrd_sum:32,x_val:18,x_y_prod:32,x_y_sqrd:32,xarrai:[27,60],xmax:35,xmin:35,y_0:32,y_1:32,y_gen:18,y_sqrd_sum:32,year:[5,8,52,55,56],yerr:47,yes:50,yet:[1,8,10,22,25,41,53],yield:[12,15,18,26,36,49,50,53],you:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,63],your:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,16,17,19,20,21,22,25,26,27,31,35,36,38,40,41,43,45,46,47,49,50,52,53,57,58,63],your_usernam:4,yourself:[1,2,4,6,8,22,28,35,47,49,50,51,57],zero:[8,9,14,15,20,25,45,47,50,52,60],zerodivisionerror:[8,9,21],zeros_lik:32,zip:[12,18,22,36,48],zoe:12,zone:[55,56],zoom:47,zordon:8},titles:["Exercises","Introducing the Python Programming Language","Setting Up a Development Environment","An Informal Introduction to Python","Installing Python","Jupyter Notebooks","Doing Numerical Work in Python","A Quick Guide to Formatting","Basic Object Types","Conditional Statements","Data Structures (Part I): Introduction","Data Structures (Part III): Sets & the Collections Module","Data Structures (Part II): Dictionaries","For-Loops and While-Loops","Basics of Functions","Generators & Comprehension Expressions","Introducing Control Flow","Iterables","Python\u2019s \u201cItertools\u201d","Difference Fanout","Encode as String","Within Margin Percentage","Merging Two Dictionaries","Is Palindrome","Scope","Sequence Types","Variables & Assignment","Accessing Data Along Multiple Dimensions in an Array","Advanced Indexing","Iterating Over Arrays & Array-Traversal Order","Basic Array Attributes","Introducing Basic and Advanced Indexing","Array Broadcasting","Functions for Creating NumPy Arrays","Introducing the ND-array","Playing Darts and Estimating Pi","Measuring the Accuracy of a Classification Model","\u201cVectorized\u201d Operations: Optimized Computations on NumPy Arrays","Applications of Object Oriented Programming","A Brief Summary of Terms and Concepts","Defining a New Class of Object","Instances of a Class","Inheritance","Introduction to Object Oriented Programming","Methods","Object Oriented Programming","Special Methods","Matplotlib","Import: Modules and Packages","Working with Files","Writing Good Code","Describing Data with Hypothesis","Introduction to Testing","The pytest Framework","Changelog","Python Like You Mean It","Python Like You Mean It","Module 1: Getting Started with Python","Module 2: The Essentials of Python","Module 2: Problems","Module 3: The Essentials of NumPy","Module 3: Problems","Module 4: Object Oriented Programming","Module 5: Odds and Ends","Module 6: Testing Our Code"],titleterms:{"boolean":[8,9,28],"break":13,"class":[40,41,43,44,46],"default":[11,14],"float":8,"function":[12,14,17,27,33,37],"import":[43,48],"new":[40,54],"return":14,"short":9,"static":44,"while":13,Adding:12,Are:12,Axes:[32,47],Being:50,Doing:[0,6],For:[13,32,50],IDE:53,IDEs:2,One:[22,27],The:[8,11,14,15,32,40,44,47,50,52,53,58,60],Uses:16,Using:[5,15,31,32,33,37,50],Will:2,__init__:41,about:[55,56],absolut:[48,50],access:27,accommod:14,accuraci:36,act:17,add:45,advanc:[28,31,32],algebra:37,algorithm:10,along:27,anaconda:4,anatomi:52,ani:50,applic:[32,38],arang:33,arbitrari:[14,22],arg:50,argument:[14,37,44],arithmet:0,arrai:[27,28,29,30,31,32,33,34,37,49],assert:[52,53],assign:[8,26,28,31],attribut:[30,40,41],augment:[8,28,31],axi:37,basic:[8,12,14,28,30,31,37,52],benefit:31,beyond:47,binari:37,bool:9,bound:25,brief:[4,39],broadcast:32,buggi:22,callabl:50,can:[8,12],cell:5,chain:15,challeng:22,changelog:54,check:0,circuit:9,classif:36,claus:13,code:[5,50,52,53,64],collect:11,column:29,combin:28,comparison:9,complex:[8,10,12],comprehens:[8,9,11,12,13,14,15,17,18,19,25,26,27,28,31,32,37,40,41,44,45,47,48,49,50,51,52,53],comput:[4,37],concept:39,conclus:37,conda:[4,48],condit:9,constant:33,construct:[0,12],consum:15,contain:46,content:54,continu:13,contributor:[55,56],control:16,convent:50,correct:22,counter:11,creat:[5,11,15,33,41,46,47,53],cut:52,dabbl:3,dart:35,data:[0,10,11,12,27,31,33,51],decor:53,def:14,defin:[40,41,45],definit:40,delimit:16,dequ:11,describ:[10,51],develop:2,dict:50,dictionari:[11,12,22],did:4,differ:19,difference_fanout:19,dimens:[27,32],dimension:[27,28,31,37],displai:47,distanc:32,document:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50,51,52,53],doe:1,easi:[55,56],elif:9,ellipsi:31,els:[9,13],encod:20,end:[6,63],enhanc:53,enrich:53,enumer:17,environ:[2,4],essenti:[8,58,60],estim:35,exampl:[5,49],exercis:[0,8,9,13,14,15,17,25,26,47,48],express:[9,15],extend:22,extens:19,extra:22,familiar:5,fanout:19,fewer:27,figur:47,file:49,first:52,fixtur:53,flow:16,fly:15,form:40,format:[7,8],framework:53,from:33,gener:[15,22,40],get:57,github:[55,56],given:12,glob:49,good:50,googl:50,grade:0,guid:[7,50],handl:[22,25],hint:50,how:29,hypothesi:51,ident:41,iii:11,imag:47,immut:26,improv:8,indent:50,index:[25,27,28,31],indic:[25,27,55],inform:3,inherit:[42,45],inlin:[9,14],input:22,insert:32,inspect:12,instal:[1,4,48],instanc:[41,44],integ:[8,27,28,31],integr:2,interfac:46,interpret:1,intra:48,introduc:[1,8,15,16,25,27,31,34],introduct:[3,4,10,43,52],isn:[55,56],iter:[15,17,29],itertool:18,join:33,jupyt:[5,47],just:4,kei:[12,50],keyword:[14,37],lab:5,languag:[1,5],learn:2,level:41,like:[46,55,56],linear:37,link:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50,51,52,53],linspac:33,list:[0,3,8,10,15,19,38,50],liter:50,load:49,logic:[8,9,37],loop:[13,19,32],major:29,manag:48,manipul:27,map:12,margin:21,markdown:5,math:8,mathemat:[37,46],matplotlib:47,mean:[1,55,56],measur:36,merg:22,mess:3,method:[41,44,46],minor:22,mode:49,model:36,modul:[8,11,48,50,57,58,59,60,61,62,63,64],more:12,multi:37,multipl:[14,26,27],mutabl:26,mutat:8,name:[11,14,26,50],neg:27,nest:15,newaxi:[31,32],next:15,non:9,none:[8,50],notat:8,note:43,notebook:[5,47],noth:50,numba:6,number:[3,8,14,22],numer:[6,8,12],numpi:[6,31,33,37,49,50,60],object:[8,9,14,26,31,32,38,40,41,43,45,46,47,49,62],odd:63,offici:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50,51,52,53],ones:33,open:49,oper:[0,8,9,11,31,37,45,46],optim:[22,32,37],option:50,order:[12,29],organ:53,orient:[38,43,45,62],other:5,our:[52,53,64],out:[25,31,52],output:50,over:[15,29],overload:45,own:[15,48],packag:[48,53],pairwis:32,palindrom:23,parameter:53,part:[10,11,12],path:49,pathlib:49,pep8:50,percentag:21,perform:31,pickl:49,pip:48,pitfal:13,place:[28,31],plai:[3,35],plot:47,plymi:[55,56],point:8,popul:53,posit:14,potenti:13,precis:[8,12],problem:[22,35,59,61],produc:31,program:[1,38,43,45,62],pyplot:47,pytest:53,python:[0,1,3,4,6,8,16,18,33,48,49,50,53,55,56,57,58],pythonpath:48,quack:50,quick:7,radd:45,random:33,rang:15,read:[8,9,11,12,13,14,15,17,18,25,26,27,28,31,32,35,37,40,41,44,45,47,48,49,50,51,52,53],readabl:8,recommend:2,referenc:26,rel:48,relev:35,remark:6,represent:46,reshap:27,retriev:12,risk:31,row:29,rule:32,run:[5,53],sampl:33,save:[47,49],scheme:28,scientif:8,scope:[16,24],script:1,self:44,sequenc:[8,25,33],sequenti:[10,33,37],server:5,set:[2,11,50],shadow:24,shop:38,should:52,shouldn:[55,56],simpl:[0,22,32],site:48,size:32,slice:[0,25,27,31],solut:[8,9,11,12,13,14,15,17,18,19,20,21,22,23,25,26,27,28,31,32,35,36,37,40,41,44,45,47,48,49,50,51,52,53],sourc:[52,53],space:50,special:46,specifi:[14,31,33,37,49],start:57,statement:[8,9,14,48,52],store:[12,15],string:[0,3,8,20,46],structur:[10,11,12],studio:5,style:50,subplot:47,suit:53,summari:[1,6,8,39,42],suppli:27,support:5,syntax:53,tabl:55,term:39,terminolog:43,test:[52,53,64],text:49,textbook:[55,56],than:27,thi:[4,55,56],time:12,tip:[23,35],togeth:33,too:[55,56],travers:29,trick:17,truth:9,tupl:[10,11,15,25,31,50],two:[22,27],type:[0,8,25,26,33,43,50],unari:37,underli:31,understand:[8,37],union:50,unoptim:32,unpack:17,unvector:[35,36],using:[15,19],util:[32,53],valid:26,valu:[9,12,14,50],variabl:[24,26],variou:0,vector:[35,36,37],version:0,via:28,view:31,visual:5,warn:12,what:[1,2,4,12,50,55,56],whitespac:16,why:[1,52],within:[21,53],word:12,work:[6,17,25,40,49,52],write:[49,50,52],you:[2,55,56],your:[15,48],yourself:5,zero:[22,27,33]}}) \ No newline at end of file diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree index 2901885f..8edd98db 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree index 2b44335b..94840c07 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/GettingStartedWithPython.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree index 9123377b..b911e312 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree index f7aac1e1..b087ca0b 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Informal_Intro_Python.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree index 9b4c0976..b7d9abec 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Installing_Python.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree index 7ed4d74c..c46058ba 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Jupyter_Notebooks.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree index bab50111..ea268b6c 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/Numerical_Work_In_Python.doctree differ diff --git a/docs_backup/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree b/docs_backup/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree index 0331c9d8..e0cd10f7 100644 Binary files a/docs_backup/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree and b/docs_backup/.doctrees/Module1_GettingStartedWithPython/SiteFormatting.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree index 3a31b9f4..d0152ce2 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Basic_Objects.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree index 49846bb0..6d23e5c5 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/ConditionalStatements.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree index 907be265..f0735840 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree index 9ff612cc..ad59d9a5 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree index 311528cc..ad1b16f8 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree index 1dabff82..c305c4ba 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/ForLoops.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Functions.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Functions.doctree index e5197247..3ed93a2c 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Functions.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Functions.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree index 2b552a55..79116ec5 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Generators_and_Comprehensions.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Introduction.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Introduction.doctree index 4945e045..a016e414 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Introduction.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Introduction.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Iterables.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Iterables.doctree index 77707304..9069c11a 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Iterables.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Iterables.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Itertools.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Itertools.doctree index 123a1592..b650001d 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Itertools.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Itertools.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree index 5161053a..111c0b06 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/DifferenceFanout.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree index a123ce19..74502d12 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/EncodeAsString.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree index 6ff79b19..841ae59a 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MarginPercentage.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree index 55364d99..f4fc253f 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/MergeMaxDicts.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree index eeb5adaa..82de2686 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Problems/Palindrome.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Scope.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Scope.doctree index ccf5565c..7365ebbe 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Scope.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Scope.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree index 962ef728..f4dcf0ab 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/SequenceTypes.doctree differ diff --git a/docs_backup/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree b/docs_backup/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree index 9596ef04..a186f0de 100644 Binary files a/docs_backup/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree and b/docs_backup/.doctrees/Module2_EssentialsOfPython/Variables_and_Assignment.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree index 757c5d83..0156d7a6 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree index 1ca2c3ea..5829f29c 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/AdvancedIndexing.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree index 777ef364..a51e577c 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/ArrayTraversal.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree index 68e77426..ea18080b 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicArrayAttributes.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree index a4f501ad..0e40761e 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/BasicIndexing.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree index 9af2245e..dd124c77 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/Broadcasting.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree index 568c8a9b..51533ca5 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree index 2b044fca..5b74d7f8 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/IntroducingTheNDarray.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree index 5df708b9..72817dcc 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/Approximating_pi.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree index 0d1a1fa5..0859ad63 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/Problems/ComputeAccuracy.doctree differ diff --git a/docs_backup/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree b/docs_backup/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree index 73708327..77612c7b 100644 Binary files a/docs_backup/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree and b/docs_backup/.doctrees/Module3_IntroducingNumpy/VectorizedOperations.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/Applications_of_OOP.doctree b/docs_backup/.doctrees/Module4_OOP/Applications_of_OOP.doctree index bb5f80a1..7f595c01 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/Applications_of_OOP.doctree and b/docs_backup/.doctrees/Module4_OOP/Applications_of_OOP.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/Brief_Review.doctree b/docs_backup/.doctrees/Module4_OOP/Brief_Review.doctree index 604722b6..bf63858b 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/Brief_Review.doctree and b/docs_backup/.doctrees/Module4_OOP/Brief_Review.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/ClassDefinition.doctree b/docs_backup/.doctrees/Module4_OOP/ClassDefinition.doctree index ce39f798..16a0f0f6 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/ClassDefinition.doctree and b/docs_backup/.doctrees/Module4_OOP/ClassDefinition.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/ClassInstances.doctree b/docs_backup/.doctrees/Module4_OOP/ClassInstances.doctree index b5db43c7..d90356db 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/ClassInstances.doctree and b/docs_backup/.doctrees/Module4_OOP/ClassInstances.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/Inheritance.doctree b/docs_backup/.doctrees/Module4_OOP/Inheritance.doctree index d3f0901e..26eb12b3 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/Inheritance.doctree and b/docs_backup/.doctrees/Module4_OOP/Inheritance.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/Introduction_to_OOP.doctree b/docs_backup/.doctrees/Module4_OOP/Introduction_to_OOP.doctree index 0725ed98..d693196a 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/Introduction_to_OOP.doctree and b/docs_backup/.doctrees/Module4_OOP/Introduction_to_OOP.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/Methods.doctree b/docs_backup/.doctrees/Module4_OOP/Methods.doctree index 9386d5d4..520da9d2 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/Methods.doctree and b/docs_backup/.doctrees/Module4_OOP/Methods.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree b/docs_backup/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree index 2f61b9a8..9a9c6a2e 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree and b/docs_backup/.doctrees/Module4_OOP/ObjectOrientedProgramming.doctree differ diff --git a/docs_backup/.doctrees/Module4_OOP/Special_Methods.doctree b/docs_backup/.doctrees/Module4_OOP/Special_Methods.doctree index b0d77eee..ea0d5d9b 100644 Binary files a/docs_backup/.doctrees/Module4_OOP/Special_Methods.doctree and b/docs_backup/.doctrees/Module4_OOP/Special_Methods.doctree differ diff --git a/docs_backup/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree b/docs_backup/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree index f920ee25..9aed3db8 100644 Binary files a/docs_backup/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree and b/docs_backup/.doctrees/Module5_OddsAndEnds/Matplotlib.doctree differ diff --git a/docs_backup/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree b/docs_backup/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree index 2562c73b..b6f4bd66 100644 Binary files a/docs_backup/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree and b/docs_backup/.doctrees/Module5_OddsAndEnds/Modules_and_Packages.doctree differ diff --git a/docs_backup/.doctrees/Module5_OddsAndEnds/Testing_Code_Scratch.doctree b/docs_backup/.doctrees/Module5_OddsAndEnds/Testing_Code_Scratch.doctree new file mode 100644 index 00000000..eb4c5927 Binary files /dev/null and b/docs_backup/.doctrees/Module5_OddsAndEnds/Testing_Code_Scratch.doctree differ diff --git a/docs_backup/.doctrees/Module5_OddsAndEnds/Testing_Your_Code.doctree b/docs_backup/.doctrees/Module5_OddsAndEnds/Testing_Your_Code.doctree new file mode 100644 index 00000000..1eb3f7aa Binary files /dev/null and b/docs_backup/.doctrees/Module5_OddsAndEnds/Testing_Your_Code.doctree differ diff --git a/docs_backup/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree b/docs_backup/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree index 84055f60..40485538 100644 Binary files a/docs_backup/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree and b/docs_backup/.doctrees/Module5_OddsAndEnds/WorkingWithFiles.doctree differ diff --git a/docs_backup/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree b/docs_backup/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree index 4ab77e0d..9e56eca8 100644 Binary files a/docs_backup/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree and b/docs_backup/.doctrees/Module5_OddsAndEnds/Writing_Good_Code.doctree differ diff --git a/docs_backup/.doctrees/Module6_Testing/Intro_to_Testing.doctree b/docs_backup/.doctrees/Module6_Testing/Intro_to_Testing.doctree new file mode 100644 index 00000000..21176d5f Binary files /dev/null and b/docs_backup/.doctrees/Module6_Testing/Intro_to_Testing.doctree differ diff --git a/docs_backup/.doctrees/Module6_Testing/Pytest.doctree b/docs_backup/.doctrees/Module6_Testing/Pytest.doctree new file mode 100644 index 00000000..ede71ddb Binary files /dev/null and b/docs_backup/.doctrees/Module6_Testing/Pytest.doctree differ diff --git a/docs_backup/.doctrees/changes.doctree b/docs_backup/.doctrees/changes.doctree new file mode 100644 index 00000000..0af8ba41 Binary files /dev/null and b/docs_backup/.doctrees/changes.doctree differ diff --git a/docs_backup/.doctrees/environment.pickle b/docs_backup/.doctrees/environment.pickle index 3435cb95..5ae8950a 100644 Binary files a/docs_backup/.doctrees/environment.pickle and b/docs_backup/.doctrees/environment.pickle differ diff --git a/docs_backup/.doctrees/index.doctree b/docs_backup/.doctrees/index.doctree index 7de2d754..b83baaab 100644 Binary files a/docs_backup/.doctrees/index.doctree and b/docs_backup/.doctrees/index.doctree differ diff --git a/docs_backup/.doctrees/intro.doctree b/docs_backup/.doctrees/intro.doctree index 15b6cc0c..1cc79017 100644 Binary files a/docs_backup/.doctrees/intro.doctree and b/docs_backup/.doctrees/intro.doctree differ diff --git a/docs_backup/.doctrees/module_1.doctree b/docs_backup/.doctrees/module_1.doctree index 5bb04ecb..c1fe881a 100644 Binary files a/docs_backup/.doctrees/module_1.doctree and b/docs_backup/.doctrees/module_1.doctree differ diff --git a/docs_backup/.doctrees/module_2.doctree b/docs_backup/.doctrees/module_2.doctree index 52cd1d1e..be909990 100644 Binary files a/docs_backup/.doctrees/module_2.doctree and b/docs_backup/.doctrees/module_2.doctree differ diff --git a/docs_backup/.doctrees/module_2_problems.doctree b/docs_backup/.doctrees/module_2_problems.doctree index cfab9baf..418bd5b2 100644 Binary files a/docs_backup/.doctrees/module_2_problems.doctree and b/docs_backup/.doctrees/module_2_problems.doctree differ diff --git a/docs_backup/.doctrees/module_3.doctree b/docs_backup/.doctrees/module_3.doctree index 716858e1..aab64ab4 100644 Binary files a/docs_backup/.doctrees/module_3.doctree and b/docs_backup/.doctrees/module_3.doctree differ diff --git a/docs_backup/.doctrees/module_3_problems.doctree b/docs_backup/.doctrees/module_3_problems.doctree index c9e96cfc..370eb14c 100644 Binary files a/docs_backup/.doctrees/module_3_problems.doctree and b/docs_backup/.doctrees/module_3_problems.doctree differ diff --git a/docs_backup/.doctrees/module_4.doctree b/docs_backup/.doctrees/module_4.doctree index 47179949..d4092341 100644 Binary files a/docs_backup/.doctrees/module_4.doctree and b/docs_backup/.doctrees/module_4.doctree differ diff --git a/docs_backup/.doctrees/module_5.doctree b/docs_backup/.doctrees/module_5.doctree index 733088f6..404a2a53 100644 Binary files a/docs_backup/.doctrees/module_5.doctree and b/docs_backup/.doctrees/module_5.doctree differ diff --git a/docs_backup/.doctrees/module_6.doctree b/docs_backup/.doctrees/module_6.doctree new file mode 100644 index 00000000..49561460 Binary files /dev/null and b/docs_backup/.doctrees/module_6.doctree differ diff --git a/docs_backup/.doctrees/nbsphinx/Module1_GettingStartedWithPython_Jupyter_Notebooks_9_0.png b/docs_backup/.doctrees/nbsphinx/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_0.png similarity index 100% rename from docs_backup/.doctrees/nbsphinx/Module1_GettingStartedWithPython_Jupyter_Notebooks_9_0.png rename to docs_backup/.doctrees/nbsphinx/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_0.png diff --git a/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html b/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html index f7f2d0a6..a323c24e 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python.html @@ -97,6 +97,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html b/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html index b3853caa..07a4eb82 100644 --- a/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html +++ b/docs_backup/Module1_GettingStartedWithPython/GettingStartedWithPython.html @@ -116,6 +116,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -294,7 +296,7 @@

    Why Python?int main() { std::vector<int> a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - std::cout << std::accumulate(a.begin(), e.end(), 0) << std::endl; + std::cout << std::accumulate(a.begin(), a.end(), 0) << std::endl; }

    diff --git a/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html b/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html index fd33c535..4c23350c 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html +++ b/docs_backup/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html @@ -116,6 +116,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -238,33 +240,33 @@

    Recommended IDEs
  • can be resource-heavy, especially for a laptop
  • may be overwhelming to new users (but has good documentation and tutorials)
  • +
  • Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers
  • Visual Studio Code with the Python extension: A lightweight, highly customizable IDE.

    Pros

    • lightweight and elegant
    • -
    • works with many different languages, so you only need to familiarize yourself with one IDE
    • +
    • completely free
    • +
    • works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer
    • a huge number of extensions can be downloaded to add functionality to the editor; these are created by a large community of open-source developers.
    • +
    • has native support for Jupyter notebooks, meaning that you get VSCode’s intellisense, debugger, and ability to inspect variables, all in a notebook.

    Cons

      -
    • currently less polished and less powerful than PyCharm, although Microsoft is now formally supporting the Python extension
    • -
    • can require some tinkering to get features working
    • +
    • configuring VSCode for python development can have a moderate learning curve for newcomers
    • +
    • many features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm

    Takeaway:

    Integrated Development Environments (IDEs) provide powerful tools for helping you write well-formatted and typo-free code. We recommend using PyCharm Community Edition or Visual Studio Code (with the Python extension installed) for your Python IDE.

    -
    -

    Jupyter Lab:

    -

    Jupyter Lab is a new IDE that is being developed by the same team that develops the Jupyter Notebook. It aims to mix the polish and power of a traditional IDE, along with the convenience and great utility of the notebook environment. As of writing this, Jupyter Lab is still in the beta release phase. Given the massive popularity of Jupyter Notebook, Jupyter Lab will likely become a widely used IDE, quickly.

    -

    diff --git a/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html b/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html index 10a7170f..e6c8437d 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Informal_Intro_Python.html @@ -114,6 +114,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html b/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html index 36ceca32..b339ef72 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Installing_Python.html @@ -114,6 +114,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html b/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html index df76bda4..72308c11 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html +++ b/docs_backup/Module1_GettingStartedWithPython/Jupyter_Notebooks.html @@ -6,7 +6,7 @@ - + @@ -100,12 +100,14 @@
  • Installing Python
  • An Informal Introduction to Python
  • Jupyter Notebooks @@ -119,6 +121,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -414,11 +418,19 @@

    Jupyter Notebooks +

    Jupyter Lab

    +

    Jupyter lab is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. Among its useful features and polished user interface - compared to that a Jupyter notebook server - Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. This is facilitates effective data +science work flows.

    +

    It is recommended that you peruse the Jupyter lab documentation to get a feel for all of its added capabilities.

    +

    The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical. Both Jupyter notebook and Jupyter lab should already be installed via Anaconda.

    +

    Running a Notebook Server & Creating a Notebook

    +

    Enough gushing about Jupyter notebooks. Let’s start using them!

    In your terminal, navigate to a directory (a.k.a folder) that you are okay creating files in. If you don’t know how to do this, Google it!

    Once you are in the desired directory, execute in your terminal (type the following, and then hit <ENTER>): jupyter notebook

    +

    Alternatively, if you want to work in Jupyter lab, run: jupyter lab

    You should see some text appear in your terminal:

    Starting a jupyter notebook server on your machine

    This is a “notebook server” that is running on your machine - it basically handles all of the communication between your browser and your machine. A new window or tab should open in your web browser, which looks like a file explorer.

    @@ -514,7 +526,7 @@

    An Example Notebook

    -../_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_9_0.png +../_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_0.png

    Notice that this notebook interface is great for making adjustments to this plot. You can easily change the color or line-style of the plot and redraw it without having to recompute the functions. You simply re-execute the cell containing the plot code. This is especially nice when the numerical computations required to generate the curves are costly.

    @@ -562,6 +574,10 @@

    Using Jupyter Notebooks with Other Languageshere. It should be noted that these efforts are not all equally mature. For instance, whereas the Python and Julia kernels are robust, the Haskell kernel cannot run natively on Windows machines, and the C++ kernel is still in early development, as of writing this.

    +
    +

    Jupyter Notebook Support in Visual Studio Code

    +

    Native Jupyter notebook support was recently added to Visual Studio Code. This means that you can now edit Jupyter notebooks within the Visual Studio Code IDE, and that you will benefit from added features like code-completion, debugging, and variable inspection.

    +
    diff --git a/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html b/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html index 05084617..fdaf624b 100644 --- a/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html +++ b/docs_backup/Module1_GettingStartedWithPython/Numerical_Work_In_Python.html @@ -97,6 +97,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module1_GettingStartedWithPython/SiteFormatting.html b/docs_backup/Module1_GettingStartedWithPython/SiteFormatting.html index f0de554a..bc19030c 100644 --- a/docs_backup/Module1_GettingStartedWithPython/SiteFormatting.html +++ b/docs_backup/Module1_GettingStartedWithPython/SiteFormatting.html @@ -109,6 +109,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Basic_Objects.html b/docs_backup/Module2_EssentialsOfPython/Basic_Objects.html index 557c12fb..edf36355 100644 --- a/docs_backup/Module2_EssentialsOfPython/Basic_Objects.html +++ b/docs_backup/Module2_EssentialsOfPython/Basic_Objects.html @@ -150,6 +150,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/ConditionalStatements.html b/docs_backup/Module2_EssentialsOfPython/ConditionalStatements.html index 888baa74..1444116b 100644 --- a/docs_backup/Module2_EssentialsOfPython/ConditionalStatements.html +++ b/docs_backup/Module2_EssentialsOfPython/ConditionalStatements.html @@ -128,6 +128,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/DataStructures.html b/docs_backup/Module2_EssentialsOfPython/DataStructures.html index ac16d222..7253a483 100644 --- a/docs_backup/Module2_EssentialsOfPython/DataStructures.html +++ b/docs_backup/Module2_EssentialsOfPython/DataStructures.html @@ -125,6 +125,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html b/docs_backup/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html index 48fdc84c..df11f991 100644 --- a/docs_backup/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html +++ b/docs_backup/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.html @@ -133,6 +133,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html b/docs_backup/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html index ce76be2b..4235cdc3 100644 --- a/docs_backup/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html +++ b/docs_backup/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.html @@ -134,6 +134,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/ForLoops.html b/docs_backup/Module2_EssentialsOfPython/ForLoops.html index 9947d1ed..9db6cfaf 100644 --- a/docs_backup/Module2_EssentialsOfPython/ForLoops.html +++ b/docs_backup/Module2_EssentialsOfPython/ForLoops.html @@ -127,6 +127,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Functions.html b/docs_backup/Module2_EssentialsOfPython/Functions.html index af03f7d9..a4c9dd7a 100644 --- a/docs_backup/Module2_EssentialsOfPython/Functions.html +++ b/docs_backup/Module2_EssentialsOfPython/Functions.html @@ -136,6 +136,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -321,7 +323,7 @@

    The def<

    The return Statement

    -

    In general, any Python object can follow a function’s return statement. Furthermore, an empty return statement can be specified, or the return statement of a function can be omitted altogether. In both of these cases, the function will return the ``None`` object.

    +

    In general, any Python object can follow a function’s return statement. Furthermore, an empty return statement can be specified, or the return statement of a function can be omitted altogether. In both of these cases, the function will return the None object.

    # this function returns `None`
     # an "empty" return statement
     def f():
    diff --git a/docs_backup/Module2_EssentialsOfPython/Generators_and_Comprehensions.html b/docs_backup/Module2_EssentialsOfPython/Generators_and_Comprehensions.html
    index 38fe390f..f0bd538e 100644
    --- a/docs_backup/Module2_EssentialsOfPython/Generators_and_Comprehensions.html
    +++ b/docs_backup/Module2_EssentialsOfPython/Generators_and_Comprehensions.html
    @@ -140,6 +140,8 @@
     
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Introduction.html b/docs_backup/Module2_EssentialsOfPython/Introduction.html index 6ddc84dc..1a13e140 100644 --- a/docs_backup/Module2_EssentialsOfPython/Introduction.html +++ b/docs_backup/Module2_EssentialsOfPython/Introduction.html @@ -120,6 +120,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Iterables.html b/docs_backup/Module2_EssentialsOfPython/Iterables.html index 84fa80eb..c2579c7f 100644 --- a/docs_backup/Module2_EssentialsOfPython/Iterables.html +++ b/docs_backup/Module2_EssentialsOfPython/Iterables.html @@ -127,6 +127,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Itertools.html b/docs_backup/Module2_EssentialsOfPython/Itertools.html index aa436310..181f2269 100644 --- a/docs_backup/Module2_EssentialsOfPython/Itertools.html +++ b/docs_backup/Module2_EssentialsOfPython/Itertools.html @@ -121,6 +121,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Problems/DifferenceFanout.html b/docs_backup/Module2_EssentialsOfPython/Problems/DifferenceFanout.html index 43240d2e..bec385da 100644 --- a/docs_backup/Module2_EssentialsOfPython/Problems/DifferenceFanout.html +++ b/docs_backup/Module2_EssentialsOfPython/Problems/DifferenceFanout.html @@ -113,6 +113,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Problems/EncodeAsString.html b/docs_backup/Module2_EssentialsOfPython/Problems/EncodeAsString.html index bdbe1e80..d8ece4dd 100644 --- a/docs_backup/Module2_EssentialsOfPython/Problems/EncodeAsString.html +++ b/docs_backup/Module2_EssentialsOfPython/Problems/EncodeAsString.html @@ -111,6 +111,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Problems/MarginPercentage.html b/docs_backup/Module2_EssentialsOfPython/Problems/MarginPercentage.html index 6d1f28a9..1da966be 100644 --- a/docs_backup/Module2_EssentialsOfPython/Problems/MarginPercentage.html +++ b/docs_backup/Module2_EssentialsOfPython/Problems/MarginPercentage.html @@ -111,6 +111,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html b/docs_backup/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html index 11a9aca3..6d2e1bdf 100644 --- a/docs_backup/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html +++ b/docs_backup/Module2_EssentialsOfPython/Problems/MergeMaxDicts.html @@ -120,6 +120,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Problems/Palindrome.html b/docs_backup/Module2_EssentialsOfPython/Problems/Palindrome.html index fddcfe82..660f4043 100644 --- a/docs_backup/Module2_EssentialsOfPython/Problems/Palindrome.html +++ b/docs_backup/Module2_EssentialsOfPython/Problems/Palindrome.html @@ -112,6 +112,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Scope.html b/docs_backup/Module2_EssentialsOfPython/Scope.html index 7f2b21aa..4684dd87 100644 --- a/docs_backup/Module2_EssentialsOfPython/Scope.html +++ b/docs_backup/Module2_EssentialsOfPython/Scope.html @@ -121,6 +121,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/SequenceTypes.html b/docs_backup/Module2_EssentialsOfPython/SequenceTypes.html index 19324d74..70259204 100644 --- a/docs_backup/Module2_EssentialsOfPython/SequenceTypes.html +++ b/docs_backup/Module2_EssentialsOfPython/SequenceTypes.html @@ -128,6 +128,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module2_EssentialsOfPython/Variables_and_Assignment.html b/docs_backup/Module2_EssentialsOfPython/Variables_and_Assignment.html index 3a7be27a..19e16262 100644 --- a/docs_backup/Module2_EssentialsOfPython/Variables_and_Assignment.html +++ b/docs_backup/Module2_EssentialsOfPython/Variables_and_Assignment.html @@ -126,6 +126,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html b/docs_backup/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html index 860c0bed..3e8d92f9 100644 --- a/docs_backup/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html +++ b/docs_backup/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.html @@ -130,6 +130,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/AdvancedIndexing.html b/docs_backup/Module3_IntroducingNumpy/AdvancedIndexing.html index 29ccefe0..a2b0bbea 100644 --- a/docs_backup/Module3_IntroducingNumpy/AdvancedIndexing.html +++ b/docs_backup/Module3_IntroducingNumpy/AdvancedIndexing.html @@ -124,6 +124,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/ArrayTraversal.html b/docs_backup/Module3_IntroducingNumpy/ArrayTraversal.html index c5ba0f18..282dd400 100644 --- a/docs_backup/Module3_IntroducingNumpy/ArrayTraversal.html +++ b/docs_backup/Module3_IntroducingNumpy/ArrayTraversal.html @@ -116,6 +116,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.html b/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.html index 11bf076a..917d749a 100644 --- a/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.html +++ b/docs_backup/Module3_IntroducingNumpy/BasicArrayAttributes.html @@ -115,6 +115,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html b/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html index 8f506440..ea2dca95 100644 --- a/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html +++ b/docs_backup/Module3_IntroducingNumpy/BasicIndexing.html @@ -130,6 +130,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/Broadcasting.html b/docs_backup/Module3_IntroducingNumpy/Broadcasting.html index 242168fe..fca97027 100644 --- a/docs_backup/Module3_IntroducingNumpy/Broadcasting.html +++ b/docs_backup/Module3_IntroducingNumpy/Broadcasting.html @@ -129,6 +129,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -602,16 +604,16 @@

    Pairwise Distances Using For-Loops
    def pairwise_dists_looped(x, y):
         """  Computing pairwise distances using for-loops
     
    -         Parameters
    -         ----------
    -         x : numpy.ndarray, shape=(M, D)
    -         y : numpy.ndarray, shape=(N, D)
    +     Parameters
    +     ----------
    +     x : numpy.ndarray, shape=(M, D)
    +     y : numpy.ndarray, shape=(N, D)
     
    -         Returns
    -         -------
    -         numpy.ndarray, shape=(M, N)
    -             The Euclidean distance between each pair of
    -             rows between `x` and `y`."""
    +     Returns
    +     -------
    +     numpy.ndarray, shape=(M, N)
    +         The Euclidean distance between each pair of
    +         rows between `x` and `y`."""
         # `dists[i, j]` will store the Euclidean
         # distance between  `x[i]` and `y[j]`
         dists = np.empty((5, 6))
    @@ -653,18 +655,18 @@ 

    Pairwise Distances Using Broadcasting (Unoptimized)
    def pairwise_dists_crude(x, y):
         """  Computing pairwise distances using vectorization.
     
    -         This method uses memory-inefficient broadcasting.
    +     This method uses memory-inefficient broadcasting.
     
    -         Parameters
    -         ----------
    -         x : numpy.ndarray, shape=(M, D)
    -         y : numpy.ndarray, shape=(N, D)
    +     Parameters
    +     ----------
    +     x : numpy.ndarray, shape=(M, D)
    +     y : numpy.ndarray, shape=(N, D)
     
    -         Returns
    -         -------
    -         numpy.ndarray, shape=(M, N)
    -             The Euclidean distance between each pair of
    -             rows between `x` and `y`."""
    +     Returns
    +     -------
    +     numpy.ndarray, shape=(M, N)
    +         The Euclidean distance between each pair of
    +         rows between `x` and `y`."""
         # The use of `np.newaxis` here is equivalent to our
         # use of the `reshape` function
         return np.sqrt(np.sum((x[:, np.newaxis] - y[np.newaxis])**2, axis=2))
    @@ -723,22 +725,22 @@ 

    Optimized Pairwise Distances\((M, N)\) to do so! This is the memory-efficient, vectorized form - the stuff that dreams are made of. Let’s write the function that performs this computation in full.

    def pairwise_dists(x, y):
         """ Computing pairwise distances using memory-efficient
    -        vectorization.
    -
    -        Parameters
    -        ----------
    -        x : numpy.ndarray, shape=(M, D)
    -        y : numpy.ndarray, shape=(N, D)
    -
    -        Returns
    -        -------
    -        numpy.ndarray, shape=(M, N)
    -            The Euclidean distance between each pair of
    -            rows between `x` and `y`."""
    +    vectorization.
    +
    +    Parameters
    +    ----------
    +    x : numpy.ndarray, shape=(M, D)
    +    y : numpy.ndarray, shape=(N, D)
    +
    +    Returns
    +    -------
    +    numpy.ndarray, shape=(M, N)
    +        The Euclidean distance between each pair of
    +        rows between `x` and `y`."""
         dists = -2 * np.matmul(x, y.T)
    -    dists +=  np.sum(x**2, axis=1)[:, np.newaxis]
    +    dists += np.sum(x**2, axis=1)[:, np.newaxis]
         dists += np.sum(y**2, axis=1)
    -    return  np.sqrt(dists)
    +    return np.sqrt(dists)
     

    -

    This object is belongs to the NumPy-defined type numpy.ndarray.

    +

    This object belongs to the NumPy-defined type numpy.ndarray.

    # An ND-array belongs to the type `numpy.ndarray`
     >>> type(x)
     numpy.ndarray
    diff --git a/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html b/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html
    index 6180442e..eb234ed8 100644
    --- a/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html
    +++ b/docs_backup/Module3_IntroducingNumpy/Problems/Approximating_pi.html
    @@ -112,6 +112,8 @@
     
     
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html b/docs_backup/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html index 8193bb31..f2ee0586 100644 --- a/docs_backup/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html +++ b/docs_backup/Module3_IntroducingNumpy/Problems/ComputeAccuracy.html @@ -109,6 +109,8 @@
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module3_IntroducingNumpy/VectorizedOperations.html b/docs_backup/Module3_IntroducingNumpy/VectorizedOperations.html index 752f3aa7..7acbcad9 100644 --- a/docs_backup/Module3_IntroducingNumpy/VectorizedOperations.html +++ b/docs_backup/Module3_IntroducingNumpy/VectorizedOperations.html @@ -128,6 +128,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/Applications_of_OOP.html b/docs_backup/Module4_OOP/Applications_of_OOP.html index 3672c9ce..c7e80271 100644 --- a/docs_backup/Module4_OOP/Applications_of_OOP.html +++ b/docs_backup/Module4_OOP/Applications_of_OOP.html @@ -114,6 +114,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/Brief_Review.html b/docs_backup/Module4_OOP/Brief_Review.html index fde7ca8c..f1d51b60 100644 --- a/docs_backup/Module4_OOP/Brief_Review.html +++ b/docs_backup/Module4_OOP/Brief_Review.html @@ -111,6 +111,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/ClassDefinition.html b/docs_backup/Module4_OOP/ClassDefinition.html index 78982692..2b931275 100644 --- a/docs_backup/Module4_OOP/ClassDefinition.html +++ b/docs_backup/Module4_OOP/ClassDefinition.html @@ -117,6 +117,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/ClassInstances.html b/docs_backup/Module4_OOP/ClassInstances.html index 25d0a2cd..1bd1e19e 100644 --- a/docs_backup/Module4_OOP/ClassInstances.html +++ b/docs_backup/Module4_OOP/ClassInstances.html @@ -116,6 +116,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/Inheritance.html b/docs_backup/Module4_OOP/Inheritance.html index fa7a1761..1ed82b3f 100644 --- a/docs_backup/Module4_OOP/Inheritance.html +++ b/docs_backup/Module4_OOP/Inheritance.html @@ -115,6 +115,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/Introduction_to_OOP.html b/docs_backup/Module4_OOP/Introduction_to_OOP.html index 8881caf9..16005451 100644 --- a/docs_backup/Module4_OOP/Introduction_to_OOP.html +++ b/docs_backup/Module4_OOP/Introduction_to_OOP.html @@ -115,6 +115,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/Methods.html b/docs_backup/Module4_OOP/Methods.html index 5f818d3e..3f60b83f 100644 --- a/docs_backup/Module4_OOP/Methods.html +++ b/docs_backup/Module4_OOP/Methods.html @@ -120,6 +120,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module4_OOP/ObjectOrientedProgramming.html b/docs_backup/Module4_OOP/ObjectOrientedProgramming.html index fc1a5766..24321dac 100644 --- a/docs_backup/Module4_OOP/ObjectOrientedProgramming.html +++ b/docs_backup/Module4_OOP/ObjectOrientedProgramming.html @@ -97,6 +97,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -163,204 +165,6 @@ -
    -

    Testing Your Code

    -

    This section will introduce us to the critically-important and often-overlooked process of testing code. We will begin by considering the basic motivations behind writing tests. Next, we will study the basic anatomy of a test-function, including its nucleus: the assert statement. Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework pytest. This will inform how to structure our tests alongside our -Python project that we are developing, and will allow us to incisively run our tests with the press of a single button. Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. Finally, we will take a step back to consider some strategies for writing effective tests. Among these is a methodology that is near and dear to my heart: property-based testing. This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing -library Hypothesis waiting to greet us (adorned with the mad Hatter’s cap and all).

    -
    -

    Why Should We Write Tests?

    -

    With great power comes great responsibility: tests help us be responsible for the code that we create and that others will (hopefully) use.

    -

    The fact of the matter is that everyone already tests their code to some extent. After coding, say, a new function, it is only natural to contrive an input to feed it, and to check that it returns the output that you expected. To the extent that anyone would want to see evidence that their code works, we need not motivate the importance of testing.

    -

    Less obvious is the massive benefits that we stand to gain from formalizing this testing process. And by “formalizing”, we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. We will accumulate these functions into a “test suite” that we can run quickly and repeatedly.

    -

    There are plenty of practical details ahead for us to learn, so let’s expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite:

    -
      -
    • It saves us lots of time: > After you have devised a test scenario for your code, it may only take us a second or so to run it - perhaps we need only run a couple of Jupyter notebook cells to check the output. > However, this will quickly become unwieldy as we write more code and devise more test scenarios. > Soon we will be dissuaded from running our tests except for on rare occasions. > With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of -green check-marks (or red x’s…) will summarize the health of our project (insofar as our tests serve as good diagnostics). > This, of course, also means that we will find and fix bugs much faster! > In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost.
    • -
    • It increases the “shelf life” of our code: > If you’ve ever dusted off a project that you haven’t used for years (or perhaps only months or weeks…), you might know the tribulations of getting old code to work. > Perhaps, in the interim, new versions of your project’s dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project. > And perhaps we can’t even remember all of the ways in which our project is supposed to work. > Our test suite provides us -with a simple and incisive way to dive back into our work. > It will point us to any potential incompatibilities that have accumulated over time. > It also provides us with a large collection of detailed use-cases of our code; > we can read through our tests remind ourselves of the inner-workings of our project.
    • -
    • It will inform the design and usability of our project for the better: > Although it may not be obvious from the outset, writing testable code leads to writing better code. > This is, in part, because the process of writing tests gives us the opportunity to actually use our code under varied circumstances. > The process of writing tests will help us suss out cumbersome function interfaces, brittle statefulness, and redundant capabilities in our code. If we find it frustrating to use our -code within our tests, then surely others will find it frustrating to use in applied settings.
    • -
    • It makes it easier for others to contribute to a project: > Having a healthy test suite lowers the barrier to entry for a project. > A contributor can make improvements to the project and quickly check to see if they have broken it or changed any of its behavior.
    • -
    -

    This all sounds great, but where do we even begin to kick off the process of writing a test suite? Let’s start by seeing what constitutes a basic test function.

    +
    +
    [1]:
    +
    -
    -

    The Basic Anatomy of a Test Function

    -
    def count_vowels(x: str, include_y: bool = False) -> int:
    +
    +def test_count_vowels_basic():
    +    assert count_vowels("aA bB yY", include_y=False) == 2
    +    assert count_vowels("aA bB yY", include_y=True) == 4
    +    assert count_vowels("", include_y=True) == 0
    +
    +
    +
    +
    +
    [2]:
    +
    +
    +
    +def count_vowels(x: str, include_y: bool = False) -> int:
         """Returns the number of vowels contained in `x`
     
         Examples
    @@ -427,28 +419,65 @@ 

    The Basic Anatomy of a Test Function -

    SCRATCH

    -

    As we become capable Python users, we will naturally find ourselves moving away from writing short, trivial programs in favor of creating useful and increasingly-sophisticated projects. It is only naturally try using your code to verify its behavior. You may even devise several scenarios to exercise your project. Clearly this sort of testing need no justification; it is a ubiquitous practice among coders. Less obvious are the major pitfalls associated with this highly-manual means of testing.

    -

    Let’s consider some of the pitfalls of casual, manual tests. To do so, consider the following unfortunate scenario: you carefully run your code through several test scenarios and see that

    -
      -
    • Fortunately, it is exceedingly easy to convert this casual and flawed testing workflow to one that is far more powerful and efficient.
    • -
    -
    x += 2
    -
    -x+= 4
    +
    +
    [3]:
     
    +
    +count_vowels("happy", include_y=)
    +
    +
    +
    [ ]:
     
    -
    +>>> assert 0 in [1, 2, 3], "0 is not in the list"
    +
    +
    +
    +
    +
    [5]:
    +
    +
    +
    +a_list =[]
    +a_number = 22
    +a_string = "abcdef"
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +assert count_vowels(a_string) < a_number, f"Number of vowels in `a_string`, {count_vowels(a_string)} exceeds {a_number}"
    +
    +
    +
    +
    +
    [6]:
    +
    +
    +
    +assert count_vowels(a_string) < a_number/100, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}"
     
    +
    +
    +
    +
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-6-51c17da13eaa> in <module>
    +----> 1 assert count_vowels(a_string) < a_number/100, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}"
    +
    +AssertionError: Number of vowels, 2, exceeds 22
    +
    diff --git a/docs_backup/Module5_OddsAndEnds/Testing_Your_Code.html b/docs_backup/Module5_OddsAndEnds/Testing_Your_Code.html new file mode 100644 index 00000000..db62de0e --- /dev/null +++ b/docs_backup/Module5_OddsAndEnds/Testing_Your_Code.html @@ -0,0 +1,482 @@ + + + + + + + + + + + + + Testing Your Code — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    Testing Your Code

    +

    This section will introduce us to the critically-important and often-overlooked process of testing code. We will begin by considering some driving motivations for writing tests. Next, we will study the basic anatomy of a test-function, including the assert statement, which serves as the nucleus of our test functions. Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework pytest. This will inform how +we structure our tests alongside our Python project that we are developing; with pytest, we can incisively run our tests with the press of a single button. Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. Finally, we will take a step back to consider some strategies for writing effective tests. Among these is a methodology that is near and dear to my heart: property-based testing. This will take us down a bit of a rabbit hole, where we will find +the powerful property-based testing library Hypothesis waiting to greet us (adorned with the mad Hatter’s cap and all).

    +
    +

    Why Should We Write Tests?

    +

    With great power comes great responsibility: tests help us be responsible for the code that we create and that others will (hopefully) use.

    +

    The fact of the matter is that everyone already tests their code to some extent. After coding, say, a new function, it is only natural to contrive an input to feed it, and to check that it returns the output that you expected. To the extent that anyone would want to see evidence that their code works, we need not motivate the importance of testing.

    +

    Less obvious is the massive benefits that we stand to gain from formalizing this testing process. And by “formalizing”, we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. We will accumulate these functions into a “test suite” that we can run quickly and repeatedly.

    +

    There are plenty of practical details ahead for us to learn, so let’s expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite:

    +
      +
    • It saves us lots of time: > After you have devised a test scenario for your code, it may only take us a second or so to run it - perhaps we need only run a couple of Jupyter notebook cells to check the output. > However, this will quickly become unwieldy as we write more code and devise more test scenarios. > Soon we will be dissuaded from running our tests except for on rare occasions. > With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of +green check-marks (or red x’s…) will summarize the health of our project (insofar as our tests serve as good diagnostics). > This, of course, also means that we will find and fix bugs much faster! > In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost.
    • +
    • It increases the “shelf life” of our code: > If you’ve ever dusted off a project that you haven’t used for years (or perhaps only months or weeks…), you might know the tribulations of getting old code to work. > Perhaps, in the interim, new versions of our project’s dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project’s code. > And perhaps we can’t even remember all of the ways in which our project is supposed to work. > Our test suite provides +us with a simple and incisive way to dive back into our work. > It will point us to any potential incompatibilities that have accumulated over time. > It also provides us with a large collection of detailed use-cases of our code; > we can read through our tests remind ourselves of the inner-workings of our project.
    • +
    • It will inform the design and usability of our project for the better: > Although it may not be obvious from the outset, writing testable code leads to writing better code. > This is, in part, because the process of writing tests gives us the opportunity to actually use our code under varied circumstances. > The process of writing tests will help us suss out cumbersome function interfaces, brittle statefulness, and redundant capabilities in our code. If we find it frustrating to use our +code within our tests, then surely others will find it frustrating to use in applied settings.
    • +
    • It makes it easier for others to contribute to a project: > Having a healthy test suite lowers the barrier to entry for a project. > A contributor can make improvements to the project and quickly check to see if they have broken it or changed any of its behavior.
    • +
    +

    This all sounds great, but where do we even start the process writing a test suite? Let’s begin by seeing what constitutes a basic test function.

    +
    +
    +

    The Basic Anatomy of a Test Function

    +

    Let’s write a function that tests the following count_values code:

    +
    # Defining a function that we will be testing
    +
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    """Returns the number of vowels contained in `x`.
    +
    +    The vowel 'y' is included optionally.
    +
    +    Examples
    +    --------
    +    >>> count_vowels("happy")
    +    1
    +    >>> count_vowels("happy", include_y=True)
    +    2
    +    """
    +    vowels = set("aeiouAEIOU")
    +    if include_y:
    +        vowels.update("yY")
    +    return sum(1 for char in x if char in vowels)
    +
    +
    +

    (Note that we will be making use of type hinting to help document the interfaces of our functions. You may want to briefly review the linked material if this is unfamiliar to you)

    +

    For our most basic test, we can simply call count_values under various contrived inputs and assert that it returns the expected output. The desired behavior for this test function, upon being run, is to:

    +
      +
    • Raise an error if any of our assertions failed to hold true.
    • +
    • Complete “silently” if all of our assertions hold true (i.e. our test function will simply return None)
    • +
    +

    Here, we will be making use of Python’s assert statements, whose behavior will be easy to deduce from the context of this test alone; we will be formally introduced to them soon.

    +
    # Writing a test function for `count_vowels`
    +
    +def test_count_vowels_basic():
    +    assert count_vowels("aA bB yY", include_y=False) == 2
    +    assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +
    +

    To run this test, we simply call the function:

    +
    # running our test function
    +>>> test_count_vowels_basic()  # passes: returns None | fails: raises error
    +
    +
    +

    As described above, the fact our function runs and simply returns None means that our code has passed this test. We’ve written and run our very first test! It certainly isn’t the most robust test, but it is a good start.

    +

    Let’s look more carefully at the structure of test_count_vowels_basic. Note that this function doesn’t take in any inputs; thanks to Python’s scoping rules, we can reference our count_vowels function within our test as long as it is defined in the same “namespace” as test_count_vowels_basic. That is, we can either define count_vowels in the same .py file (or Jupyter notebook, if you are following +along with this material in a notebook) as test_count_vowels_basic, or we can import count_vowels from wherever it is defined, and into the file containing our test. The latter scenario is by far the most common one in practice. More on this later.

    +
    +

    Reading Comprehension: The Basic Anatomy of a Test

    +

    Add an additional assertion to the body of test_count_vowels_basic, which tests whether count_vowels handles the empty-string ("") case appropriately. Make sure to run your updated test to see if it passes.

    +
    +
    +

    Testing Our Tests

    +

    It is surprisingly easy to unwittingly write a test that always passes or that fails to test our code as we had intended. This is a particularly treacherous mistake to make as it leads us to falsely believe that our function is working as-expected. Thus a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior in such a way that our test ought to raise an error. Once we confirm that our test does indeed raise an error +as-expected, we restore the function to its original form and re-run the test and see that it passes.

    +

    We ought to mutate our function in a way that is trivial to undo; we can use of code-comments towards this end. All IDEs have the ability to “block-comment” selected code. In a Jupyter notebook code cell, we can highlight multiple lines of code and press CTRL + /: this will comment-out these lines of code. The same key-combination will also un-comment a highlighted block of +commented code.

    +
    +

    Reading Comprehension: Testing Your Test via Manual Mutation

    +

    Temporarily change the body of count_vowels such that the second assertion in test_count_vowels_basic raises an error. Run the test to confirm that the second assertion raises, and then restore count_vowels to its original form. Finally, rerun the test to see that count_vowels once again passes all of the assertions.

    +
    +

    With our first test function under our belt, it is time for us to clearly understand how assert statements work and how they should be used.

    +
    +
    +

    Assert Statements

    +

    Similar to return, def, or if, the term assert is a reserved term in the Python language. It has the following specialized behavior:

    +
    # demonstrating the rudimentary behavior of the `assert` statement
    +
    +# asserting an expression whose boolean-value is `True` will complete "silently"
    +>>> assert 1 < 2
    +
    +# asserting an expression whose boolean-value is `False` raises an error
    +>>> assert 2 < 1
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-5-c82711d5fe4d> in <module>
    +----> 1 assert 2 < 1
    +
    +AssertionError:
    +
    +# we can include an error message with our assertion
    +>>> assert 0 in [1, 2, 3], "0 is not in the list"
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-8-e72fb36dc785> in <module>
    +----> 1 assert 0 in [1, 2, 3], "0 is not in the list"
    +
    +AssertionError: 0 is not in the list
    +
    +
    +

    The general form of an assertion statement is:

    +
    assert <expression> [, <error-message>]
    +
    +
    +

    When an assertion statement is executed, the built-in bool function is called on the object that is returned by <expression>; if bool(<expression>) returns False, then an AssertionError is raised. If you included a string in the assertion statement - separated from <expression> by a comma - then this string will be printed as the error message.

    +

    See that the assertion statement:

    +
    assert expression, error_message
    +
    +
    +

    is effectively shorthand for the following code:

    +
    # long-form equivalent of: `assert expression, error_message`
    +if bool(expression) is False:
    +    raise AssertionError(error_message)
    +
    +
    +
    +

    Reading Comprehension: Assertions

    +

    Given the following objects:

    +
    a_list = []
    +a_number = 22
    +a_string = "abcdef"
    +
    +
    +

    Write two assertion statements, each one with the corresponding behavior:

    +
      +
    • asserts that a_list is not empty
    • +
    • asserts that the number of vowels in a_string is less than a_number; include and error message that prints the actual number of vowels
    • +
    +
    +
    +

    What is the Purpose of an Assertion?

    +

    In our code, an assertion should be used as a statement that is true unless there is a bug our code. It is plain to see that the assertions in test_count_vowels_basic fit this description. However, it can also be useful to include assertions within our source code itself. For instance, we know that count_vowels should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string. We can +explicitly assert that this is the case:

    +
    # an example of including an assertion within our source code
    +
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    vowels = set("aeiouAEIOU")
    +    if include_y:
    +        vowels.update("yY")
    +    count = sum(1 for char in x if char in vowels)
    +
    +    # This assertion should always be true: it is asserting that
    +    # the internal logic of our function is correct
    +    assert isinstance(count, int) and 0 <= count <= len(x)
    +    return count
    +
    +
    +

    Note that this assertion is not meant to check if the user passed bad inputs for x and include_y. Rather, it is meant to assert that our own internal logic holds true.

    +

    Admittedly, the count_vowels function is simple enough that the inclusion of this assertion is rather pedantic. That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base.

    +
    +
    +
    + +
    +

    Reading Comprehension Solutions

    +

    The Basic Anatomy of a Test: Solution

    +

    Add an additional assertion to the body of test_count_vowels_basic, which tests whether count_vowels handles the empty-string ("") case appropriately. Make sure to run your updated test to see if it passes.

    +
    def test_count_vowels_basic():
    +    assert count_vowels("aA bB yY", include_y=False) == 2
    +    assert count_vowels("aA bB yY", include_y=True) == 4
    +    assert count_vowels("", include_y=True) == 0
    +
    +
    +
    # running the test in a notebook-cell: the function should simply return
    +# `None` if all assertions hold true
    +>>> test_count_vowels_basic()
    +
    +
    +

    Testing Your Test via Manual Mutation: Solution

    +

    Temporarily change the body of count_vowels such that the second assertion in test_count_vowels_basic raises an error. > Let’s comment out the if include_y block in our code - this should prevent us from counting y’s, and thus should violate the second assertion in our test.

    +
    # Breaking the behavior of `include_y=True`
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    vowels = set("aeiouAEIOU")
    +    # if include_y:
    +    #    vowels.update("yY")
    +    return sum(1 for char in x if char in vowels)
    +
    +
    +
    # the second assertion should raise an error
    +>>> test_count_vowels_basic()
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-5-32301ff829e9> in <module>
    +----> 1 test_count_vowels_basic()
    +
    +<ipython-input-4-99ef0ca3d859> in test_count_vowels_basic()
    +      1 def test_count_vowels_basic():
    +      2     assert count_vowels("aA bB yY", include_y=False) == 2
    +----> 3     assert count_vowels("aA bB yY", include_y=True) == 4
    +
    +AssertionError:
    +
    +
    +
    +
    Great! That assertion really does help to ensure that we are counting y’s correctly.
    +

    Restore count_vowels to its original form and rerun the test to see that count_vowels once again passes all of the assertions.

    +
    # Restore the behavior of `include_y=True`
    +def count_vowels(x: str, include_y: bool = False) -> int:
    +    vowels = set("aeiouAEIOU")
    +    if include_y:
    +        vowels.update("yY")
    +    return sum(1 for char in x if char in vowels)
    +
    +
    +
    # confirming that we restored the proper behavior in `count_vowels`
    +>>> test_count_vowels_basic()
    +
    +
    +

    Assertions: Solution

    +
    a_list = []
    +a_number = 22
    +a_string = "abcdef"
    +
    +
    +

    Assert that a_list is not empty:

    +
    >>> assert a_list
    +---------------------------------------------------------------------------
    +AssertionError                            Traceback (most recent call last)
    +<ipython-input-10-2eba8294859e> in <module>
    +----> 1 assert a_list
    +
    +AssertionError:
    +
    +
    +
    +
    You may have written assert len(a_list) > 0 - this is also correct. However, recall that calling bool on any sequence (list, tuple, string, etc.) will return False if the sequence is empty. This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - that bool will be called on whatever the provided expression is.
    +

    Assert that the number of vowels in a_string is fewer than a_number; include and error message that prints the actual number of vowels:

    +
    >>> assert count_vowels(a_string) < a_number, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}"
    +
    +
    +
    +
    Note that we make use of an f-string as a convenient means for writing an informative error message.
    +
    +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs_backup/Module5_OddsAndEnds/WorkingWithFiles.html b/docs_backup/Module5_OddsAndEnds/WorkingWithFiles.html index 0069ca95..30364847 100644 --- a/docs_backup/Module5_OddsAndEnds/WorkingWithFiles.html +++ b/docs_backup/Module5_OddsAndEnds/WorkingWithFiles.html @@ -124,6 +124,8 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/Module5_OddsAndEnds/Writing_Good_Code.html b/docs_backup/Module5_OddsAndEnds/Writing_Good_Code.html index 667c6407..fe962795 100644 --- a/docs_backup/Module5_OddsAndEnds/Writing_Good_Code.html +++ b/docs_backup/Module5_OddsAndEnds/Writing_Good_Code.html @@ -128,6 +128,8 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -572,14 +574,15 @@

    What is It Good For? (Absolutely Nothing)count_vowels function in a library of code that we are developing, and we mistakenly think that the output of this function is a string that we want to capitalize. Our IDE will see that we are trying to capitalize an integer and will thus warn us:

    PyCharm uses type-hints to check our code for consistency

    -

    This saves us the trouble of having to run our code, hit an error, read through the stack trace, and debug our mistake. Instead, we immediately see our inconsistency get flagged. In fact, we probably never would have even made the mistake at all, as our IDE would have shown a list of integer-methods for us to choose from, and not string-methods. This would have likely alerted us to our misapprehension.

    +

    This saves us the trouble of having to run our code, hit an error, read through the stack trace, and debug our mistake. Instead, we immediately see our inconsistency get flagged. In fact, we probably never would have even made the mistake at all, as our IDE would have shown a list of integer-methods for us to choose from, and not string-methods. Type-hints would have likely alerted us to our misapprehension.

    It does not take long to experience the benefits of type-hinting through your IDE. This both accelerates your coding by informing you of the object types that you are working with on the fly, and helps to expose oversights in your code as soon as they are made.

    -

    Finally, it is also worthwhile to highlight the mypy project, which is used to perform static type-checking on your code based on your type-hints. That is, mypy will automatically traverse your code and find potential bugs by identifying type conflicts in your code (e.g. trying to capitalize an integer) by checking their annotated and inferred types. This tool is most useful for large-scale code bases. Companies like Dropbox make keen use of mypy to identify -inconsistencies in their code without having to hit runtime errors. Keep mypy in mind as you mature as a Python developer and find yourself working on projects of growing complexity.

    +

    Finally, it is also worthwhile to highlight two projects, mypy and pyright, which are used to perform static type-checking on your code based on your type-hints. That is, mypy and pyright will both automatically traverse your code and find potential bugs by identifying type conflicts in your code (e.g. trying to capitalize an integer) by checking their annotated and inferred types. These tools are especially useful for +large-scale code bases. Companies like Dropbox and Microsoft make keen use of static type-checking to identify inconsistencies in their code without having to hit runtime errors. Keep mypy, pyright, and other type-checking utilities in mind as you mature as a Python developer and find yourself working on projects of growing complexity. If you are using VSCode as your IDE, you +can install the pyright vscode extension to leverage type checking within your IDE.

    Takeaway:

    There is a simple syntax for annotating functions, class-methods, and variables with type-hints; this is a formal mechanism for documenting the types of objects that are expected as inputs to the function, as well as the return type of the function. It is critical to note that that type-hints are never enforced by Python - they only serve as a form of documentation.

    -

    That being said, IDEs have powerful abilities to inspect type-hints and to highlight potential inconsistencies in your code. These capabilities can greatly facilitate your code-development. There are also third-party libraries like mypy that can be used to provide more rigorous type enforcement in your code.

    +

    That being said, IDEs have powerful abilities to inspect type-hints and to highlight potential inconsistencies in your code. These capabilities can greatly facilitate your code-development. There are also third-party libraries like mypy and pyright that can be used to provide more rigorous type enforcement in your code.

    @@ -668,6 +671,19 @@

    Callable[[<a +

    +
    +

    Literal[<value>, ...]

    +
      +
    • What it hints: That the variable will be passed one of the exact values
    • +
    • Examples:
        +
      • Hint that a variable that will be the integer 1: Literal[1]
      • +
      • Hint that a variable that will be the either the string "sum" or the string "mean": Literal["sum", "mean"]
      • +
      • Hint that a variable that will be either the list [1, 2] or the string "abc": Literal[[1, 2], "abc"]
      • +
      +
    • +
    • Compatibility Note: The Literal type-hint was introduced in Python 3.8 - it is not available in earlier versions of Python.
    • +

    Let’s take, for example, a function that takes in:

    • a dictionary of student grades, which maps names (strings) to grades (list of floats)
    • @@ -750,7 +766,7 @@

      Writing Good Type-Hints (quack quack)the duck test: if your function is expecting a duck then hint for something that walks like a duck, quacks like a duck, etc. This will help you avoid writing type-hints that are overly narrow, and which are ultimately non-Pythonic in their strictness.

      To be more concrete, let’s revisit our count_vowels function:

      def count_vowels(x: str, include_y: bool = False) -> int:
      -    """Returns the number of vowels contained in `in_string`"""
      +    """Returns the number of vowels contained in `x`"""
           vowels = set("aeiouAEIOU")
           if include_y:
               vowels.update("yY")
      @@ -856,14 +872,16 @@ 

      The NumPy Documentation Style Parameters ---------- x : numpy.ndarray, shape=(M, D) - An optional description of ``x`` + An array of M, D-dimensional vectors. + y : numpy.ndarray, shape=(N, D) - An optional description of ``y`` + An array of N, D-dimensional vectors. Returns ------- numpy.ndarray, shape=(M, N) - The pairwise distances + The pairwise distances between the M rows of ``x`` and the N + rows of ``y``. Notes ----- @@ -907,7 +925,7 @@

      The NumPy Documentation Style Parameters ---------- - grade_book : Dict[str, List[float]] + grade_book : Dict[str, Iterable[float]] The dictionary (name -> grades) of all of the students' grades. diff --git a/docs_backup/Module6_Testing/Intro_to_Testing.html b/docs_backup/Module6_Testing/Intro_to_Testing.html new file mode 100644 index 00000000..6c81b74c --- /dev/null +++ b/docs_backup/Module6_Testing/Intro_to_Testing.html @@ -0,0 +1,640 @@ + + + + + + + + + + + + + Introduction to Testing — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + + + +
      +

      Introduction to Testing

      +

      This section will show us just how simple it is to write rudimentary tests. We need only recall some of Python’s basic scoping rules and introduce ourselves to the assert statement to write a genuine test function. That being said, we will quickly encounter some important questions to ponder. How do we know that our tests work? And, how do we know that our tests are effective? These questions will drive us deeper into the world of testing.

      +

      Before we hit the ground running, let’s take a moment to consider some motivations for testing out code.

      +
      +

      Why Should We Write Tests?

      +

      The fact of the matter is that it is intuitive for most people to test their code to some extent. After writing, say, a new function, it is only natural to contrive an input to feed it, and to check that the function returns the output that we expected. To the extent that one would want to see evidence that their code works, we need not motivate the importance of testing.

      +

      Less obvious are the massive benefits that we stand to gain from automating this testing process. And by “automating”, we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. We will accumulate these test functions into a “test suite” that we can run quickly and repeatedly.

      +

      There are plenty of practical details ahead for us to learn, so let’s expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite:

      +

      It saves us lots of time:

      +
      +

      After you have devised a test scenario for your code, it may only take us a second or so to run it; perhaps we need only run a couple of Jupyter notebook cells to verify the output of our code. This, however, will quickly become unwieldy as we write more code and devise more test scenarios. Soon we will be dissuaded from running our tests except for on rare occasions.

      +

      With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x’s…) will summarize the health of our project (insofar as our tests serve as good diagnostics). This, of course, also means that we will find and fix bugs much faster! In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost.

      +
      +

      It increases the “shelf life” of our code:

      +
      +
      If you’ve ever dusted off a project that you haven’t used for years (or perhaps only months or weeks…), you might know the tribulations of getting old code to work. Perhaps, in the interim, new versions of our project’s dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project’s code. And perhaps we can’t even remember all of the ways in which our project is supposed to work. Our test suite provides us with a simple and incisive way to dive back +into our work. It will point us to any potential incompatibilities that have accumulated over time. It also provides us with a large collection of detailed use-cases of our code; we can read through our tests and remind ourselves of the inner-workings of our project.
      +

      It will inform the design and usability of our project for the better:

      +
      +
      Although it may not be obvious from the outset, writing testable code leads to writing better code. This is, in part, because the process of writing tests gives us the opportunity to actually use our code under varied circumstances. The process of writing tests will help us suss out bad design decisions and redundant capabilities in our code. Ultimately, if we find it frustrating to use our code within our tests, then surely others will find the code frustrating to use in applied +settings.
      +

      It makes it easier for others to contribute to a project:

      +
      +
      Having a healthy test suite lowers the barrier to entry for a project. A contributor can rely on our project’s tests to quickly check to see if their changes to our code have broken the project or changed any of its behavior in unexpected ways.
      +

      This all sounds great, but where do we even start the process of writing a test suite? Let’s begin by seeing what constitutes a basic test function.

      +
      +
      +

      Writing Our First Tests

      +
      +

      Our “Source Code”

      +

      We need some code to test. For the sake of this introduction, let’s borrow a couple of functions that may look familiar from previous modules. These will serve as our “source code”; i.e. these are functions that we have written for our project and that need to be tested.

      +
      # Defining functions that we will be testing
      +
      +def count_vowels(x, include_y=False):
      +    """Returns the number of vowels contained in `x`.
      +
      +    The vowel 'y' is included optionally.
      +
      +    Parameters
      +    ----------
      +    x : str
      +        The input string
      +
      +    include_y : bool, optional (default=False)
      +        If `True` count y's as vowels
      +
      +    Returns
      +    -------
      +    vowel_count: int
      +
      +    Examples
      +    --------
      +    >>> count_vowels("happy")
      +    1
      +    >>> count_vowels("happy", include_y=True)
      +    2
      +    """
      +    vowels = set("aeiouAEIOU")
      +    if include_y:
      +        vowels.update("yY")
      +    return sum(1 for char in x if char in vowels)
      +
      +
      +def merge_max_mappings(dict1, dict2):
      +    """ Merges two dictionaries based on the largest value
      +    in a given mapping.
      +
      +    Parameters
      +    ----------
      +    dict1 : Dict[str, float]
      +    dict2 : Dict[str, float]
      +
      +    Returns
      +    -------
      +    merged : Dict[str, float]
      +        The dictionary containing all of the keys common
      +        between `dict1` and `dict2`, retaining the largest
      +        value from common mappings.
      +
      +    Examples
      +    --------
      +    >>> x = {"a": 1, "b": 2}
      +    >>> y = {"b": 100, "c": -1}
      +    >>> merge_max_mappings(x, y)
      +    {'a': 1, 'b': 100, 'c': -1}
      +    """
      +    # `dict(dict1)` makes a copy of `dict1`. We do this
      +    # so that updating `merged` doesn't also update `dict1`
      +    merged = dict(dict1)
      +    for key, value in dict2.items():
      +        if key not in merged or value > merged[key]:
      +            merged[key] = value
      +    return merged
      +
      +
      +

      As always, it is useful for us to follow along with this material in a Jupyter notebook. We ought to take time to define these functions and run inputs through them to make sure that we understand what they are doing. Testing code that we don’t understand is a lost cause!

      +
      +
      +

      The Basic Anatomy of a Test

      +

      Let’s write a test for count_vowels. For our most basic test, we can simply call count_values under various contrived inputs and assert that it returns the expected output. The desired behavior for this test function, upon being run, is to:

      +
        +
      • Raise an error if any of our assertions failed to hold true.
      • +
      • Complete “silently” if all of our assertions hold true (i.e. our test function will simply return None)
      • +
      +

      Here, we will be making use of Python’s assert statements, whose behavior will be easy to deduce from the context of this test alone. We will be formally introduced to the assert statement soon.

      +
      # Writing a rudimentary test function for `count_vowels`
      +
      +def test_count_vowels_basic():
      +    assert count_vowels("aA bB yY", include_y=False) == 2
      +    assert count_vowels("aA bB yY", include_y=True) == 4
      +
      +
      +

      To run this test, we simply call the function:

      +
      # running our test function
      +>>> test_count_vowels_basic()  # passes: returns None | fails: raises error
      +
      +
      +

      As described above, the fact our function runs and simply returns None (i.e. we see no output when we run this test in a console or notebook cell) means that our code has passed this test. We’ve written and run our very first test! It certainly isn’t the most robust test, but it is a good start.

      +

      Let’s look more carefully at the structure of test_count_vowels_basic. Note that this function doesn’t take in any inputs; thanks to Python’s scoping rules, we can reference our count_vowels function within our test as long as it is defined in the same “namespace” as test_count_vowels_basic. That is, we can either define count_vowels in the same .py file (or Jupyter notebook, if you are following +along with this material in a notebook) as test_count_vowels_basic, or we can import count_vowels, from wherever it is defined, into the file containing our test. The latter scenario is by far the most common one in practice. More on this later.

      +
      +

      Takeaway:

      +

      A “test function” is designed to provide an encapsulated “environment” (namespace to be more precise) in which we can exercise parts of our source code and assert that the code behaves as-expected. The basic anatomy of a test function is such that it:

      +
        +
      • contains one or more assert statements, each of which will raise an error if our source code misbehaves
      • +
      • simply returns None if all of the aforementioned assertions held true
      • +
      • can be run end-to-end simply by calling the test function without passing it any parameters; we rely on Python’s scoping rules to call our source code within the body of the test function without explicitly passing anything to said test function
      • +
      +
      +
      +

      Reading Comprehension: Adding Assertions to a Test

      +

      Add an additional assertion to the body of test_count_vowels_basic, which tests that count_vowels handles empty-string ("") input appropriately. Make sure to run your updated test to see if it passes.

      +
      +
      +

      Reading Comprehension: The Basic Anatomy of a Test

      +

      Write a rudimentary test function for merge_max_mappings. This should adhere to the basic structure of a test function that we just laid out. See if you can think of some “edge cases” to test, which we may have overlooked when writing merge_max_mappings.

      +
      +
      +
      +
      +

      The assert Statement

      +

      With our first test functions under our belt, it is time for us to clearly understand how assert statements work and how they should be used.

      +

      Similar to return, def, or if, the term assert is a reserved term in the Python language. It has the following specialized behavior:

      +
      # demonstrating the rudimentary behavior of the `assert` statement
      +
      +# asserting an expression whose boolean-value is `True` will complete "silently"
      +>>> assert 1 < 2
      +
      +# asserting an expression whose boolean-value is `False` raises an error
      +>>> assert 2 < 1
      +---------------------------------------------------------------------------
      +AssertionError                            Traceback (most recent call last)
      +<ipython-input-5-c82711d5fe4d> in <module>
      +----> 1 assert 2 < 1
      +
      +AssertionError:
      +
      +# we can include an error message with our assertion
      +>>> assert 0 in [1, 2, 3], "0 is not in the list"
      +---------------------------------------------------------------------------
      +AssertionError                            Traceback (most recent call last)
      +<ipython-input-8-e72fb36dc785> in <module>
      +----> 1 assert 0 in [1, 2, 3], "0 is not in the list"
      +
      +AssertionError: 0 is not in the list
      +
      +
      +

      The general form of an assertion statement is:

      +
      assert <expression> [, <error-message>]
      +
      +
      +

      When an assertion statement is executed, the built-in bool function is called on the object that is returned by <expression>; if bool(<expression>) returns False, then an AssertionError is raised. If you included a string in the assertion statement - separated from <expression> by a comma - then this string will be printed as the error message.

      +

      See that the assertion statement:

      +
      assert expression, error_message
      +
      +
      +

      is effectively shorthand for the following code (barring some additional details):

      +
      # long-form equivalent of: `assert expression, error_message`
      +if bool(expression) is False:
      +    raise AssertionError(error_message)
      +
      +
      +
      +

      Reading Comprehension: Assertions

      +

      Given the following objects:

      +
      a_list = []
      +a_number = 22
      +a_string = "abcdef"
      +
      +
      +

      Write two assertion statements with the respective behaviors:

      +
        +
      • asserts that a_list is not empty
      • +
      • asserts that the number of vowels in a_string is less than a_number; include an error message that prints the actual number of vowels
      • +
      +
      +

      In our code, an assertion should be used as a statement that is true unless there is a bug in our code. It is plain to see that the assertions in test_count_vowels_basic fit this description. However, it can also be useful to include assertions within our source code itself. For instance, we know that count_vowels should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string. We can +explicitly assert that this is the case:

      +
      # an example of including an assertion within our source code
      +
      +def count_vowels(x: str, include_y: bool = False) -> int:
      +    vowels = set("aeiouAEIOU")
      +    if include_y:
      +        vowels.update("yY")
      +    count = sum(1 for char in x if char in vowels)
      +
      +    # This assertion should always be true: it is asserting that
      +    # the internal logic of our function is correct
      +    assert isinstance(count, int) and 0 <= count <= len(x)
      +    return count
      +
      +
      +

      Note that this assertion is not meant to check if the user passed bad inputs for x and include_y. Rather, it is meant to assert that our own internal logic holds true.

      +

      Admittedly, the count_vowels function is simple enough that the inclusion of this assertion is rather pedantic. That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base. We will also see that keen use of assertions can make it much easier for us to write good tests.

      +
      +

      Disabling Assertions:

      +

      Python code can be run in an “optimized” mode such that all assertions are skipped by the Python interpreter during execution. This can be achieved by specifying the command line option -O (the letter “O”, not zero), e.g.:

      +
      python -O my_code.py
      +
      +
      +

      or by setting the PYTHONOPTIMIZE environment variable.

      +

      The idea here is that we may want assertions within our source code to perform expensive checks to guarantee internal consistency within our code, and that we want the ability to forgo these checks when we are no longer debugging our code. Because they can be skipped in this way, assertions should never be used for practical error handling.

      +
      +
      +
      +

      Testing Our Tests

      +

      It is surprisingly easy to unwittingly write a broken test: a test that always passes, or a test that simply doesn’t exercise our code in the way that we had intended. Broken tests are insidious; they are alarms that fail to sound when they are supposed to. They create misdirection in the bug-finding process and can mask problems with our code. Thus a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior so that we can verify +that our test works. Once we confirm that our test does indeed raise an error as-expected, we restore the function to its original form and re-run the test and see that it passes.

      +

      A practical note: we ought to mutate our function in a way that is trivial to undo. We can make use of code-comments towards this end. All IDEs have the ability to “block-comment” selected code. In order to block-comment code in a Jupyter notebook code cell, highlight the lines of code and press CTRL + /. The same key-combination will also un-comment a highlighted block of +commented code.

      +
      +

      Reading Comprehension: Testing Your Test via Manual Mutation

      +

      Temporarily change the body of count_vowels such that the second assertion in test_count_vowels_basic raises an error. Run the test to confirm that the second assertion raises, and then restore count_vowels to its original form. Finally, rerun the test to see that count_vowels once again passes all of the assertions.

      +

      Repeat this process given the test that you wrote for merge_max_mappings. Try breaking the function such that it always merges in values from dict2, even if those values are smaller.

      +
      +
      +

      Mutation Testing:

      +

      There is an entire subfield of automated testing known as “mutation testing”, where tools like Cosmic Ray are used to make temporary, incisive mutations to your source code - like change a + to a - or change a 1 to a -1 - and then run your test suite. The idea here is that such mutations ought to cause one or more of your tests to fail. A mutation that fails to +trigger at least one test failure is likely an indicator that your tests could stand to be more robust.

      +

      Automated mutation testing tools might be a bit too “heavy duty” at this point in our testing journey, but they are great to keep in mind.

      +
      +
      +
      +

      Our Work, Cut Out

      +

      We see now that the concept of a “test function” isn’t all that fancy. Compared to other code that we have written, writing a function that simply runs a hand full of assertions is far from a heavy lift for us. Of course, we must be diligent and take care to test our tests, but we can certainly manage this as well. With this in hand, we should take stock of the work and challenges that lie in our path ahead.

      +

      It is necessary that we evolve beyond manual testing. There are multiple facets to this observation. First, we must learn how to organize our test functions into a test suite that can be run in one fell swoop. Next, it will become increasingly apparent that a test function often contains large amounts of redundant code shared across its litany of assertions. We will want to “parametrize” our tests to distill them down to their most concise and functional forms. Finally, and most importantly, it +may already be evident that the process of contriving known inputs and outputs to use in our tests is a highly manual and tedious process; furthermore, it is a process that will become increasingly cumbersome as our source code becomes more sophisticated. To combat this, we will seek out alternative, powerful testing methodologies, including property-based testing.

      +
      + +
      +

      Reading Comprehension Solutions

      +

      Adding Assertions to a Test: Solution

      +

      Add an additional assertion to the body of test_count_vowels_basic, which tests whether count_vowels handles the empty-string ("") case appropriately. Make sure to run your updated test to see if it passes.

      +
      def test_count_vowels_basic():
      +    # test basic strings with uppercase and lowercase letters
      +    assert count_vowels("aA bB yY", include_y=False) == 2
      +    assert count_vowels("aA bB yY", include_y=True) == 4
      +
      +    # test empty strings
      +    assert count_vowels("", include_y=False) == 0
      +    assert count_vowels("", include_y=True) == 0
      +
      +
      +
      # running the test in a notebook-cell: the function should simply return
      +# `None` if all assertions hold true
      +>>> test_count_vowels_basic()
      +
      +
      +

      The Basic Anatomy of a Test: Solution

      +

      Write a rudimentary test function for merge_max_mappings.

      +
      +
      Let’s test the use case that is explicitly documented in the Examples section of the function’s docstring. We can also test cases where one or both of the inputs are empty dictionaries. These can often be problematic edge cases that we didn’t consider when writing our code.
      +
      def test_merge_max_mappings():
      +    # test documented behavior
      +    dict1 = {"a": 1, "b": 2}
      +    dict2 = {"b": 20, "c": -1}
      +    expected = {'a': 1, 'b': 20, 'c': -1}
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +    # test empty dict1
      +    dict1 = {}
      +    dict2 = {"a": 10.2, "f": -1.0}
      +    expected = dict2
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +    # test empty dict2
      +    dict1 = {"a": 10.2, "f": -1.0}
      +    dict2 = {}
      +    expected = dict1
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +    # test both empty
      +    dict1 = {}
      +    dict2 = {}
      +    expected = {}
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +
      +
      # running the test (seeing no errors means the tests all passed)
      +>>> test_merge_max_mappings()
      +
      +
      +

      Assertions: Solution

      +
      a_list = []
      +a_number = 22
      +a_string = "abcdef"
      +
      +
      +

      Assert that a_list is not empty:

      +
      >>> assert a_list
      +---------------------------------------------------------------------------
      +AssertionError                            Traceback (most recent call last)
      +<ipython-input-10-2eba8294859e> in <module>
      +----> 1 assert a_list
      +
      +AssertionError:
      +
      +
      +
      +
      You may have written assert len(a_list) > 0 - this is also correct. However, recall that calling bool on any sequence (list, tuple, string, etc.) will return False if the sequence is empty. This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - that bool will be called on whatever the provided expression is.
      +

      Assert that the number of vowels in a_string is fewer than a_number; include an error message that prints the actual number of vowels:

      +
      >>> assert count_vowels(a_string) < a_number, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}"
      +
      +
      +
      +
      Note that we make use of an f-string as a convenient means for writing an informative error message.
      +

      Testing Your Test via Manual Mutation: Solution

      +

      Temporarily change the body of count_vowels such that the second assertion in test_count_vowels_basic raises an error. > Let’s comment out the if include_y block in our code. This should prevent us from counting y’s, and thus should violate the second assertion in our test.

      +
      # Breaking the behavior of `include_y=True`
      +def count_vowels(x: str, include_y: bool = False) -> int:
      +    vowels = set("aeiouAEIOU")
      +    # if include_y:
      +    #    vowels.update("yY")
      +    return sum(1 for char in x if char in vowels)
      +
      +
      +
      # the second assertion should raise an error
      +>>> test_count_vowels_basic()
      +---------------------------------------------------------------------------
      +AssertionError                            Traceback (most recent call last)
      +<ipython-input-5-32301ff829e9> in <module>
      +----> 1 test_count_vowels_basic()
      +
      +<ipython-input-4-99ef0ca3d859> in test_count_vowels_basic()
      +      1 def test_count_vowels_basic():
      +      2     assert count_vowels("aA bB yY", include_y=False) == 2
      +----> 3     assert count_vowels("aA bB yY", include_y=True) == 4
      +
      +AssertionError:
      +
      +
      +
      +
      See that the error output, which is called a “stack trace”, indicates with an ASCII-arrow that our second assertion is the one that is failing. Thus we can be confident that that assertion really does help to ensure that we are counting y’s correctly.
      +

      Restore count_vowels to its original form and rerun the test to see that count_vowels once again passes all of the assertions.

      +
      +
      We simply un-comment out the block of code and rerun our test.
      +
      # Restore the behavior of `include_y=True`
      +def count_vowels(x: str, include_y: bool = False) -> int:
      +    vowels = set("aeiouAEIOU")
      +    if include_y:
      +        vowels.update("yY")
      +    return sum(1 for char in x if char in vowels)
      +
      +
      +
      # confirming that we restored the proper behavior in `count_vowels`
      +>>> test_count_vowels_basic()
      +
      +
      +
      +
      + + +
      + +
      + + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs_backup/Module6_Testing/Pytest.html b/docs_backup/Module6_Testing/Pytest.html new file mode 100644 index 00000000..90768ab8 --- /dev/null +++ b/docs_backup/Module6_Testing/Pytest.html @@ -0,0 +1,796 @@ + + + + + + + + + + + + + The pytest Framework — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + + + +
      +

      The pytest Framework

      +

      Thus far, our process for running tests has been an entirely manual one. It is time for us to arrange our test functions into a proper “test suite” and to learn to leverage the pytest framework to run them. We will begin by reorganizing our source code to create an installable Python package. We will then learn how to structure and run a test suite for this +Python package, using pytest.

      +

      The pytest framework does much more than just run tests; for instance, it will enrich the assertions in our tests to produce verbose, informative error messages. Furthermore it provides valuable means for enhancing our tests via mechanisms like fixtures and parameterizing decorators. Ultimately, all of this functionality helps to eliminate manual and redundant aspects of the testing process.

      +
      +

      Note

      +

      It can be useful to create a separate conda environment for the sake of this lesson, so that we can work through this material starting from a blank slate. If you do create a new conda environment, be sure to activate that environment and install NumPy and Jupyter notebook: conda install numpy notebook

      +
      +

      Let’s install pytest. Installing from the conda-forge channel will install the most up-to-date version of pytest. In a terminal where conda can be accessed, run:

      +
      conda install -c conda-forge pytest
      +
      +
      +

      Or, pytest is installable via pip:

      +
      pip install pytest
      +
      +
      +
      +

      Regarding Alternative Testing Frameworks (a note from the author of PLYMI):

      +

      When sifting through tutorials, blogs, and videos about testing in Python, it is common to see pytest presented alongside, and on an equal footing with, the alternative testing frameworks: nose and unittest. This strikes me as… bizarre.

      +

      unittest is the testing framework that comes with the Python standard library. As a test runner, its design is clunky, archaic, and, ironically, un-pythonic. While unittest.mock provides extremely valuable functionality for advanced testing, all of its functionality can be leveraged while using pytest as your testing framework.

      +

      nose, which simply extends the functionality of unittest, is no longer being maintained. There is a project, “Nose2”, which is carrying the torch of nose. However, this is a fledgling project by comparison to pytest. As of writing this, pytest was downloaded 12 million times last month versus nose2’s 150 thousand downloads.

      +

      The takeaway here is that, when it comes to picking a testing framework for Python, pytest is the clear choice. Any discussion that you come across to the contrary is likely outdated.

      +
      +
      +

      Creating a Python Package with Tests

      +

      It’s time to create a proper test suite. Before proceeding any further, we should reread the material presented in Module 5 - Import: Modules and Packages and recall the essentials of import statements, modules, and Python packages. This material serves as the foundation for this section.

      +
      +

      Organizing our Source Code

      +

      Let’s create a Python package, which we will call plymi_mod6, with the following directory structure:

      +
      project_dir/     # the "parent directory" houses our source code, tests, and all other relevant files
      +  - setup.py     # script responsible for installing `plymi_mod6` package
      +  - plymi_mod6/  # directory containing source code of `plymi_mod6` package
      +      |-- __init__.py
      +      |-- basic_functions.py
      +      |-- numpy_functions.py
      +  - tests/        # test-suite for `plymi_mod6` package (to be run using pytest)
      +      |-- conftest.py # optional configuration file for pytest
      +      |-- test_basic_functions.py
      +      |-- test_numpy_functions.py
      +
      +
      +

      A reference implementation of this package can be found in this GitHub repository. Populate the basic_functions.py file with the two functions that we were using as our source code in the previous section: count_vowels and merge_max_mappings. In the numpy_functions.py module, add the pairwise_dists function that appears in Module 3’s discussion of optimized pairwise +distances. Don’t forget to include import numpy as np in your script in accordance with how pairwise_dists calls NumPy functions.

      +

      We have arranged these functions so that they can be imported from the basic_functions module and the numpy_functions module, respectively, which reside in our plymi_mod6 package. Let’s fill out our setup.py script and install this package so that we can import it regardless of our current working directory. The content of setup.py will be:

      +
      from setuptools import find_packages, setup
      +
      +setup(
      +    name="plymi_mod6",
      +    packages=find_packages(exclude=["tests", "tests.*"]),
      +    version="1.0.0",
      +    author="Your Name",
      +    description="A template Python package for learning about testing",
      +    install_requires=["numpy >= 1.10.0"],
      +    tests_require=["pytest>=5.3", "hypothesis?=5.0"],
      +    python_requires=">=3.6",
      +)
      +
      +
      +

      This setup file dictates that a user must have Python 3.6+ installed - we will bar Python 3.5 and below so that we are free to make use of f-strings in our code, which were introduced in Python 3.6. Additionally, we will require pytest and hypothesis for running tests; the Hypothesis library will be introduced in a later section.

      +

      Finally, let’s install our package locally in development mode. Navigate to the directory containing setup.py and run:

      +
      pip install --editable .
      +
      +
      +

      Now, we should be able to start a python console, IPython console, or Jupyter notebook in any directory and import our package:

      +
      # checking that we can import our `plymi_mod6` package
      +>>> from plymi_mod6.basic_functions import count_vowels
      +>>> count_vowels("Happy birthday", include_y=True)
      +5
      +
      +
      +
      +
      +
      +

      Populating and Running Our Test Suite

      +

      pytest’s system for “test discovery” is quite simple: pytest need only be pointed to a directory with files named test_*.py in it, and it will find all of the functions in these files whose names start with the word “test” and will run all such functions.

      +

      Thus, let’s populate the file test_basic_functions.py with the functions test_count_vowels_basic and test_merge_max_mappings, which we wrote in the previous section of this module:

      +
      # The contents of test_basic_functions.py
      +
      +# we must import the functions we are testing
      +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings
      +
      +
      +def test_count_vowels_basic():
      +    # test basic strings with uppercase and lowercase letters
      +    assert count_vowels("aA bB yY", include_y=False) == 2
      +    assert count_vowels("aA bB yY", include_y=True) == 4
      +
      +    # test empty strings
      +    assert count_vowels("", include_y=False) == 0
      +    assert count_vowels("", include_y=True) == 0
      +
      +
      +def test_merge_max_mappings():
      +    # test documented behavior
      +    dict1 = {"a": 1, "b": 2}
      +    dict2 = {"b": 20, "c": -1}
      +    expected = {'a': 1, 'b': 20, 'c': -1}
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +    # test empty dict1
      +    dict1 = {}
      +    dict2 = {"a": 10.2, "f": -1.0}
      +    expected = dict2
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +    # test empty dict2
      +    dict1 = {"a": 10.2, "f": -1.0}
      +    dict2 = {}
      +    expected = dict1
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +    # test both empty
      +    dict1 = {}
      +    dict2 = {}
      +    expected = {}
      +    assert merge_max_mappings(dict1, dict2) == expected
      +
      +
      +

      As described before, count_vowels and merge_max_mappings must both be imported from our plymi_mod6 package, so that our functions are in the same namespace as our tests. A reference implementation of test_basic_functions.py can be viewed here. Finally, add a dummy test - a test function that will always pass - to test_basic_numpy.py. We will replace this with a useful test later.

      +

      Without further ado, let’s run our test suite! In our terminal, with the appropriate conda environment active, we navigate to the root directory of the project, which contains the tests/ directory, and run pytest tests/. The following output should appear:

      +
      $ pytest tests/
      +============================= test session starts =============================
      +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0
      +rootdir: C:\Users\plymi_user\plymi_root_dir
      +collected 3 items
      +
      +tests\test_basic_functions.py ..                                         [ 66%]
      +tests\test_basic_numpy.py .                                              [100%]
      +
      +============================== 3 passed in 0.04s ==============================
      +
      +
      +

      This output indicates that three test-functions were found across two files and that all of the tests “passed”; i.e. the functions ran without raising any errors. The first two tests are located in tests/test_basic_functions.py; the two dots indicate that two functions were run, and the [66%] indicator simply denotes that the test-suite is 66% (two-thirds) complete. The following reading comprehension problem will lead us to see what looks like for pytest to report a failing test.

      +
      +

      Reading Comprehension: Running a Test Suite

      +

      Temporarily add a new “broken” test to tests/test_basic_functions.py. The name that you give this test should adhere to pytest’s simple rules for test-discovery. Design the test function so that is sure to fail when it is run.

      +

      Rerun your test suite and compare its output to what you saw before - is it easy to identify which test failed and what caused it to fail? Make sure to remove this function from your test suite once you are finished answering this question.

      +
      +

      We can also direct pytest to run the tests in a specific .py file. E.g. executing:

      +
      pytest tests/test_basic_functions.py
      +
      +
      +

      will cue pytest to only run the tests in test_basic_functions.py.

      +

      A key component to leveraging tests effectively is the ability to exercise ones tests repeatedly and rapidly with little manual overhead. Clearly, pytest is instrumental towards this end - this framework made the process of organizing and running our test suite exceedingly simple! That being said, there will certainly be occasions when we want to run a specific test function. Suppose, for instance, that we are writing a new function, and repeatedly want to run one of our tests that is pointing +to a bug in our work-in-progress. We can leverage pytest in conjunction with an IDE to run our tests in such incisive ways.

      +
      +

      Utilizing pytest within an IDE

      +

      Both PyCharm and VSCode can be configured to make keen use of pytest. The following images show a couple of the enhancements afforded to us by PyCharm; comparable features are available in VSCode. The IDEs will “discover” tests, and provide us with the ability to run individual tests. For example, in the following image, the green “play button” allows us to run +test_count_vowels_basic.

      +
      +

      +Running an individual test in PyCharm +

      +

      Furthermore, IDEs can provide a rich tree view of all the tests that are being run. This is especially useful as our test suite grows to contain a considerable number of tests. In the following image, we see that test_version is failing - we can click on the failing test in this tree-view, and our IDE will navigate us directly to the failing test.

      +
      +

      +Viewing an enhanced tree-view of your test suite +

      +

      The first step for leveraging these features in your IDE is to enable the pytest framework in the IDE. The following links point to detailed instructions for configuring pytest with PyCharm and VSCode, respectively:

      + +

      These linked materials also include advanced details, like instructions for running tests in parallel, which are beyond the scope of this material but are useful nonetheless.

      +
      +
      +
      +

      Enhanced Testing with pytest

      +

      In addition to providing us with a simple means for organizing and running our test suite, pytest has powerful features that will both simplify and enhance our tests. We will now leverage these features in our test suite.

      +
      +

      Enriched Assertions

      +

      A failing “bare” assertion - an assert statement without an error message - can be a frustrating thing. Suppose, for instance, that one of our test-assertions about count_vowels fails:

      +
      # a failing assertion without an error message is not informative
      +
      +assert count_vowels("aA bB yY", include_y=True) == 4
      +---------------------------------------------------------------------------
      +AssertionError                            Traceback (most recent call last)
      +<ipython-input-2-f89f8b6a7213> in <module>
      +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4
      +
      +AssertionError:
      +
      +
      +

      The problem with this bare assertion is that we don’t know what count_vowels("aA bB yY", include_y=True) actually returned! We now have to go through the trouble of starting a python console, importing this function, and calling it with this specific input in order to see what our function was actually returning. An obvious remedy to this is for us to write our own error message, but this too is quite cumbersome when we consider the large number of assertions that we are destined to write.

      +

      Fortunately, pytest comes to the rescue: it will “hijack” any failing bare assertion and will insert a useful error message for us. This is known as “assertion introspection”. For example, if the aforementioned assertion failed when being run by pytest, we would see the following output:

      +
      # pytest will write informative error messages for us
      +
      +assert count_vowels("aA bB yY", include_y=True) == 4
      +---------------------------------------------------------------------------
      +AssertionError                            Traceback (most recent call last)
      +~\Learning_Python\Python\Module6_Testing\Untitled1.ipynb in <module>
      +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4
      +
      +AssertionError: assert 2 == 4
      + +  where 2 = <function count_vowels at 0x000001B91B913708>('aA bB yY', include_y=True
      +
      +
      +

      See that the error message that pytest included for us indicates that count_vowels("aA bB yY", include_y=True) returned 2, when we expected it to return 4. From this we might suspect that count_vowels is not counting y’s correctly.

      +

      Here are some more examples of “enriched assertions”, as provided by pytest. See that these error messages even provide useful “diffs”, which specify specifically how two similar objects differ, where possible.

      +
      # comparing unequal lists
      +assert [1, 2, 3] == [1, 2]
      +E         Left contains one more item: 3
      +E         Full diff:
      +E         - [1, 2, 3]
      +E         ?      ---
      +E         + [1, 2]
      +
      +
      +
      # comparing unequal dictionaries
      +assert {"a": 1, "b": 2} == {"a": 1, "b": 3}
      +E       AssertionError: assert {'a': 1, 'b': 2} == {'a': 1, 'b': 3}
      +E         Omitting 1 identical items, use -vv to show
      +E         Differing items:
      +E         {'b': 2} != {'b': 3}
      +E         Full diff:
      +E         - {'a': 1, 'b': 2}
      +E         ?               ^
      +E         + {'a': 1, 'b': 3}...
      +
      +
      +
      # comparing unequal strings
      +assert "moo" == "moon"
      +E       AssertionError: assert 'moo' == 'moon'
      +E         - moo
      +E         + moon
      +E         ?    +
      +
      +
      +
      +
      +

      Parameterized Tests

      +

      Looking back to both test_count_vowels_basic and test_merge_max_mappings, we see that there is a lot of redundancy within the bodies of these test functions. The assertions that we make within a given test-function share identical forms - they differ only in the parameters that we feed into our functions and their expected output. Another shortcoming of this test-structure is that a failing assertion will block subsequent assertions from being evaluated. That is, if the second assertion +in a test_count_vowels_basic fails, the third and fourth assertions will not be evaluated in that run. This precludes us from potentially seeing useful patterns among the failing assertions.

      +

      pytest provides a useful tool that will allow us to eliminate these structural shortcomings by transforming our test-functions into so-called parameterized tests. Let’s parametrize the following test:

      +
      # a simple test with redundant assertions
      +
      +def test_range_length_unparameterized():
      +    assert len(range(0)) == 0
      +    assert len(range(1)) == 1
      +    assert len(range(2)) == 2
      +    assert len(range(3)) == 3
      +
      +
      +

      This test is checking the property len(range(n)) == n, where n is any non-negative integer. Thus the parameter to be varied here is the “size” of the range-object being created. Let’s treat it as such by using pytest to write a parameterized test:

      +
      # parameterizing a test
      +import pytest
      +
      +# note that this test must be run by pytest to work properly
      +@pytest.mark.parametrize("size", [0, 1, 2, 3])
      +def test_range_length(size):
      +    assert len(range(size)) == size
      +
      +
      +

      Make note that a pytest-parameterized test must be run using pytest; an error will raise if we manually call test_range_length(). When executed, pytest will treat this parameterized test as four separate tests - one for each parameter value:

      +
      test_basic_functions.py::test_range_length[0] PASSED                     [ 25%]
      +test_basic_functions.py::test_range_length[1] PASSED                     [ 50%]
      +test_basic_functions.py::test_range_length[2] PASSED                     [ 75%]
      +test_basic_functions.py::test_range_length[3] PASSED                     [100%]
      +
      +
      +

      See that we have successfully eliminated the redundancy from test_range_length; the body of the function now contains only a single assertion, making obvious the property that is being tested. Furthermore, the four assertions are now being run independently from one another and thus we can potentially see patterns across multiple fail cases in concert.

      +
      +

      Decorators

      +

      The syntax used to parameterize this test may look alien to us, as we have yet to encounter this construct thus far. pytest.mark.parameterize(...) is a decorator - an object that is used to “wrap” a function in order to transform its behavior. The pytest.mark.parameterize(...) decorator wraps our test function so that pytest can call it multiple times, once for each parameter value. The @ character, in this context, denotes the application of a decorator:

      +
      # general syntax for applying a decorator to a function
      +
      +@the_decorator
      +def the_function_being_decorated(<arguments_for_function>):
      +    pass
      +
      +
      +

      For an in-depth discussion of decorators, please refer to Real Python’s Primer on decorators.

      +
      +
      +

      Parameterization Syntax

      +

      The general form for creating a parameterizing decorator with a single parameter, as we formed above, is:

      +
      @pytest.mark.parametrize("<param-name>", [<val-1>, <val-2>, ...])
      +def test_function(<param-name>):
      +    ...
      +
      +
      +

      We will often have tests that require multiple parameters. The general form for creating the parameterization decorator for \(N\) parameters, each of which assume \(J\) values, is:

      +
      @pytest.mark.parametrize("<param-name1>, <param-name2>, [...], <param-nameN>",
      +                         [(<param1-val1>, <param2-val1>, [...], <paramN-val1>),
      +                          (<param1-val2>, <param2-val2>, [...], <paramN-val2>),
      +                          ...
      +                          (<param1-valJ>, <param2-valJ>, [...], <paramN-valJ>),
      +                         ])
      +def test_function(<param-name1>, <param-name2>, [...], <param-nameN>):
      +    ...
      +
      +
      +

      For example, let’s take the following trivial test:

      +
      def test_inequality_unparameterized():
      +    assert 1 < 2 < 3
      +    assert 4 < 5 < 6
      +    assert 7 < 8 < 9
      +    assert 10 < 11 < 12
      +
      +
      +

      and rewrite it in parameterized form. The decorator will have three distinct parameter, and each parameters, let’s simply call them a, b, and c, will take on four values.

      +
      # the parameterized form of `test_inequality_unparameterized`
      +@pytest.mark.parametrize("a, b, c", [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)])
      +def test_inequality(a, b, c):
      +    assert a < b < c
      +
      +
      +
      +

      Note

      +

      The formatting for multi-parameter tests can quickly become unwieldy. It isn’t always obvious where one should introduce line breaks and indentations to improve readability. This is a place where the “black” auto-formatter really shines! Black will make all of these formatting decisions for us - we can write our parameterized tests as haphazardly as we like and simply run black to format our code.

      +
      +
      +

      Reading Comprehension: Parameterizing Tests

      +

      Rewrite test_count_vowels_basic as a parameterized test with the parameters: input_string, include_y, and expected_count.

      +

      Rewrite test_merge_max_mappings as a parameterized test with the parameters: dict_a, dict_b, and expected_merged.

      +

      Before rerunning test_basic_functions.py predict how many distinct test cases will be reported by pytest.

      +
      +

      Finally, you can apply multiple parameterizing decorators to a test so that pytest will run all combinations of the respective parameter values.

      +
      # testing all combinations of `x` and `y`
      +@pytest.mark.parametrize("x", [0, 1, 2])
      +@pytest.mark.parametrize("y", [10, 20])
      +def test_all_combinations(x, y):
      +    # will run:
      +    # x=0 y=10
      +    # x=0 y=20
      +    # x=1 y=10
      +    # x=1 y=20
      +    # x=2 y=10
      +    # x=2 y=20
      +    pass
      +
      +
      +
      +
      +
      +

      Fixtures

      +

      The final major pytest feature that we will discuss are “fixtures”. A fixture, roughly speaking, is a means by which we can share information and functionality across our tests. Fixtures can be defined within our conftest.py file, and pytest will automatically “discover” them and make them available for use throughout our test suite in a convenient way.

      +

      Exploring fixtures will quickly take us beyond our depths for the purposes of this introductory material, so we will only scratch the surface here. We can read about advanced details of fixtures here.

      +

      Below are examples of two useful fixtures.

      +
      # contents of conftest.py
      +
      +import os
      +import tempfile
      +
      +import pytest
      +
      +@pytest.fixture()
      +def cleandir():
      +    """ This fixture will use the stdlib `tempfile` module to
      +    change the current working directory to a tmp-dir for the
      +    duration of the test.
      +
      +    Afterwards, the test session returns to its previous working
      +    directory, and the temporary directory and its contents
      +    will be automatically deleted.
      +
      +    Yields
      +    ------
      +    str
      +        The name of the temporary directory."""
      +    with tempfile.TemporaryDirectory() as tmpdirname:
      +        old_dir = os.getcwd()  # get current working directory (cwd)
      +        os.chdir(tmpdirname)   # change cwd to the temp-directory
      +        yield tmpdirname       # yields control to the test to be run
      +        os.chdir(old_dir)      # restore the cwd to the original directory
      +    # Leaving the context manager will prompt the deletion of the
      +    # temporary directory and its contents. This cleanup will be
      +    # triggered even if errors were raised during the test.
      +
      +
      +@pytest.fixture()
      +def dummy_email():
      +    """ This fixture will simply have pytest pass the string:
      +                   'dummy.email@plymi.com'
      +    to any test-function that has the parameter name `dummy_email` in
      +    its signature.
      +    """
      +    return "dummy.email@plymi.com"
      +
      +
      +

      The first one, cleandir, can be used in conjunction with tests that need to write files. We don’t want our tests to leave behind files on our machines; the cleandir fixture will ensure that our tests will write files to a temporary directory that will be deleted once the test is complete.

      +

      Second is a simple fixture called dummy_email. Suppose that our project needs to interact with a specific email address, suppose it’s dummy.email@plymi.com, and that we have several tests that need access to this address. This fixture will pass this address to any test function that has the parameter name dummy_email in its signature.

      +

      A reference implementation of conftest.py in our project can be found here. Several reference tests that make use of these fixtures can be found here.

      +

      Let’s create a file tests/test_using_fixtures.py, and write some tests that put these fixtures to use:

      +
      # contents of test_using_fixtures.py
      +import pytest
      +
      +# When run, this test will be executed within a
      +# temporary directory that will automatically be
      +# deleted - along with all of its contents - once
      +# the test ends.
      +#
      +# Thus we can have this test write a file, and we
      +# need not worry about having it clean up after itself.
      +@pytest.mark.usefixtures("cleandir")
      +def test_writing_a_file():
      +    with open("a_text_file.txt", mode="w") as f:
      +        f.write("hello world")
      +
      +    with open("a_text_file.txt", mode="r") as f:
      +        file_content = f.read()
      +
      +    assert file_content == "hello world"
      +
      +
      +# We can use the `dummy_email` fixture to provide
      +# the same email address to many tests. In this
      +# way, if we need to change the email address, we
      +# can simply update the fixture and all of the tests
      +# will be affected by the update.
      +#
      +# Note that we don't need to use a decorator here.
      +# pytest is smart, and will see that the parameter-name
      +# `dummy_email` matches the name of our fixture. It will
      +# thus call these tests using the value returned by our
      +# fixture
      +
      +def test_email1(dummy_email):
      +    assert "dummy" in dummy_email
      +
      +
      +def test_email2(dummy_email):
      +    assert "plymi" in dummy_email
      +
      +
      +def test_email3(dummy_email):
      +    assert ".com" in dummy_email
      +
      +
      +
      +
      + +
      +

      Reading Comprehension Solutions

      +

      Running a Test Suite: Solution

      +
      +
      Let’s add the test function test_broken_function to our test suite. We must include the word “test” in the function’s name so that pytest will identify it as a test to run. There are limitless ways in which we can make this test fail; we’ll introduce a trivial false-assertion:
      +
      def test_broken_function():
      +    assert [1, 2, 3] == [1, 2]
      +
      +
      +
      +
      After introducing this broken test into test_basic_functions.py , running our tests should result in the following output:
      +
      $ pytest tests/
      +============================= test session starts =============================
      +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0
      +rootdir: C:\Users\plymi_user\plymi_root_dir
      +collected 4 items
      +
      +tests\test_basic_functions.py ..F                                        [ 75%]
      +tests\test_basic_numpy.py .                                              [100%]
      +
      +================================== FAILURES ===================================
      +____________________________ test_broken_function _____________________________
      +
      +    def test_broken_function():
      +>       assert [1, 2, 3] == [1, 2]
      +E       assert [1, 2, 3] == [1, 2]
      +E         Left contains one more item: 3
      +E         Use -v to get the full diff
      +
      +tests\test_basic_functions.py:40: AssertionError
      +========================= 1 failed, 3 passed in 0.07s =========================
      +
      +
      +
      +
      Four tests were “discovered” and run by pytest. The pattern ..F indicates that the first two tests in test_basic_functions passed and the third test failed. It then indicates which test failed, and specifically that the assertion was false because a length-2 list cannot be equal to a length-3 list.
      +

      Parameterizing Tests: Solution

      +

      A reference implementation for this solution within the plymi_mod6 project can be found here.

      +

      The contents of test_basic_functions.py, rewritten to use pytest-parameterized tests:

      +
      import pytest
      +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings
      +
      +
      +@pytest.mark.parametrize(
      +    "input_string, include_y, expected_count",
      +    [("aA bB yY", False, 2), ("aA bB yY", True, 4), ("", False, 0), ("", True, 0)],
      +)
      +def test_count_vowels_basic(input_string, include_y, expected_count):
      +    assert count_vowels(input_string, include_y) == expected_count
      +
      +
      +@pytest.mark.parametrize(
      +    "dict_a, dict_b, expected_merged",
      +    [
      +        (dict(a=1, b=2), dict(b=20, c=-1), dict(a=1, b=20, c=-1)),
      +        (dict(), dict(b=20, c=-1), dict(b=20, c=-1)),
      +        (dict(a=1, b=2), dict(), dict(a=1, b=2)),
      +        (dict(), dict(), dict()),
      +    ],
      +)
      +def test_merge_max_mappings(dict_a, dict_b, expected_merged):
      +    assert merge_max_mappings(dict_a, dict_b) == expected_merged
      +
      +
      +

      Running these tests via pytest should produce eight distinct test-case: four for test_count_vowels_basic and four for test_merge_max_mappings.

      +
      ============================= test session starts =============================
      +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0
      +cachedir: .pytest_cache
      +rootdir: C:\Users\plymi_user\Learning_Python\plymi_mod6_src
      +collecting ... collected 8 items
      +
      +test_basic_functions.py::test_count_vowels_basic[aA bB yY-False-2] PASSED [ 12%]
      +test_basic_functions.py::test_count_vowels_basic[aA bB yY-True-4] PASSED [ 25%]
      +test_basic_functions.py::test_count_vowels_basic[-False-0] PASSED        [ 37%]
      +test_basic_functions.py::test_count_vowels_basic[-True-0] PASSED         [ 50%]
      +test_basic_functions.py::test_merge_max_mappings[dict_a0-dict_b0-expected_merged0] PASSED [ 62%]
      +test_basic_functions.py::test_merge_max_mappings[dict_a1-dict_b1-expected_merged1] PASSED [ 75%]
      +test_basic_functions.py::test_merge_max_mappings[dict_a2-dict_b2-expected_merged2] PASSED [ 87%]
      +test_basic_functions.py::test_merge_max_mappings[dict_a3-dict_b3-expected_merged3] PASSED [100%]
      +
      +============================== 8 passed in 0.07s ==============================
      +
      +
      +
      +
      + + +
      + +
      + + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs_backup/_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_9_0.png b/docs_backup/_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_0.png similarity index 100% rename from docs_backup/_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_9_0.png rename to docs_backup/_images/Module1_GettingStartedWithPython_Jupyter_Notebooks_10_0.png diff --git a/docs_backup/_images/individual_test.png b/docs_backup/_images/individual_test.png new file mode 100644 index 00000000..381fba2d Binary files /dev/null and b/docs_backup/_images/individual_test.png differ diff --git a/docs_backup/_images/test_tree_view.png b/docs_backup/_images/test_tree_view.png new file mode 100644 index 00000000..5b352aa5 Binary files /dev/null and b/docs_backup/_images/test_tree_view.png differ diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/GettingStartedWithPython.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/GettingStartedWithPython.md.txt index 3728d2b0..ed1f2f1a 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/GettingStartedWithPython.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/GettingStartedWithPython.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Basic description of the Python programming language, Difficulty: Easy, Category: Background :keywords: python, install, basics, scripts, interpreter, foundations -``` + # Introducing the Python Programming Language @@ -76,7 +76,7 @@ Do not use word processing programs, like Microsoft Word, to write code. They wi Now that you have a Python script, how do you get the computer to read it and follow its instructions? You will need to install a **Python interpreter** on your computer to accomplish this. This is what people mean, whether they know it or not, when they tell you to "install Python" on your computer. - + ## What is a Python Interpreter and What Does it Mean to "Install Python"? A Python interpreter is any computer program that is capable of doing the following: @@ -117,7 +117,6 @@ this will instruct the Python interpreter program `python` to read your text fil In practice, you will be able to simply execute `python my_script.py` in any directory, and your computer will know where to look to find the `python` program. This will be set up during the installation process. It may be confusing to think that the Python language is interpreted by using a program written in another language. How, then, is that language interpreted? The answer, in the case of CPython, is that C code need not be interpreted; programs exist for Windows, Mac, and Linux that can translate C code directly into machine instructions. - ## Why Python? @@ -136,7 +135,7 @@ This can be reproduced by the following C++ code, which is arguably less-intuiti int main() { std::vector a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - std::cout << std::accumulate(a.begin(), e.end(), 0) << std::endl; + std::cout << std::accumulate(a.begin(), a.end(), 0) << std::endl; } ``` diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md.txt index c1ada19f..2390a6b2 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Integrated Development Environments, Difficulty: Easy, Category: Tools :keywords: python, introduction, IDE, PyCharm, VSCode, Jupyter, recommendation, tools -``` + # Setting Up a Development Environment ## What You Will Learn @@ -49,39 +49,34 @@ There are many excellent IDEs that can be configured to work well with Python. T - works well out-of-the-box - long-supported by professionals and thus is very reliable - highly configurable -- fully-featured +- fully-featured, with an excellent debugger, context-dependent "intellisense", type-inference, and more +- the free "community version" is extremely robust and feature-rich. **Cons** - can be resource-heavy, especially for a laptop - may be overwhelming to new users (but has good documentation and tutorials) + - Jupyter notebook support requires the premium version of PyCharm, making it inaccessible to newcomers [Visual Studio Code](https://code.visualstudio.com/) with the [Python extension](https://code.visualstudio.com/docs/languages/python): A lightweight, highly customizable IDE. **Pros** -- lightweight and elegant -- works with many different languages, so you only need to familiarize yourself with one IDE +- lightweight and elegant +- completely free +- works with many different languages, so you only need to familiarize yourself with one IDE if you are a polyglot programmer - a huge number of extensions can be downloaded to add functionality to the editor; these are created by a large community of open-source developers. +- [has native support for Jupyter notebooks](https://code.visualstudio.com/docs/python/jupyter-support), meaning that you get VSCode's intellisense, debugger, and ability to inspect variables, all in a notebook. **Cons** -- currently less polished and less powerful than PyCharm, although Microsoft is now formally supporting the Python extension -- can require some tinkering to get features working - +- configuring VSCode for python development can have a moderate learning curve for newcomers +- many features, like context-aware intellisense and type-inference, are simply more polished and powerful in PyCharm +
      **Takeaway**: Integrated Development Environments (IDEs) provide powerful tools for helping you write well-formatted and typo-free code. We recommend using PyCharm Community Edition or Visual Studio Code (with the Python extension installed) for your Python IDE.
      - - -
      - -**Jupyter Lab**: - -[Jupyter Lab](https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html) is a new IDE that is being developed by the same team that develops the Jupyter Notebook. It aims to mix the polish and power of a traditional IDE, along with the convenience and great utility of the notebook environment. As of writing this, Jupyter Lab is still in the beta release phase. Given the massive popularity of Jupyter Notebook, Jupyter Lab will likely become a widely used IDE, quickly. - -
      diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/Informal_Intro_Python.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/Informal_Intro_Python.md.txt index aa53eea6..d098134a 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/Informal_Intro_Python.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/Informal_Intro_Python.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Informal Introduction to Python, Difficulty: Easy, Category: Tutorial :keywords: python, installation, script, introduction, ipython, console, quick introduction -``` + # An Informal Introduction to Python Now that you have the Anaconda distribution of Python installed on your machine, let's write some simple Python code! We are going to forego writing a full Python script for now, and instead make use of a convenient tool for doing quick code scratchwork. The IPython console was installed as a part of Anaconda; it will allow us to build incrementally off of snippets of code, instead of having to execute an entire script all at once. diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/Installing_Python.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/Installing_Python.md.txt index eb1e42bb..c415deee 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/Installing_Python.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/Installing_Python.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Installing Python with Anaconda, Difficulty: Easy, Category: Tutorial :keywords: python, anaconda, instructions, environments, beginner, data science, introduction -``` + ## Installing Python @@ -46,7 +46,7 @@ Some of the packages provided by Anaconda, like NumPy, have been [optimized](htt You will need to know how to open a terminal (cmd.exe for Windows users) on your computer, and how to navigate between directories in the terminal. If you do not know how to do this, read a 'how-to' for whatever operating system you are using. - + ### What did this just do to my computer? This created a directory called `Anaconda3` (or some variant of this) on your computer, which contains all of the files associated with the CPython interpreter, all of the modules in Python's standard library, the aforementioned 3rd party packages that come as part of the Anaconda distribution (e.g. NumPy, SciPy, Jupyter, iPython), and the `conda` package manager. It also contains the executable files for all of these applications. The default install location for Anaconda is: @@ -101,4 +101,3 @@ And like that, conda environments give you all of the powers of a necromancer, a Conda environments have more uses than simply switching back and forth between Python 3 and 2. Many people like to make a new conda environment for every major project that they work on, so that they can freely install any dependencies that are needed for that particular project, without worrying about conflicts with their other work. You should be keen on making regular use of conda environments. It is highly recommended that you take time to read through [this tutorial on managing conda environments](https://conda.io/docs/user-guide/tasks/manage-environments.html). - diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/Jupyter_Notebooks.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/Jupyter_Notebooks.md.txt index 9b63e963..0bb42a42 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/Jupyter_Notebooks.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/Jupyter_Notebooks.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Jupyter notebooks, Difficulty: Easy, Category: Tutorial - :keywords: jupyter, notebook, kernel, basics, server, console, command line, plot, beginner, data science -``` + :keywords: jupyter, jupyter lab, notebook, kernel, basics, server, console, plot, beginner, data science + # Jupyter Notebooks In recent years, the Jupyter Notebook has become a massively popular tool for doing research-oriented work in Python and other languages alike. Its emergence marked a paradigm shift in the way data science is conducted. @@ -25,14 +25,24 @@ A Jupyter notebook is similar to the IPython console, but, instead of only being In this way, the Jupyter Notebook stands out as an excellent tool for many practical applications. You could work on a notebook while you are working through sections of this website, for instance, testing out snippets of code, and answering reading-comprehension questions as you proceed through the text, and using markdown-headers to visually separate different portions of the notebook. When I do research, I am always creating Jupyter notebooks in which I write code that analyzes data, I plot various results, presented in different ways, and I write detailed markdown-text blocks to document my work. The end result is something that I can share with my labmates, and easily revisit months later without having to struggle to recall what I had done. -Enough gushing about Jupyter notebooks. Let's start using them! +## Jupyter Lab +[Jupyter lab](https://jupyterlab.readthedocs.io/) is a new web interface from Project Jupyter that provides a rich web-based interface for managing and running Jupyter notebooks, console terminals, and text editors, all within your browser. Among its useful features and polished user interface - compared to that a Jupyter notebook server - Jupyter lab provides moveable panes for viewing data, images, and code output apart from the rest of the notebook. This is facilitates effective data science work flows. + +It is recommended that you peruse the [Jupyter lab documentation](https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html) to get a feel for all of its added capabilities. + + +The following instructions are laid out for running a Jupyter notebook server. That being said, the process for running a Jupyter lab server and working with notebooks therein is nearly identical. Both Jupyter notebook and Jupyter lab should already be [installed via Anaconda](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html). ## Running a Notebook Server & Creating a Notebook +Enough gushing about Jupyter notebooks. Let's start using them! + In your terminal, navigate to a directory (a.k.a folder) that you are okay creating files in. If you don't know how to do this, Google it! Once you are in the desired directory, execute in your terminal (type the following, and then hit ``): `jupyter notebook` +Alternatively, if you want to work in Jupyter lab, run: `jupyter lab` + You should see some text appear in your terminal: ![Starting a jupyter notebook server on your machine](attachments/jupyter_login.PNG) @@ -175,3 +185,5 @@ The Jupyter Notebook does not work exclusively with Python. A "kernel" can be de The ever-growing list of available kernels for use with Jupyter can be found [here](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels). It should be noted that these efforts are not all equally mature. For instance, whereas the Python and Julia kernels are robust, the Haskell kernel cannot run natively on Windows machines, and the C++ kernel is still in early development, as of writing this. +### Jupyter Notebook Support in Visual Studio Code +Native Jupyter notebook support was [recently added to Visual Studio Code](https://devblogs.microsoft.com/python/announcing-support-for-native-editing-of-jupyter-notebooks-in-vs-code/). This means that you can now edit Jupyter notebooks within the [Visual Studio Code IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), and that you will benefit from added features like code-completion, debugging, and variable inspection. \ No newline at end of file diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md.txt index 5ec2450e..f68dab65 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/Numerical_Work_In_Python.md.txt @@ -4,8 +4,8 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python diff --git a/docs_backup/_sources/Module1_GettingStartedWithPython/SiteFormatting.md.txt b/docs_backup/_sources/Module1_GettingStartedWithPython/SiteFormatting.md.txt index f5f71a49..0f38f692 100644 --- a/docs_backup/_sources/Module1_GettingStartedWithPython/SiteFormatting.md.txt +++ b/docs_backup/_sources/Module1_GettingStartedWithPython/SiteFormatting.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Overview of formatting in Python Like You Mean It, Difficulty: Easy, Category: Instructions :keywords: overview, formatting, background, code block, console style -``` + # A Quick Guide to Formatting diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Basic_Objects.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Basic_Objects.md.txt index aefed226..b9f5a4a7 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Basic_Objects.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Basic_Objects.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Basics of Python Objects, Difficulty: Easy, Category: Section :keywords: integers, booleans, floats, floating point precision, lists, strings, fundamentals -``` + # Basic Object Types @@ -805,7 +805,7 @@ To answer some of the following questions, you will need to peruse the documenta 3\. Remove the whitespace from both ends of: `" basket "` - + 4\. Create a string that will print as (the second line begins with a tab-character): ``` Hello @@ -817,7 +817,6 @@ Hello 6\. Only kids 13 and up are allowed to see Wayne's World. Given the variables `name` (a string) and `age` (an integer), use an f-string that will display: "NAME is old enough to watch the movie: BOOL", where NAME is to be replaced with the kid's name, and BOOL should be `True` if the kid is at least 13 years old, and `False` otherwise.

      - ## Lists diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/ConditionalStatements.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/ConditionalStatements.md.txt index 95af737f..b6192abb 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/ConditionalStatements.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/ConditionalStatements.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Conditional Statements, Difficulty: Easy, Category: Section :keywords: if, else, elif, inline if, switch statement, comparison operator, bool, truth, is operator -``` + # Conditional Statements diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures.md.txt index f7889e76..81631b47 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Data Structures, Difficulty: Medium, Category: Section :keywords: Big-O, complexity, efficiency, algorithm, interview preparation, list, tuple, sequence -``` + # Data Structures (Part I): Introduction diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md.txt index 5cc59ade..9ac0a106 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_III_Sets_and_More.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Introduction to Sets, Difficulty: Medium, Category: Section :keywords: set, complexity, comparison, union, intersection, membership, hashing, lookup, interview preparation -``` + # Data Structures (Part III): Sets & the Collections Module diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md.txt index 5333500b..d3e9d010 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/DataStructures_II_Dictionaries.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Introduction to Dictionaries, Difficulty: Medium, Category: Section :keywords: dictionary, complexity, key, value, iteration, get item, hashing, lookup, interview preparation -``` + # Data Structures (Part II): Dictionaries Python's dictionary allows you to store key-value pairs, and then pass the dictionary a key to quickly retrieve its corresponding value. Specifically, you construct the dictionary by specifying one-way mappings from key-objects to value-objects. **Each key must map to exactly one value**, meaning that a key must be unique. diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/ForLoops.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/ForLoops.md.txt index 4b37e619..821c4d40 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/ForLoops.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/ForLoops.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Contorl flow with for-loops and while-loops, Difficulty: Easy, Category: Section :keywords: for-loop, while-loop, break, control flow, basic programming -``` + # For-Loops and While-Loops In this section, we will introduce the essential "for-loop" control flow paradigm along with the formal definition of an "iterable". The utility of these items cannot be understated. Moving forward, you will likely find use for these concepts in nearly every piece of Python code that you write! diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Functions.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Functions.md.txt index a2d8c6c5..2d670f3d 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Functions.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Functions.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Functions and Function Signatures, Difficulty: Medium, Category: Section :keywords: functions, *args, **kwargs, signature, default parameter, docstring, return, vowel count, syntax, basics -``` + # Basics of Functions @@ -68,7 +68,7 @@ In this section, we will learn about the syntax for defining and calling functio A Python **function** is an object that encapsulates code. *Calling* the function will execute the encapsulated code and *return* an object. A function can be defined so that it accepts *arguments*, which are objects that are to be passed to the encapsulated code.
      - + ## The `def` Statement Similar to `if`, `else`, and `for`, the `def` statement is reserved by the Python language to signify the definition of functions (and a few other things that we'll cover later). The following is the general syntax for defining a Python function: @@ -88,7 +88,6 @@ def (): The `return` statement is also reserved by Python. It denotes the end of a function; if reached, a `return` statement immediately concludes the execution of the function and returns the specified object. Note that, like an if-statement and a for-loop, the `def` statment must end in a colon and the body of the function is [delimited by whitespace](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Introduction.html#Python-Uses-Whitespace-to-Delimit-Scope): - ```python @@ -138,7 +137,7 @@ Write a function named `count_even`. It should accept one input argument, named ## The `return` Statement -In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the `None` object*. +In general, any Python object can follow a function's `return` statement. Furthermore, an **empty** `return` statement can be specified, or the **return** statement of a function can be omitted altogether. In both of these cases, *the function will return the* `None` *object*. ```python # this function returns `None` diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Generators_and_Comprehensions.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Generators_and_Comprehensions.md.txt index 7baae451..25da3c6c 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Generators_and_Comprehensions.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Generators_and_Comprehensions.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: generators comprehensions and efficiency, Difficulty: Easy, Category: Section :keywords: generator, range, list comprehension, generator comprehension, nested comprehensions, inline for-loop, filtered, iterator -``` + # Generators & Comprehension Expressions
      @@ -197,7 +197,6 @@ Generator comprehensions are **not** the only method for defining generators in
      -
      **Reading Comprehension: Writing a Generator Comprehension**: @@ -212,7 +211,6 @@ Note that (3, 5) is *not* in the series. Iterate over the generator and print its contents to verify your solution.
      - ### Storing generators diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Introduction.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Introduction.md.txt index 6bbf1be7..7f48f672 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Introduction.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Introduction.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: introduction to control flow, Difficulty: Easy, Category: Section :keywords: overview, summary, if, else, function, for-loop, if, else, control flow -``` + # Introducing Control Flow diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Iterables.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Iterables.md.txt index 5eb7fc49..2a53dcd7 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Iterables.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Iterables.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: the basics of iterables in python, Difficulty: Medium, Category: Section :keywords: iterables, max, min, sum, all, any, itertools, enumerate, unpack -``` + # Iterables Our encounter with for-loops introduced the term *iterable* - an object that can be "iterated over", such as in a for-loop. diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Itertools.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Itertools.md.txt index 3b6ec9eb..c4efa8f4 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Itertools.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Itertools.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: simple use cases of python itertools, Difficulty: Easy, Category: Tutorial :keywords: itertools, examples, zip, range, enumerate, chain, combinations -``` + # Python's "Itertools" diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/DifferenceFanout.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/DifferenceFanout.md.txt index e56ab94e..6bebd45f 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/DifferenceFanout.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/DifferenceFanout.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: For-Loop Exercise, Difficulty: Easy, Category: Practice Problem :keywords: for loops, list, function, list comprehension, practice problem -``` + diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/EncodeAsString.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/EncodeAsString.md.txt index 19af2c47..1b90cf5a 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/EncodeAsString.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/EncodeAsString.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: String Encoding Exercise, Difficulty: Medium, Category: Practice Problem :keywords: function, string, casting, practice problem -``` + # Encode as String Sometimes it is very important to handle different input object types differently in a function. This problem will exercise your understanding of types, control-flow, dictionaries, and more. @@ -30,7 +30,7 @@ Sometimes it is very important to handle different input object types differentl - If the object is a string, keep it as is. - If the object is of any other type, return `''`. - + ``` Python # example behavior >>> s = concat_to_str([12,-14.23,"hello", True, @@ -40,7 +40,6 @@ Sometimes it is very important to handle different input object types differentl ``` **Tips**: check out the `isinstance` function introduced [here](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html) for handling different types. Also, consider creating a helper function for the conversion from integer to our special-format string, since we have to do it twice. It's always good to extrapolate repeated tasks into functions. You'll also need to hard-code the conversion from each digit to its English spell-out. - ## Solution diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MarginPercentage.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MarginPercentage.md.txt index d8b24c81..ddce8aeb 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MarginPercentage.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MarginPercentage.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Within Margin Exercise, Difficulty: Medium, Category: Practice Problem :keywords: function, control flow, comparisons, practice problem -``` + # Within Margin Percentage diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md.txt index f5293e78..95f9be13 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/MergeMaxDicts.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Dictionary Merge Exercise, Difficulty: Easy, Category: Practice Problem :keywords: dictionary, merge, practice problem -``` + # Merging Two Dictionaries diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/Palindrome.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/Palindrome.md.txt index 4921dcbe..098fa12b 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Problems/Palindrome.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Problems/Palindrome.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Palindrome Exercise, Difficulty: Easy, Category: Practice Problem :keywords: string, palindrome, practice problem -``` + # Is Palindrome diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Scope.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Scope.md.txt index b784bdd4..15b6b594 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Scope.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Scope.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: variable score and namespaces in python, Difficulty: Medium, Category: Section :keywords: variable, namespace, function, scope, shadowing -``` + # Scope diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/SequenceTypes.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/SequenceTypes.md.txt index 25790196..2ada1cdd 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/SequenceTypes.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/SequenceTypes.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: understanding python sequences, Difficulty: Easy, Category: Section :keywords: list, tuple, string, slice, index, negative index, get item, pop, append, examples -``` + # Sequence Types diff --git a/docs_backup/_sources/Module2_EssentialsOfPython/Variables_and_Assignment.md.txt b/docs_backup/_sources/Module2_EssentialsOfPython/Variables_and_Assignment.md.txt index 9e317466..0869b676 100644 --- a/docs_backup/_sources/Module2_EssentialsOfPython/Variables_and_Assignment.md.txt +++ b/docs_backup/_sources/Module2_EssentialsOfPython/Variables_and_Assignment.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: variable naming and assignment, Difficulty: Medium, Category: Section :keywords: variable naming, valid names, mutable, immutable, reference, pointer -``` + # Variables & Assignment diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md.txt index 85f78fe4..0287cbb7 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Indexing into multi-dimensional numpy arrays, Difficulty: Easy, Category: Section :keywords: numpy array, multidimensional, index, slice, negative index, rows, columns -``` + # Accessing Data Along Multiple Dimensions in an Array diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/AdvancedIndexing.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/AdvancedIndexing.md.txt index cc91851d..101ed3d2 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/AdvancedIndexing.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/AdvancedIndexing.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Advanced indexing with numpy arrays, Difficulty: Hard, Category: Section :keywords: numpy array, integer array indexing, boolean array indexing, copy indexing, advanced -``` + # Advanced Indexing diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/ArrayTraversal.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/ArrayTraversal.md.txt index 115b2f34..da718d02 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/ArrayTraversal.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/ArrayTraversal.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Numpy array traversal ordering, Difficulty: Medium, Category: Section :keywords: row-major order, c order, column-major order, f order, traversal, array iteration -``` + # Iterating Over Arrays & Array-Traversal Order In this section, you will learn: diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/BasicArrayAttributes.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/BasicArrayAttributes.md.txt index 527ee446..1cee79bf 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/BasicArrayAttributes.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/BasicArrayAttributes.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Numpy array attributes, Difficulty: Easy, Category: Section :keywords: ndim, shape, size, itemsize, dtype, examples -``` + # Basic Array Attributes diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/BasicIndexing.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/BasicIndexing.md.txt index 5e61cdab..fae04f4b 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/BasicIndexing.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/BasicIndexing.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Numpy array basic indexing, Difficulty: Medium, Category: Section :keywords: basic index, slice, no copy index, multidimensional array, nd array, view, reverse, axis -``` + # Introducing Basic and Advanced Indexing diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt index 41a8f5a6..cd83934a 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/Broadcasting.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Numpy array broadcasting, Difficulty: Medium, Category: Section :keywords: broadcasting, vectorization, rules, mismatched shapes, distances -``` + # Array Broadcasting @@ -138,7 +138,7 @@ The two arrays are broadcast-compatible if either of these conditions are satisf

    - + Note that it is okay to have one array with a higher-dimensionality and thus to have "dangling" leading dimensions. Any size-1 dimension or "missing" dimension will be filled-in by broadcasting the content of that array. Considering the example from the preceding subsection, let's see that the shape-(4,3) and shape-(3,) arrays satisfy these rules for broadcast-compatibility: @@ -180,7 +180,6 @@ result-shape: INCOMPATIBLE result-shape: 2 x 1 ``` - NumPy provides the function [broadcast_to](https://docs.scipy.org/doc/numpy/reference/generated/numpy.broadcast_to.html#numpy.broadcast_to), which can be used to broadcast an array to a specified shape. This can help us build our intuition for broadcasting. Let's broadcast a shape-(3,4) array to a shape-(2,3,4) array: @@ -487,16 +486,16 @@ Performing this computation using for-loops proceeds as follows: def pairwise_dists_looped(x, y): """ Computing pairwise distances using for-loops - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # `dists[i, j]` will store the Euclidean # distance between `x[i]` and `y[j]` dists = np.empty((5, 6)) @@ -546,18 +545,18 @@ Voilà! We have produced the distances in a vectorized way. Let's write this out def pairwise_dists_crude(x, y): """ Computing pairwise distances using vectorization. - This method uses memory-inefficient broadcasting. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + This method uses memory-inefficient broadcasting. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" # The use of `np.newaxis` here is equivalent to our # use of the `reshape` function return np.sqrt(np.sum((x[:, np.newaxis] - y[np.newaxis])**2, axis=2)) @@ -629,23 +628,23 @@ In total, we have successfully used vectorization to compute the all pairs of di ```python def pairwise_dists(x, y): - """ Computing pairwise distances using memory-efficient - vectorization. - - Parameters - ---------- - x : numpy.ndarray, shape=(M, D) - y : numpy.ndarray, shape=(N, D) - - Returns - ------- - numpy.ndarray, shape=(M, N) - The Euclidean distance between each pair of - rows between `x` and `y`.""" + """ Computing pairwise distances using memory-efficient + vectorization. + + Parameters + ---------- + x : numpy.ndarray, shape=(M, D) + y : numpy.ndarray, shape=(N, D) + + Returns + ------- + numpy.ndarray, shape=(M, N) + The Euclidean distance between each pair of + rows between `x` and `y`.""" dists = -2 * np.matmul(x, y.T) - dists += np.sum(x**2, axis=1)[:, np.newaxis] + dists += np.sum(x**2, axis=1)[:, np.newaxis] dists += np.sum(y**2, axis=1) - return np.sqrt(dists) + return np.sqrt(dists) ``` diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md.txt index 67f18ec4..2fac459f 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Creating numpy arrays, Difficulty: Easy, Category: Section :keywords: create array, ndarray, ones, random, zeros, empty, examples, arange, linspace, reshape, hstack, vstack -``` + # Functions for Creating NumPy Arrays diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/IntroducingTheNDarray.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/IntroducingTheNDarray.md.txt index a5c0ffa8..bc9abc67 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/IntroducingTheNDarray.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/IntroducingTheNDarray.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Introduction to numpy arrays, Difficulty: Easy, Category: Section :keywords: numpy array, ndarray, introduction, overview -``` + # Introducing the ND-array @@ -40,7 +40,7 @@ Let's take a sneak peek to see at what this module has in store. The following c >>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8]) ``` -This object is belongs to the NumPy-defined type `numpy.ndarray`. +This object belongs to the NumPy-defined type `numpy.ndarray`. ```python # An ND-array belongs to the type `numpy.ndarray` diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md.txt index a4e7323d..b2b59efa 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/Problems/ComputeAccuracy.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Measuring classification accuracy, Difficulty: Easy, Category: Practice Problem :keywords: numpy, vectorization, practice, machine learning, classifier -``` + # Measuring the Accuracy of a Classification Model diff --git a/docs_backup/_sources/Module3_IntroducingNumpy/VectorizedOperations.md.txt b/docs_backup/_sources/Module3_IntroducingNumpy/VectorizedOperations.md.txt index 48defb53..1c893ee6 100644 --- a/docs_backup/_sources/Module3_IntroducingNumpy/VectorizedOperations.md.txt +++ b/docs_backup/_sources/Module3_IntroducingNumpy/VectorizedOperations.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Vectorized operations with numpy arrays, Difficulty: Easy, Category: Section :keywords: vectorize, optimized, calculation, numpy, fast, C routine, MKL, sum, linear algebra, optimized -``` + # "Vectorized" Operations: Optimized Computations on NumPy Arrays diff --git a/docs_backup/_sources/Module4_OOP/Applications_of_OOP.md.txt b/docs_backup/_sources/Module4_OOP/Applications_of_OOP.md.txt index fdb32205..fe93d859 100644 --- a/docs_backup/_sources/Module4_OOP/Applications_of_OOP.md.txt +++ b/docs_backup/_sources/Module4_OOP/Applications_of_OOP.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Applications of object-oriented programming, Difficulty: Medium, Category: Section :keywords: summary, tutorial, python shopping list, object oriented, method, attribute -``` + # Applications of Object Oriented Programming diff --git a/docs_backup/_sources/Module4_OOP/Brief_Review.md.txt b/docs_backup/_sources/Module4_OOP/Brief_Review.md.txt index 94b3b9f1..29d35c97 100644 --- a/docs_backup/_sources/Module4_OOP/Brief_Review.md.txt +++ b/docs_backup/_sources/Module4_OOP/Brief_Review.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Brief review of object oriented programming, Difficulty: Easy, Category: Tutorial :keywords: class definition, simple, examples, overview, init, initialize, type, object -``` + ## A Brief Summary of Terms and Concepts diff --git a/docs_backup/_sources/Module4_OOP/ClassDefinition.md.txt b/docs_backup/_sources/Module4_OOP/ClassDefinition.md.txt index 77bb461c..6419727b 100644 --- a/docs_backup/_sources/Module4_OOP/ClassDefinition.md.txt +++ b/docs_backup/_sources/Module4_OOP/ClassDefinition.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: The rules for defining classes in python, Difficulty: Easy, Category: Section :keywords: class definition, scope, class object, attribute, method -``` + diff --git a/docs_backup/_sources/Module4_OOP/ClassInstances.md.txt b/docs_backup/_sources/Module4_OOP/ClassInstances.md.txt index a7cfbe96..7d5cc65c 100644 --- a/docs_backup/_sources/Module4_OOP/ClassInstances.md.txt +++ b/docs_backup/_sources/Module4_OOP/ClassInstances.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Class instances versus objects, Difficulty: Medium, Category: Section :keywords: instance, class creation, init, self, isinstance -``` + # Instances of a Class diff --git a/docs_backup/_sources/Module4_OOP/Inheritance.md.txt b/docs_backup/_sources/Module4_OOP/Inheritance.md.txt index 95eda792..95114973 100644 --- a/docs_backup/_sources/Module4_OOP/Inheritance.md.txt +++ b/docs_backup/_sources/Module4_OOP/Inheritance.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Class inheritance, Difficulty: Easy, Category: Section :keywords: inherit, object oriented, overwrite, sub class, issubclass -``` + # Inheritance diff --git a/docs_backup/_sources/Module4_OOP/Introduction_to_OOP.md.txt b/docs_backup/_sources/Module4_OOP/Introduction_to_OOP.md.txt index a3e21e44..e061c9c9 100644 --- a/docs_backup/_sources/Module4_OOP/Introduction_to_OOP.md.txt +++ b/docs_backup/_sources/Module4_OOP/Introduction_to_OOP.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Introducing object oriented programming in python, Difficulty: Easy, Category: Section :keywords: class, type, creation, definition, intro, overview, basics, meaning -``` + # Introduction to Object Oriented Programming diff --git a/docs_backup/_sources/Module4_OOP/Methods.md.txt b/docs_backup/_sources/Module4_OOP/Methods.md.txt index 3e30d16e..92d9723a 100644 --- a/docs_backup/_sources/Module4_OOP/Methods.md.txt +++ b/docs_backup/_sources/Module4_OOP/Methods.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: The different kinds of class methods, Difficulty: Medium, Category: Section :keywords: instance, class method, static method, property, abstract method, class funtion -``` + # Methods diff --git a/docs_backup/_sources/Module4_OOP/ObjectOrientedProgramming.md.txt b/docs_backup/_sources/Module4_OOP/ObjectOrientedProgramming.md.txt index 5138eb49..8c5802a6 100644 --- a/docs_backup/_sources/Module4_OOP/ObjectOrientedProgramming.md.txt +++ b/docs_backup/_sources/Module4_OOP/ObjectOrientedProgramming.md.txt @@ -4,8 +4,8 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python @@ -328,7 +328,6 @@ class Rational: self.denom = denom // factor - def __add__(self, other): ''' Overload the `+` operator @@ -424,7 +423,6 @@ class Rational: ''' return 'Rational({}, {})'.format(self.num, self.denom) ``` - ```python diff --git a/docs_backup/_sources/Module4_OOP/Special_Methods.md.txt b/docs_backup/_sources/Module4_OOP/Special_Methods.md.txt index c1e9c780..45a91811 100644 --- a/docs_backup/_sources/Module4_OOP/Special_Methods.md.txt +++ b/docs_backup/_sources/Module4_OOP/Special_Methods.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Controlling behavior with special methods, Difficulty: Medium, Category: Section :keywords: dunder method, special method, operator overload, repr, getitem, custom syntax, __init__ -``` + # Special Methods diff --git a/docs_backup/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt b/docs_backup/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt index 40a39915..e359b39a 100644 --- a/docs_backup/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt +++ b/docs_backup/_sources/Module5_OddsAndEnds/Modules_and_Packages.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Understanding imports modules and packages, Difficulty: Easy, Category: Section :keywords: custom package, module, script, import, setup, pip, conda, relative import, absolute import -``` + # Import: Modules and Packages @@ -404,18 +404,17 @@ In lieu of printing out your `PYTHONPATH`, you can look up the location of your It must be mentioned that we are sweeping some details under the rug here. Installing NumPy does not merely entail copying its various modules and packages wholesale into site-packages. That being said, we will not dive any deeper into the technical details of package installation beyond understanding where packages are installed and thus where our Python interpreter looks to import them. - ### Installing Your Own Python Package -Suppose that we are happy with the work we have done on our `face_detector` project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter's working directory. Here we will construct a basic setup script that will allow us to accomplish this. +Suppose that we are happy with the work we have done on our `face_detector` project. We will want to install this package - placing it in our site-packages directory so that we can import it irrespective of our Python interpreter's working directory. Here we will construct a basic setup script that will allow us to accomplish this. For completeness, we will also indicate how one would include a test suite along side the source code in this directory structure. We note outright that the purpose of this section is strictly to provide you with the minimum set of instructions needed to install a package. We will not be diving into what is going on under the hood at all. Please refer to [An Introduction to Distutils](https://docs.python.org/3/distutils/introduction.html#an-introduction-to-distutils) and [Packaging Your Project](https://packaging.python.org/tutorials/packaging-projects/#packaging-your-project) for a deeper treatment of this topic. Carrying on, we will want to create a setup-script, `setup.py`, *in the same directory as our package*. That is, our directory structure should look like: ``` -- setup.py -- face_detection/ +- setup.py # script responsible for installing `face_detection` package +- face_detection/ # source code of `face_detection` package |-- __init__.py |-- utils.py |-- database.py @@ -424,33 +423,41 @@ Carrying on, we will want to create a setup-script, `setup.py`, *in the same dir |-- __init__.py |-- calibration.py |-- config.py +- tests/ # test-suite for `face_detection` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_utils.py + |-- test_database.py + |-- test_model.py + |-- camera/ + |-- test_calibration.py + |-- test_config.py ``` - + +A `tests/` directory can be included at the same directory level as `setup.py` and `face_detection/`. This is the recommended structure for using pytest as our test-runner. The bare bones build script for preparing your package for installation, `setup.py`, is as follows: ```python # contents of setup.py -import setuptools +from setuptools import find_packages, setup -setuptools.setup( +setup( name="face_detection", - version="1.0", - packages=setuptools.find_packages(), + version="1.0.0", + packages=find_packages(exclude=["tests", "tests.*"]), + python_requires=">=3.5", ) ``` - - +The `exclude` expression is used to ensure that specific directories or files are not included in the installation of `face_detection`. We use `exclude=["tests", "tests.*"]` to avoid installing the test-suite along side `face_detection` - If you read through the additional materials linked above, you will see that there are many more fields of optional information that can be provided in this setup script, such as the author name, any installation requirements that the package has, and more. Armed with this script, we are ready to install our package locally on our machine! In your terminal, navigate to the directory containing this setup script and your package that it being installed. Run ```shell -python setup.py install +pip install . ``` and voilà, your package `face_detection` will have been installed to site-packages. You are now free to import this package from any directory on your machine. In order to uninstall this package from your machine execute the following from your terminal: @@ -459,14 +466,13 @@ and voilà, your package `face_detection` will have been installed to site-packa pip uninstall face_detection ``` -One final but important detail. The installed version of your package will no longer "see" the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead you can install your package in develop mode, such that a symbolic link to your source code is placed in your site-packages. Thus any changes that you make to your code will immediately be reflected in your system-wide installation. Thus, instead of running `python setup.py install`, execute the following to install a package in develop mode: +One final but important detail. The installed version of your package will no longer "see" the source code. That is, if you go on to make any changes to your code, you will have to uninstall and reinstall your package before your will see the effects system-wide. Instead you can install your package in "development mode", such that a symbolic link to your source code is placed in your site-packages. Thus any changes that you make to your code will immediately be reflected in your system-wide installation. Thus, instead of running `python setup.py install`, execute the following to install a package in develop mode: ```shell -python setup.py develop +pip install --editable . ``` - - + ## pip and conda: Package Managers Python packages can be shared worldwide. There are two widely-used Python package managers, `pip` and `conda`. `pip` downloads and installs packages from [The Python Package Index (PyPI)](https://pypi.org/), whereas `conda` downloads and installs packages from the Anaconda Cloud. Both `conda` and `pip` are installed as part of the [Anaconda distribution](http://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#Installing-Anaconda). @@ -488,7 +494,7 @@ Both managers will install packages to your site-packages directory. There are substantial benefits for using `conda` rather than `pip` to install packages. First and foremost, `conda` has a powerful "environment solver", which tracks the inter-dependencies of Python packages. Thus it will attempt to install, upgrade, and downgrade packages as needed to accommodate your installations. Additionally, the default list of packages available via `conda` are curated and maintained by Continuum Analytics, the creators of Anaconda. To elucidate one of the benefits of this, installing NumPy via `pip` will deliver the vanilla version of NumPy to you; `conda` will install an [mkl-optimized version of NumPy](https://software.intel.com/en-us/articles/numpyscipy-with-intel-mkl), which can execute routines substantially faster. Finally, `conda` also serves as [an environment manager](https://conda.io/docs/user-guide/tasks/manage-environments.html), which allows you to maintain multiple, non-conflicting environments that can house different configurations of installed Python packages and even different versions of Python itself. That being said, there are some benefits to using `pip`. PyPi is accessible and easy to upload packages to; this is likely the easiest means for distributing a Python package worldwide. As such, `pip` provides access to a wider range of Python packages. That being said, `conda` can also be directed to install packages from custom channels - providing access to packages outside of the curated Anaconda distribution. This has become a popular method of installation for machine learning libraries like PyTorch and TensorFlow. - + You are free to install some packages using `conda` and others with `pip`. Just take care not to accidentally install the same package with both - this can lead to a real mess. diff --git a/docs_backup/_sources/Module5_OddsAndEnds/Testing_Code_Scratch.ipynb.txt b/docs_backup/_sources/Module5_OddsAndEnds/Testing_Code_Scratch.ipynb.txt new file mode 100644 index 00000000..ae790840 --- /dev/null +++ b/docs_backup/_sources/Module5_OddsAndEnds/Testing_Code_Scratch.ipynb.txt @@ -0,0 +1,118 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def test_count_vowels_basic():\n", + " assert count_vowels(\"aA bB yY\", include_y=False) == 2\n", + " assert count_vowels(\"aA bB yY\", include_y=True) == 4\n", + " assert count_vowels(\"\", include_y=True) == 0" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def count_vowels(x: str, include_y: bool = False) -> int:\n", + " \"\"\"Returns the number of vowels contained in `x`\n", + "\n", + " Examples\n", + " --------\n", + " >>> count_vowels(\"happy\")\n", + " 1\n", + " >>> count_vowels(\"happy\", include_y=True)\n", + " 2\n", + " \"\"\"\n", + " vowels = set(\"aeiouAEIOU\")\n", + " if include_y:\n", + " vowels.update(\"yY\")\n", + " return sum(1 for char in x if char in vowels)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "count_vowels(\"happy\", include_y=)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + ">>> assert 0 in [1, 2, 3], \"0 is not in the list\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "a_list =[]\n", + "a_number = 22\n", + "a_string = \"abcdef\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert count_vowels(a_string) < a_number, f\"Number of vowels in `a_string`, {count_vowels(a_string)} exceeds {a_number}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "ename": "AssertionError", + "evalue": "Number of vowels, 2, exceeds 22", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAssertionError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32massert\u001b[0m \u001b[0mcount_vowels\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma_string\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m<\u001b[0m \u001b[0ma_number\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m100\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34mf\"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mAssertionError\u001b[0m: Number of vowels, 2, exceeds 22" + ] + } + ], + "source": [ + "assert count_vowels(a_string) < a_number/100, f\"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}\"" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:.conda-jupy] *", + "language": "python", + "name": "conda-env-.conda-jupy-py" + }, + "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.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs_backup/_sources/Module5_OddsAndEnds/Testing_Your_Code.ipynb.txt b/docs_backup/_sources/Module5_OddsAndEnds/Testing_Your_Code.ipynb.txt new file mode 100644 index 00000000..e6448554 --- /dev/null +++ b/docs_backup/_sources/Module5_OddsAndEnds/Testing_Your_Code.ipynb.txt @@ -0,0 +1,463 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + ".. meta::\n", + " :description: Topic: Writing tests for your code, Difficulty: Medium, Category: Section\n", + " :keywords: test, pytest, automated, unit, integration, property-based, hypothesis " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing Your Code\n", + "\n", + "This section will introduce us to the critically-important and often-overlooked process of testing code. \n", + "We will begin by considering some driving motivations for writing tests.\n", + "Next, we will study the basic anatomy of a test-function, including the `assert` statement, which serves as the nucleus of our test functions.\n", + "Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework [pytest](https://docs.pytest.org/).\n", + "This will inform how we structure our tests alongside our Python project that we are developing; with pytest, we can incisively run our tests with the press of a single button.\n", + "Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests.\n", + "Finally, we will take a step back to consider some strategies for writing effective tests.\n", + "Among these is a methodology that is near and dear to my heart: property-based testing.\n", + "This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library [Hypothesis](https://hypothesis.readthedocs.io/) waiting to greet us (adorned with the mad Hatter's cap and all).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Why Should We Write Tests?\n", + "With great power comes great responsibility: tests help us be responsible for the code that we create and that others will (hopefully) use.\n", + "\n", + "The fact of the matter is that everyone already tests their code to some extent.\n", + "After coding, say, a new function, it is only natural to contrive an input to feed it, and to check that it returns the output that you expected.\n", + "To the extent that anyone would want to see evidence that their code works, we need not motivate the importance of testing.\n", + "\n", + "Less obvious is the massive benefits that we stand to gain from formalizing this testing process.\n", + "And by \"formalizing\", we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end.\n", + "We will accumulate these functions into a \"test suite\" that we can run quickly and repeatedly.\n", + "\n", + "There are plenty of practical details ahead for us to learn, so let's expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite:\n", + "\n", + "- It saves us lots of time:\n", + " > After you have devised a test scenario for your code, it may only take us a second or so to run it - perhaps we need only run a couple of Jupyter notebook cells to check the output.\n", + " > However, this will quickly become unwieldy as we write more code and devise more test scenarios.\n", + " > Soon we will be dissuaded from running our tests except for on rare occasions.\n", + " > With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x's...) will summarize the health of our project (insofar as our tests serve as good diagnostics).\n", + " > This, of course, also means that we will find and fix bugs much faster!\n", + " > In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost.\n", + "- It increases the \"shelf life\" of our code:\n", + " > If you've ever dusted off a project that you haven't used for years (or perhaps only months or weeks...), you might know the tribulations of getting old code to work.\n", + " > Perhaps, in the interim, new versions of our project's dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project's code.\n", + " > And perhaps _we can't even remember_ all of the ways in which our project is supposed to work.\n", + " > Our test suite provides us with a simple and incisive way to dive back into our work.\n", + " > It will point us to any potential incompatibilities that have accumulated over time.\n", + " > It also provides us with a large collection of detailed use-cases of our code;\n", + " > we can read through our tests remind ourselves of the inner-workings of our project.\n", + "- It will inform the design and usability of our project for the better:\n", + " > Although it may not be obvious from the outset, writing testable code leads to writing better code.\n", + " > This is, in part, because the process of writing tests gives us the opportunity to actually _use_ our code under varied circumstances.\n", + " > The process of writing tests will help us suss out cumbersome function interfaces, brittle statefulness, and redundant capabilities in our code. If _we_ find it frustrating to use our code within our tests, then surely others will find it frustrating to use in applied settings.\n", + "- It makes it easier for others to contribute to a project:\n", + " > Having a healthy test suite lowers the barrier to entry for a project. \n", + " > A contributor can make improvements to the project and quickly check to see if they have broken it or changed any of its behavior.\n", + "\n", + "This all sounds great, but where do we even start the process writing a test suite? \n", + "Let's begin by seeing what constitutes a basic test function." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lines_to_next_cell": 0 + }, + "source": [ + "## The Basic Anatomy of a Test Function\n", + "Let's write a function that tests the following `count_values` code:\n", + "\n", + "```python\n", + "# Defining a function that we will be testing\n", + "\n", + "def count_vowels(x: str, include_y: bool = False) -> int:\n", + " \"\"\"Returns the number of vowels contained in `x`.\n", + " \n", + " The vowel 'y' is included optionally.\n", + "\n", + " Examples\n", + " --------\n", + " >>> count_vowels(\"happy\")\n", + " 1\n", + " >>> count_vowels(\"happy\", include_y=True)\n", + " 2\n", + " \"\"\"\n", + " vowels = set(\"aeiouAEIOU\")\n", + " if include_y:\n", + " vowels.update(\"yY\")\n", + " return sum(1 for char in x if char in vowels)\n", + "```\n", + "\n", + "(Note that we will be making use of [type hinting](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Writing_Good_Code.html#Type-Hinting) to help document the interfaces of our functions.\n", + "You may want to briefly review the linked material if this is unfamiliar to you)\n", + "\n", + "For our most basic test, we can simply call `count_values` under various contrived inputs and *assert* that it returns the expected output.\n", + "The desired behavior for this test function, upon being run, is to:\n", + "\n", + "- Raise an error if any of our assertions *failed* to hold true.\n", + "- Complete \"silently\" if all of our assertions hold true (i.e. our test function will simply [return None](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Functions.html#The-return-Statement))\n", + "\n", + "Here, we will be making use of Python's `assert` statements, whose behavior will be easy to deduce from the context of this test alone; we will be formally introduced to them soon.\n", + "\n", + "```python\n", + "# Writing a test function for `count_vowels`\n", + "\n", + "def test_count_vowels_basic():\n", + " assert count_vowels(\"aA bB yY\", include_y=False) == 2\n", + " assert count_vowels(\"aA bB yY\", include_y=True) == 4\n", + "```\n", + "\n", + "To run this test, we simply call the function:\n", + "\n", + "```python\n", + "# running our test function\n", + ">>> test_count_vowels_basic() # passes: returns None | fails: raises error\n", + "```\n", + "\n", + "As described above, the fact our function runs and simply returns `None` means that our code has passed this test. We've written and run our very first test! It certainly isn't the most robust test, but it is a good start.\n", + "\n", + "Let's look more carefully at the structure of `test_count_vowels_basic`.\n", + "Note that this function doesn't take in any inputs;\n", + "thanks to [Python's scoping rules](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Scope.html), we can reference our `count_vowels` function within our test as long as it is defined in the same \"namespace\" as `test_count_vowels_basic`.\n", + "That is, we can either define `count_vowels` in the same .py file (or Jupyter notebook, if you are following along with this material in a notebook) as `test_count_vowels_basic`, or we can [import](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Import-Statements) `count_vowels` from wherever it is defined, and into the file containing our test.\n", + "The latter scenario is by far the most common one in practice. \n", + "More on this later.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: The Basic Anatomy of a Test**\n", + "\n", + "Add an additional assertion to the body of `test_count_vowels_basic`, which tests whether `count_vowels` handles the empty-string (`\"\"`) case appropriately.\n", + "Make sure to run your updated test to see if it passes.\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Testing Our Tests\n", + "\n", + "It is surprisingly easy to unwittingly write a test that always passes or that fails to test our code as we had intended.\n", + "This is a particularly treacherous mistake to make as it leads us to falsely believe that our function is working as-expected.\n", + "**Thus a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior in such a way that our test ought to raise an error.**\n", + "Once we confirm that our test does indeed raise an error as-expected, we restore the function to its original form and re-run the test and see that it passes. \n", + "\n", + "We ought to mutate our function in a way that is trivial to undo; we can use of code-comments towards this end.\n", + "All [IDEs](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) have the ability to \"block-comment\" selected code.\n", + "In a Jupyter notebook code cell, we can highlight multiple lines of code and press `CTRL + /`: this will comment-out these lines of code.\n", + "The same key-combination will also un-comment a highlighted block of commented code.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Testing Your Test via Manual Mutation**\n", + "\n", + "Temporarily change the body of `count_vowels` such that the second assertion in `test_count_vowels_basic` raises an error.\n", + "Run the test to confirm that the second assertion raises,\n", + "and then restore `count_vowels` to its original form.\n", + "Finally, rerun the test to see that `count_vowels` once again passes all of the assertions.\n", + "\n", + "
    \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With our first test function under our belt, it is time for us to clearly understand how `assert` statements work and how they should be used. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lines_to_next_cell": 0 + }, + "source": [ + "### Assert Statements\n", + "Similar to `return`, `def`, or `if`, the term `assert` is a reserved term in the Python language. \n", + "It has the following specialized behavior:\n", + "\n", + "```python\n", + "# demonstrating the rudimentary behavior of the `assert` statement\n", + "\n", + "# asserting an expression whose boolean-value is `True` will complete \"silently\"\n", + ">>> assert 1 < 2\n", + "\n", + "# asserting an expression whose boolean-value is `False` raises an error\n", + ">>> assert 2 < 1\n", + "---------------------------------------------------------------------------\n", + "AssertionError Traceback (most recent call last)\n", + " in \n", + "----> 1 assert 2 < 1\n", + "\n", + "AssertionError: \n", + "\n", + "# we can include an error message with our assertion\n", + ">>> assert 0 in [1, 2, 3], \"0 is not in the list\"\n", + "---------------------------------------------------------------------------\n", + "AssertionError Traceback (most recent call last)\n", + " in \n", + "----> 1 assert 0 in [1, 2, 3], \"0 is not in the list\"\n", + "\n", + "AssertionError: 0 is not in the list\n", + "```\n", + "\n", + "The general form of an assertion statement is:\n", + "\n", + "```python\n", + "assert [, ] \n", + "```\n", + "\n", + "When an assertion statement is executed, the built-in `bool` function is called on the object that is returned by ``; if `bool()` returns `False`, then an `AssertionError` is raised.\n", + "If you included a string in the assertion statement - separated from `` by a comma - then this string will be printed as the error message.\n", + "\n", + "See that the assertion statement: \n", + "```python\n", + "assert expression, error_message\n", + "```\n", + "\n", + "is effectively shorthand for the following code:\n", + "\n", + "```python\n", + "# long-form equivalent of: `assert expression, error_message`\n", + "if bool(expression) is False:\n", + " raise AssertionError(error_message)\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
    \n", + "\n", + "**Reading Comprehension: Assertions**\n", + "\n", + "Given the following objects:\n", + "\n", + "```python\n", + "a_list = []\n", + "a_number = 22\n", + "a_string = \"abcdef\"\n", + "```\n", + "\n", + "Write two assertion statements, each one with the corresponding behavior:\n", + "\n", + "- asserts that `a_list` is _not_ empty\n", + "- asserts that the number of vowels in `a_string` is less than `a_number`; include and error message that prints the actual number of vowels\n", + "\n", + "
    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### What is the Purpose of an Assertion?\n", + "In our code, an assertion should be used as _a statement that is true unless there is a bug our code_.\n", + "It is plain to see that the assertions in `test_count_vowels_basic` fit this description.\n", + "However, it can also be useful to include assertions within our source code itself.\n", + "For instance, we know that `count_vowels` should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string.\n", + "We can explicitly assert that this is the case:\n", + "\n", + "```python\n", + "# an example of including an assertion within our source code\n", + "\n", + "def count_vowels(x: str, include_y: bool = False) -> int:\n", + " vowels = set(\"aeiouAEIOU\")\n", + " if include_y:\n", + " vowels.update(\"yY\")\n", + " count = sum(1 for char in x if char in vowels)\n", + " \n", + " # This assertion should always be true: it is asserting that \n", + " # the internal logic of our function is correct\n", + " assert isinstance(count, int) and 0 <= count <= len(x)\n", + " return count\n", + "```\n", + "\n", + "Note that this assertion *is not meant to check if the user passed bad inputs for* `x` *and* `include_y`.\n", + "Rather, it is meant to assert that our own internal logic holds true.\n", + "\n", + "Admittedly, the `count_vowels` function is simple enough that the inclusion of this assertion is rather pedantic.\n", + "That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Links to Official Documentation\n", + "\n", + "- [The assert statement](https://docs.python.org/3/reference/simple_stmts.html?highlight=assert#the-assert-statement)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading Comprehension Solutions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The Basic Anatomy of a Test: Solution**\n", + "\n", + "Add an additional assertion to the body of `test_count_vowels_basic`, which tests whether `count_vowels` handles the empty-string (`\"\"`) case appropriately.\n", + "Make sure to run your updated test to see if it passes.\n", + "\n", + "```python\n", + "def test_count_vowels_basic():\n", + " assert count_vowels(\"aA bB yY\", include_y=False) == 2\n", + " assert count_vowels(\"aA bB yY\", include_y=True) == 4\n", + " assert count_vowels(\"\", include_y=True) == 0\n", + "```\n", + "\n", + "```python\n", + "# running the test in a notebook-cell: the function should simply return\n", + "# `None` if all assertions hold true\n", + ">>> test_count_vowels_basic()\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Testing Your Test via Manual Mutation: Solution**\n", + "\n", + "Temporarily change the body of `count_vowels` such that the _second_ assertion in `test_count_vowels_basic` raises an error.\n", + "> Let's comment out the `if include_y` block in our code - this should prevent us from counting y's, and thus should violate the second assertion in our test.\n", + "\n", + "```python\n", + "# Breaking the behavior of `include_y=True`\n", + "def count_vowels(x: str, include_y: bool = False) -> int:\n", + " vowels = set(\"aeiouAEIOU\")\n", + " # if include_y:\n", + " # vowels.update(\"yY\")\n", + " return sum(1 for char in x if char in vowels)\n", + "```\n", + "\n", + "```python\n", + "# the second assertion should raise an error\n", + ">>> test_count_vowels_basic()\n", + "---------------------------------------------------------------------------\n", + "AssertionError Traceback (most recent call last)\n", + " in \n", + "----> 1 test_count_vowels_basic()\n", + "\n", + " in test_count_vowels_basic()\n", + " 1 def test_count_vowels_basic():\n", + " 2 assert count_vowels(\"aA bB yY\", include_y=False) == 2\n", + "----> 3 assert count_vowels(\"aA bB yY\", include_y=True) == 4\n", + "\n", + "AssertionError: \n", + "```\n", + "\n", + "> Great! That assertion really does help to ensure that we are counting y's correctly.\n", + "\n", + "Restore `count_vowels` to its original form and rerun the test to see that `count_vowels` once again passes all of the assertions.\n", + "\n", + "```python\n", + "# Restore the behavior of `include_y=True`\n", + "def count_vowels(x: str, include_y: bool = False) -> int:\n", + " vowels = set(\"aeiouAEIOU\")\n", + " if include_y:\n", + " vowels.update(\"yY\")\n", + " return sum(1 for char in x if char in vowels)\n", + "```\n", + "\n", + "```python\n", + "# confirming that we restored the proper behavior in `count_vowels`\n", + ">>> test_count_vowels_basic()\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Assertions: Solution**\n", + "```python\n", + "a_list = []\n", + "a_number = 22\n", + "a_string = \"abcdef\"\n", + "```\n", + "\n", + "Assert that `a_list` is _not_ empty:\n", + "\n", + "```python\n", + ">>> assert a_list\n", + "---------------------------------------------------------------------------\n", + "AssertionError Traceback (most recent call last)\n", + " in \n", + "----> 1 assert a_list\n", + "\n", + "AssertionError: \n", + "```\n", + "\n", + "> You may have written `assert len(a_list) > 0` - this is also correct.\n", + "> However, recall that calling `bool` on any sequence (list, tuple, string, etc.) will return `False` if the sequence is empty.\n", + "> This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - that `bool` will be called on whatever the provided expression is.\n", + "\n", + "Assert that the number of vowels in `a_string` is fewer than `a_number`; include and error message that prints the actual number of vowels:\n", + "\n", + "```python\n", + ">>> assert count_vowels(a_string) < a_number, f\"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}\"\n", + "```\n", + "\n", + "> Note that we make use of an [f-string](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) as a convenient means for writing an informative error message." + ] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,md" + }, + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs_backup/_sources/Module5_OddsAndEnds/WorkingWithFiles.md.txt b/docs_backup/_sources/Module5_OddsAndEnds/WorkingWithFiles.md.txt index e8fce932..3370e091 100644 --- a/docs_backup/_sources/Module5_OddsAndEnds/WorkingWithFiles.md.txt +++ b/docs_backup/_sources/Module5_OddsAndEnds/WorkingWithFiles.md.txt @@ -4,19 +4,19 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python name: python3 --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Working with aths and files, Difficulty: Medium, Category: Section :keywords: open file, read file, pathlib, join directory, context manager, close file, rb, binary file, utf-8, encoding, pickle, numpy, load, archive, npy, npz, pkl, glob, read lines, write, save -``` + # Working with Files This section will discuss the best practices for writing Python code that involves reading from and writing to files. We will learn about the built-in `pathlib.Path` object, which will help to ensure that the code that we write is portable across operating systems (OS) (e.g. Windows, MacOS, Linux). We will also be introduced to a *context manager*, `open`, which will permit us to read-from and write-to a file safely; by "safely" we mean that we will be assured that any file that we open will eventually be closed properly, so that it will not be corrupted even in the event that our code hits an error. Next, we will learn how to "glob" for files, meaning that we will learn to search for and list files whose names match specific patterns. Lastly, we will briefly encounter the `pickle` module which allows us to save (or "pickle") and load Python objects to and from your computer's file system. @@ -249,7 +249,6 @@ with open("a_poem.txt", mode="r") as my_open_file: ``` - ## Globbing for Files There are many cases in which we may want to construct a list of files to iterate over. For example, if we have several data files, it would be useful to create a file list which we can iterate through and process in sequence. One way to do this would be to manually construct such a list of files: @@ -317,9 +316,8 @@ Write a glob pattern for each of the following prompts - Glob all file that starts with the letter 'q', contains a 'w', and ends with a '.npy' extension
    - - + The `*` wildcard is not the only pattern available to us. Sometimes it can be useful to match certain subsets of characters. For example, we may only want to match file names that start with a number. With the `*` wildcard alone, that's not possible. Luckily for us, these common use-cases are also taken care of. To match a subset of characters, we can use square brackets: `[abc]*` will match anything that starts with 'a', 'b', or 'c' and nothing else. We can also use a '-' inside our brackets to glob groups of characters. For example: @@ -345,7 +343,6 @@ Write a glob pattern for each of the following prompts - All txt files that have the letters 'q' or 'z' in them

    - ## Saving & Loading Python Objects: pickle diff --git a/docs_backup/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt b/docs_backup/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt index 2ae43b2b..43be9158 100644 --- a/docs_backup/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt +++ b/docs_backup/_sources/Module5_OddsAndEnds/Writing_Good_Code.md.txt @@ -4,8 +4,8 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.0-rc0 + format_version: '1.2' + jupytext_version: 1.3.0rc1 kernelspec: display_name: Python 3 language: python @@ -13,11 +13,11 @@ jupyter: --- -```raw_mimetype="text/restructuredtext" + .. meta:: :description: Topic: Writing good code, Difficulty: Easy, Category: Section :keywords: pep8, code style, lint, format, best practices, type hint, documentation, numpydoc, sphinx, typing, annotation, whitespace -``` + # Writing Good Code @@ -436,11 +436,11 @@ For example, suppose that we are using the `count_vowels` function in a library ![PyCharm uses type-hints to check our code for consistency](pics/pycharm1.png) -This saves us the trouble of having to run our code, hit an error, read through the stack trace, and debug our mistake. Instead, we immediately see our inconsistency get flagged. In fact, we probably never would have even made the mistake at all, as our IDE would have shown a list of integer-methods for us to choose from, and not string-methods. This would have likely alerted us to our misapprehension. +This saves us the trouble of having to run our code, hit an error, read through the stack trace, and debug our mistake. Instead, we immediately see our inconsistency get flagged. In fact, we probably never would have even made the mistake at all, as our IDE would have shown a list of integer-methods for us to choose from, and not string-methods. Type-hints would have likely alerted us to our misapprehension. It does not take long to experience the benefits of type-hinting through your IDE. This both accelerates your coding by informing you of the object types that you are working with on the fly, and helps to expose oversights in your code as soon as they are made. -Finally, it is also worthwhile to highlight the [mypy](http://mypy-lang.org/) project, which is used to perform static type-checking on your code based on your type-hints. That is, mypy will automatically traverse your code and find potential bugs by identifying type conflicts in your code (e.g. trying to capitalize an integer) by checking their annotated and inferred types. This tool is most useful for large-scale code bases. Companies like Dropbox make keen use of mypy to identify inconsistencies in their code without having to hit runtime errors. Keep mypy in mind as you mature as a Python developer and find yourself working on projects of growing complexity. +Finally, it is also worthwhile to highlight two projects, [mypy](http://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright), which are used to perform static type-checking on your code based on your type-hints. That is, mypy and pyright will both automatically traverse your code and find potential bugs by identifying type conflicts in your code (e.g. trying to capitalize an integer) by checking their annotated and inferred types. These tools are especially useful for large-scale code bases. Companies like Dropbox and Microsoft make keen use of static type-checking to identify inconsistencies in their code without having to hit runtime errors. Keep mypy, pyright, and other type-checking utilities in mind as you mature as a Python developer and find yourself working on projects of growing complexity. If you are using [VSCode as your IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html), you can install the [pyright vscode extension](https://marketplace.visualstudio.com/items?itemName=ms-pyright.pyright) to leverage type checking within your IDE.
    @@ -449,7 +449,7 @@ Finally, it is also worthwhile to highlight the [mypy](http://mypy-lang.org/) pr There is a simple syntax for annotating functions, class-methods, and variables with type-hints; this is a formal mechanism for documenting the types of objects that are expected as inputs to the function, as well as the return type of the function. It is critical to note that that type-hints are *never* enforced by Python - they only serve as a form of documentation. -That being said, IDEs have powerful abilities to inspect type-hints and to highlight potential inconsistencies in your code. These capabilities can greatly facilitate your code-development. There are also third-party libraries like [mypy](http://mypy-lang.org/) that can be used to provide more rigorous type enforcement in your code. +That being said, IDEs have powerful abilities to inspect type-hints and to highlight potential inconsistencies in your code. These capabilities can greatly facilitate your code-development. There are also third-party libraries like [mypy](http://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright) that can be used to provide more rigorous type enforcement in your code.
    @@ -519,7 +519,16 @@ The following is a summary some of the most critical members of the `typing` mod - Hint a function that takes in a string and an integer and returns `None`: `Callable[[str, int], None]` - Hint a method that accepts arbitrary arguments and returns a boolean: `Callable[..., bool]` - + +#### `Literal[, ...]` + +- **What it hints:** That the variable will be passed one of the exact values +- **Examples:** + + - Hint that a variable that will be the integer `1`: `Literal[1]` + - Hint that a variable that will be the either the string `"sum"` or the string `"mean"`: `Literal["sum", "mean"]` + - Hint that a variable that will be either the list `[1, 2]` or the string `"abc"`: `Literal[[1, 2], "abc"]` +- **Compatibility Note:** The `Literal` type-hint was introduced in Python 3.8 - it is not available in earlier versions of Python. Let's take, for example, a function that takes in: @@ -627,7 +636,7 @@ To be more concrete, let's revisit our `count_vowels` function: ```python def count_vowels(x: str, include_y: bool = False) -> int: - """Returns the number of vowels contained in `in_string`""" + """Returns the number of vowels contained in `x`""" vowels = set("aeiouAEIOU") if include_y: vowels.update("yY") @@ -725,7 +734,7 @@ There is great wisdom in placing such a high value on documentation. In this sec PLYMI uses Numpy-style docstrings throughout most of the text (except for when we are trying to keep the functions brief). This is ultimately just a choice of style/aesthetics. Ultimately, the critical takeaway here is to **pick a documentation style, learn it, and stick to it faithfully**. Once again, it is hard to overstate how important it is to anchor your code with clear and consistent documentation. It will aid you in your code-writing process, it will enable users to adopt and perhaps contribute to your code, and it will ensure longevity for your hard work. - + ### The NumPy Documentation Style The NumPy documentation style is specified in full [here](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard). It is strongly recommended that you read through it in full. There are details in the specification that we will pass over here for the sake of simplicity and to avoid rewriting their specification. We will focus on the guidelines for documenting functions, but note that they specify rules for documenting [classes](https://www.pythonlikeyoumeanit.com/module_4.html) and [modules](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Modules). @@ -743,7 +752,6 @@ A docstring should at least consist of: - An extended summary of the function, which provides a more verbose description of things. - A `Parameters` section, which details the types of the input parameters along with descriptions of them. (This section is not necessary if your function is parameterless). - A `Returns` section (or `Yields` for a generator), which details the object that is returned by the function. (This is not necessary if your function always returns `None`). - There are additional, optional sections that can be used to improve your documentation: @@ -766,14 +774,16 @@ def pairwise_dists(x: np.ndarray, y: np.ndarray) -> np.ndarray: Parameters ---------- x : numpy.ndarray, shape=(M, D) - An optional description of ``x`` + An array of M, D-dimensional vectors. + y : numpy.ndarray, shape=(N, D) - An optional description of ``y`` + An array of N, D-dimensional vectors. Returns ------- numpy.ndarray, shape=(M, N) - The pairwise distances + The pairwise distances between the M rows of ``x`` and the N + rows of ``y``. Notes ----- @@ -821,7 +831,7 @@ def compute_student_stats(grade_book: Dict[str, Iterable[float]], Parameters ---------- - grade_book : Dict[str, List[float]] + grade_book : Dict[str, Iterable[float]] The dictionary (name -> grades) of all of the students' grades. diff --git a/docs_backup/_sources/Module6_Testing/Intro_to_Testing.md.txt b/docs_backup/_sources/Module6_Testing/Intro_to_Testing.md.txt new file mode 100644 index 00000000..6e3a285a --- /dev/null +++ b/docs_backup/_sources/Module6_Testing/Intro_to_Testing.md.txt @@ -0,0 +1,565 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +.. meta:: + :description: Topic: Writing tests for your code, Difficulty: Easy, Category: Section + :keywords: test, automated, unit, assert + + +# Introduction to Testing + +This section will show us just how simple it is to write rudimentary tests. We need only recall some of Python's basic scoping rules and introduce ourselves to the `assert` statement to write a genuine test function. That being said, we will quickly encounter some important questions to ponder. How do we know that our tests work? And, how do we know that our tests are effective? These questions will drive us deeper into the world of testing. + +Before we hit the ground running, let's take a moment to consider some motivations for testing out code. + + +## Why Should We Write Tests? + +The fact of the matter is that it is intuitive for most people to test their code to some extent. +After writing, say, a new function, it is only natural to contrive an input to feed it, and to check that the function returns the output that we expected. +To the extent that one would want to see evidence that their code works, we need not motivate the importance of testing. + +Less obvious are the massive benefits that we stand to gain from automating this testing process. +And by "automating", we mean taking the test scenarios that we were running our code through, and encapsulating them in their own functions that can be run from end-to-end. +We will accumulate these test functions into a "test suite" that we can run quickly and repeatedly. + +There are plenty of practical details ahead for us to learn, so let's expedite this discussion and simply list some of the benefits that we can expect to reap from writing a robust test suite: + +**It saves us lots of time**: + +> After you have devised a test scenario for your code, it may only take us a second or so to run it; perhaps we need only run a couple of Jupyter notebook cells to verify the output of our code. +> This, however, will quickly become unwieldy as we write more code and devise more test scenarios. +> Soon we will be dissuaded from running our tests except for on rare occasions. +> +> With a proper test suite, we can run all of our test scenarios with the push of a button, and a series of green check-marks (or red x's...) will summarize the health of our project (insofar as our tests serve as good diagnostics). +> This, of course, also means that we will find and fix bugs much faster! +> In the long run, our test suite will afford us the ability to aggressively exercise (and exorcise) our code at little cost. + +**It increases the "shelf life" of our code:** + +> If you've ever dusted off a project that you haven't used for years (or perhaps only months or weeks...), you might know the tribulations of getting old code to work. +> Perhaps, in the interim, new versions of our project's dependencies, like PyTorch or Matplotlib, were released and have incompatibilities with our project's code. +> And perhaps _we can't even remember_ all of the ways in which our project is supposed to work. +> Our test suite provides us with a simple and incisive way to dive back into our work. +> It will point us to any potential incompatibilities that have accumulated over time. +> It also provides us with a large collection of detailed use-cases of our code; +> we can read through our tests and remind ourselves of the inner-workings of our project. + + +**It will inform the design and usability of our project for the better:** + +> Although it may not be obvious from the outset, writing testable code leads to writing better code. +> This is, in part, because the process of writing tests gives us the opportunity to actually _use_ our code under varied circumstances. +> The process of writing tests will help us suss out bad design decisions and redundant capabilities in our code. Ultimately, if _we_ find it frustrating to use our code within our tests, then surely others will find the code frustrating to use in applied settings. + +**It makes it easier for others to contribute to a project:** + +> Having a healthy test suite lowers the barrier to entry for a project. +> A contributor can rely on our project's tests to quickly check to see if their changes to our code have broken the project or changed any of its behavior in unexpected ways. + +This all sounds great, but where do we even start the process of writing a test suite? +Let's begin by seeing what constitutes a basic test function. + + + +## Writing Our First Tests + +### Our "Source Code" +We need some code to test. For the sake of this introduction, let's borrow a couple of functions that may look familiar from previous modules. +These will serve as our "source code"; i.e. these are functions that we have written for our project and that need to be tested. + +```python +# Defining functions that we will be testing + +def count_vowels(x, include_y=False): + """Returns the number of vowels contained in `x`. + + The vowel 'y' is included optionally. + + Parameters + ---------- + x : str + The input string + + include_y : bool, optional (default=False) + If `True` count y's as vowels + + Returns + ------- + vowel_count: int + + Examples + -------- + >>> count_vowels("happy") + 1 + >>> count_vowels("happy", include_y=True) + 2 + """ + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + return sum(1 for char in x if char in vowels) + + +def merge_max_mappings(dict1, dict2): + """ Merges two dictionaries based on the largest value + in a given mapping. + + Parameters + ---------- + dict1 : Dict[str, float] + dict2 : Dict[str, float] + + Returns + ------- + merged : Dict[str, float] + The dictionary containing all of the keys common + between `dict1` and `dict2`, retaining the largest + value from common mappings. + + Examples + -------- + >>> x = {"a": 1, "b": 2} + >>> y = {"b": 100, "c": -1} + >>> merge_max_mappings(x, y) + {'a': 1, 'b': 100, 'c': -1} + """ + # `dict(dict1)` makes a copy of `dict1`. We do this + # so that updating `merged` doesn't also update `dict1` + merged = dict(dict1) + for key, value in dict2.items(): + if key not in merged or value > merged[key]: + merged[key] = value + return merged +``` + +As always, it is useful for us to follow along with this material in a Jupyter notebook. +We ought to take time to define these functions and run inputs through them to make sure that we understand what they are doing. +Testing code that we don't understand is a lost cause! + + +### The Basic Anatomy of a Test + +Let's write a test for `count_vowels`. For our most basic test, we can simply call `count_values` under various contrived inputs and *assert* that it returns the expected output. +The desired behavior for this test function, upon being run, is to: + +- Raise an error if any of our assertions *failed* to hold true. +- Complete "silently" if all of our assertions hold true (i.e. our test function will simply [return None](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Functions.html#The-return-Statement)) + +Here, we will be making use of Python's `assert` statements, whose behavior will be easy to deduce from the context of this test alone. +We will be formally introduced to the `assert` statement soon. + +```python +# Writing a rudimentary test function for `count_vowels` + +def test_count_vowels_basic(): + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 +``` + +To run this test, we simply call the function: + +```python +# running our test function +>>> test_count_vowels_basic() # passes: returns None | fails: raises error +``` + +As described above, the fact our function runs and simply returns `None` (i.e. we see no output when we run this test in a console or notebook cell) means that our code has passed this test. We've written and run our very first test! It certainly isn't the most robust test, but it is a good start. + +Let's look more carefully at the structure of `test_count_vowels_basic`. +Note that this function doesn't take in any inputs; +thanks to [Python's scoping rules](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Scope.html), we can reference our `count_vowels` function within our test as long as it is defined in the same "namespace" as `test_count_vowels_basic`. +That is, we can either define `count_vowels` in the same .py file (or Jupyter notebook, if you are following along with this material in a notebook) as `test_count_vowels_basic`, or we can [import](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Import-Statements) `count_vowels`, from wherever it is defined, into the file containing our test. +The latter scenario is by far the most common one in practice. +More on this later. + + + +
    + +**Takeaway**: + +A "test function" is designed to provide an encapsulated "environment" (namespace to be more precise) in which we can exercise parts of our source code and assert that the code behaves as-expected. The basic anatomy of a test function is such that it: + +- contains one or more `assert` statements, each of which will raise an error if our source code misbehaves +- simply returns `None` if all of the aforementioned assertions held true +- can be run end-to-end simply by calling the test function without passing it any parameters; we rely on Python's scoping rules to call our source code within the body of the test function without explicitly passing anything to said test function + +
    + + +
    + +**Reading Comprehension: Adding Assertions to a Test** + +Add an additional assertion to the body of `test_count_vowels_basic`, which tests that `count_vowels` handles empty-string (`""`) input appropriately. +Make sure to run your updated test to see if it passes. + +
    + + +
    + +**Reading Comprehension: The Basic Anatomy of a Test** + +Write a rudimentary test function for `merge_max_mappings`. This should adhere to the basic structure of a test function that we just laid out. See if you can think of some "edge cases" to test, which we may have overlooked when writing `merge_max_mappings`. + +
    + + +## The `assert` Statement +With our first test functions under our belt, it is time for us to clearly understand how `assert` statements work and how they should be used. + +Similar to `return`, `def`, or `if`, the term `assert` is a reserved term in the Python language. +It has the following specialized behavior: + +```python +# demonstrating the rudimentary behavior of the `assert` statement + +# asserting an expression whose boolean-value is `True` will complete "silently" +>>> assert 1 < 2 + +# asserting an expression whose boolean-value is `False` raises an error +>>> assert 2 < 1 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert 2 < 1 + +AssertionError: + +# we can include an error message with our assertion +>>> assert 0 in [1, 2, 3], "0 is not in the list" +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert 0 in [1, 2, 3], "0 is not in the list" + +AssertionError: 0 is not in the list +``` + +The general form of an assertion statement is: + +```python +assert [, ] +``` + +When an assertion statement is executed, the built-in `bool` function is called on the object that is returned by ``; if `bool()` returns `False`, then an `AssertionError` is raised. +If you included a string in the assertion statement - separated from `` by a comma - then this string will be printed as the error message. + +See that the assertion statement: +```python +assert expression, error_message +``` + +is effectively shorthand for the following code (barring some additional details): + +```python +# long-form equivalent of: `assert expression, error_message` +if bool(expression) is False: + raise AssertionError(error_message) +``` + + + +
    + +**Reading Comprehension: Assertions** + +Given the following objects: + +```python +a_list = [] +a_number = 22 +a_string = "abcdef" +``` + +Write two assertion statements with the respective behaviors: + +- asserts that `a_list` is _not_ empty +- asserts that the number of vowels in `a_string` is less than `a_number`; include an error message that prints the actual number of vowels + +
    + + + +#### What is the Purpose of an Assertion? +In our code, an assertion should be used as _a statement that is true unless there is a bug in our code_. +It is plain to see that the assertions in `test_count_vowels_basic` fit this description. +However, it can also be useful to include assertions within our source code itself. +For instance, we know that `count_vowels` should always return a non-negative integer for the vowel-count, and that it is illogical for this count to exceed the number of characters in the input string. +We can explicitly assert that this is the case: + +```python +# an example of including an assertion within our source code + +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + count = sum(1 for char in x if char in vowels) + + # This assertion should always be true: it is asserting that + # the internal logic of our function is correct + assert isinstance(count, int) and 0 <= count <= len(x) + return count +``` + +Note that this assertion *is not meant to check if the user passed bad inputs for* `x` *and* `include_y`. +Rather, it is meant to assert that our own internal logic holds true. + +Admittedly, the `count_vowels` function is simple enough that the inclusion of this assertion is rather pedantic. +That being said, as we write increasingly sophisticated code, we will find that this sort of assertion will help us catch bad internal logic and oversights within our code base. +We will also see that keen use of assertions can make it much easier for us to write good tests. + +
    + +**Disabling Assertions**: + +Python code can be run in an "optimized" mode such that *all assertions are skipped by the Python interpreter during execution*. +This can be achieved by specifying the command line option `-O` (the letter "O", not zero), e.g.: + +```shell +python -O my_code.py +``` + +or by setting the `PYTHONOPTIMIZE` [environment variable](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE). + +The idea here is that we may want assertions within our source code to perform expensive checks to guarantee internal consistency within our code, and that we want the ability to forgo these checks when we are no longer debugging our code. +Because they can be skipped in this way, *assertions should never be used for practical error handling*. + +
    + + + +## Testing Our Tests + +It is surprisingly easy to unwittingly write a broken test: a test that always passes, or a test that simply doesn't exercise our code in the way that we had intended. +Broken tests are insidious; they are alarms that fail to sound when they are supposed to. +They create misdirection in the bug-finding process and can mask problems with our code. +**Thus a critical step in the test-writing process is to intentionally mutate the function of interest - to corrupt its behavior so that we can verify that our test works.** +Once we confirm that our test does indeed raise an error as-expected, we restore the function to its original form and re-run the test and see that it passes. + +A practical note: we ought to mutate our function in a way that is trivial to undo. We can make use of code-comments towards this end. +All [IDEs](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) have the ability to "block-comment" selected code. +In order to block-comment code in a Jupyter notebook code cell, highlight the lines of code and press `CTRL + /`. +The same key-combination will also un-comment a highlighted block of commented code. + + + +
    + +**Reading Comprehension: Testing Your Test via Manual Mutation** + +Temporarily change the body of `count_vowels` such that the second assertion in `test_count_vowels_basic` raises an error. +Run the test to confirm that the second assertion raises, +and then restore `count_vowels` to its original form. +Finally, rerun the test to see that `count_vowels` once again passes all of the assertions. + +Repeat this process given the test that you wrote for `merge_max_mappings`. +Try breaking the function such that it always merges in values from `dict2`, even if those values are smaller. + +
    + + + +
    + +**Mutation Testing**: + +There is an entire subfield of automated testing known as ["mutation testing"](https://en.wikipedia.org/wiki/Mutation_testing), where tools like [Cosmic Ray](https://cosmic-ray.readthedocs.io/en/latest/index.html) are used to make temporary, incisive mutations to your source code - like change a `+` to a `-` or change a `1` to a `-1` - and then run your test suite. +The idea here is that such mutations *ought to cause one or more of your tests to fail*. +A mutation that fails to trigger at least one test failure is likely an indicator that your tests could stand to be more robust. + +Automated mutation testing tools might be a bit too "heavy duty" at this point in our testing journey, but they are great to keep in mind. + +
    + + +## Our Work, Cut Out + +We see now that the concept of a "test function" isn't all that fancy. +Compared to other code that we have written, writing a function that simply runs a hand full of assertions is far from a heavy lift for us. +Of course, we must be diligent and take care to test our tests, but we can certainly manage this as well. +With this in hand, we should take stock of the work and challenges that lie in our path ahead. + +It is necessary that we evolve beyond manual testing. +There are multiple facets to this observation. +First, we must learn how to organize our test functions into a test suite that can be run in one fell swoop. +Next, it will become increasingly apparent that a test function often contains large amounts of redundant code shared across its litany of assertions. +We will want to "parametrize" our tests to distill them down to their most concise and functional forms. +Finally, and most importantly, it may already be evident that the process of contriving known inputs and outputs to use in our tests is a highly manual and tedious process; furthermore, it is a process that will become increasingly cumbersome as our source code becomes more sophisticated. +To combat this, we will seek out alternative, powerful testing methodologies, including property-based testing. + + +## Links to Official Documentation + +- [The assert statement](https://docs.python.org/3/reference/simple_stmts.html?highlight=assert#the-assert-statement) +- [PYTHONOPTIMIZE environment variable](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE) + + +## Reading Comprehension Solutions + + +**Adding Assertions to a Test: Solution** + +Add an additional assertion to the body of `test_count_vowels_basic`, which tests whether `count_vowels` handles the empty-string (`""`) case appropriately. +Make sure to run your updated test to see if it passes. + +```python +def test_count_vowels_basic(): + # test basic strings with uppercase and lowercase letters + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 + + # test empty strings + assert count_vowels("", include_y=False) == 0 + assert count_vowels("", include_y=True) == 0 +``` + +```python +# running the test in a notebook-cell: the function should simply return +# `None` if all assertions hold true +>>> test_count_vowels_basic() +``` + + + +**The Basic Anatomy of a Test: Solution** + +Write a rudimentary test function for `merge_max_mappings`. + +> Let's test the use case that is explicitly documented in the Examples section of the function's docstring. +> We can also test cases where one or both of the inputs are empty dictionaries. +> These can often be problematic edge cases that we didn't consider when writing our code. + +```python +def test_merge_max_mappings(): + # test documented behavior + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 20, "c": -1} + expected = {'a': 1, 'b': 20, 'c': -1} + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict1 + dict1 = {} + dict2 = {"a": 10.2, "f": -1.0} + expected = dict2 + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict2 + dict1 = {"a": 10.2, "f": -1.0} + dict2 = {} + expected = dict1 + assert merge_max_mappings(dict1, dict2) == expected + + # test both empty + dict1 = {} + dict2 = {} + expected = {} + assert merge_max_mappings(dict1, dict2) == expected +``` + +```python +# running the test (seeing no errors means the tests all passed) +>>> test_merge_max_mappings() +``` + + + +**Assertions: Solution** +```python +a_list = [] +a_number = 22 +a_string = "abcdef" +``` + +Assert that `a_list` is _not_ empty: + +```python +>>> assert a_list +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert a_list + +AssertionError: +``` + +> You may have written `assert len(a_list) > 0` - this is also correct. +> However, recall that calling `bool` on any sequence (list, tuple, string, etc.) will return `False` if the sequence is empty. +> This is a reminder that an assertion statement need not include an explicit logical statement, such as an inequality - that `bool` will be called on whatever the provided expression is. + +Assert that the number of vowels in `a_string` is fewer than `a_number`; include an error message that prints the actual number of vowels: + +```python +>>> assert count_vowels(a_string) < a_number, f"Number of vowels, {count_vowels(a_string)}, exceeds {a_number}" +``` + +> Note that we make use of an [f-string](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) as a convenient means for writing an informative error message. + + + +**Testing Your Test via Manual Mutation: Solution** + +Temporarily change the body of `count_vowels` such that the _second_ assertion in `test_count_vowels_basic` raises an error. +> Let's comment out the `if include_y` block in our code. This should prevent us from counting y's, and thus should violate the second assertion in our test. + +```python +# Breaking the behavior of `include_y=True` +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + # if include_y: + # vowels.update("yY") + return sum(1 for char in x if char in vowels) +``` + +```python +# the second assertion should raise an error +>>> test_count_vowels_basic() +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 test_count_vowels_basic() + + in test_count_vowels_basic() + 1 def test_count_vowels_basic(): + 2 assert count_vowels("aA bB yY", include_y=False) == 2 +----> 3 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: +``` + +> See that the error output, which is called a "stack trace", indicates with an ASCII-arrow that our second assertion is the one that is failing. +> Thus we can be confident that that assertion really does help to ensure that we are counting y's correctly. + +Restore `count_vowels` to its original form and rerun the test to see that `count_vowels` once again passes all of the assertions. + +> We simply un-comment out the block of code and rerun our test. + +```python +# Restore the behavior of `include_y=True` +def count_vowels(x: str, include_y: bool = False) -> int: + vowels = set("aeiouAEIOU") + if include_y: + vowels.update("yY") + return sum(1 for char in x if char in vowels) +``` + +```python +# confirming that we restored the proper behavior in `count_vowels` +>>> test_count_vowels_basic() +``` + diff --git a/docs_backup/_sources/Module6_Testing/Pytest.md.txt b/docs_backup/_sources/Module6_Testing/Pytest.md.txt new file mode 100644 index 00000000..d044b64e --- /dev/null +++ b/docs_backup/_sources/Module6_Testing/Pytest.md.txt @@ -0,0 +1,753 @@ +--- +jupyter: + jupytext: + text_representation: + extension: .md + format_name: markdown + format_version: '1.2' + jupytext_version: 1.3.0 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +.. meta:: + :description: Topic: Writing tests for your code, Difficulty: Easy, Category: Section + :keywords: test, automated, pytest, parametrize, fixture, suite, decorator, clean directory + + +# The pytest Framework + +Thus far, our process for running tests has been an entirely manual one. It is time for us to arrange our test functions into a proper "test suite" and to learn to leverage [the pytest framework](https://docs.pytest.org/en/latest/) to run them. +We will begin by reorganizing our source code to create an installable [Python package](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Packages). +We will then learn how to structure and run a test suite for this Python package, using pytest. + +The pytest framework does much more than just run tests; +for instance, it will enrich the assertions in our tests to produce verbose, informative error messages. +Furthermore it provides valuable means for enhancing our tests via mechanisms like fixtures and parameterizing decorators. +Ultimately, all of this functionality helps to eliminate manual and redundant aspects of the testing process. + + + +
    + +**Note** + +It can be useful to [create a separate conda environment](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Installing_Python.html#A-Brief-Introduction-to-Conda-Environments) for the sake of this lesson, so that we can work through this material starting from a blank slate. +If you do create a new conda environment, be sure to activate that environment and install NumPy and Jupyter notebook: `conda install numpy notebook` +
    + + + +Let's install pytest. Installing from [the conda-forge channel](https://conda-forge.org/) will install the most up-to-date version of pytest. In a terminal where conda can be accessed, run: + +```shell +conda install -c conda-forge pytest +``` + +Or, pytest is installable via pip: + +```shell +pip install pytest +``` + + +
    + +**Regarding Alternative Testing Frameworks** (a note from the author of PLYMI): + +When sifting through tutorials, blogs, and videos about testing in Python, it is common to see `pytest` presented alongside, and on an equal footing with, the alternative testing frameworks: `nose` and `unittest`. +This strikes me as... bizarre. + +`unittest` is the testing framework that comes with the Python standard library. +As a test runner, its design is clunky, archaic, and, ironically, un-pythonic. +While [unittest.mock](https://docs.python.org/3/library/unittest.mock.html) provides extremely valuable functionality for advanced testing, all of its functionality can be leveraged while using pytest as your testing framework. + +`nose`, which simply extends the functionality of `unittest`, **is no longer being maintained**. +There is a project, "Nose2", which is carrying the torch of `nose`. However, this is a fledgling project by comparison to `pytest`. +As of writing this, `pytest` was downloaded 12 million times last month versus `nose2`'s 150 thousand downloads. + +The takeaway here is that, when it comes to picking a testing framework for Python, `pytest` is the clear choice. +Any discussion that you come across to the contrary is likely outdated. +
    + + +## Creating a Python Package with Tests + +It's time to create a proper test suite. +Before proceeding any further, we should reread the material presented in [Module 5 - Import: Modules and Packages](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html) and recall the essentials of import statements, modules, and Python packages. +This material serves as the foundation for this section. + +### Organizing our Source Code +Let's create a Python package, which we will call `plymi_mod6`, with the following directory structure: + +``` +project_dir/ # the "parent directory" houses our source code, tests, and all other relevant files + - setup.py # script responsible for installing `plymi_mod6` package + - plymi_mod6/ # directory containing source code of `plymi_mod6` package + |-- __init__.py + |-- basic_functions.py + |-- numpy_functions.py + - tests/ # test-suite for `plymi_mod6` package (to be run using pytest) + |-- conftest.py # optional configuration file for pytest + |-- test_basic_functions.py + |-- test_numpy_functions.py +``` + +A reference implementation of this package can be found [in this GitHub repository](https://github.com/rsokl/plymi_mod6). +Populate the `basic_functions.py` file with the two functions that we were using as our source code in the previous section: `count_vowels` and `merge_max_mappings`. +In the `numpy_functions.py` module, add the `pairwise_dists` function that appears in [Module 3's discussion of optimized pairwise distances](https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/Broadcasting.html#Optimized-Pairwise-Distances). +Don't forget to include `import numpy as np` in your script in accordance with how `pairwise_dists` calls NumPy functions. + +We have arranged these functions so that they can be imported from the `basic_functions` module and the `numpy_functions` module, respectively, which reside in our `plymi_mod6` package. +Let's fill out our `setup.py` script and install this package so that we can import it regardless of our current working directory. The content of `setup.py` will be: + +```python +from setuptools import find_packages, setup + +setup( + name="plymi_mod6", + packages=find_packages(exclude=["tests", "tests.*"]), + version="1.0.0", + author="Your Name", + description="A template Python package for learning about testing", + install_requires=["numpy >= 1.10.0"], + tests_require=["pytest>=5.3", "hypothesis?=5.0"], + python_requires=">=3.6", +) +``` + +This setup file dictates that a user must have Python 3.6+ installed - we will bar Python 3.5 and below so that we are free to make use of [f-strings](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Formatting-strings) in our code, which were introduced in Python 3.6. Additionally, we will require pytest and hypothesis for running tests; the Hypothesis library will be introduced in a later section. + +Finally, let's install our package locally [in development mode](https://www.pythonlikeyoumeanit.com/Module5_OddsAndEnds/Modules_and_Packages.html#Installing-Your-Own-Python-Package). +Navigate to the directory containing `setup.py` and run: + +```shell +pip install --editable . +``` + +Now, we should be able to start a python console, IPython console, or Jupyter notebook in any directory and import our package: + +```python +# checking that we can import our `plymi_mod6` package +>>> from plymi_mod6.basic_functions import count_vowels +>>> count_vowels("Happy birthday", include_y=True) +5 +``` + + + +## Populating and Running Our Test Suite + +pytest's [system for "test discovery"](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) is quite simple: +pytest need only be pointed to a directory with files named `test_*.py` in it, and it will find all of the functions in these files _whose names start with the word "test"_ and will run all such functions. + +Thus, let's populate the file ``test_basic_functions.py`` with the functions `test_count_vowels_basic` and `test_merge_max_mappings`, which we wrote in the previous section of this module: + +```python +# The contents of test_basic_functions.py + +# we must import the functions we are testing +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings + + +def test_count_vowels_basic(): + # test basic strings with uppercase and lowercase letters + assert count_vowels("aA bB yY", include_y=False) == 2 + assert count_vowels("aA bB yY", include_y=True) == 4 + + # test empty strings + assert count_vowels("", include_y=False) == 0 + assert count_vowels("", include_y=True) == 0 + + +def test_merge_max_mappings(): + # test documented behavior + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 20, "c": -1} + expected = {'a': 1, 'b': 20, 'c': -1} + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict1 + dict1 = {} + dict2 = {"a": 10.2, "f": -1.0} + expected = dict2 + assert merge_max_mappings(dict1, dict2) == expected + + # test empty dict2 + dict1 = {"a": 10.2, "f": -1.0} + dict2 = {} + expected = dict1 + assert merge_max_mappings(dict1, dict2) == expected + + # test both empty + dict1 = {} + dict2 = {} + expected = {} + assert merge_max_mappings(dict1, dict2) == expected + +``` + +As described before, `count_vowels` and `merge_max_mappings` must both be imported from our `plymi_mod6` package, so that our functions are in the same namespace as our tests. +A reference implementation of `test_basic_functions.py` can be viewed [here](https://github.com/rsokl/plymi_mod6/blob/master/tests/test_basic_functions.py). +Finally, add a dummy test - a test function that will always pass - to `test_basic_numpy.py`. +We will replace this with a useful test later. + +Without further ado, let's run our test suite! In our terminal, with the appropriate conda environment active, we navigate to the root directory of the project, which contains the `tests/` directory, and run `pytest tests/`. +The following output should appear: + + +``` +$ pytest tests/ +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +rootdir: C:\Users\plymi_user\plymi_root_dir +collected 3 items + +tests\test_basic_functions.py .. [ 66%] +tests\test_basic_numpy.py . [100%] + +============================== 3 passed in 0.04s ============================== +``` + + +This output indicates that three test-functions were found across two files and that all of the tests "passed"; i.e. the functions ran without raising any errors. +The first two tests are located in `tests/test_basic_functions.py`; the two dots indicate that two functions were run, and the `[66%]` indicator simply denotes that the test-suite is 66% (two-thirds) complete. +The following reading comprehension problem will lead us to see what looks like for pytest to report a failing test. + + +
    + +**Reading Comprehension: Running a Test Suite** + +Temporarily add a new "broken" test to `tests/test_basic_functions.py`. +The name that you give this test should adhere to pytest's simple rules for test-discovery. +Design the test function so that is sure to fail when it is run. + +Rerun your test suite and compare its output to what you saw before - is it easy to identify which test failed and what caused it to fail? +Make sure to remove this function from your test suite once you are finished answering this question. + +
    + + + +We can also direct pytest to run the tests in a specific .py file. E.g. executing: + +```shell +pytest tests/test_basic_functions.py +``` + +will cue pytest to only run the tests in `test_basic_functions.py`. + +A key component to leveraging tests effectively is the ability to exercise ones tests repeatedly and rapidly with little manual overhead. +Clearly, pytest is instrumental towards this end - this framework made the process of organizing and running our test suite exceedingly simple! +That being said, there will certainly be occasions when we want to run a _specific_ test function. +Suppose, for instance, that we are writing a new function, and repeatedly want to run one of our tests that is pointing to a bug in our work-in-progress. +We can leverage pytest in conjunction with [an IDE](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) to run our tests in such incisive ways. + + +### Utilizing pytest within an IDE + +Both [PyCharm and VSCode](https://www.pythonlikeyoumeanit.com/Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks.html) can be configured to make keen use of pytest. +The following images show a couple of the enhancements afforded to us by PyCharm; comparable features are available in VSCode. +The IDEs will "discover" tests, and provide us with the ability to run individual tests. +For example, in the following image, the green "play button" allows us to run `test_count_vowels_basic`. + + +
    +

    +Running an individual test in PyCharm +

    +
    + + +Furthermore, IDEs can provide a rich tree view of all the tests that are being run. +This is especially useful as our test suite grows to contain a considerable number of tests. +In the following image, we see that `test_version` is failing - we can click on the failing test in this tree-view, and our IDE will navigate us directly to the failing test. + + +
    +

    +Viewing an enhanced tree-view of your test suite +

    +
    + + +The first step for leveraging these features in your IDE is to enable the pytest framework in the IDE. +The following links point to detailed instructions for configuring pytest with PyCharm and VSCode, respectively: + +- [Running tests in PyCharm](https://www.jetbrains.com/help/pycharm/pytest.html) +- [Running tests in VSCode](https://code.visualstudio.com/docs/python/testing) + +These linked materials also include advanced details, like instructions for running tests in parallel, which are beyond the scope of this material but are useful nonetheless. + + +## Enhanced Testing with pytest + +In addition to providing us with a simple means for organizing and running our test suite, pytest has powerful features that will both simplify and enhance our tests. +We will now leverage these features in our test suite. + + +### Enriched Assertions + +A failing "bare" assertion - an `assert` statement without an error message - can be a frustrating thing. +Suppose, for instance, that one of our test-assertions about `count_vowels` fails: + +```python +# a failing assertion without an error message is not informative + +assert count_vowels("aA bB yY", include_y=True) == 4 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) + in +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: +``` + +The problem with this bare assertion is that we don't know what `count_vowels("aA bB yY", include_y=True)` actually returned! +We now have to go through the trouble of starting a python console, importing this function, and calling it with this specific input in order to see what our function was actually returning. An obvious remedy to this is for us to write our own error message, but this too is quite cumbersome when we consider the large number of assertions that we are destined to write. + +Fortunately, pytest comes to the rescue: it will "hijack" any failing bare assertion and will _insert a useful error message for us_. +This is known as ["assertion introspection"](https://docs.pytest.org/en/latest/assert.html#assertion-introspection-details). +For example, if the aforementioned assertion failed when being run by pytest, we would see the following output: + +```python +# pytest will write informative error messages for us + +assert count_vowels("aA bB yY", include_y=True) == 4 +--------------------------------------------------------------------------- +AssertionError Traceback (most recent call last) +~\Learning_Python\Python\Module6_Testing\Untitled1.ipynb in +----> 1 assert count_vowels("aA bB yY", include_y=True) == 4 + +AssertionError: assert 2 == 4 + + where 2 = ('aA bB yY', include_y=True +``` + +See that the error message that pytest included for us indicates that `count_vowels("aA bB yY", include_y=True)` returned `2`, when we expected it to return `4`. +From this we might suspect that `count_vowels` is not counting y's correctly. + +Here are some more examples of "enriched assertions", as provided by pytest. +See that these error messages even provide useful "diffs", which specify specifically _how_ two similar objects differ, where possible. + +```python +# comparing unequal lists +assert [1, 2, 3] == [1, 2] +E Left contains one more item: 3 +E Full diff: +E - [1, 2, 3] +E ? --- +E + [1, 2] +``` + +```python +# comparing unequal dictionaries +assert {"a": 1, "b": 2} == {"a": 1, "b": 3} +E AssertionError: assert {'a': 1, 'b': 2} == {'a': 1, 'b': 3} +E Omitting 1 identical items, use -vv to show +E Differing items: +E {'b': 2} != {'b': 3} +E Full diff: +E - {'a': 1, 'b': 2} +E ? ^ +E + {'a': 1, 'b': 3}... +``` + +```python +# comparing unequal strings +assert "moo" == "moon" +E AssertionError: assert 'moo' == 'moon' +E - moo +E + moon +E ? + +``` + + + + +### Parameterized Tests + +Looking back to both `test_count_vowels_basic` and `test_merge_max_mappings`, we see that there is a lot of redundancy within the bodies of these test functions. +The assertions that we make within a given test-function share identical forms - they differ only in the parameters that we feed into our functions and their expected output. +Another shortcoming of this test-structure is that a failing assertion will block subsequent assertions from being evaluated. +That is, if the second assertion in a `test_count_vowels_basic` fails, the third and fourth assertions will not be evaluated in that run. +This precludes us from potentially seeing useful patterns among the failing assertions. + +pytest provides a useful tool that will allow us to eliminate these structural shortcomings by transforming our test-functions into so-called _parameterized tests_. Let's parametrize the following test: + +```python +# a simple test with redundant assertions + +def test_range_length_unparameterized(): + assert len(range(0)) == 0 + assert len(range(1)) == 1 + assert len(range(2)) == 2 + assert len(range(3)) == 3 +``` + +This test is checking the property `len(range(n)) == n`, where `n` is any non-negative integer. +Thus the parameter to be varied here is the "size" of the range-object being created. +Let's treat it as such by using pytest to write a parameterized test: + +```python +# parameterizing a test +import pytest + +# note that this test must be run by pytest to work properly +@pytest.mark.parametrize("size", [0, 1, 2, 3]) +def test_range_length(size): + assert len(range(size)) == size +``` + +Make note that a pytest-parameterized test must be run using pytest; an error will raise if we manually call `test_range_length()`. +When executed, pytest will treat this parameterized test as _four separate tests_ - one for each parameter value: + +``` +test_basic_functions.py::test_range_length[0] PASSED [ 25%] +test_basic_functions.py::test_range_length[1] PASSED [ 50%] +test_basic_functions.py::test_range_length[2] PASSED [ 75%] +test_basic_functions.py::test_range_length[3] PASSED [100%] +``` + +See that we have successfully eliminated the redundancy from `test_range_length`; +the body of the function now contains only a single assertion, making obvious the property that is being tested. +Furthermore, the four assertions are now being run independently from one another and thus we can potentially see patterns across multiple fail cases in concert. + + + +#### Decorators + +The syntax used to parameterize this test may look alien to us, as we have yet to encounter this construct thus far. +`pytest.mark.parameterize(...)` is a _decorator_ - an object that is used to "wrap" a function in order to transform its behavior. +The `pytest.mark.parameterize(...)` decorator wraps our test function so that pytest can call it multiple times, once for each parameter value. +The `@` character, in this context, denotes the application of a decorator: + +```python +# general syntax for applying a decorator to a function + +@the_decorator +def the_function_being_decorated(): + pass +``` + +For an in-depth discussion of decorators, please refer to [Real Python's Primer on decorators](https://realpython.com/primer-on-python-decorators/#simple-decorators). + + + +#### Parameterization Syntax + +The general form for creating a parameterizing decorator with *a single parameter*, as we formed above, is: + +```python +@pytest.mark.parametrize("", [, , ...]) +def test_function(): + ... +``` + +We will often have tests that require multiple parameters. +The general form for creating the parameterization decorator for $N$ parameters, +each of which assume $J$ values, is: + +```python +@pytest.mark.parametrize(", , [...], ", + [(, , [...], ), + (, , [...], ), + ... + (, , [...], ), + ]) +def test_function(, , [...], ): + ... +``` + +For example, let's take the following trivial test: + +```python +def test_inequality_unparameterized(): + assert 1 < 2 < 3 + assert 4 < 5 < 6 + assert 7 < 8 < 9 + assert 10 < 11 < 12 +``` + +and rewrite it in parameterized form. +The decorator will have three distinct parameter, and each parameters, let's simply call them `a`, `b`, and `c`, will take on four values. + +```python +# the parameterized form of `test_inequality_unparameterized` +@pytest.mark.parametrize("a, b, c", [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]) +def test_inequality(a, b, c): + assert a < b < c +``` + + +
    + +**Note** + +The formatting for multi-parameter tests can quickly become unwieldy. +It isn't always obvious where one should introduce line breaks and indentations to improve readability. +This is a place where the ["black" auto-formatter](https://black.readthedocs.io/en/stable/) really shines! +Black will make all of these formatting decisions for us - we can write our parameterized tests as haphazardly as we like and simply run black to format our code. +
    + + + +
    + +**Reading Comprehension: Parameterizing Tests** + +Rewrite `test_count_vowels_basic` as a parameterized test with the parameters: `input_string`, `include_y`, and `expected_count`. + +Rewrite `test_merge_max_mappings` as a parameterized test with the parameters: `dict_a`, `dict_b`, and `expected_merged`. + +Before rerunning `test_basic_functions.py` predict how many distinct test cases will be reported by pytest. + +
    + + + +Finally, you can apply multiple parameterizing decorators to a test so that pytest will run _all combinations of the respective parameter values_. + +```python +# testing all combinations of `x` and `y` +@pytest.mark.parametrize("x", [0, 1, 2]) +@pytest.mark.parametrize("y", [10, 20]) +def test_all_combinations(x, y): + # will run: + # x=0 y=10 + # x=0 y=20 + # x=1 y=10 + # x=1 y=20 + # x=2 y=10 + # x=2 y=20 + pass +``` + + +### Fixtures + +The final major pytest feature that we will discuss are "fixtures". +A fixture, roughly speaking, is a means by which we can share information and functionality across our tests. +Fixtures can be defined within our `conftest.py` file, and pytest will automatically "discover" them and make them available for use throughout our test suite in a convenient way. + +Exploring fixtures will quickly take us beyond our depths for the purposes of this introductory material, so we will only scratch the surface here. +We can read about advanced details of fixtures [here](https://docs.pytest.org/en/latest/fixture.html#fixture). + +Below are examples of two useful fixtures. + + +```python +# contents of conftest.py + +import os +import tempfile + +import pytest + +@pytest.fixture() +def cleandir(): + """ This fixture will use the stdlib `tempfile` module to + change the current working directory to a tmp-dir for the + duration of the test. + + Afterwards, the test session returns to its previous working + directory, and the temporary directory and its contents + will be automatically deleted. + + Yields + ------ + str + The name of the temporary directory.""" + with tempfile.TemporaryDirectory() as tmpdirname: + old_dir = os.getcwd() # get current working directory (cwd) + os.chdir(tmpdirname) # change cwd to the temp-directory + yield tmpdirname # yields control to the test to be run + os.chdir(old_dir) # restore the cwd to the original directory + # Leaving the context manager will prompt the deletion of the + # temporary directory and its contents. This cleanup will be + # triggered even if errors were raised during the test. + + +@pytest.fixture() +def dummy_email(): + """ This fixture will simply have pytest pass the string: + 'dummy.email@plymi.com' + to any test-function that has the parameter name `dummy_email` in + its signature. + """ + return "dummy.email@plymi.com" +``` + + + +The first one, `cleandir`, can be used in conjunction with tests that need to write files. +We don't want our tests to leave behind files on our machines; the `cleandir` fixture will ensure that our tests will write files to a temporary directory that will be deleted once the test is complete. + +Second is a simple fixture called `dummy_email`. +Suppose that our project needs to interact with a specific email address, suppose it's `dummy.email@plymi.com`, and that we have several tests that need access to this address. +This fixture will pass this address to any test function that has the parameter name `dummy_email` in its signature. + +A reference implementation of `conftest.py` in our project can be found [here](https://github.com/rsokl/plymi_mod6/blob/fixtures/tests/conftest.py). +Several reference tests that make use of these fixtures can be found [here](https://github.com/rsokl/plymi_mod6/blob/fixtures/tests/test_using_fixtures.py). + +Let's create a file `tests/test_using_fixtures.py`, and write some tests that put these fixtures to use: + +```python +# contents of test_using_fixtures.py +import pytest + +# When run, this test will be executed within a +# temporary directory that will automatically be +# deleted - along with all of its contents - once +# the test ends. +# +# Thus we can have this test write a file, and we +# need not worry about having it clean up after itself. +@pytest.mark.usefixtures("cleandir") +def test_writing_a_file(): + with open("a_text_file.txt", mode="w") as f: + f.write("hello world") + + with open("a_text_file.txt", mode="r") as f: + file_content = f.read() + + assert file_content == "hello world" + + +# We can use the `dummy_email` fixture to provide +# the same email address to many tests. In this +# way, if we need to change the email address, we +# can simply update the fixture and all of the tests +# will be affected by the update. +# +# Note that we don't need to use a decorator here. +# pytest is smart, and will see that the parameter-name +# `dummy_email` matches the name of our fixture. It will +# thus call these tests using the value returned by our +# fixture + +def test_email1(dummy_email): + assert "dummy" in dummy_email + + +def test_email2(dummy_email): + assert "plymi" in dummy_email + + +def test_email3(dummy_email): + assert ".com" in dummy_email +``` + + +## Links to Official Documentation + +- [pytest](https://docs.pytest.org/en/latest/) +- [pytest's system for test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) +- [Testing in PyCharm](https://www.jetbrains.com/help/pycharm/pytest.html) +- [Testing in VSCode](https://code.visualstudio.com/docs/python/testing) +- [Assertion introspection](https://docs.pytest.org/en/latest/assert.html#assertion-introspection-details) +- [Parameterizing tests](https://docs.pytest.org/en/latest/parametrize.html) +- [Fixtures](https://docs.pytest.org/en/latest/fixture.html#fixture) + + +## Reading Comprehension Solutions + + +**Running a Test Suite: Solution** + +> Let's add the test function `test_broken_function` to our test suite. +> We must include the word "test" in the function's name so that pytest will identify it as a test to run. +> There are limitless ways in which we can make this test fail; we'll introduce a trivial false-assertion: + +```python +def test_broken_function(): + assert [1, 2, 3] == [1, 2] +``` + +> After introducing this broken test into `test_basic_functions.py` , running our tests should result in the following output: + +``` +$ pytest tests/ +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +rootdir: C:\Users\plymi_user\plymi_root_dir +collected 4 items + +tests\test_basic_functions.py ..F [ 75%] +tests\test_basic_numpy.py . [100%] + +================================== FAILURES =================================== +____________________________ test_broken_function _____________________________ + + def test_broken_function(): +> assert [1, 2, 3] == [1, 2] +E assert [1, 2, 3] == [1, 2] +E Left contains one more item: 3 +E Use -v to get the full diff + +tests\test_basic_functions.py:40: AssertionError +========================= 1 failed, 3 passed in 0.07s ========================= +``` + +> Four tests were "discovered" and run by pytest. The pattern `..F` indicates that the first two tests in `test_basic_functions` passed and the third test failed. +> It then indicates which test failed, and specifically that the assertion was false because a length-2 list cannot be equal to a length-3 list. + + + +**Parameterizing Tests: Solution** + +A reference implementation for this solution within the `plymi_mod6` project can be found [here](https://github.com/rsokl/plymi_mod6/blob/parameterized/tests/test_basic_functions.py). + +The contents of `test_basic_functions.py`, rewritten to use pytest-parameterized tests: + +```python +import pytest +from plymi_mod6.basic_functions import count_vowels, merge_max_mappings + + +@pytest.mark.parametrize( + "input_string, include_y, expected_count", + [("aA bB yY", False, 2), ("aA bB yY", True, 4), ("", False, 0), ("", True, 0)], +) +def test_count_vowels_basic(input_string, include_y, expected_count): + assert count_vowels(input_string, include_y) == expected_count + + +@pytest.mark.parametrize( + "dict_a, dict_b, expected_merged", + [ + (dict(a=1, b=2), dict(b=20, c=-1), dict(a=1, b=20, c=-1)), + (dict(), dict(b=20, c=-1), dict(b=20, c=-1)), + (dict(a=1, b=2), dict(), dict(a=1, b=2)), + (dict(), dict(), dict()), + ], +) +def test_merge_max_mappings(dict_a, dict_b, expected_merged): + assert merge_max_mappings(dict_a, dict_b) == expected_merged +``` + +Running these tests via pytest should produce eight distinct test-case: four for `test_count_vowels_basic` and four for `test_merge_max_mappings`. + +``` +============================= test session starts ============================= +platform win32 -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.12.0 +cachedir: .pytest_cache +rootdir: C:\Users\plymi_user\Learning_Python\plymi_mod6_src +collecting ... collected 8 items + +test_basic_functions.py::test_count_vowels_basic[aA bB yY-False-2] PASSED [ 12%] +test_basic_functions.py::test_count_vowels_basic[aA bB yY-True-4] PASSED [ 25%] +test_basic_functions.py::test_count_vowels_basic[-False-0] PASSED [ 37%] +test_basic_functions.py::test_count_vowels_basic[-True-0] PASSED [ 50%] +test_basic_functions.py::test_merge_max_mappings[dict_a0-dict_b0-expected_merged0] PASSED [ 62%] +test_basic_functions.py::test_merge_max_mappings[dict_a1-dict_b1-expected_merged1] PASSED [ 75%] +test_basic_functions.py::test_merge_max_mappings[dict_a2-dict_b2-expected_merged2] PASSED [ 87%] +test_basic_functions.py::test_merge_max_mappings[dict_a3-dict_b3-expected_merged3] PASSED [100%] + +============================== 8 passed in 0.07s ============================== +``` + + diff --git a/docs_backup/_sources/changes.rst.txt b/docs_backup/_sources/changes.rst.txt new file mode 100644 index 00000000..30a370d6 --- /dev/null +++ b/docs_backup/_sources/changes.rst.txt @@ -0,0 +1,27 @@ +========= +Changelog +========= + +This is a record of all past mygrad releases and what went into them, +in reverse chronological order. All previous releases should still be available +on pip. + + +---------- +2019-12-14 +---------- + +We're finally keeping a formal changelog! This update includes our first discussion of features that were introduced in Python 3.8. Also includes various typo/grammar fixes. + +~~~~~~~~~~~ +New Content +~~~~~~~~~~~ + +- `Module 1 - Jupyter Notebooks: `_ included a brief discussion of Jupyter lab + +- `Module 1 - Setting Up a Development Environment: `_ Updated IDE discussion to reflect recent improvements to VSCode for Python. + +- `Module 5 - Writing Good Code: `_ Added ``typing.Literal``, which was introduced in Python 3.8, to the discussion of type-hints . + +- `Module 5 - Writing Good Code: `_ ``pyright`` is now listed alongside ``mypy`` as a tool for doing static type analysis. + diff --git a/docs_backup/_sources/index.rst.txt b/docs_backup/_sources/index.rst.txt index 5c83f04d..3274b75e 100644 --- a/docs_backup/_sources/index.rst.txt +++ b/docs_backup/_sources/index.rst.txt @@ -12,7 +12,7 @@ What this is ------------ Python Like You Mean It (PLYMI) is a free resource for learning the basics of Python & NumPy, and moreover, becoming a competent Python user. The features of the Python language that are emphasized here were chosen to help those who are particularly interested in STEM applications (data analysis, machine learning, numerical work, etc.). -I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.6, as of writing this). +I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.8, as of writing this). What this isn't @@ -64,6 +64,8 @@ I started learning to use Python in graduate school for my physics research, and module_3_problems.rst module_4.rst module_5.rst + module_6.rst + changes.rst Indices and tables ================== diff --git a/docs_backup/_sources/intro.rst.txt b/docs_backup/_sources/intro.rst.txt index d404dea3..6e719964 100644 --- a/docs_backup/_sources/intro.rst.txt +++ b/docs_backup/_sources/intro.rst.txt @@ -12,7 +12,7 @@ What this is ------------ Python Like You Mean It (PLYMI) is a free resource for learning the basics of Python & NumPy, and moreover, becoming a competent Python user. The features of the Python language that are emphasized here were chosen to help those who are particularly interested in STEM applications (data analysis, machine learning, numerical work, etc.). -I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.7, as of writing this). +I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.8, as of writing this). What this isn't diff --git a/docs_backup/_sources/module_5.rst.txt b/docs_backup/_sources/module_5.rst.txt index 0c0bf09f..63c8036d 100644 --- a/docs_backup/_sources/module_5.rst.txt +++ b/docs_backup/_sources/module_5.rst.txt @@ -1,5 +1,5 @@ Module 5: Odds and Ends -===================================== +======================= This module contains materials that are extraneous to the essentials of Python as a language and of NumPy, but are nonetheless critical to doing day-to-day work using these tools. The first section introduces some general guidelines for writing "good code". Specifically, it points you, the reader, to a style guide that many people in the Python community abide by. It also introduces a relatively new and increasingly-popular feature of Python, called type-hinting, which permits us to enhance our code with type-documentation annotations. The reader will also be introduced to NumPy's and Google's respective specifications for writing good docstrings. diff --git a/docs_backup/_sources/module_6.rst.txt b/docs_backup/_sources/module_6.rst.txt new file mode 100644 index 00000000..4e20e2c1 --- /dev/null +++ b/docs_backup/_sources/module_6.rst.txt @@ -0,0 +1,20 @@ +Module 6: Testing Your Code +=========================== +This module will introduce us to the critically-important and often-overlooked process of testing code. +We will begin by considering some general motivations for writing tests. +Next, we will study the basic anatomy of a test-function, including the :code:`assert` statement, which serves as the nucleus of our test functions. +Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework `pytest `_. +This will inform how we structure our tests alongside our Python project; with pytest, we can incisively run our tests with the press of a single button. +Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. +Finally, we will take a step back to consider some strategies for writing effective tests. +Among these is a methodology that is near and dear to my heart: property-based testing. +This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library `Hypothesis `_ waiting to greet us (adorned with the mad Hatter's cap and all). + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + Module6_Testing/Intro_to_Testing.md + Module6_Testing/Pytest.md + + diff --git a/docs_backup/changes.html b/docs_backup/changes.html new file mode 100644 index 00000000..55ea3dd2 --- /dev/null +++ b/docs_backup/changes.html @@ -0,0 +1,264 @@ + + + + + + + + + + + Changelog — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    Changelog

    +

    This is a record of all past mygrad releases and what went into them, +in reverse chronological order. All previous releases should still be available +on pip.

    +
    +

    2019-12-14

    +

    We’re finally keeping a formal changelog! This update includes our first discussion of features that were introduced in Python 3.8. Also includes various typo/grammar fixes.

    +
    +

    New Content

    + +
    +
    +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs_backup/genindex.html b/docs_backup/genindex.html index 59bfc211..e281cea5 100644 --- a/docs_backup/genindex.html +++ b/docs_backup/genindex.html @@ -98,6 +98,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/index.html b/docs_backup/index.html index 0cf34670..b7a34de3 100644 --- a/docs_backup/index.html +++ b/docs_backup/index.html @@ -98,6 +98,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -196,7 +198,7 @@

    Python Like You Mean It

    What this is

    Python Like You Mean It (PLYMI) is a free resource for learning the basics of Python & NumPy, and moreover, becoming a competent Python user. The features of the Python language that are emphasized here were chosen to help those who are particularly interested in STEM applications (data analysis, machine learning, numerical work, etc.).

    -

    I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.6, as of writing this).

    +

    I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.8, as of writing this).

    diff --git a/docs_backup/intro.html b/docs_backup/intro.html index 21f0a3ad..fba1994e 100644 --- a/docs_backup/intro.html +++ b/docs_backup/intro.html @@ -108,6 +108,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -206,7 +208,7 @@

    Python Like You Mean It

    What this is

    Python Like You Mean It (PLYMI) is a free resource for learning the basics of Python & NumPy, and moreover, becoming a competent Python user. The features of the Python language that are emphasized here were chosen to help those who are particularly interested in STEM applications (data analysis, machine learning, numerical work, etc.).

    -

    I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.7, as of writing this).

    +

    I want this to be a lean, one-stop resource for learning the essentials of Python from scratch. The reader will begin by learning about what Python is and what installing Python even means, and will hopefully walk away with a solid understanding of a substantial core of the language and its premiere numerical library, NumPy. I am also placing an emphasis on best practices throughout this site and am teaching to the latest version of Python (version 3.8, as of writing this).

    What this isn’t

    diff --git a/docs_backup/module_1.html b/docs_backup/module_1.html index 7daa7e83..9f753e1a 100644 --- a/docs_backup/module_1.html +++ b/docs_backup/module_1.html @@ -107,6 +107,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • @@ -226,6 +228,7 @@

    Module 1: Getting Started with PythonJupyter Notebooks diff --git a/docs_backup/module_2_problems.html b/docs_backup/module_2_problems.html index 5e5063cd..75cbb0a0 100644 --- a/docs_backup/module_2_problems.html +++ b/docs_backup/module_2_problems.html @@ -106,6 +106,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/module_3.html b/docs_backup/module_3.html index 47d036b9..5c0e7395 100644 --- a/docs_backup/module_3.html +++ b/docs_backup/module_3.html @@ -110,6 +110,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/module_3_problems.html b/docs_backup/module_3_problems.html index 0fa38c30..17cf284c 100644 --- a/docs_backup/module_3_problems.html +++ b/docs_backup/module_3_problems.html @@ -103,6 +103,8 @@
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/module_4.html b/docs_backup/module_4.html index 7aa41019..3b0cc789 100644 --- a/docs_backup/module_4.html +++ b/docs_backup/module_4.html @@ -109,6 +109,8 @@
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/module_5.html b/docs_backup/module_5.html index 114edea4..96a387a8 100644 --- a/docs_backup/module_5.html +++ b/docs_backup/module_5.html @@ -105,6 +105,8 @@
  • Import: Modules and Packages
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/module_6.html b/docs_backup/module_6.html new file mode 100644 index 00000000..1de914d4 --- /dev/null +++ b/docs_backup/module_6.html @@ -0,0 +1,281 @@ + + + + + + + + + + + Module 6: Testing Your Code — Python Like You Mean It + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +
    +

    Module 6: Testing Your Code

    +

    This module will introduce us to the critically-important and often-overlooked process of testing code. +We will begin by considering some general motivations for writing tests. +Next, we will study the basic anatomy of a test-function, including the assert statement, which serves as the nucleus of our test functions. +Armed with the ability to write a rudimentary test, we will welcome, with open arms, the powerful testing framework pytest. +This will inform how we structure our tests alongside our Python project; with pytest, we can incisively run our tests with the press of a single button. +Furthermore, it will allow us to greatly streamline and even begin to automate some of our tests. +Finally, we will take a step back to consider some strategies for writing effective tests. +Among these is a methodology that is near and dear to my heart: property-based testing. +This will take us down a bit of a rabbit hole, where we will find the powerful property-based testing library Hypothesis waiting to greet us (adorned with the mad Hatter’s cap and all).

    + +
    + + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/docs_backup/objects.inv b/docs_backup/objects.inv index 700aa7e5..7d79a929 100644 Binary files a/docs_backup/objects.inv and b/docs_backup/objects.inv differ diff --git a/docs_backup/search.html b/docs_backup/search.html index d7afa441..23057c32 100644 --- a/docs_backup/search.html +++ b/docs_backup/search.html @@ -98,6 +98,8 @@
  • Module 3: Problems
  • Module 4: Object Oriented Programming
  • Module 5: Odds and Ends
  • +
  • Module 6: Testing Your Code
  • +
  • Changelog
  • diff --git a/docs_backup/searchindex.js b/docs_backup/searchindex.js index d51c40bb..0b4881cd 100644 --- a/docs_backup/searchindex.js +++ b/docs_backup/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python","Module1_GettingStartedWithPython/GettingStartedWithPython","Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks","Module1_GettingStartedWithPython/Informal_Intro_Python","Module1_GettingStartedWithPython/Installing_Python","Module1_GettingStartedWithPython/Jupyter_Notebooks","Module1_GettingStartedWithPython/Numerical_Work_In_Python","Module1_GettingStartedWithPython/SiteFormatting","Module2_EssentialsOfPython/Basic_Objects","Module2_EssentialsOfPython/ConditionalStatements","Module2_EssentialsOfPython/DataStructures","Module2_EssentialsOfPython/DataStructures_III_Sets_and_More","Module2_EssentialsOfPython/DataStructures_II_Dictionaries","Module2_EssentialsOfPython/ForLoops","Module2_EssentialsOfPython/Functions","Module2_EssentialsOfPython/Generators_and_Comprehensions","Module2_EssentialsOfPython/Introduction","Module2_EssentialsOfPython/Iterables","Module2_EssentialsOfPython/Itertools","Module2_EssentialsOfPython/Problems/DifferenceFanout","Module2_EssentialsOfPython/Problems/EncodeAsString","Module2_EssentialsOfPython/Problems/MarginPercentage","Module2_EssentialsOfPython/Problems/MergeMaxDicts","Module2_EssentialsOfPython/Problems/Palindrome","Module2_EssentialsOfPython/Scope","Module2_EssentialsOfPython/SequenceTypes","Module2_EssentialsOfPython/Variables_and_Assignment","Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions","Module3_IntroducingNumpy/AdvancedIndexing","Module3_IntroducingNumpy/ArrayTraversal","Module3_IntroducingNumpy/BasicArrayAttributes","Module3_IntroducingNumpy/BasicIndexing","Module3_IntroducingNumpy/Broadcasting","Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays","Module3_IntroducingNumpy/IntroducingTheNDarray","Module3_IntroducingNumpy/Problems/Approximating_pi","Module3_IntroducingNumpy/Problems/ComputeAccuracy","Module3_IntroducingNumpy/VectorizedOperations","Module4_OOP/Applications_of_OOP","Module4_OOP/Brief_Review","Module4_OOP/ClassDefinition","Module4_OOP/ClassInstances","Module4_OOP/Inheritance","Module4_OOP/Introduction_to_OOP","Module4_OOP/Methods","Module4_OOP/ObjectOrientedProgramming","Module4_OOP/Special_Methods","Module5_OddsAndEnds/Matplotlib","Module5_OddsAndEnds/Modules_and_Packages","Module5_OddsAndEnds/WorkingWithFiles","Module5_OddsAndEnds/Writing_Good_Code","index","intro","module_1","module_2","module_2_problems","module_3","module_3_problems","module_4","module_5"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,nbsphinx:1,sphinx:55},filenames:["Module1_GettingStartedWithPython\\Exercises\\Informal_Intro_Python.ipynb","Module1_GettingStartedWithPython\\GettingStartedWithPython.md","Module1_GettingStartedWithPython\\Getting_Started_With_IDEs_and_Notebooks.md","Module1_GettingStartedWithPython\\Informal_Intro_Python.md","Module1_GettingStartedWithPython\\Installing_Python.md","Module1_GettingStartedWithPython\\Jupyter_Notebooks.md","Module1_GettingStartedWithPython\\Numerical_Work_In_Python.md","Module1_GettingStartedWithPython\\SiteFormatting.md","Module2_EssentialsOfPython\\Basic_Objects.md","Module2_EssentialsOfPython\\ConditionalStatements.md","Module2_EssentialsOfPython\\DataStructures.md","Module2_EssentialsOfPython\\DataStructures_III_Sets_and_More.md","Module2_EssentialsOfPython\\DataStructures_II_Dictionaries.md","Module2_EssentialsOfPython\\ForLoops.md","Module2_EssentialsOfPython\\Functions.md","Module2_EssentialsOfPython\\Generators_and_Comprehensions.md","Module2_EssentialsOfPython\\Introduction.md","Module2_EssentialsOfPython\\Iterables.md","Module2_EssentialsOfPython\\Itertools.md","Module2_EssentialsOfPython\\Problems\\DifferenceFanout.md","Module2_EssentialsOfPython\\Problems\\EncodeAsString.md","Module2_EssentialsOfPython\\Problems\\MarginPercentage.md","Module2_EssentialsOfPython\\Problems\\MergeMaxDicts.md","Module2_EssentialsOfPython\\Problems\\Palindrome.md","Module2_EssentialsOfPython\\Scope.md","Module2_EssentialsOfPython\\SequenceTypes.md","Module2_EssentialsOfPython\\Variables_and_Assignment.md","Module3_IntroducingNumpy\\AccessingDataAlongMultipleDimensions.md","Module3_IntroducingNumpy\\AdvancedIndexing.md","Module3_IntroducingNumpy\\ArrayTraversal.md","Module3_IntroducingNumpy\\BasicArrayAttributes.md","Module3_IntroducingNumpy\\BasicIndexing.md","Module3_IntroducingNumpy\\Broadcasting.md","Module3_IntroducingNumpy\\FunctionsForCreatingNumpyArrays.md","Module3_IntroducingNumpy\\IntroducingTheNDarray.md","Module3_IntroducingNumpy\\Problems\\Approximating_pi.ipynb","Module3_IntroducingNumpy\\Problems\\ComputeAccuracy.md","Module3_IntroducingNumpy\\VectorizedOperations.md","Module4_OOP\\Applications_of_OOP.md","Module4_OOP\\Brief_Review.md","Module4_OOP\\ClassDefinition.md","Module4_OOP\\ClassInstances.md","Module4_OOP\\Inheritance.md","Module4_OOP\\Introduction_to_OOP.md","Module4_OOP\\Methods.md","Module4_OOP\\ObjectOrientedProgramming.md","Module4_OOP\\Special_Methods.md","Module5_OddsAndEnds\\Matplotlib.ipynb","Module5_OddsAndEnds\\Modules_and_Packages.md","Module5_OddsAndEnds\\WorkingWithFiles.md","Module5_OddsAndEnds\\Writing_Good_Code.md","index.rst","intro.rst","module_1.rst","module_2.rst","module_2_problems.rst","module_3.rst","module_3_problems.rst","module_4.rst","module_5.rst"],objects:{},objnames:{},objtypes:{},terms:{"**kwarg":14,"*arg":14,"0th":[8,29],"0x00000146ce118620":49,"0x000001e768fe8a40":15,"0x000002a32898c6a8":14,"0x1d50de887b8":41,"0x1d50de896d8":41,"0x1d50de897b8":41,"0x1d50de89940":41,"0x1d50de899e8":41,"0x1d50de89a20":41,"0x1d50de89a58":41,"0x1d50de89a90":41,"0x1d50de89ac8":41,"0x1d50de89b00":41,"0x1d50de89b38":41,"0x20de1082608":18,"0x20de109ec18":18,"0x20de10a7728":18,"0x23e3557b3f0":18,"0x284f0008da0":44,"0x2ae8f65fcf8":41,"0x2ae8f666f60":41,"0x2ae8f68f2e8":41,"10000j":8,"10_000j":8,"10x10":47,"111111111111111e":8,"15x25":47,"16j":48,"1_000_000":8,"1e12":8,"1e3":8,"1e34":50,"1e9":8,"1st":[25,37],"1x10":8,"1x4":36,"207d18d18af2":27,"2246467991473532e":48,"2_3_4":8,"2cool":26,"2e10":8,"2f755f117ac9":27,"2mb":32,"2nd":12,"2x2":27,"2x3":[37,47],"2x3x4":33,"32x32":[32,37],"3471672109ee":9,"38e":8,"3rd":[4,37,49,50,53],"3x4":[15,33],"48x48":32,"4th":31,"50x75x3":47,"551115123125783e":8,"5_6_7":8,"662_607_004":8,"6gb":32,"74c002a67890":12,"7th":25,"\u0113z":27,"\u4e2d\u6587\u7248":[51,52],"\u4f60\u597d":8,"absolute import":48,"abstract method":44,"abstract":[27,28,42,45,50],"array iter":29,"basic index":31,"basic program":13,"best practic":50,"big-o":10,"binary fil":49,"boolean array index":28,"boolean":[12,20,26,35,36,37,50,54,56],"break":[3,4,8,17,23,24,26,50,54],"byte":[8,30,49],"c order":29,"c routin":37,"case":[1,3,4,5,9,10,12,13,14,15,17,19,20,21,22,23,25,27,31,32,36,37,40,45,47,49,50,54],"catch":[8,9,12,20,50],"char":[11,14,23,50],"class creat":41,"class definit":[39,40],"class funt":44,"class method":44,"class object":40,"class":[8,11,17,22,26,36,38,39,42,45,48,49,50,51,58,59],"close fil":49,"code block":7,"code styl":50,"column-major ord":29,"command lin":5,"comparison oper":9,"console styl":7,"context manag":49,"control flow":[13,16,21],"copy index":28,"create arrai":33,"custom packag":48,"custom syntax":46,"data sci":[4,5],"default paramet":14,"default":[4,5,8,15,25,27,29,31,33,37,43,44,46,47,48,49,50,56],"dunder method":46,"export":4,"f order":29,"final":[5,8,19,20,26,31,32,35,42,47,48,50,54,56,59],"float":[3,12,15,20,21,26,27,28,31,33,36,37,43,44,46,47,50],"floating point precis":8,"for loop":19,"for-loop":[13,16],"function":[0,1,2,3,5,6,7,8,9,10,11,15,16,18,19,20,21,22,23,24,28,29,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,51,54,56,58,59],"generator comprehens":15,"get item":[12,25],"import":[0,3,4,5,6,8,10,11,12,14,15,17,18,19,20,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,41,44,47,49,50,51,52,54,58,59],"inline for-loop":15,"inline if":9,"int":[1,8,9,16,19,20,28,31,33,36,40,41,43,45,50,58],"integer array index":28,"interview prepar":[10,11,12],"is oper":9,"join directori":49,"linear algebra":37,"list comprehens":[15,19],"long":[2,4,8,10,12,15,19,20,23,31,37,43,47,48,50,54],"machine learn":36,"mismatched shap":32,"multidimensional arrai":31,"nd arrai":31,"negative index":[25,27],"nested comprehens":15,"new":[1,2,3,4,5,8,10,12,15,17,19,22,23,25,26,27,31,32,37,38,41,42,43,44,49,50,51,52,58,59],"no copy index":31,"null":8,"numpy arrai":[27,28,34],"object ori":[38,42,47],"ol\u00e1":8,"open fil":49,"operator overload":46,"practice problem":[19,20,21,22,23],"public":47,"python shopping list":38,"quick introduct":3,"read fil":49,"read lin":49,"relative import":48,"return":[3,4,5,6,7,8,9,10,11,12,13,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,32,36,37,38,40,41,42,43,44,45,46,47,48,49,50,54],"row-major ord":29,"short":[3,8,13,15,37,54],"special method":46,"static method":44,"static":[41,50,58],"sub class":42,"super":[42,45],"switch stat":9,"switch":4,"throw":[27,35],"true":[3,5,8,9,10,11,12,13,14,15,16,17,20,22,23,24,25,26,28,29,31,32,34,35,36,37,39,40,41,42,44,45,46,47,49,50],"try":[0,3,8,11,12,13,15,19,22,25,26,32,35,38,44,45,48,50,56],"type hint":50,"utf-8":49,"valid nam":26,"var":[13,14,15,26,37,41,49],"variable nam":26,"voil\u00e0":[1,32,48],"vowel count":14,"while":[0,3,4,5,16,17,19,22,24,26,27,30,31,32,47,50,51,54],"while-loop":13,And:[4,5,11,14,20,36],Are:[8,15,32],Axes:[56,59],Being:25,But:[16,51,52],Doing:[26,32,38],For:[0,1,3,4,5,7,8,9,10,11,12,14,15,16,17,19,25,26,27,28,29,30,31,33,35,36,37,41,43,44,45,46,47,48,49,51,54],IDE:[1,2,48,50],IDEs:[1,16,48,50,53],IDs:36,Its:[5,8,16,37,41,45,47],Not:[5,27,36],One:[8,15,16,29,37,45,47,48,49,56],Such:[7,14],That:[1,2,4,8,9,10,11,12,13,14,15,17,19,20,24,25,26,27,29,31,32,35,36,40,41,42,43,44,45,46,48,49,50,51,52,58],The:[1,2,3,4,5,6,7,9,10,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,39,41,42,43,45,46,48,49,51,52,55,57,58,59],Their:[14,25],Then:[1,8,10,12,18,19,26,27,28,32,38,41],There:[1,2,3,4,5,8,9,10,13,14,15,18,19,22,25,26,31,32,33,34,36,37,43,44,47,48,49,50],These:[1,4,5,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,37,41,43,46,48,49,50,54,55,56,57],Tis:23,Use:[0,5,8,9,11,13,14,15,16,17,28,32,35,46,47,49,50],Uses:54,Using:[0,6,8,9,13,14,18,22,25,26,27,28,35,38,41,45,47,49,54,56],Will:[9,25,36,53],With:[4,11,41,49],Yes:4,__add__:[44,45,46],__all__:48,__contains__:46,__div__:46,__eq__:45,__ge__:45,__getitem__:[17,46,50],__gt__:45,__init__:[38,39,42,43,44,45,46,48,50,58],__iter__:[17,46],__le__:45,__len__:[46,50],__lt__:45,__main__:[39,40,41,44],__mul__:[45,46],__ne__:45,__next__:46,__pow__:[45,46],__radd__:45,__repr__:[42,43,45,46],__rmul__:45,__rsub__:45,__rtruediv__:45,__setitem__:46,__str__:[45,46],__sub__:[45,46],__truediv__:[45,46],_data:46,_need:[38,46],_purchas:[38,46],_use_gpu:50,_var2:26,a858573fdc63:26,a_dir:48,a_long_list_nam:50,a_poem:49,abacus:32,abbrevi:[8,34,47],abc:[3,9,25,49,50],abcabcabc:9,abcd:[17,25,44],abcdef:29,abcdefg:25,abcdefghij:13,abid:[22,50,59],abil:[8,9,14,16,25,26,27,29,41,43,44,46,50,54,59],abl:[1,3,4,5,8,12,14,22,25,26,27,29,31,32,37,44,45,47,48,51,52,56],about:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,19,22,29,32,33,35,37,38,41,43,44,45,46,47,49,50,54,58,59],abov:[4,5,8,14,22,27,31,32,35,36,39,41,48,50],abs:[8,15,21],abs_tol:8,absolut:[8,15,32,37,49],acceler:50,accept:[11,12,14,15,17,22,25,36,37,38,42,44,46,47,49,50],access:[1,3,8,9,10,11,15,17,18,19,20,22,24,25,28,29,31,32,33,34,40,41,43,44,48,49,51,56,58],accident:[4,5,48],accommod:[8,9,11,12,16,22,32,38,48,50],accomod:49,accompani:[55,57],accomplish:[0,1,3,12,14,48],accord:[1,8,9,10,12,14,20,27,29,30,31,32,35,37,41,44,47,49,50],accordingli:[1,35,46],account:[8,9,23,32,51,52],accru:50,accumul:[1,50],accuraci:[35,51,57],accustom:50,ace:25,aceg:25,achiev:[17,32,56],acquaint:[3,54],acquir:[51,52],across:[5,8,16,18,22,35,36,49,50],act:[37,54],action:[3,7,8,37,42,49,50],activ:[4,5,48],actual:[4,6,8,9,14,15,19,21,25,27,31,32,33,35,41,50,53,54,59],adam:8,add:[1,2,4,8,10,11,12,14,16,17,28,32,35,37,38,44,46,47,50,58],add_2:14,add_3:31,add_new_item:[38,46],added:[10,12,13,15,22,28,38,40,46,50,59],adding:[11,12,13,26,49,50,51,52,54],addit:[4,8,9,11,12,14,16,33,35,37,40,44,45,47,48,50],addition:[1,5,22,28,38,41,43,47,48],address:[14,15,22,32,41,44],adher:[16,29,50],adjust:[5,27,29],ado:4,adopt:[44,50],advanc:[2,4,6,12,15,27,29,34,51,56],advantag:[10,11,37,45],advis:[4,16,49],aeiou:[13,49],aeiouaeiou:[14,50],aesthet:50,affect:[3,16,26,31,41,43,46,47],afford:27,afoot:22,aforement:[1,4,16],after:[3,4,8,11,12,13,14,15,19,22,24,27,32,40,50,55,57],afterward:31,again:[3,10,15,24,31,32,43,50],against:[10,19,22,36],age:8,agre:27,aha:20,ahead:19,aid:50,aim:[2,28,47],air:50,aka:50,akaclass:50,akin:[8,40],aks:27,albeit:32,albert:49,alert:50,alex:51,alexding123:[51,52],alfr:8,algebra:[10,11,56],algorithm:[12,17,21,22,50,54],alia:[4,41,48,50],alias:[48,50],alias_nam:48,alic:22,alien:8,align:[8,32,47,50],alik:[5,7,15,53],all:[1,3,4,5,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,58,59],all_cap:50,all_fanout:19,allclos:[32,37],allevi:32,alloc:[8,31],allot:8,allow:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,19,21,23,25,27,28,29,31,32,33,34,36,38,40,41,42,45,46,47,48,49,50,53,54,59],almost:[8,10,12,27,32,50],alon:49,along:[2,3,8,11,13,15,17,20,22,23,24,28,29,30,31,32,33,34,35,37,47,48,50,51,52,54,56],alongsid:50,alpha:[35,47],alphabet:[8,27,38,50],alphanumer:[23,26],alreadi:[4,6,8,9,10,12,15,25,31,38,40,41,42,44,45,48,49,50],also:[2,3,4,6,8,9,10,11,12,14,15,17,20,21,22,23,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,44,45,46,47,48,49,50,51,52,53,55,56,57,59],altern:[8,9],although:[1,2,5,8,12,15,17,19,23,25,27,28,29,37,40,43,47,49,50,54],altogeth:14,alwai:[3,5,8,9,12,13,16,20,22,27,28,29,32,37,38,42,44,47,48,50],alyosha:50,ambigu:[27,56],amend:[26,33],among:[1,8,12,22,25,27,37,44,50,56],amort:10,amount:[8,29,33,37,38,45,47,49,54],amp:47,amplitud:47,anaconda3:4,anaconda:[3,6,47,48,53],analog:37,analysi:[8,10,35,43,51,52],analyt:48,analyz:[5,10,49,50,56],anchor:50,anew:49,angi:18,angl:48,ani:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,22,24,25,26,29,30,31,32,35,37,40,41,43,44,45,46,48,49,53],anim:47,annabel:[51,52],annabellelew:[51,52],annot:[14,47,50,59],anoth:[1,5,8,9,11,12,15,22,25,28,29,31,32,35,41,42,43,46,47,48,50,58],another_long_nam:50,answer:[1,5,8,28,37,49],anticip:[21,44],anyon:[1,21,59],anyth:[1,8,9,12,14,44,45,47,49,50],anywher:[8,9,14,24,48,50],api:[47,59],appear:[1,3,5,7,8,15,19,25,26,45,47,48],append:[0,3,8,10,11,13,15,17,19,20,25,26,35,36,41,44,45,46,49,50],appendix:46,appendleft:11,appl:[3,8,11,12,14,15,18,22,25,38,39,40,46,50],applepie_yum_yum:26,appli:[19,27,28,32,35,37,41,50],applic:[4,5,6,11,27,29,37,47,51,52,54,56,58],apply_fanout:19,appreci:[15,22,35,46],approach:[32,36],appropri:[0,14,21,22,26,28,29,32,38,41,49,50],approv:50,approx:35,approxim:[8,14,35,37],arang:[6,27,28,29,35,37,47,56],arbitrari:[25,28,32,40,46,50,55],arbitrarili:[8,15,28],archiv:49,area:[35,43],area_:35,aren:22,arg1:50,arg2:50,arg3:50,arg4:50,arg5:50,arg6:50,arg:[14,22,24,46],argmax:[36,37],argmin:37,arguabl:[1,21],argument:[9,12,15,17,22,24,31,33,36,39,40,41,46,47,49,50,54],aris:54,arithmet:[3,8,9,31,32,37],arm:[9,19,28,30,48,53,54,56],around:[8,34,41,43,50],arr:[27,31],arrai:[6,9,25,26,35,36,43,47,48,50,51,56,59],arriv:[12,56],arrow:50,articl:6,artifact:46,as_integer_ratio:8,ascrib:[9,25,27],ashlei:[12,17,26,27],asid:2,ask:25,aspect:[8,19,24,28,46,47],assert:45,assess:23,assign:[0,1,3,5,7,9,13,14,17,22,25,27,39,40,41,48,51,54,56],associ:[4,8,9,10,12,36,37,45,47,48,50],assort:[27,32],assum:[1,4,8,9,10,12,19,21,24,25,35,36,44,49,50],assumpt:[47,50],assur:49,asterisk:14,astrophys:56,astropi:56,astyp:47,atrophi:50,attempt:[4,8,13,19,25,26,40,44,45,48],attent:[17,43,50,54,58],attr:[40,42],attract:6,attribut:[38,39,42,43,44,45,46,48,51,56,58],attribute_nam:40,attributeerror:[39,40,45],augment:[38,56],author:48,auto:[43,48],autocomplet:[2,3,5],autom:50,automat:[8,16,19,27,31,38,39,41,43,44,47,49,50],autoreload:48,avail:[3,5,7,8,10,11,12,25,27,33,37,40,45,47,48,49,50,51,52],averag:[32,35,37,54],avoid:[3,8,15,17,32,33,37,50],awai:[3,14,50,51,52],awar:[5,8,47,49],ax1:47,ax2:47,ax3:47,ax4:47,ax5:47,ax6:47,axes:[27,30,31,32,35,37,47],axi:[27,28,29,30,31,32,34,35,36,47],axs:47,b9d20096048c:15,b_attr:42,back:[4,5,13,29,50,51,52],background:[7,47],backtick:7,bad:[16,22,35,40,44,50,51,52],bad_dict:12,bad_f:14,bad_func1:14,bad_func2:14,bad_func3:14,bad_func4:14,bad_merge_max_map:22,bagel:49,balanc:54,banana:[12,18,22,50],bar:[16,47],bare:[48,56],base:[1,8,9,14,19,20,22,25,26,27,28,32,33,45,47,48,50],base_fanout:19,base_numb:19,bashrc:4,basic:[1,5,7,9,13,15,17,25,27,32,34,40,41,43,47,48,49,51,52,54,56],basic_math:48,basic_modul:48,basket:8,batch:36,batman:8,bcd:25,beauti:47,becaus:[1,4,8,9,10,11,12,13,14,15,17,22,25,27,28,29,31,33,35,36,37,44,45,48,49,51,52],becom:[1,2,5,6,9,11,13,15,17,18,27,33,37,40,48,50,51,52,53,54],bedrock:49,been:[1,4,5,8,10,12,15,20,25,27,31,32,35,37,38,40,43,45,48,50,51,52,54],beet:46,befor:[4,10,12,13,15,16,22,23,27,32,38,43,45,48,49],begin:[1,3,4,7,8,9,10,11,16,22,25,26,27,28,31,32,35,38,40,44,49,50,51,52,53,54],beginn:[4,5],behav:[8,11,12,13,14,19,20,22,25,28,31,35,36,37,41,43,44,45,46,50,58],behavior:[8,9,11,14,19,20,21,22,23,25,26,28,37,44,46,47],behind:[6,15,26,31,32,45],being:[1,2,4,5,7,8,9,12,13,14,15,17,20,22,26,27,28,29,31,32,35,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,58],belong:[8,9,18,34,39,43],below:[4,5,11,35,40,49,54],beneath:[5,13],benefit:[33,37,47,48,50],best:[6,8,22,26,28,37,47,49,51,52,59],beta:2,better:[12,22,29,49],between:[1,3,4,5,7,8,15,16,19,25,27,31,32,35,37,41,42,47,50,56,58],beyond:[3,8,12,14,15,19,27,31,32,44,46,48,59],biff:50,big:[2,4,10,12,28,31],biggest:50,billion:8,bin:[4,47,48],binari:[4,19,49,50],bind:40,bit:[8,14,15,18,29,30,33,37,47,49],black:[50,54],blank:[14,16,47,50],blazingli:6,bloat:32,block:[5,7,8,9,13,16,24,36,49,54],blog:[51,52],blogospher:25,blue:[5,32,37,47],board:35,bob:[3,8,22],bodi:[9,11,13,14,16,20,40,41,44],bogus_path:49,bohm:11,bohr:11,boil:1,boiling_point:50,bokeh:47,bolster:[44,54],bone:48,bonu:0,book:[11,32,49,50,51,52],bookkeep:[27,29],bool:[8,12,13,14,15,17,20,23,28,37,41,50,54],bool_ind:28,bool_index:28,boope:25,boopeeboopeeboopeeboopeeboope:25,border:5,both:[6,8,9,10,11,13,14,25,26,27,28,29,31,32,37,39,42,43,44,45,47,48,49,50],bottleneck:[22,23,32],bottom:[1,5,8,9,13,14,15,25,26,37,47,48],bound:[19,27,35,40,43,47,48],box:[2,54],brace:[10,12,16],bracket:[8,10,12,16,25,46,49,50],brad:[17,27],branch:[9,16,54],brand:44,bread:38,brian:[18,26],brief:[7,37,48,50,51,53,58],briefli:[4,9,11,18,24,27,43,47,49],bring:[5,44],broadcast:[28,29,31,34,35,37,47,50,51,56],broadcast_to:[32,47],broadli:41,broken:20,brought:58,browser:[5,47],bruce:[8,50],bud:50,bug:[8,9,12,17,22,31,50],buggi:55,buggy_merge_max_map:22,build:[3,4,16,27,29,32,37,42,48,53],built:[0,3,8,9,10,11,12,14,15,17,18,21,25,29,31,35,38,40,41,42,43,44,48,49,50,54],builtin:40,bullet:[6,46],bunch:[32,54],bundl:45,button:4,bye:[8,14],calcul:[0,6,19,32,34,37],calibr:48,call:[1,3,4,5,7,8,9,11,12,13,14,15,19,20,22,23,26,27,31,32,33,34,36,37,40,41,44,45,46,47,49,50,54,59],callabl:19,came:[4,6,12],camel:40,camelcas:50,camera:48,can:[0,1,2,3,4,5,6,7,9,10,11,13,14,15,16,17,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,58,59],cannot:[5,8,10,11,12,13,14,15,24,25,26,27,31,32,41,45,49,50,56],capabl:[1,17,20,37,43,47,48,50,56],capit:[8,43,44,50],capsul:14,caption:7,captur:50,capword:50,care:[10,12,14,19,20,22,32,38,48,49,50,53],carefulli:[37,50],carpent:[51,52],carri:[1,29,38,43,48],carrot:12,cassi:[17,18,27],cast:[14,20],casual:40,cat:[3,8,11,14,18,24,25,36,40,41,43],cat_dog_goose_oth:36,catcatcat:25,categori:[27,50],catwoman:8,caught:[51,52],caus:[1,13,16,22,26,31,48,49],caution:[8,38],caveat:4,cavemen:32,cavewomen:32,cba:9,cdot4:32,cdot5:32,cdot6:32,cdot7:32,cdot:[32,37],ceaselessli:13,celin:50,cell:[22,36,53],celsiu:50,center:[8,32,35,42,43],center_of_mass:32,certain:[3,32,49],certainli:12,chain:[9,18],challeng:55,chanc:5,chang:[1,3,4,5,8,12,19,22,25,26,27,31,32,35,41,48,50,51,52],channel:[32,47,48],charact:[0,1,2,3,8,9,11,13,16,23,26,43,46,49,50,54],characterist:50,charli:40,chart:47,cheat:47,check:[2,3,8,9,10,11,12,15,20,22,25,27,31,32,37,40,41,46,48,49,50,54],chees:12,chines:[51,52],chocol:50,choic:[20,50],choos:[22,27,33,47,50],chosen:[50,51,52],chunk:5,cindi:22,circl:[35,47],circuit:[13,54],circumst:[6,24,26],cite:50,civil:[33,40],clariti:16,class_:50,class_func:44,classa:11,classb:11,classif:[51,57],classifi:[36,50],classification_accuraci:36,classification_scor:36,classmethod:44,classnam:40,claus:[9,15,20,54],clean:[11,17,50,54],cleaner:[8,36,50],clear:[9,14,15,20,27,32,34,35,37,44,49,50,54],clearli:[19,50],clever:[20,22,25,32],click:[0,4,5],clockwis:43,close:[0,5,8,35,37,49,50,51,52],closur:50,cloth:46,cloud:48,cls:[44,50],cmap:47,cmath:8,cmd:[1,3,4],cnt:[7,40],cnt_div_by_3:16,code:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,31,32,34,35,36,37,38,39,40,41,42,45,47,48,49,51,52,53,54,55,56,57,59],coerc:32,coexist:43,coffe:46,coher:[37,50],col:[15,28,47],collabor:50,collect:[1,4,8,9,10,12,13,17,25,27,32,37,40,43,48,49,50,51,54],colon:[9,11,13,14,25,50],color:[2,5,7,32,37,47],colormap:47,column:[27,28,30,31,32,34,35,36,37,47,56],com:50,comb_l:18,combin:[14,18,24,31,32,37,41,46,56],come:[1,3,4,6,7,8,10,14,17,25,37,49,50,54,58],comfort:[18,21,37],comma:[8,14,15,25,50],command:[1,4,5,9,15,22,36,47,48,50],commensur:47,comment:7,common:[3,4,5,8,10,11,12,15,16,22,25,26,27,28,34,37,41,44,45,49,50,54],commonli:[8,9,14,29],commun:[2,5,50,59],commut:45,comp_var:24,compact:12,compani:50,compar:[6,8,9,10,11,12,15,22,23,24,27,32,36,37,50],comparison:[1,8,11,21,22,23,35,37,50,54],compat:[4,6,8,32,38,45,46],compet:[5,51,52],compil:[34,37,50],complac:[51,52],complain:44,complet:[4,5,6,8,9,10,11,12,13,20,21,27,29,33,35,36,46,48,49,50,51,52],complex32:30,complex64:33,complex:[11,26,33,48,50,54],complic:[12,15,35],compon:[6,31,48],compound:9,comprehens:[0,5,20,21,23,24,36,46,51,54,55,56,58,59],compris:[32,33],comput:[1,2,3,5,6,7,8,10,14,15,16,19,21,24,25,27,32,35,36,41,43,48,49,50,51,53,54,56],compute_area:[42,43],compute_corn:43,compute_exp:14,compute_student_stat:50,con:2,concat_to_str:20,concaten:[3,19,20,25,33,44],concept:[12,13,16,27,29,42,43,45,51,58],concern:[15,19,23,48,50,54],concis:[9,17,19,23,32,35,47,50,54,56],conclud:[10,14,26,28,32,44,48,50,58],conclus:56,concret:[13,29,32,41,50],conda:[53,59],condens:9,condit:[0,8,12,13,15,16,20,22,28,32,50,51,54],condition:16,conduc:1,conduct:[5,13],config:48,configur:[1,2,48,50],confirm:[0,44],conflict:[4,26,48,50],conform:1,confus:[1,8,15],conjunct:[17,28,49],connect:[5,47],consecut:9,consid:[6,9,10,13,15,16,19,20,21,22,23,25,27,28,29,31,32,37,41,42,44,48,50,55,57,59],consider:[6,38,54],consist:[9,14,16,25,26,27,35,41,46,48,50],consol:[3,4,5,7,8,16,22,26,36,43,45,46,47,48,50],constant:[10,48,50,56],constraint:[22,36,50],construct:[8,10,11,15,16,17,23,25,27,28,33,44,47,48,49,54,58],constructor:[8,12,15],consult:[8,11,46,47,50],consum:[11,12,23,25,32],consumpt:[15,32],contact:58,contain:[0,1,2,3,4,5,8,9,10,11,12,14,15,16,17,18,22,24,25,26,27,28,30,31,32,33,34,35,37,38,40,41,45,47,48,49,50,54,58,59],content:[1,3,5,8,9,10,11,12,13,14,15,17,24,25,26,27,28,31,32,33,34,36,37,41,46,48,49,50,51,52,53,54,55,56,57,58,59],context:[3,13,14,17,24,28,30,31,37,41,45,46,49,59],context_manag:49,context_vari:49,continu:[22,26,27,54],continuum:48,contour:47,contract:[22,40],contrast:[24,37,40,44,50],contribut:[50,51,52],contriv:18,control:[2,8,13,17,20,21,29,46,47,51,54],convei:[10,17,32,42,47,50],conveni:[1,2,3,8,9,10,15,27,32,37,44,46,47,48,49],convent:[40,44],convers:20,convert:[8,15,20,25,48,49],convinc:[22,28],convolut:[19,50],cook:[22,32],cool:12,coord:32,coordin:[11,12,32,35,38,47],copi:[22,23,26,27,28,31,32,41,46,48,51,52],core:[3,10,18,50,51,52,56],corner:[5,43],cornerston:[51,52,54],correct:[25,36,50,55],correctli:[9,22,36,50],correspond:[1,8,11,12,14,15,17,18,20,21,24,25,27,28,29,31,32,33,35,36,37,47],corrupt:49,cos:[5,37,47],costli:5,could:[3,5,8,9,12,18,22,27,29,32,34,37,44,47,50,51,52],count:[3,8,10,11,12,14,16,17,18,21,25,35,36,41,45,50],count_even:14,count_vowel:[14,50],counterpart:31,coupl:[8,20],cours:[1,2,3,4,5,6,14,16,26,27,49],courtnei:50,cout:1,cover:[8,12,14,17,37,49],cow:[12,14,17,18,24],cpython:[1,3,4,5,10,12,50],craft:59,creat:[0,1,2,3,4,8,9,12,17,18,20,22,23,25,26,27,28,29,31,32,34,35,37,38,39,40,42,43,44,45,48,49,50,51,52,53,54,56,58,59],creation:[11,32,33,40,41,43,49],creativ:25,creator:[48,50],credit:19,criterion:22,critic:[4,5,10,16,25,29,31,41,43,48,50,51,52,53,56,59],cross:[4,46],crowd:50,crucial:6,crude:35,crust:49,cryptic:8,ctrl:[0,5],cube:[9,48],cue:[3,27,37],cumsum:35,cumul:35,curat:[36,48],curi:11,curli:[8,10,12,16],current:[2,5,8,15,35,44,48,50,51,52],current_num:17,cursor:5,curv:[5,35,47],custom:[6,8,43,47,48,49,50,58],custom_dot_product:50,custom_inherit:50,customiz:2,cut:5,cute:20,cycl:47,d3_arrai:27,d5_arrai:27,d_sinc:5,dabbl:53,dai:[4,59],danger:[9,51,52],dangl:32,dart:[51,57],dart_posit:35,dash:[35,47,50],data1:49,data2:49,data:[2,3,4,5,15,22,25,28,29,30,32,34,36,37,43,45,47,48,49,50,51,52,53,54,56,58,59],databas:[48,50],datafram:43,dataset:[27,47],datatyp:33,date:[1,8,50,51,52],datum:36,davi:50,david:[11,12,18,49,51,52],deactiv:4,dead:[4,9],deal:[3,8,10,12,19,28,36,37,48],debat:21,debug:[2,22,50],decid:35,decim:[3,8,12,32],decis:50,decod:49,decor:44,dedic:[2,17,31],deduc:35,deem:27,deep:[25,51,52],deepen:43,deeper:[15,47,48],deepli:[48,51,52],def:[5,6,7,10,12,16,19,20,21,22,23,24,26,31,32,36,38,39,40,41,42,43,44,45,46,48,50,54],defacto:44,defaultdict:[11,48],defin:[1,3,5,7,8,11,13,14,15,16,20,22,24,26,27,31,33,34,37,38,39,42,43,44,46,48,49,50,51,54,56,58],definit:[2,10,12,13,14,15,16,17,24,27,29,31,32,37,38,39,41,42,43,44,48,50,58],deg_to_rad:48,degre:[35,48,56],deleg:37,delet:5,deliev:48,delimit:[8,9,13,14,46,49,50,54],deliv:48,deliveri:48,delv:[26,28,31,37],demand:[15,54],demarc:14,demo:3,demonin:45,demonstr:[7,8,9,11,12,13,18,19,22,24,25,26,28,29,31,32,33,37,40,41,44,46,47,48,49,50],denom:45,denot:[5,8,9,10,14,27,37,40,49],depend:[4,10,12,13,21,26,29,45,48,49,56],depict:[27,35],deriv:5,describ:[1,11,20,30,37,41,42,43,48,50,54],descript:[8,10,11,14,22,28,29,48,50],deserv:17,design:[1,3,8,11,21,27,36,37,40,43,44,46,47,49,50,54,55,56,57],desir:[5,21,22,27,29,32,44,46],desktop:[48,49],despit:[22,48],detail:[4,5,7,8,12,14,17,25,26,27,28,29,32,37,44,45,47,48,49,50,54],detect:[12,48],determin:[1,8,9,10,19,23,28,31,32,33,35,42,46,50],dev:[22,33,35,36],develop:[1,5,23,32,38,47,48,50,51,52,53,56],deviat:[21,35,37],devic:[8,51,52],devis:22,diagon:28,diagram:[25,27,32],dict1:22,dict2:22,dict:[11,12,17,22,41,44,58],dictat:[12,40],dictionari:[9,10,14,15,17,20,26,43,44,46,49,50,51,54,55],did:[3,8,10,13,19,20,22,35,38,44,53],didn:[29,35,44],diff:32,differ:[2,3,5,6,8,9,10,11,12,14,15,16,20,22,23,24,25,29,31,32,34,43,44,45,47,48,50,51,54,55,56,58],difference_fanout:55,difference_upd:[38,46],differenti:[1,2,43],difficult:[28,50],digit:[8,20,32,37,51,52],dilig:[8,48],dimens:[28,29,30,31,33,34,35,37,51,56],dimension:[6,29,30,32,33,34,43,47,56],ding:51,direct:[32,37,48],directli:[1,2,4,6,8,15,25,31,36,48,49],directori:[1,4,5,47,48,49],discard:8,discern:[12,30,50],discourag:23,discov:40,discret:47,discuss:[2,4,8,9,12,13,14,15,22,25,26,27,28,29,30,31,32,37,39,42,43,44,46,48,49,50,51,52,53,54,56,58],disk:49,dismai:8,dispatch:56,displai:[3,7,8,25,26,35,43,46,59],dispos:8,dist:32,dist_from_origin:35,distanc:[35,50,56],distil:[47,51,52,54],distinct:[7,9,11,14,17,25,26,28,31,34,37,41,42,43,47],distinctli:7,distinguish:[2,7,11,34,43,44,49,54,58],distribut:[3,4,11,33,37,47,48,53],distutil:48,div:37,dive:[4,15,25,46,48,56],divers:[47,50],divid:[8,32,33,35,36,37,46,50],divide_func:48,divis:[8,9,16,32,37,46],divorc:31,dlib:50,doc2:9,doc:[14,35,50],docstr:[14,22,40,50,59],document:[1,2,3,5,45,51,52,54,56,58,59],doe:[3,5,8,9,10,11,12,14,15,20,22,23,25,26,27,28,31,33,37,41,42,44,45,47,48,50,53,54],doesn:[5,11,12,17,22,25,32,44,45,51,52],dog:[3,11,14,18,24,25,36,40,50],doing:[1,3,4,5,6,8,33,34,47,48,53,54,56,59],domain:[5,28,33,36,47],don:[5,8,9,12,19,27,31,45,49,50,51,52],done:[5,29,37,40,48],doom:32,dos:50,dot:[8,32,37,40,47,48],dot_index:9,doubl:[3,8,10,41,46,50],down:[1,20,27,37,48,49,51,52,59],downgrad:48,download:[1,2,4,48],downsid:[11,12,23],downstream:22,dpi:47,draw:[33,43,47,58],drawn:[10,18],dream:32,drill:48,dropbox:50,dropdown:5,dtype:[28,30,33,34,37],duck:50,dude:3,due:[12,37,48],dummi:[40,41,44,48],dummy_inst:41,dump:49,dunder:[41,46],dure:[1,15,35,48,50],dynam:47,dynload:48,e7cf39509d06:12,each:[9,10,11,12,13,14,15,16,17,18,19,20,22,23,25,27,28,29,30,31,32,33,34,35,36,37,40,41,43,47,48,49,50,54,55,56,57],earli:[5,13],earlier:[8,12,15,19,27,35,41,50],easi:[2,4,17,22,37,45,48,49,50,54],easier:[29,35,38,46,50],easiest:48,easili:[2,5,7,14,19,22,32,35,51,52],echo:46,econom:15,ed60a54ccf0b:15,edg:[14,20,21,27],edit:[2,5,50,51,52,53],editor:[1,2,48,50],educ:53,edward:12,effect:[4,8,11,12,16,22,29,32,35,37,40,47,48,50,54,56],effici:[3,6,10,11,12,15,16,17,18,23,31,32,37,50,54,56],effort:5,egg:46,eigenvalu:37,eight:[9,16,20],einstein:11,either:[8,9,11,13,14,22,27,29,32,37,38,40,44,45,49,50],electr:8,electron:47,eleg:[2,6,9,17,28,35,42,46,47,59],elegantli:8,element:[10,11,12,15,18,19,25,26,27,28,29,30,31,32,34,35,37,38,44,45,46,50,54],elementwis:[35,37],elif:[14,16,17,20,22,26,54],elimin:36,elppa:25,els:[14,15,16,17,20,21,22,24,26,35,36,44,45,46,49,50,54],elsewher:[16,26],elucid:48,email:54,emb:[5,47],embark:[16,53],embed:47,embellish:50,embodi:[40,48],embrac:47,emerg:5,emit:23,emmi:[41,49],emphas:[8,20,32,51,52,55,57],emphasi:[50,51,52],empow:58,empti:[0,8,9,11,12,13,14,19,21,22,25,27,29,32,33,41,50],emul:[46,47],enabl:[2,4,5,19,43,46,47,48,49,50,54,56],encapsul:[14,16,24,31,39,41,43,45,50,54,58],enclos:13,encod:[36,49,51,55],encount:[4,8,11,13,15,17,24,25,27,41,43,44,49,50],encourag:[4,50],end:[1,3,4,5,8,9,10,11,13,14,15,16,17,18,19,25,26,28,29,32,34,35,37,40,49,50,51],endear:37,endeavor:54,endl:1,endors:2,endswith:8,enforc:50,engin:[1,8],english:[1,8,20,50],enhanc:[50,59],enjoi:35,enough:[5,8,29,51,52],enrol:11,ensur:[1,4,8,22,25,38,49,50],entail:[1,12,26,40,48],enter:[3,5,7,11,13,14,16,38,49],entertain:35,entir:[3,8,10,15,17,20,24,25,26,31,36,37,46,48,49],entireti:[10,37,55,57],entri:[3,8,10,11,14,17,25,26,27,28,29,31,32,33,34,37,38,41,47,48,50],enumer:[18,19,22,29,32,35,48],env:4,envelop:14,environ:[1,5,46,47,48,51,53],envis:32,eps:47,equal:[5,8,9,11,12,28,30,32,33,37,42],equat:[0,3,5,8,28,32,35,47],equip:54,equival:[8,9,11,13,14,15,19,20,21,22,23,25,27,28,31,32,33,37,41,42,44,46,50],eras:[5,49],err_low:47,err_upp:47,error:[1,2,5,8,9,12,13,14,19,21,25,26,27,36,44,45,47,49,50],errorbar:47,esc:5,especi:[1,2,5,19,20,27,28,30,45,48,50],essenti:[1,5,11,12,13,15,17,18,28,37,42,43,47,48,51,52,53,55,57,58,59],establish:[32,58],estim:[8,51,57],etc:[2,4,22,25,31,35,37,40,50,51,52,58],euclidean:[32,50],euler:[11,41,48],evalu:[0,5,9,12,13,14,17,20,22,33,40,47,50],even:[5,6,7,8,9,10,12,13,14,15,16,17,19,20,24,28,32,34,38,40,41,44,48,49,50,51,52],even_gen:15,evenli:[5,8,33,47],event:[11,49],eventu:[49,50],ever:[3,5,9,13,14,15,17,32],everi:[4,5,13,15,16,22,25,31,35,37,41,49,50],everyth:5,everywher:[36,37],evil:23,evolv:35,exact:[8,15,28,32,41],exactli:[8,11,12,15,16,28,32,37,45],exagger:50,exam:[12,22,26,27,32],exam_1:22,exam_1_scor:18,exam_2:22,exam_2_scor:18,examin:45,exampl:[1,3,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,36,37,39,41,42,43,44,45,46,47,48,50,53,54,59],example_arrai:30,example_default_dict:11,example_dict:12,example_gen:15,example_scop:24,exce:[8,13],exceedingli:[14,50],excel:[2,3,5,11,46,50],except:[8,14,15,26,50],exception:1,excit:5,exclud:[14,15,25,33,46],exclus:[5,15,33,37],exe:[1,3,4],execut:[1,2,3,4,5,6,8,9,13,14,16,20,24,39,40,41,43,44,45,47,48,54],exemplifi:50,exercis:[20,54,55,57,59],exhaust:[8,11,15,28,37,45,46,51,52],exhibit:28,exist:[1,4,8,10,11,12,22,24,26,32,40,42,46,49,50,58],exit:[13,14,19,22],exp:[8,31,37,47],expand:[9,16,43],expect:[1,4,7,10,14,15,35,37,40,44,45,47,48,49,50],expel:20,experi:[2,35,50],experienc:[51,52],experiment:8,explain:[5,8,25,44,48],explan:[10,46,49,55,57],explicit:[1,12,14,23,27,31,32,35,37],explicitli:[9,11,15,18,25,29,32,37,41,44],explor:[3,5,25,49],expon:8,exponenti:37,expos:[8,27,50],express:[0,8,10,12,13,14,19,20,22,23,31,36,37,40,46,50,51,54],expression_1:9,expression_2:9,expression_n:9,extend:[8,9,29,35,47,50,55],extens:[2,8,17,35,37,47,49,50,55],extent:[19,43],extern:44,extra:[19,32,55],extract:[9,11,15],extran:59,extraordinarili:49,extrapol:[20,27],extrem:[12,15,17,22,28,31,35,44,46,49,54],f8487d9d0863:[8,9],face:[44,48],face_detect:48,face_detector:48,facial:48,facilit:[2,10,11,17,28,29,47,48,50,56],fact:[1,5,8,9,12,14,15,26,37,43,46,50,58],factor:[10,45,47],factori:[3,8,14,21],fail:[9,11,26,45,49],failur:19,faithfulli:50,fall:[16,21,27,28,35,47],fallen:35,fals:[0,3,8,9,10,11,12,13,14,15,17,20,23,25,26,28,31,35,36,37,40,41,45,46,49,50],familiar:[1,2,3,4,8,9,10,11,17,20,21,31,34,35,37,45,47,50,53,54],fanci:[14,20],fancier:15,fanout:[51,55],fantast:[6,8,49,53],far:[6,8,17,25,27,29,31,39,41,43,46,47,48,50,54],farmer:8,fashion:[22,27,37],fast:[6,12,18,37],faster:[4,6,10,36,37,48],favor:8,featur:[1,2,3,5,11,15,16,17,33,34,43,47,48,50,51,52,56,59],fed:[3,11,12,15,22,37,47],federici:[51,52],feed:[11,14,15,33,36,37,41],feedback:[51,52],feel:[15,25,35,46,53,54],fell:[12,17,35],fermi:[11,41],few:[3,8,10,14,15,16,18,38,45,46,50,58],fewer:[19,31],feynman:11,fidel:50,field:[8,48],fig:[5,35,47],figsiz:47,figur:59,file12345:49,file1:49,file2:49,file3:49,file4:49,file:[1,2,4,5,9,24,26,45,47,48,51,59],file_var:24,filefilefil:49,filenam:[2,9,47],fill:[29,31,32,33,37,47],fill_between:[35,47],filter:[9,11,15,21,23],filtered_str:23,find:[1,4,5,8,9,10,11,13,15,18,19,22,25,29,31,32,35,36,46,48,49,50,58],find_alpha:50,find_packag:48,fine:[8,33],finish:41,finit:[8,15,25],first:[1,2,3,4,5,8,9,11,12,13,14,15,16,17,19,20,22,23,25,27,29,31,32,35,36,37,41,43,44,45,46,48,49,50,56,58,59],first_item:9,fit:49,five:[8,20,25,33,36,50],fix:50,flag:50,flake8:50,flaw:22,flesh:48,flexibl:[6,12,14,16,26,28,31,40,47,48,50],flip:[22,27],float16:33,float32:33,float64:30,float_kei:12,floor:8,flour:46,flow:[13,17,20,21,51,52,54],fly:50,focu:50,focus:47,folder:[1,5],folli:12,follow:[0,1,3,4,5,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,36,37,39,40,41,44,45,46,47,48,49,50,51,52],food:[12,46],footprint:32,for_block:24,forai:43,forc:49,forego:3,foregon:18,foremost:[1,2,48,50],forese:14,forev:0,forget:49,forgiv:16,form:[3,8,9,11,15,17,18,20,23,25,26,28,31,32,33,37,41,44,46,48,49,50,58],formal:[2,5,8,9,10,13,16,27,28,32,36,40,50,54],format:[1,2,3,5,14,20,26,40,42,43,45,46,47,49,50,51,53],formatt:50,former:[3,9,46,55,57],formul:32,formula:[0,35,48,50],forth:4,fortran:29,fortun:[6,15,19,32,49,50,51,52],forward:[13,28,32,43,59],found:[5,8,9,11,22,27,33,46,47,49,50],foundat:[1,51,52,56],four:[11,16,20,27,33,36,37,40,50],frac:[5,8,14,15,30,32,35,45],frac_correct:36,fraction:[8,21,35,36,47],framework:48,free:[1,2,15,17,22,32,42,48,50,51,52],freeli:[4,31],frequent:[3,8,10,15,50],fresh:53,friend:35,friendli:[44,49],from:[1,2,3,5,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,35,36,37,38,40,41,43,44,45,46,47,48,49,50,51,52,54,56,58,59],fromkei:44,front:20,frozen:[11,12,26],frozenset:[11,12],fruit:12,fruit_or_veggi:12,fulfil:48,full:[3,9,15,27,29,32,37,46,47,48,50],fuller:58,fulli:[2,35,43,58],fun:[19,35,51,52],func:[14,24,44,50],func_a:50,func_b:50,func_block:24,func_c:50,func_d:50,func_nam:50,func_var:24,fundament:[6,8,31,50,56],funni:27,further:[4,6,9,22,27,43,58],furthermor:[5,8,9,10,14,17,25,28,29,31,32,35,41,47,50,51,52],fyi:27,game:[9,37],gather:38,gaug:50,gauss:11,gaussian:[33,47],gcd:45,gen:15,gen_1:[15,18],gen_2:[15,18],gener:[3,5,8,9,11,12,13,14,17,18,19,20,21,23,25,26,27,29,32,33,35,36,37,42,43,46,47,48,49,50,51,53,54,55,56,58,59],genesi:[51,52],genexpr:15,get:[1,2,4,5,6,8,10,11,12,14,19,25,27,28,31,32,36,37,40,41,44,46,48,49,50,51,52],get_area:[42,45],get_first_and_last:50,get_max:12,get_zip:48,getattr:40,getitem:46,getsitepackag:48,gfedcba:25,gheliabci:17,git:2,give:[0,4,6,16,24,25,27,35,36,41,45,46,48,56,59],given:[0,1,2,5,7,8,9,10,11,13,14,15,16,17,18,19,21,22,23,25,27,28,29,31,32,35,36,37,41,42,43,44,47,49,50,54],glad:54,glanc:[17,19,29,32,44,47],glare:32,glimps:3,glob:59,global:22,goal:[43,47],goe:[8,26,50],going:[3,41,45,48],good:[2,5,9,16,17,20,22,25,34,48,49,51,52,55,57,59],good_f:14,goodby:15,googl:[5,46,59],goos:[32,36],goosei:40,got:[51,52],gracefulli:38,grade:[11,12,17,26,27,32,49,50,54],grade_book:50,grade_lookup:50,gradebook:[11,27,50],graduat:[48,51,52],grai:47,grammar:[1,50],grammat:1,grape:[12,22,38,40,46],graph:[15,47],graphic:47,grasp:[25,41],grayscal:47,great:[2,3,5,8,11,12,14,15,17,25,37,50,51,52],greater:[0,8,9,15,22,28],greatest:[22,45],greatli:[17,36,43,44,46,50,54,59],green:[5,32,37,47],grid:[5,32,33,35,37,47],grigg:[51,52],groceri:12,grocery_list:50,gross:[8,16],gross_merge_max_map:22,group:[8,49,50],grow:[5,15,50,54],grumpi:1,guarante:[1,8,9,12,20,35],guess:[22,28,37],gui:14,guid:[47,51,52,53,59],guidelin:[50,59],gush:5,had:[5,8,12,19,20,21,24,32,35,37,48,51,52,56],half:47,hand:[5,8,12,15,29,50],handi:[25,49],handl:[4,5,9,14,20,21,29,38,46,49,50],hang:[37,50],haphazardli:31,happen:[0,5,8,9,13,15,17,24,27,44,45,53],happi:[14,48],happili:50,hard:[8,16,18,20,22,31,50,51,52,56],hardboiled800:[51,52],harmon:15,has:[1,2,4,5,8,9,11,12,13,14,15,16,18,22,23,24,25,27,29,30,31,32,33,34,35,36,37,39,40,41,44,45,46,47,48,49,50,51,52,53,54,56],hasattr:[40,46],hash:[11,12],hashabl:[12,44,50],haskel:5,hasn:12,hat:[3,8,11,25],have:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,24,25,26,27,28,29,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58],header:[5,50],health:9,hear:0,heavi:[2,22],heavili:[1,43],heed:8,height:[42,43,45,47],heisenberg:11,hello:[1,3,8,13,14,15,17,20,25,40,41,43,46,50],hello_world:9,help:[1,2,5,8,9,13,14,15,17,19,22,25,26,32,35,38,41,48,49,50,51,52,56],helper:20,henc:45,her:[9,11,41],here:[1,2,5,6,7,8,10,11,12,13,17,18,20,21,22,23,24,26,27,28,29,31,32,35,36,37,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,59],herein:44,heterogen:[10,12],high:[5,6,27,33,36,37,46,47,50],higher:[8,27,29,32,47,50],highest:[10,36],highli:[2,4,8,9,12,17,37,47,49,56],highlight:[2,3,50],hill:49,him:18,hint:[3,8,25,59],his:[9,41],hist:47,histogram:[47,59],histor:43,historgram:47,histori:35,hit:[0,3,5,35,44,49,50],hline:35,hold:[3,8,11,13,14,50,54],home:[4,48],homogen:[30,37],hood:[10,17,19,38,41,44,45,46,48,49,54],hope:54,hopefulli:[10,16,35,51,52],hopper:11,horizont:[32,33,35,37,50],horrai:36,host:48,hour:6,hous:[48,50],how:[1,3,4,5,8,10,12,14,15,16,21,22,25,26,27,32,35,37,41,43,44,46,47,48,49,50,51,52,54,56,59],howev:[6,8,9,10,12,14,15,17,20,22,25,27,31,33,36,37,38,40,43,45,48,49],hstack:33,html:50,http:50,huge:[1,2,5,6,31,50,51,52],human:[1,50],hundr:[6,15,35,51,52],hyperbol:37,hypothet:[35,36],idea:2,ideal:[12,27,47],ident:[8,9,26,47,48,58],identifi:[13,22,25,27,41,50],idiomat:50,if_block:24,ignor:[11,23,32,38],iii:[32,51,54],ill:25,illustr:28,ilovepython:23,imag:[5,8,32,36,37,49,50,56,59],imagin:35,imaginari:8,imbal:22,immedi:[3,8,11,13,14,17,18,19,20,22,27,32,33,42,48,50],immut:[8,10,11,12,25,54],imort:48,impact:[12,22,32,50,56],implement:[1,10,12,16,17,22,25,32,37,38,43,44,45,46,49,50,56],impolit:3,impos:27,imposs:[14,25],imprecis:8,improv:[1,17,35,43,46,50,51,52,54,59],imread:47,imsav:47,imshow:47,in_arg1:24,in_arg2:24,in_circl:35,in_str:[14,50],inaccess:46,inadmiss:32,inadvert:22,inch:47,includ:[1,3,4,7,8,9,11,12,13,14,15,16,17,22,25,26,27,33,35,37,38,40,41,42,43,47,48,49,50,53,54,55,56,57,59],include_i:[14,50],inclus:[11,15,33,50],incompat:[8,12,32],inconsequenti:17,inconsist:[16,50],incorrect:16,increas:[8,10,16,29],increasingli:[50,59],incred:[6,27,37,45],increment:[3,8,17],ind0:28,ind1:28,ind2:28,ind3:28,ind4:28,ind:28,ind_0:28,ind_1:28,ind_2:28,inde:[5,31,44,50],indel:56,indent:[9,13,14,16,40,49],indentationerror:16,independ:[4,5,9,15,17,22,28,33,35,36,41,59],index:[3,8,9,10,11,12,15,17,19,20,21,29,32,34,35,36,37,43,46,48,50,51,56],index_2d:28,indexerror:[9,25,27],indic:[0,3,7,8,11,14,15,19,28,30,31,32,37,44,47,48,49,50],individu:[3,8,11,25,27,31,34,35,37,41,43,46,48,49],ineffici:32,inequ:[8,22],inevit:[8,31],infer:50,influenc:[51,52],info:8,inform:[1,8,10,14,26,31,37,43,44,47,48,50,51,53],inher:[12,29],inherit:[43,50,51,58],init:[35,39,41,45],initi:[4,11,15,17,19,22,26,27,32,33,39,41,44,45,48,50,54],inject:8,inlin:[15,20,21,22,47,54],inner:[19,33],innermost:19,input:[3,5,7,8,9,10,12,14,15,17,19,20,23,24,26,27,29,31,37,38,40,44,46,47,50],input_str:[23,40],insert:[8,27,29,31],insid:[12,16,24,45,49],insidi:22,insight:[28,48,56,59],inspect:[8,15,25,30,35,40,43,46,49,50,59],inst:44,instal:[2,3,6,51,52,53,59],instanc:[0,1,2,4,5,7,8,9,10,11,12,15,17,18,20,25,26,27,28,29,31,32,37,38,39,40,42,43,46,47,48,49,50,51,58],instanti:[39,41],instead:[2,3,4,5,8,9,10,11,15,19,25,27,29,33,34,35,36,37,38,42,44,47,48,49,50],instruct:[1,4,15,16,25,28,31,32,33,36,37,41,47,48,49,50],instrument:6,instuct:1,int32:[30,33,34],int64:28,int_to_str:20,integ:[1,3,7,9,10,12,13,14,15,18,20,22,25,26,29,30,33,36,37,40,41,45,46,47,50,56],integer_flag:50,integr:[1,45,50,53],intend:[31,50],intens:[47,50],inter:[17,48],interact:[4,41,43,44,46,47,48,58],interchang:[8,27,50],interest:[6,15,32,43,51,52,59],interfac:[2,3,5,8,10,25,27,28,34,47,49,54,56,58],intermedi:[19,31,32],intermediari:29,intern:50,internet:5,interpet:1,interpret:[3,4,5,8,10,17,24,28,32,33,35,47,48,50,53],interrupt:[0,13],intersect:[10,11],interv:[10,16,33,35],intra:59,intro:43,introduc:[9,10,11,13,17,20,32,33,37,40,43,45,47,49,50,51,53,54,56,58,59],introduct:[2,16,34,41,42,48,51,53,54,58],introductori:1,intuit:[1,8,15,17,23,27,28,29,32,37,38,53,56],invalid:[11,14,26],invalu:56,inventori:54,invers:[29,37,47,49],invert:[12,37],inverted_x:12,investig:26,invok:[4,11,14,15,28,31,32,37,39,41,44,45,46,47,49,54],involv:[8,10,12,15,17,29,31,49,54],iostream:1,ipynb:[5,49],ipython:[0,2,3,4,5,7,8,9,12,15,22,26,27,36,47,48],irrat:[35,48],irrespect:[28,42,48],is_bound:14,is_equ:23,is_in:10,is_in_circl:35,is_in_slow:10,is_palindrom:23,isalnum:23,isalpha:11,isclos:[8,28],isdigit:8,isinst:[8,9,20,25,34,38,39,41,42,45,46,50],islow:15,isn:[1,5,6,8,11,14,24,25,50],isort:50,issu:[4,6,8,32,44,51,52,59],issubclass:[42,43],isupp:9,it_var:24,item1:[8,11],item2:[8,10,11],item3:8,item:[3,7,8,9,10,11,12,13,14,15,17,18,20,21,25,26,27,28,29,31,37,38,41,46,47,50],item_to_transcript:20,item_to_transcript_alt:20,itemn:8,items:30,items_to_pric:12,iter:[8,10,11,12,13,14,16,18,19,20,22,23,25,31,32,37,38,40,41,44,46,49,50,51,54,56,58],iter_3:18,iter_4:18,iter_cnt:17,itertool:[17,24,36,41,51,54],ith:10,its:[1,3,4,5,8,9,10,11,12,13,14,15,17,19,20,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,59],itself:[8,12,14,19,29,39,43,44,48,50],jack:8,jackenzi:8,jan:50,jane:8,jargon:8,java:[1,16],javascript:47,job:[10,20],join:[3,8,15,20,23,25,46,47,51,52,56],jpg:47,judici:[9,19,27],julia:[5,56],jupyt:[0,2,4,7,13,16,22,36,46,48,49,51,53,59],just:[5,8,9,10,11,12,15,18,19,20,22,25,32,35,37,38,43,44,45,48,49,50,51,52,53],jython:1,kamasi:41,keen:[4,22,32,36,50,56],keep:[2,8,11,12,15,17,19,20,22,27,31,32,35,38,45,46,50],kei:[3,10,11,14,22,37,44,46,47,54,58],kept:[51,52],kernel:[0,5,13,48],key1:12,key2:12,key3:12,keyboard:[5,46],keyerror:[11,12,22],keyword:[31,33,36,47,49],kid:8,kill:5,kind:15,king:50,kit:[51,52],know:[1,4,5,10,13,14,15,17,19,25,28,33,35,36,37,40,41,43,44,45,48,50,51,52],knowledg:[19,38,48],known:[1,3,8,12,15,17,19,24,25,29,31,36,37,40,43,46,48,49,50,56],kwarg:[14,50],l_2:32,lab:[2,5],label:[5,27,35,36,47],labmat:[5,51,52],labor:50,lack:[25,51,52],ladi:49,laid:[29,37,47],lame:8,land:[4,35],landscap:56,languag:[2,3,4,6,8,10,14,16,24,25,26,29,37,43,50,51,52,53,54,56,58,59],laptop:2,larg:[1,2,5,6,8,15,20,21,32,43,47,48,50],large_int:8,large_num:8,larger:[8,10,22,32,48],largest:[12,17,22,27,32,36],lassi:50,last:[0,3,8,9,12,13,15,23,25,26,27,28,29,31,32,35,40,45,48,50],lastli:[7,8,12,31,37,38,43,47,48,49,50,53],late:49,later:[0,1,3,5,8,14,27,32,37,48,49],latest:[1,4,27,51,52],latex:[5,47],latter:[3,9,20,50],laundri:33,layout:[27,28,32,37,43,47,48],ldot:32,lead:[8,16,17,31,32,33,37,43,48,50,59],lean:[51,52],learn:[0,1,3,6,8,9,10,14,15,29,32,38,41,43,46,47,48,49,50,51,52,53,54,56,59],learning_python:48,least:[8,13,25,27,28,31,50,51,52],leav:[8,9,14,19,22,31,32,40,41,49],left:[9,14,17,23,26,28,29,32,37,45,47],legend:[5,35,47],legibl:50,leisur:27,len:[0,3,8,9,10,12,14,15,18,19,21,22,23,25,36,46,50],length:[3,8,10,15,18,25,27,30,32,33,37,42,46,50],leq:37,less:[1,2,8,9,12,22,25,27,36,37,40,47],lesson:[8,17,22],let:[3,4,5,8,10,12,13,15,16,20,22,24,27,29,32,33,34,35,37,38,39,41,42,43,44,45,46,47,48,49,50],letter:[8,11,13,15,17,25,40,49],level:[4,10,16,37,39,46,47,48,50,58],leverag:[4,8,9,35,36,37,41,42,43,46,47,48,49,50,56,59],lew:[51,52],lexicon:43,lib:[4,48],liber:[24,50],librari:[1,3,4,5,8,27,33,34,37,43,47,48,49,50,51,52,53,56,59],lies:[9,44,51,52],lieu:[38,48,49],lifetim:50,light:[8,32,37,42,44],lightweight:[2,50],like:[1,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,22,23,24,26,27,29,31,32,33,34,35,36,37,40,41,43,44,45,47,48,49,50,53,54,55,57,58,59],likewis:[9,43],limit:[6,8,12,19,37,45,48,49],limitless:19,linalg:35,line:[3,5,7,8,9,14,15,16,20,32,35,36,45,47,49,50,59],linear:[10,47,56],linearli:[10,15,16,47],linestyl:[35,47],link:[35,54,55,56,57,58,59],linspac:[5,47,56],lint:50,linter:50,linux:[1,3,4,49],list1:26,list2:26,list:[4,5,9,11,12,13,14,17,18,20,21,22,23,24,25,26,27,28,29,31,33,34,35,37,40,41,43,44,45,46,47,48,49,53,54,55,58],list_famous_dog:50,list_of_ag:50,list_of_dummi:41,list_of_nam:50,list_of_peopl:41,list_of_stud:50,list_of_temperatur:50,list_purchased_item:38,list_unpurchased_item:38,listofstud:50,liter:8,littl:[45,49],live:[4,23,47,50],load:[47,59],load_databas:48,load_ext:48,loc:47,local:[5,48,50],locat:[4,25,31,43,47,48,49],log10:[8,37],log2:37,log:[8,17,26,31,33,35,37,47],log_:37,logarithm:[8,37,47],logic:[12,16,20,22,26,28,35,36,38,44,54,56],logical_and:28,logical_or:28,long_variable_nam:50,longer:[13,15,22,31,48,50],longev:50,look:[1,2,3,5,8,9,12,14,16,20,25,27,30,31,32,36,37,41,43,44,45,47,48,49,50,53],lookup:[11,12],loop:[0,7,12,14,15,16,17,20,21,22,23,34,35,36,37,40,41,50,51,54,55],loosei:40,lost:[8,27],lot:[14,51,52],love:[23,51,52],low:[36,37],lower:[8,10,11,12,14,15,23,32,35,40,47],lowercas:[3,8,11,15,49,50],luckili:49,luxuri:8,mac:[1,3,4],machin:[1,3,4,5,6,8,10,43,48,49,50,51,52,56,59],machineri:15,maco:49,mad:9,made:[1,8,18,20,22,31,32,35,45,48,50,51,52],magic:[6,22,47,48],magnitud:47,mai:[1,2,7,8,9,10,14,15,17,19,20,22,23,26,27,28,29,31,32,37,40,44,45,46,49,50],mail:48,main:[1,38],maintain:[1,4,12,48,50],major:[4,5,6,8,16,18,25,28,32,33,34,36,37,49,50,51,52,56],make:[3,4,5,6,8,9,11,12,14,15,16,17,19,20,22,23,25,27,28,29,31,32,34,35,36,37,38,41,43,44,45,46,47,48,49,50,51,52,54,55,57],manag:[4,12,19,44,49,50,59],mangl:23,mani:[1,2,3,4,5,6,8,10,11,14,15,16,18,19,25,27,29,31,33,35,37,47,48,49,50,51,52,54,56,59],manifest:[3,29,54],manifestli:[8,27],manipul:[3,41,43,47,54,56,58],manner:50,manual:[4,15,17,22,49],manufactur:21,map:[1,10,11,14,20,22,37,44,50],march:50,margin:[51,55],mari:49,mark:[1,3,5,8,38,46,47,50,56],mark_purchased_item:[38,46],marker:47,mascharka:[51,52],mass:32,massiv:[2,5,32,37,47,49],master:41,match:[14,22,27,28,32,36,37,47,49,50],materi:[12,15,31,37,48,50,51,52,55,57,59],math:[3,5,14,37,48],mathcal:[10,11,12],mathemat:[3,5,6,8,9,10,31,32,33,34,50,56,58],matlab:[37,56],matmul:32,matplotib:47,matplotlib:[4,5,35,51,53,56,59],matric:[37,47],matrix:[6,15,32,37,47],matter:[3,5,8,12,14,20,25,27,29,32,44,54],matur:[5,43,50,59],max:[12,14,17,22,32,36,37],max_kei:12,max_key_optim:12,max_num:50,max_or_min:14,max_red_quad:37,max_val:[12,32],maximum:[12,22,37],mean:[3,4,5,8,9,10,12,13,14,15,17,19,22,23,24,25,26,27,31,32,33,34,35,36,37,39,42,43,45,46,48,49,50,53,54,55,56,57,58,59],mean_exam_scor:32,mean_i:32,mean_imag:37,mean_in_circl:35,mean_x:32,meaning:24,meaningfulli:10,meant:[7,8,9,13,14,15,20,25,26,44,46,50,55,57],measur:[8,51,57],meaur:47,mechan:[8,11,19,25,26,31,32,41,50,56,58],median:[37,50],melon:46,member:[8,10,11,13,14,15,17,19,25,48,50],membership:[9,10,11,12,15,25,46,50,54],memor:[10,37],memori:[1,8,12,14,15,17,18,23,25,26,30,31,32,41,44,50,54],mention:48,menu:[3,5],mere:[3,7,10,20,22,32,40,41,43,47,48,50],merg:[20,46,50,51,55],merge_max_map:22,mess:[48,53],messag:[44,45],messi:9,met:[16,20,28,54],method:[0,8,10,15,17,20,28,29,30,31,32,33,34,38,39,40,42,43,45,47,48,49,50,51,58],methodolog:29,metric:21,microsecond:37,microsoft:[1,2,48],middl:[3,11,47],might:[3,17,22,27,32,45,48,50],milk:[12,38,46],mill:1,min:[14,17,19,37],min_blu:37,mind:[8,11,19,22,26,31,32,35,50],mine:[55,57],miniconda3:48,minimalist:47,minimum:[37,48],minor:[44,55],minut:4,mirror:[10,12,15],mis:[46,49],misapprehens:50,mislead:15,miss:[11,14,32,51,52],misspel:2,mistak:[1,2,22,31,50,51,52],mistakenli:[14,38,50],mix:[2,3,7,14,25,37],mkdir:49,mkl:[6,37,48],mobil:[51,52],mod:[8,37],mode:[5,14,26,48,50],model:[24,32,48,51,57],modern:[16,43,47,53,58],modif:49,modifi:[2,8,41,44,48,49,50],modul:[2,3,4,9,12,14,15,16,17,18,26,27,34,37,41,42,43,45,49,51],modular:[16,54],module5_oddsandend:[48,49],module_nam:48,modulo:[8,37],moment:[1,4,16,38],momentarili:41,monitor:[32,37],montalcini:11,month:5,moo:[3,8,10,11,12,14,18,25,44],more:[1,2,3,4,5,6,8,9,10,11,13,14,15,16,17,20,21,22,23,25,27,28,29,31,32,33,35,36,37,38,39,40,41,43,46,47,48,49,50,51,52,53,54,56,58,59],moreov:[36,51,52],most:[1,5,8,9,11,12,15,16,17,24,26,27,32,45,46,47,48,49,50,53,56],most_common:11,motiv:[4,10,49],move:[13,19,32,41,43,59],movi:8,much:[0,1,2,3,5,8,12,16,22,32,33,35,36,45,46,49,51,52,54,58],muli:9,multi:[8,27,33,34,49,50],multidimension:[27,29,30,33,37],multipl:[3,5,8,12,18,19,20,25,31,32,34,37,38,43,46,47,48,49,51,54,56],multipli:[32,34,35,37,46],must:[3,8,9,10,11,12,13,14,15,16,22,23,25,26,27,28,29,31,32,36,37,41,44,48,49,50],mutabl:[8,10,11,12,22,25,54],mutat:[10,11,22,25,26],mxnet:43,my_arch:49,my_archive_fil:49,my_arrai:49,my_cod:1,my_cub:48,my_dequ:11,my_dict:12,my_dir:48,my_fil:[9,49],my_fold:49,my_func:[7,16,24],my_imag:47,my_list:[3,9,10,14,17,24,38],my_loaded_grad:49,my_modul:48,my_open_fil:49,my_script:1,my_squar:[42,45],my_text:1,mygrad:[43,56],mygui:40,mylist:46,mypi:50,n_circl:35,n_total:35,naiv:44,name:[2,3,4,5,8,9,12,17,18,22,24,25,27,37,38,40,41,44,45,46,48,49,54,58],name_to_scor:12,namedtupl:11,nameerror:[8,13,24],namespac:[5,24],nano:1,nanosecond:10,napolean:50,narrow:50,nativ:[4,5,37,47,50],natur:[3,8,19,25,27,32,37,49,59],navig:[4,5,48,50],ncircl:35,ncol:47,ndarrai:[25,28,30,31,32,33,34,36,50,58],ndenumer:29,ndim:[30,43],nearest:25,nearli:[13,25,37,47,54],necessari:[9,10,16,17,28,32,48,49,50],necessarili:[12,15,32,47],necromanc:4,need:[1,2,4,5,8,10,14,15,17,18,19,20,22,27,29,32,34,35,36,41,42,44,47,48,49,50,51,52,54],neg:[0,3,8,9,20,23,25,28,31,37],neg_index:25,negat:[8,9,50],neighbor:19,neither:14,nest:[9,10,19,32,33,48],nestl:9,network:43,neural:43,never:[0,5,8,9,10,11,13,14,22,29,37,50],new_dict:44,new_fold:49,new_kei:12,new_list:46,new_subarrai:31,new_valu:[12,44],newaxi:[28,56],newfound:[3,9,54],newlin:8,next:[3,5,8,12,13,19,23,29,31,33,36,38,41,42,43,44,46,48,49,50,53,54,56,58,59],ngrid:47,nice:[2,3,5,8,10,11,12,14,20,25,31,35,47,48,50],nicer:2,niceti:[17,54],nick:12,niel:41,nimbl:[4,5],nine:20,njit:6,nlog:10,noether:[11,41],noisi:35,non:[6,8,11,15,17,19,23,27,32,37,45,48,50,54],none:[9,10,11,14,17,20,22,24,25,31,32,41,44,46,48,54],none_indic:17,nonetheless:59,nonetyp:8,nonsens:46,nontrivi:28,nonzero:[9,13],nor:[9,11,14,22,24,47],norm:35,normal:[11,12,23,32,33,37],normed_imag:32,notat:[10,28,31,37],note:[0,1,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,27,29,31,32,35,37,41,44,45,46,47,48,49,50,58],notebook:[0,2,4,7,13,16,22,35,36,46,48,49,51,53,59],notepad:1,noth:[1,2,8,15,24,44,49],notic:[5,20,23,37,38,45,50],notifi:8,notimpl:45,novic:31,now:[0,1,2,3,4,6,7,8,9,10,11,12,14,15,17,19,22,25,26,27,30,31,32,35,37,41,42,45,46,47,48,49,51,52,54],npy:49,npz:49,nrow:47,nthi:49,nuanc:[10,27,31,44,54],num:[9,13,14,16,17,45],num_correct:36,num_health:9,num_in_circl:35,num_loop:13,num_thrown:35,num_vowel:14,numba_result:6,number:[0,1,2,4,5,6,9,10,11,12,13,15,16,17,19,25,26,27,28,29,30,31,32,33,34,35,36,37,41,43,44,45,46,47,48,49,50,53,54,55,56],number_of_arg:14,numer:[1,5,9,14,26,27,32,34,35,37,43,46,51,52,56],numpi:[1,4,5,9,25,26,27,28,29,30,32,34,35,36,43,47,48,51,52,53,57,58,59],numpy_result:6,numpydoc:50,nwai:49,nwhat:3,obei:[1,8],obj1:12,obj2:12,obj:[10,11,12,25,40],object:[3,10,11,12,13,15,17,19,20,22,25,28,30,33,34,37,39,42,44,48,50,51,54,56,59],obscur:[8,19,33,50],observ:[37,45],obtain:[6,20,46],obviou:[8,44,46],obvious:49,occas:49,occur:[3,4,8,25,44,45,47],occurr:[10,25,28],odd:[8,13,15,16,49,51],odd_numb:50,off:[3,5,11,13,32,42,50,54],office_suppli:46,offici:[1,54,56,58,59],offload:6,offset:32,often:[2,8,16,27,32,33,41,45],ok_func:14,okai:[5,9,16,32],old:[5,8],omit:[14,25],onc:[1,3,4,5,8,9,12,13,14,15,17,22,24,25,26,28,32,35,38,39,40,41,47,49,50],one:[0,1,2,3,5,6,8,9,11,12,14,15,16,17,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,38,41,42,43,44,46,47,48,49,50,51,52,56,58,59],ones:[8,56],onion:12,onli:[2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,24,25,27,28,29,30,31,32,33,36,37,38,41,42,43,44,46,47,48,49,50,54,59],onlin:47,onto:1,oop:45,opaqu:[47,50],open:[1,2,3,4,5,8,26,47,48,50,59],opencv:56,opened_fil:[26,49],oper:[1,4,5,6,10,12,15,19,21,22,26,27,29,32,34,35,36,41,43,44,49,50,51,54,56,58],operand:[32,37,45],opportun:[35,54],oppos:59,opt_merge_max_map:22,optim:[1,4,6,10,11,12,14,23,36,48,51,55,56],option:[4,5,8,14,15,29,31,43,44,48],orang:[3,18,47],orchestr:20,order:[5,8,9,10,11,14,15,16,17,18,22,23,25,26,27,28,31,32,35,36,37,38,48,50,51,52,56],ordereddict:12,org:[1,48],organ:[3,35,48,50],orient:[5,8,17,41,42,47,51,59],origin:[8,17,21,22,26,27,29,31,35],other:[0,1,2,3,4,6,8,10,11,12,14,15,16,17,19,20,22,24,25,26,28,29,31,33,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,56],otherwis:[8,9,11,13,19,32,33,35,46,50,56],ought:[9,12,37,38,42,45],ould:3,our:[1,2,3,5,8,9,10,11,12,14,15,17,19,20,22,23,24,25,26,27,28,30,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,58,59],ourselv:[3,34,44,48,54,58],out0:49,out1:49,out2:49,out:[0,1,2,3,5,8,9,11,12,13,15,17,20,21,23,26,27,28,29,32,35,36,37,38,44,46,47,48,49,50,51,52,56],outcom:[8,37,50],outer:[19,25],outermost:19,output:[0,3,5,7,14,15,19,22,27,28,29,37,47,49],outright:[12,13,15,48],outsid:[13,16,19,21,24,35,40,48],over:[1,4,8,10,11,12,13,14,16,17,18,19,20,21,22,32,34,35,36,37,41,45,46,47,49,50,51,54,56],overal:[22,32],overli:[10,50],overload:46,overlook:32,overrid:[14,24,49],overridden:[14,24],oversight:[19,50],overst:[18,50,56],overview:[7,8,16,34,37,39,43,48],overwhelm:[2,51,52],overwrit:[31,42,49],overwritten:37,overwrot:42,own:[4,6,8,10,14,16,17,26,29,38,40,41,42,43,45,46,49,50,54,59],pack:[12,14,22,31,50],packag:[1,3,4,6,34,47,51,59],package_nam:48,pad:8,page:[4,5,8,9,13,14,15,25,26,50,51,52],pai:[48,50,54],painstakingli:37,pair:[11,12,14,17,18,19,21,32,37,41,47,50],pairwis:[37,50,56],pairwise_dist:[32,50],pairwise_dists_crud:32,pairwise_dists_loop:32,palindrom:[51,55],paltri:15,pan:47,panda:[43,51,52,56],paradigm:[5,13,37,54],paramet:[12,14,15,19,20,21,22,23,32,35,36,38,43,44,45,46,50],parameterless:50,paramount:[50,54],parent:[28,31,42,45],parenthes:[8,14,15,25,50],parenthesi:[14,50],parenthet:15,pars:[1,50],part:[1,3,4,8,19,20,21,22,24,26,43,48,49,50,51,54,56],parti:[4,49,50,53,56],particip:1,particular:[4,11,22,28,36,40,41,43,44,50,54],particularli:[6,17,28,51,52,54],pass:[1,12,13,14,15,16,19,21,22,24,26,27,31,33,36,39,41,42,43,44,45,46,49,50],past:[5,13,46],path:[4,27,48,59],path_to_data1:49,path_to_fil:49,pathet:35,pathlib:59,pattern:[9,17,20,34,47,48,49,50],pdf:[9,47],peach:38,pear:[18,22],peculiar:[20,41,46],peek:[16,34,43],pen:46,pencil:46,peopl:[1,4,14,43,50,51,52,59],pep8:59,pep:50,per:[22,36,47],percentag:[51,55],perceptu:47,perfect:[4,5,8,11],perfectli:8,perform:[1,3,4,5,6,8,9,10,13,15,17,19,22,23,27,28,29,32,34,35,36,37,45,47,48,50],perhap:[8,9,35,47,50],period:[3,8,9,47],permiss:28,permit:[5,8,9,10,17,19,20,25,26,27,28,29,31,32,40,42,43,47,48,49,50,54,58,59],persist:[3,7,12,13],person:[41,51,52],pertin:50,perus:[8,11],pessimist:10,pet:23,petar:[51,52],petarmhg:[51,52],phase:2,phone:3,phrase:[37,40],phrase_of_the_dai:48,physic:[27,51,52],pick:[3,32,50,51,52],pickl:59,pictur:[36,48],pie:[15,47],piec:[3,13,16,25,36,45,51,52,55,57],pillow:14,pineappl:38,pip:[4,59],pixel:[32,37,47],pixel_std_dev:37,pizza:[12,40],pizzashop:40,pkl:49,place:[1,4,8,12,14,20,25,27,32,37,38,40,46,48,50,51,52,56],placehold:[8,26,32,37],plai:[19,20,32,51,53,57],plain:[1,7],plan:50,platform:[4,59],player:47,pleas:[3,8,9,11,33,37,48,49,51,52],pleasantli:37,plenti:3,plot:[5,35,56,59],plotli:47,plt:[5,35,47],plu:49,plug:43,plymi:[35,49,50,55,57],png:[47,49],point:[3,4,5,9,12,15,16,19,20,22,23,26,27,28,29,32,33,35,36,37,46,47,49,50,51,52,59],point_to_region:12,pointer:26,polish:2,pop:[8,10,25],popul:[22,28,33,41,46,47,49],popular:[1,2,4,5,15,43,48,50,53,56,59],portabl:[38,49],portion:[5,9,37],pos_index:25,pose:25,posit:[0,3,8,9,10,11,13,17,19,25,27,28,32,35,37,43,44,48,50],posixpath:49,poss:30,possess:[8,10,31,32,37,39,40,43,47,48,58],possibl:[8,13,17,19,21,26,27,28,32,38,40,49,50],post:[51,52],poster:12,potenti:[19,23,29,50],potpourri:47,power:[2,4,5,6,8,9,19,25,28,31,34,35,37,42,45,46,47,48,49,50,53,54,56,59],practic:[1,5,8,9,13,14,15,25,26,28,36,37,43,49,51,52,55,57,59],pre:[1,10,37],prece:46,preced:[1,8,9,11,12,17,20,24,25,28,29,30,31,32,33,37,46,50],preceed:25,precis:[1,27,31,37],pred_label:36,predict:[0,26,28,36],prefer:[9,15,20,22,38,50],prefix:3,prematur:[13,23],premier:[5,34,51,52],prepar:[32,47,48],prepend:4,prescrib:[34,37,56],prescript:20,presenc:3,present:[5,12,22,33,46,47,48,49,51,52,53,55,56,57,59],preserv:29,press:[5,32,49],pressur:50,presum:49,presumpt:22,pretti:45,prev_num:17,prevent:[15,50],previou:[4,8,14,19,22,27,32,35,47],previous:[13,50],price:12,primari:50,print:[0,1,3,7,8,9,12,13,14,15,16,17,24,26,35,41,45,46,48,49],print_kwarg:14,printabl:[43,46],prior:[5,12,19,50],priorit:[4,47],pro:2,probabl:[18,35,50],problem:[4,10,19,20,21,23,32,36,37,51,52],problemat:[9,12,31,50],proce:[5,15,19,25,29,32,40,42,44,47,48,49,54],proceed:[8,27,43],process:[1,2,3,4,9,11,13,26,29,32,34,35,36,37,41,44,46,48,49,50,51,52,53,54,56],produc:[8,9,11,12,13,15,17,21,22,23,24,25,26,27,28,29,32,33,35,36,37,39,41,44,46,47,48,49,50,56],product:[8,19,30,32,37,41],profession:2,program:[5,6,8,16,17,41,42,51,52,53,54],programm:[6,8],programmat:[8,30],progress:48,project:[4,36,48,50,51,52,59],prolif:50,promin:[5,59],promis:[22,50],prompt:[46,49],prone:[36,49],pronounc:[27,41],proper:14,properli:[5,22,49],properti:[42,43,44],propos:50,protocol:[49,50,58],prototyp:[1,2,4,5],proud:35,provid:[1,2,3,4,5,6,7,8,10,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,35,37,38,41,42,43,45,46,47,48,49,50,51,52,54,56],prudent:50,pseudo:[9,15],pts:32,publish:[47,50],punctuat:[11,15],purchas:[38,46],purchased_item:46,pure:[6,7,23,37,43],purpl:[40,47],purpos:[7,8,14,19,32,41,45,48,50],put:[3,8,9,13,14,15,16,25,26,37,43],py27:4,pycharm:[2,50,53],pyformat:8,pypi:48,pyplot:[5,35,59],python36:48,python3:48,python:[2,5,7,9,10,11,12,13,14,15,17,19,20,23,24,25,26,27,29,31,34,37,38,39,40,41,42,43,44,45,46,47,55,56,57,58,59],pythonlikeyoumeanit:50,pytorch:[43,48,51,52],quadrant:37,quadrat:[0,3,10],qualiti:[5,47,50],queri:15,question:[3,5,8,25,50,51,52],quick:[3,39,47,51,53],quickli:[2,4,11,12,27,50],quintessenti:16,quirk:[8,49],quit:[1,6,8,9,12,15,16,17,24,25,27,50,51,52],quot:[3,8,49],quotat:[1,3,8],quotient:8,racecar:23,radian:[5,47,48],radiu:35,rais:[1,8,9,11,12,13,14,15,16,19,21,22,24,25,26,34,40,44,49,50],raiton:45,ram:32,ramp:47,ran:5,rand:[32,33,35,36,37,47],randint:36,randn:[33,47],random:[11,32,35,36,37,47,56],randomli:[10,18,33,35],rang:[6,7,11,12,14,16,18,21,22,23,25,28,33,36,40,41,47,48,49],rank:56,rapidli:[1,5,34],rare:[1,50],rat:45,rather:[1,3,8,10,15,20,22,26,28,31,35,37,41,44,46,47,48],ratio:35,ration:[8,45],rationa:45,rbg:[32,37],reach:[9,13,14,19,29,35,46],read:[1,4,5,6,21,22,23,33,51,52,54,55,56,57,58,59],readabl:[1,9,11,15,17,22,23,46,50],reader:[8,11,23,32,46,51,52,53,54,55,57,59],readi:[48,53],readili:[15,54],readlin:49,real:[8,11,27,32,37,48],realiz:35,realli:[5,16,22,32,33,44,45,50],reason:[12,14,15,20,22,27,31,43,47,54,56],recal:[3,5,8,9,10,12,14,15,16,17,19,20,22,23,27,28,29,30,31,33,35,36,37,40,41,44,45,46,48,49,50],recast:32,receiv:[22,33,38,44],recent:[5,8,9,12,15,26,27,45],recogn:[27,32,42],recognit:48,recoil:32,recommend:[4,8,11,12,17,18,35,38,46,47,49,50],recomput:5,record:[17,21],recreat:12,rect1:43,rect:45,rectangl:[41,42,43,45],red:[5,32,37,40,47],redefin:[5,15,46],redraw:5,reduc:[38,40],redund:[11,20,28,38,44,50],redundantli:32,refactor:[21,32,44],refer:[2,3,5,8,9,11,12,13,14,19,22,24,25,26,27,28,29,31,33,34,35,37,40,41,42,43,45,46,48,49,50,54],referenc:[5,7,10,11,31,41,50,54],refin:47,reflect:[22,26,31,32,48,50],refresh:37,regard:22,regardless:[12,29,32,50],region:[12,28,35,40,47],regrett:32,regular:[4,28,48],regularli:[48,50],reimplement:12,reiniti:31,reinstal:48,reiter:[22,49],rel:[1,3,8,10,14,16,20,22,25,32,33,37,44,49,51,52,59],relat:[4,11,48,49,51,52,53,56,59],relationship:[8,25,31,41,42,45],relative_po:32,releas:2,relev:[37,55,57],reli:[1,7,8,12,37,43,50,54],reliabl:[2,8,35],relic:[8,43],reload:48,remain:[9,17,31,48],remaind:[8,16,37],remaining_item:46,remedi:31,rememb:[8,22,29,41],remind:[8,49],remov:[4,8,10,11,19,26,37,38],renam:5,render:[5,8,46,47,48,50],repeat:[11,13,20,25,27,28,33,37],repeatedli:[3,13,14,28,54],repertoir:54,replac:[3,8,10,17,26,27,28,31,37,46],replic:[15,32],report:5,repr:[45,46],repres:[6,8,9,10,12,14,21,24,26,30,31,32,37,41,46,47,48],represent:[8,20,43,49,58],reproduc:[1,47,50],repurpos:26,request:[13,15,38],requir:[2,4,5,6,8,9,12,15,21,23,25,27,28,29,31,32,37,46,48,50,51,52],rerun:35,research:[1,5,51,52,53,56],resembl:32,reserv:[8,14,15,25,26,32,43,44,46,47,50,58],reset:29,reshap:[28,29,31,32,33,34,37],resid:[27,41,47,48],resolut:[32,47],resolv:[9,24,27,28,41,45,54],resourc:[2,8,15,46,47,50,51,52],respect:[5,8,9,13,14,17,20,24,27,28,29,32,33,35,37,40,44,47,49,59],respons:[20,38,47,50],rest:[7,17],restart:[5,13,48],restore_default:48,restrict:[6,8,9,24,37,48,50],result:[1,3,5,6,7,8,11,12,15,20,22,26,27,28,29,31,32,33,35,36,37,40,41,45,47,48,49,50,58],resum:49,retain:[8,22],retriev:[10,11,15,25,27,47,50],reus:54,reveal:[5,14,47],reveres:25,revers:[9,23,25,26,27,31,41],review:[5,8,16,25,27,31,50,59],revisit:[5,13,42,49,50],revolutionari:53,revolv:34,rewit:44,rewrit:[0,19,22,32,44,50],rewritten:[8,14,31],rgb:[32,37,47],rgba:47,rich:[46,50],richer:50,rid:28,right:[3,5,9,12,19,22,23,26,28,29,32,37,43,45,47,54],rightarrow:[8,9,11,12,19,20,25,28,32],rigor:[32,46,50,51,52],rival:37,road:[51,52,59],roadblock:6,roar:0,robot:3,robust:5,roll:[19,49],root:[0,3,4,32,35,37,49],root_dir:49,roster:11,rotate_imag:50,rotateimag:50,roughli:[12,36],round:[12,20,32],rout:5,routin:[27,29,32,37,48],row:[8,15,25,27,28,30,31,32,33,35,36,37,47,50,56],row_i:32,row_x:32,rsokl:[51,52],rubi:5,rudimentari:50,rug:48,rule:[1,8,12,15,16,24,27,28,29,31,37,41,47,50,56],run:[0,1,2,4,10,12,13,15,22,34,35,36,48,49,50,53],rundown:[10,11,12,25,31,39,49],running_estim:35,runtim:50,ryan:[8,11,12,14,48,50,51,52],safe:[32,49],safeti:21,sai:[5,6,8,10,15,26,27,37,45,50],said:[2,4,8,9,13,20,24,27,29,31,32,35,40,41,42,43,48,50,51,52],sake:[1,12,16,23,32,37,46,50],salient:[17,41,50],salt:46,sam:[51,52],same:[1,2,5,6,8,9,10,12,15,16,19,20,22,23,24,25,26,27,28,29,31,32,35,37,40,41,43,45,47,48,50,54,58],sampl:56,sane:4,sash:3,satisfactori:20,satisfi:[8,28,31,32,48],save:[1,5,15,50,59],savefig:47,savez:49,saw:[5,8,15,25,31,41,50],scalar:[27,37],scale:[10,33,35,47,48,50],scatter:[47,59],scenario:[9,10,21,32,45],scene:[6,15,31,32],schema:27,scheme:[11,12,25,27,31,49,56],school:[51,52],sci:[51,52],scienc:[4,5,29,47,51,52,54,56],scientif:6,scientist:[1,53],scikit:56,scipi:4,scope:[8,12,22,40,41,50,51,54],score:[12,22,26,27,32,36,54],score_offset:32,scores_per_stud:32,scratch:[8,33,42,44,51,52],scratchwork:3,screen:[1,3],script:[2,3,4,8,17,24,48,53],search:[4,49,50,51,52,59],second:[5,6,8,10,15,17,20,22,25,27,29,36,44,47,49,50,59],secretli:6,section:[1,2,4,5,7,8,9,10,13,14,15,16,17,25,27,28,29,31,32,33,37,38,40,41,42,45,46,47,48,49,50,55,57,59],see:[3,4,5,7,8,9,11,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,31,32,33,34,35,37,38,40,41,42,43,44,45,46,47,48,49,50,58],seem:[15,17,29,32,40,44],seen:[8,15,16,24,25,31,37,47,48,50,58],segment:[14,35,47],sel:27,seldom:[33,41],select:[5,27,28,30],self:[27,38,39,41,42,43,45,46,50],selina:8,semant:17,semi:[35,47],semicolon:47,send:[1,5],send_mail:48,sens:[8,15,34,38,44,51,52],sensibl:[25,29,44,46],sensit:23,sentenc:[3,8,11],separ:[3,5,8,10,14,15,16,17,20,22,25,26,47,49,50],seq1:25,seq2:25,seq3:25,seq:[10,14,23,25],sequenc:[3,9,10,12,13,14,15,16,17,18,19,20,23,26,27,28,29,34,35,37,41,43,49,50,51,54,56,58],sequenti:[3,8,11,17,25,32,36,54,56],seri:[14,15,36],serial:49,seriou:[6,8],serv:[7,16,26,41,48,49,50,51,52],server:53,servic:4,session:[3,4,48],set:[1,5,8,9,10,12,14,15,17,18,22,26,27,28,36,37,38,40,41,43,44,46,47,48,49,51,53,54,58],set_1:11,set_2:11,set_titl:[5,47],set_xlabel:[5,35,47],set_xscal:35,set_ylabel:[35,47],set_yscal:47,setattr:[40,46],setup:48,setuptool:48,seven:[8,20],sever:[3,5,6,8,14,16,18,25,33,35,38,41,45,48,49,50],shade:[35,47],shadow:[50,54],shallow:22,shameless:43,shampoo:50,shape:[27,28,29,30,31,32,33,35,36,37,43,46,47,50,56],share:[5,16,24,25,31,41,48],shares_memori:[28,31],sheet:[27,28,29,30,32,37,47],shell:[0,2,47],shift:5,shine:[9,10,12,32,37],shirt:46,shmangela:50,shmonathan:50,shock:8,shockingli:40,shop:[40,46,58],shoppinglist:[38,46,50],short_gen:15,shortcut:[5,8],shorten:14,shorthand:[25,26,27,31,34],shortli:[47,50],should:[3,4,5,7,8,9,10,12,13,14,15,16,17,19,20,22,23,25,26,28,31,32,33,34,35,36,37,38,40,41,42,44,45,46,47,48,49,50,51,52],shouldn:38,show:[5,11,16,26,27,32,34,45,47],showcas:18,shown:[22,50],shrewdli:32,side:[3,4,9,42,45,47],sidewai:47,sigh:14,sight:32,sign:[9,20],signal:[13,14,15,16,31,42],signatur:[14,22,44,46,50],signifi:[10,14,16,49],signific:[8,31,44,51,52],significantli:[4,6,28],silent:[1,12],silli:[46,50],sillyclass:46,similar:[1,5,14,15,22,25,27,32,33,37,40,41,44,47,50],similarli:[8,9,22,24,25,27,28,29,32,37,40,44,46,49],simpl:[1,2,3,4,5,8,9,12,14,15,16,17,20,25,26,27,29,35,36,37,38,39,40,43,45,46,48,49,50,55,56],simple_arrai:27,simple_merge_max_map:22,simpler:[0,36,47],simplest:[9,23,28,50],simpli:[1,2,3,4,5,8,10,12,14,15,16,19,21,22,25,26,27,29,31,32,34,35,36,37,40,44,45,46,47,48,49,50,51,52],simplic:[1,35,50],simplifi:[8,15,17,19,36],simul:35,simultan:[14,19,28,37],sin:[5,37,47],sinc:[5,8,12,15,16,19,20,25,27,36,37,40,43,45,48,49],sine:[33,47],sine_wav:47,sinewave_plt:47,sing:47,singl:[3,5,8,9,11,12,14,15,16,18,20,22,23,25,27,28,31,32,33,35,36,37,38,41,42,47,48,49,50,54],singular:[40,41],site:[51,52],situat:24,six:[9,20,37,51,52],size:[10,12,15,22,25,27,30,31,33,35,36,37,42,47,56],skill:58,skip:[9,13,15,35],sky:8,sleek:[15,17,28,46,47],slice:[3,8,9,10,11,19,23,26,28,34,37,46,50],slick:[20,35],slightli:[15,41,47,49],slot:29,slow:[6,32,37],slower:6,small:[3,5,6,8,22],smaller:[22,47],smallest:[17,27],snake:40,snake_cas:50,sneak:[16,34,43],snippet:[3,5,34,50,51,52],sock:46,softwar:[1,2,48],soil:49,soklaski:[48,50,51,52],sole:[8,10,14,15,38,41,44],solid:[47,51,52,56],solut:[0,4,51,52,54,55,56,57,58,59],solv:[4,19,21,37,44],solver:48,some:[2,3,4,5,7,8,10,11,12,17,18,19,20,26,27,29,35,36,37,38,39,41,45,47,48,49,50,51,52,53,54,56,58,59],some_dict:14,some_iterable_of_str:20,some_list:[14,48],some_long_function_nam:50,some_text:49,some_util_func:48,someon:[38,51,52,59],someth:[5,9,14,16,22,33,36,44,50],sometim:[20,49,50],somewhat:[19,27,28,46],soon:[9,15,40,43,50],sophist:[1,2,4,31,46,58],sort:[2,8,9,10,11,17,25,38,41,45,49,50,51,52],sound:[51,52],sourc:[1,2,8,25,48,50],space:[5,8,11,12,16,27,33,40,47,49],space_time_coord:11,span:14,sparingli:[14,15,20,50],speak:40,spec:50,special:[1,3,8,9,15,17,19,20,22,29,32,34,38,39,41,42,43,44,45,48,49,50,51,58],specif:[1,4,8,10,12,15,21,25,27,28,31,32,36,37,39,40,41,43,44,47,48,49,50,53,59],specifi:[1,3,4,8,9,11,12,15,16,18,25,27,28,29,32,35,36,39,40,41,42,44,47,48,50,54,56],speed:6,speedup:[10,22,37],spell:[1,20,26],spend:[7,50],spent:38,sphinx:50,split:[8,11,15,33,47],spot:[51,52],spreadsheet:[32,43],spuriou:32,sqrt:[3,8,32,35,37,47],squar:[0,3,8,9,10,12,15,25,31,32,34,35,37,42,45,46,47,48,49],stack:[27,29,32,33,36,50,54],stagnat:[51,52],stand:[5,8,41,50,56],standalon:[27,50],standard:[1,3,4,8,11,12,14,16,33,35,37,47,48,49,50,56],stapl:46,star:[8,12,34],stark:[22,37,50],starkli:58,start:[3,4,5,8,12,13,15,16,18,25,26,27,29,31,32,33,34,35,43,45,49,51,52],startswith:[8,49],stat:50,stat_func:50,stat_funct:50,state:[8,14,15,22,26,31,46,48],statement:[13,15,16,17,20,21,22,24,40,50,51,54,59],static_func:44,staticmethod:44,statist:[17,33,35,37,50],statment:[13,14],statu:[9,26],std:[1,22,33,35,36,37],std_in_circl:35,stdin:45,stem:[43,51,52,53,54,56],step:[10,13,15,23,25,27,29,32,33,37,50,53],stew:8,stick:[6,10,50],still:[2,5,8,13,14,26,28,31,32,38,40,41,44,45,48,50,54],stomp:22,stop:[15,19,25,27,33,51,52],stopiter:[13,15],store:[3,4,6,8,9,11,14,17,18,19,22,25,26,27,30,31,32,34,35,36,37,38,41,43,46,47,48,49,50,54,56],str:[8,9,14,15,20,23,25,38,40,41,43,44,45,46,49,50,58],strage:45,straight:[14,28,32],straightforward:[22,27,32,37],strang:44,stream:47,strength:47,stretch:47,strict:[1,50],strictli:[9,48,49,50],strike:46,string:[2,5,9,11,12,13,14,15,17,19,22,23,25,26,27,37,38,40,41,43,44,45,48,49,50,51,53,54,55,58],string_of_num:15,stringent:6,strip:[8,47],strive:[35,49,50],strongli:[16,18,35,46,49,50],struck:54,structur:[27,30,32,33,48,49,51,54],struggl:[5,50],student:[11,12,17,22,26,27,32,50,53,54,55,57],student_grad:26,student_list:50,studi:[11,16,32,35,37,43,50,53,54,58,59],studio:[2,50,53],stuff:32,style:[5,7,16,40,47,48,51,52,59],stylist:[20,22],styliz:5,sub:[25,27,34,48],subarrai:31,subclass:42,subdirectori:[5,48,49],subject:28,sublist:50,submit:[50,55,57],submodul:47,subpackag:48,subplot:[5,35,59],subscript:15,subsect:[5,9,15,25,26,28,31,32,50],subsequ:[8,10,13,14,15,16,20,22,24,25,26,27,28,34,37,49,58],subset:[6,11,49],substanti:[32,35,37,48,51,52],subtl:[20,22],subtract:[19,32,35,37,45,46],succe:46,success:[19,50],successfulli:32,succinct:[22,36,50],succinctli:31,suffic:[13,44],suffici:[8,10,16,37,50,51,52],suffix:[1,2,5,48,49],suggest:[9,50],suit:[1,11,20,28,32,37,47,50],sum:[1,6,8,13,14,15,17,19,21,32,35,36,37,43,44,50],sum_:[15,32],sum_func:[6,48],summar:[7,8,10,25,32,43,48,49],summari:[10,12,16,38,47,50,51,53,54,58],summed_row:32,superior:[21,46],superset:11,suppli:[25,28,31,33,37,49],support:[1,2,5,8,9,11,12,25,26,27,47,48,50],suppos:[8,9,10,11,14,17,19,22,26,27,28,29,32,36,37,38,41,42,48,49,50],suppress:47,suprem:[8,15,17],sure:[9,14,32,34,45,50],surfac:[8,33,42],surpris:[15,27,31,37,40,50],surround:[5,50],survei:[10,24,37,44,53],susan:11,swap:[4,27],sweep:48,swept:48,symbol:[7,8,11,14,26,46,48],symmetr:11,symmetric_differ:11,synonym:[41,43],syntact:[16,17],syntax:[1,2,5,6,8,9,11,12,13,14,15,16,17,19,20,21,22,25,26,27,31,38,40,41,48,49,50,53,58],syntaxerror:14,sys:[0,48],system:[4,25,26,31,43,48,49,50,59],tab:[3,5,8,16,50],tabl:[27,29,37],tabular:56,tac:25,tackl:19,tag:44,tailor:[6,32],take:[0,1,4,6,7,8,10,11,12,14,15,16,17,18,19,20,22,25,27,28,29,31,32,34,35,36,37,38,40,44,45,46,47,48,49,50,51,52,53,54,58],takeawai:[2,4,9,10,11,12,15,17,22,24,25,27,28,31,32,37,40,43,48,49,50,54],taken:[12,20,27,32,49,50,51,52],talent:50,talk:[3,7],talli:[3,11,13,21,35,36,37],tan:37,target:[10,47,48],task:[1,8,20,25,28,37,54],taylor:14,teach:[49,51,52],team:2,technic:[16,48,50,59],techniqu:[12,28,56],technolog:47,tediou:[27,29,44,49,50],tell:[1,5,14,49,50,51,52],temperatur:50,templat:9,temporarili:32,ten:[10,35,37,41],tend:43,tensor:[37,43],tensorflow:[43,48,51,52],term:[3,8,10,16,17,19,22,25,32,37,43,47,48,49,50,51,56,58],termin:[0,1,2,3,4,5,48],terminolog:[15,41,58],terrancewasabi:[48,49],terribl:[10,51,52],terrif:5,ters:28,tertiari:50,test:[1,2,5,9,10,11,12,14,21,22,25,36,41,49,50],test_0:49,test_1:49,test_appl:49,text:[1,2,3,5,7,8,9,11,13,14,15,25,26,46,48,50,51,52,54,59],text_1:11,text_2:11,textbook:8,textedit:1,than:[0,1,2,4,6,8,9,10,11,12,13,14,15,19,20,21,22,25,28,29,31,32,35,36,37,41,44,46,47,48,49,50,54],thefollow:47,thei:[1,4,5,6,8,10,12,13,15,16,17,18,20,22,24,25,26,27,29,30,31,32,37,41,43,44,45,47,48,49,50,51,52,55,56,57],them:[2,3,4,5,8,11,15,18,19,20,22,26,29,32,35,37,38,43,44,45,46,47,48,49,50,54],themselv:50,theoret:11,theori:50,therefor:[30,32,37],therein:[9,51,52],thi:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,53,54,55,56,57,58,59],thing1:48,thing2:48,thing:[3,8,14,15,27,37,43,45,49,50,58],thingth:50,think:[1,16,25,27,37,45,50,51,52],third:[5,15,26,32,49,50,56],thorough:[28,37],those:[4,8,11,14,15,21,24,25,26,28,31,35,37,42,48,50,51,52,56],though:[32,41,50],thought:[3,22,50],thousand:[6,8,10,35],three:[3,8,9,14,17,18,20,25,27,28,31,32,33,34,36,37,41,44,46,47,49],threshold:28,through:[4,5,15,17,22,27,31,32,45,46,47,48,49,50,53,55,57,58],throughout:[1,2,6,7,8,9,13,14,15,25,26,34,50,51,52],thrown:35,thu:[1,2,4,5,6,8,9,10,11,12,13,14,15,17,18,19,20,22,23,25,26,27,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,56],thusli:8,tick:[47,50],tightli:35,time:[3,4,5,6,7,8,10,11,13,15,17,18,22,23,25,28,29,31,32,34,35,36,37,38,41,45,47,49,50,53,58],timeit:[22,36],times10:8,tinker:[2,5],tip:[20,36,55,57],titl:47,tmp:41,togeth:[3,8,12,15,18,20,22,32,36,44,45,54,56],token:11,toler:8,too:[8,12,14,15,20,23,27,37,50],took:48,tool:[1,2,3,5,6,8,11,12,15,16,17,18,29,37,47,50,51,52,53,54,56,59],toolkit:54,toothpast:50,top:[0,1,5,11,13,37,43,47,48,50],topic:[28,37,42,48,56],topmost:[22,36,48],total:[3,10,13,14,15,19,20,21,27,30,32,35,36,37],total_even:14,touch:[8,31,50],tough:12,tour:[48,58],tover:8,toward:[5,8,37,50],town:47,toyplot:47,trace:50,traceback:[8,9,12,15,26,27,45],track:[2,8,11,12,15,17,27,38,45,46,48,50],trade:54,tradit:[2,8,37,54],tradition:[1,8,37],trail:[3,8,25,27,31,32,49,50],train:43,trait:50,transcript:20,transit:[29,46],translat:[1,6,15],transpar:[35,47],transpir:[26,32],transpos:[27,32],travers:[25,28,36,37,50,51,56],treacher:31,treat:[3,8,27,28,32,37,40,43,44,48,49,50],treatment:[8,28,29,46,47,48,51,52,54],tree:11,tremend:[1,5,6,34,37,56],tri:[22,36,45],trial:[8,35],triangl:47,triangular:47,trick:[20,54],trigger:[14,31],trigonometr:[8,37],trillion:8,tripl:[8,49],triplet:29,triu:47,trivial:[28,32,35,41,44],troubl:50,troubleshoot:59,true_label:36,truli:[10,31],truth:[36,54],tupl:[8,9,12,13,14,17,18,22,26,27,28,30,33,37,38,41,43,47,54,58],tuple_of_dummi:41,turn:[31,47],tutori:[2,4,8,11,12,15,38,40,42,43,47,48,49],twelv:32,twice:[10,12,17,20,38],twitter:[51,52],two:[0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,18,19,20,25,26,28,29,31,32,33,34,35,37,38,40,41,43,44,45,46,47,48,50,51,53,55,56,59],txt:[1,26,49],type:[1,2,3,5,9,10,11,12,13,15,17,20,22,24,28,30,31,34,37,38,39,40,41,42,44,45,46,47,48,49,51,54,56,58,59],typeerror:[12,14,15,25,26,44,45],typic:[2,7,8,11,14,28,37,47],typo:2,u0336:46,ubiquit:25,uint8:47,ultim:[8,20,27,49,50,58],umbrella:14,unabl:[37,45],unachiev:56,unaffect:[26,31],unambigu:[1,9,37],unanticip:22,unchang:[22,27,31,35,44],uncommon:[4,54],uncompromis:50,undefin:[2,40],under:[10,17,19,38,41,44,45,46,48,50,54],undergo:32,underli:[9,27,28,34,56],underneath:49,underscor:[8,26,40,41,46,50],underst:13,understand:[1,3,7,9,10,15,16,17,20,22,25,26,27,28,29,30,31,32,41,43,44,47,48,50,51,52,54,55,57],understat:54,understood:[7,8,14,58],undo:29,unequ:[32,33],unevalu:9,unexpect:44,unfortun:[45,51,52],unhash:12,unicod:[8,26,46,49],unifi:43,uniform:[16,30,33,47],uninstal:[4,48],union:[10,11,38],uniqu:[11,12,25,27,28,29,38,46,47],univers:[1,8],unknown:27,unless:[12,31,33,48],unlik:[11,12,25,28,37],unnecessari:[27,50],unnecessarili:[15,32],unord:[10,11,12],unpack:[14,22,28,47],unpattern:28,unpickl:49,unpopul:22,unpurchas:[38,46],unrecogn:45,unrestrict:37,unruli:50,unsign:47,unsorted_index:17,unsuccessfulli:45,unsupport:45,until:[0,12,13,15,16,24,29,45],untitl:5,unus:50,unusu:48,unvector:57,unvectorized_accuraci:36,unwieldi:27,unwittingli:[22,31],updat:[3,4,7,8,9,10,11,12,22,26,28,31,34,35,38,41,46,48,49,50,56],upgrad:48,upload:48,upon:[15,17,39],upper:[8,14,35,47],uppercas:9,upward:47,usag:[11,15,17,32],use:[0,1,2,3,4,5,6,8,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,56],use_gpu:50,used:[1,2,3,5,6,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,31,32,33,34,37,39,40,41,43,44,45,46,47,48,49,50,54],useful:[1,2,3,4,5,8,10,11,12,14,15,16,17,18,27,28,31,32,35,36,37,38,45,46,47,48,49,50,54],usefulness:27,useless:9,user:[2,3,4,7,8,11,12,14,25,27,31,33,37,43,44,47,48,49,50,51,52,54,55,56,57,58,59],uses:[4,8,10,11,16,20,25,27,29,32,35,37,47,50],using:[0,1,2,4,5,6,8,9,10,11,12,14,17,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,37,40,41,42,43,46,47,48,49,50,51,52,54,55,56,59],usr:48,utf:[8,49],util:[1,2,3,4,8,9,10,11,13,14,16,17,18,26,28,29,31,34,37,38,42,43,44,46,47,48,49,59],val:14,valid:[1,3,9,12,13,14,15,23,25,27,29,31,37,44,47,50,54],valu:[0,1,3,5,8,10,11,13,15,17,18,19,20,21,22,24,25,26,27,28,31,32,33,34,35,36,37,40,41,43,44,46,47,54],valuabl:[11,17,18,22,24,27,29,51,52],value1:12,value2:12,value3:12,valueerror:[25,27,32],vanilla:[4,6,11,48],var_nam:14,vari:[27,31,33],variabl:[0,1,2,3,4,5,7,8,9,13,14,17,22,25,31,37,38,39,40,41,43,48,49,50,51,54],varianc:[33,37],variant:4,variat:48,varieti:[8,12,25,28,33,37,41,44,46,47,50],variou:[3,5,9,10,11,12,16,24,27,28,31,37,40,43,46,47,48,50,54,58],vast:49,vastli:16,vector:[1,32,34,50,51,56,57],veget:12,veggi:12,vein:[37,48],venu:48,verbos:[12,50],veri:[2,4,5,6,8,9,12,14,15,16,20,22,25,27,32,33,34,35,37,41,44,47,50],verifi:[8,15,32,37,41,42,44,47,49],versa:[3,22,50],versatil:[12,47,56],version:[2,4,6,8,9,10,11,12,20,24,32,43,44,48,50,51,52],versu:[26,31,35,47],vert:37,vertic:[32,33,37,47,50],via:[0,4,7,8,9,11,12,13,15,20,22,25,27,31,32,35,37,39,42,47,48,49,50,56],vice:[3,22,50],video:[5,9,56],view:[12,27,28,32,38,50,51,52,56],violat:[1,50],viridi:47,visibl:24,visit:[14,20,29,51,52],visual:[2,5,8,35,47,50,53,59],vogu:8,vowel:[13,14,49,50],vscode:[2,50],vstack:33,vulner:49,wai:[0,1,3,4,5,8,9,11,12,14,15,16,20,25,27,28,29,31,32,33,35,37,38,40,43,44,45,46,47,48,49,50,56,59],walk:[45,50,51,52],want:[1,2,3,5,8,9,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,32,33,35,36,37,38,40,41,42,44,48,49,50,51,52],warn:[0,1,8,13,14,25,33,50,54],warrant:[8,25,29],wasi:47,wasn:[14,50],wast:32,watch:[8,49],wave:47,wayn:8,weak:47,wealth:10,web:[5,47],websit:[5,51,52],weirdo:8,well:[1,2,5,8,12,14,17,19,22,23,25,31,32,33,37,46,47,48,50,53,56],were:[3,5,8,9,12,16,20,31,37,38,44,48,49,50,51,52,55,57],weren:38,what:[3,5,7,8,9,11,14,15,16,17,18,20,21,22,24,25,26,27,28,29,30,31,32,33,34,37,41,44,45,48,49,53,54,56,59],whatev:[4,5,10,11,22,47,50],when:[1,3,5,6,8,9,10,11,12,13,14,15,16,17,21,22,24,25,26,27,28,29,31,32,33,37,38,41,44,45,46,47,48,49,50,53,54],whenev:[4,8,11,15,17,28,29,31,37,39,40,44,46,49],where:[1,6,8,9,10,13,14,15,16,17,21,22,23,25,27,28,29,31,32,35,38,40,41,43,45,46,47,48,49,50,53],wherea:[3,5,8,9,10,11,14,15,23,24,25,26,28,32,33,44,46,48,50],whereas:9,wherein:39,wherev:[7,8,15,28,36,48],whether:[1,12,21,23,26,32,35,36,45,56],which:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,53,54,55,56,57,58,59],while_block:24,white:16,whitespac:[8,9,13,14,23,50,54],who:[3,4,15,21,32,50,51,52,59],whole:[1,8,15,34,37,48,54],wholesal:48,whom:[32,50],whose:[8,10,11,12,15,25,26,28,35,36,42,43,44,46,47,48,49,50],why:[0,3,6,8,9,15,20,25,26,27,29,31,32,34,44,46,48,50,53,56],wide:[2,8,12,33,37,44,47,48,49,50],wider:48,width:[42,43,45,47],wildcard:49,wildli:10,win:1,window:[1,3,4,5,47,49],windowspath:49,wisdom:50,wise:[32,37],withhold:27,within:[3,5,7,8,9,10,13,14,15,16,19,22,24,25,27,28,29,31,32,33,35,36,37,40,42,43,44,47,48,49,50,51,54,55,59],within_margin_percentag:21,without:[0,4,5,7,8,9,13,14,15,16,19,22,28,31,32,34,35,47,48,49,50,54,56],won:[45,50],wonder:[3,8,46],wont:46,woof:40,word:[1,2,8,11,14,15,20,43,48],word_collect:15,word_distr:11,words_with_o:15,work:[2,3,4,5,8,10,12,14,15,23,24,26,27,28,31,32,34,36,37,38,42,44,45,46,47,48,50,51,52,53,54,55,56,57,58,59],workflow:50,world:[1,8,32,41,43,46,48],worldwid:48,worri:[4,8,11,12,19,29,37,41,49],worst:[10,12],worth:50,worthwhil:[6,26,43,47,50],would:[3,5,6,8,9,10,11,12,13,14,17,18,19,20,21,22,24,25,29,31,32,35,36,37,40,44,45,46,47,48,49,50,51,52,55,57],wow:25,wrap:[3,50],write:[1,2,3,5,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,25,26,29,32,34,35,36,38,41,42,43,45,48,51,52,53,54,56,59],writelin:49,written:[1,3,4,5,6,8,9,10,15,16,22,37,45,48,49,50,51,52,55,57],wrong:[1,9,12,14,22],wrote:[10,22,42,45,46],www:50,x_0:32,x_1:32,x_1d:32,x_i:37,x_it:15,x_left:47,x_norm:32,x_right:47,x_sqrd_sum:32,x_val:18,x_y_prod:32,x_y_sqrd:32,xarrai:[27,56],xmax:35,xmin:35,y_0:32,y_1:32,y_gen:18,y_sqrd_sum:32,year:[5,8,51,52],yerr:47,yes:50,yet:[1,8,10,22,25,41],yield:[12,15,18,26,36,49,50],you:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47,48,49,50,53,54,55,56,57,59],your:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,16,17,19,20,21,22,25,26,27,31,35,36,38,40,41,43,45,46,47,49,50,53,54,59],your_usernam:4,yourself:[1,2,4,6,8,22,28,35,47,49,50,53],zero:[8,9,14,15,20,25,45,47,50,56],zerodivisionerror:[8,9,21],zeros_lik:32,zip:[12,18,22,36,48],zoe:12,zone:[51,52],zoom:47,zordon:8},titles:["Exercises","Introducing the Python Programming Language","Setting Up a Development Environment","An Informal Introduction to Python","Installing Python","Jupyter Notebooks","Doing Numerical Work in Python","A Quick Guide to Formatting","Basic Object Types","Conditional Statements","Data Structures (Part I): Introduction","Data Structures (Part III): Sets & the Collections Module","Data Structures (Part II): Dictionaries","For-Loops and While-Loops","Basics of Functions","Generators & Comprehension Expressions","Introducing Control Flow","Iterables","Python\u2019s \u201cItertools\u201d","Difference Fanout","Encode as String","Within Margin Percentage","Merging Two Dictionaries","Is Palindrome","Scope","Sequence Types","Variables & Assignment","Accessing Data Along Multiple Dimensions in an Array","Advanced Indexing","Iterating Over Arrays & Array-Traversal Order","Basic Array Attributes","Introducing Basic and Advanced Indexing","Array Broadcasting","Functions for Creating NumPy Arrays","Introducing the ND-array","Playing Darts and Estimating Pi","Measuring the Accuracy of a Classification Model","\u201cVectorized\u201d Operations: Optimized Computations on NumPy Arrays","Applications of Object Oriented Programming","A Brief Summary of Terms and Concepts","Defining a New Class of Object","Instances of a Class","Inheritance","Introduction to Object Oriented Programming","Methods","Object Oriented Programming","Special Methods","Matplotlib","Import: Modules and Packages","Working with Files","Writing Good Code","Python Like You Mean It","Python Like You Mean It","Module 1: Getting Started with Python","Module 2: The Essentials of Python","Module 2: Problems","Module 3: The Essentials of NumPy","Module 3: Problems","Module 4: Object Oriented Programming","Module 5: Odds and Ends"],titleterms:{"boolean":[8,9,28],"break":13,"class":[40,41,43,44,46],"default":[11,14],"float":8,"function":[12,14,17,27,33,37],"import":[43,48],"new":40,"return":14,"short":9,"static":44,"while":13,Adding:12,Are:12,Axes:[32,47],Being:50,Doing:[0,6],For:[13,32,50],IDEs:2,One:[22,27],The:[8,11,14,15,32,40,44,47,50,54,56],Uses:16,Using:[5,15,31,32,33,37,50],Will:2,__init__:41,about:[51,52],absolut:[48,50],access:27,accommod:14,accuraci:36,act:17,add:45,advanc:[28,31,32],algebra:37,algorithm:10,along:27,anaconda:4,ani:50,applic:[32,38],arang:33,arbitrari:[14,22],arg:50,argument:[14,37,44],arithmet:0,arrai:[27,28,29,30,31,32,33,34,37,49],assign:[8,26,28,31],attribut:[30,40,41],augment:[8,28,31],axi:37,basic:[8,12,14,28,30,31,37],benefit:31,beyond:47,binari:37,bool:9,bound:25,brief:[4,39],broadcast:32,buggi:22,callabl:50,can:[8,12],cell:5,chain:15,challeng:22,check:0,circuit:9,classif:36,claus:13,code:50,collect:11,column:29,combin:28,comparison:9,complex:[8,10,12],comprehens:[8,9,11,12,13,14,15,17,18,19,25,26,27,28,31,32,37,40,41,44,45,47,48,49,50],comput:[4,37],concept:39,conclus:37,conda:[4,48],condit:9,constant:33,construct:[0,12],consum:15,contain:46,continu:13,contributor:[51,52],control:16,convent:50,correct:22,counter:11,creat:[5,11,15,33,41,46,47],dabbl:3,dart:35,data:[0,10,11,12,27,31,33],def:14,defin:[40,41,45],definit:40,delimit:16,dequ:11,describ:10,develop:2,dict:50,dictionari:[11,12,22],did:4,differ:19,difference_fanout:19,dimens:[27,32],dimension:[27,28,31,37],displai:47,distanc:32,document:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50],doe:1,easi:[51,52],elif:9,ellipsi:31,els:[9,13],encod:20,end:[6,59],enumer:17,environ:[2,4],essenti:[8,54,56],estim:35,exampl:[5,49],exercis:[0,8,9,13,14,15,17,25,26,47,48],express:[9,15],extend:22,extens:19,extra:22,familiar:5,fanout:19,fewer:27,figur:47,file:49,flow:16,fly:15,form:40,format:[7,8],from:33,gener:[15,22,40],get:53,github:[51,52],given:12,glob:49,good:50,googl:50,grade:0,guid:[7,50],handl:[22,25],hint:50,how:29,ident:41,iii:11,imag:47,immut:26,improv:8,indent:50,index:[25,27,28,31],indic:[25,27,51],inform:3,inherit:[42,45],inlin:[9,14],input:22,insert:32,inspect:12,instal:[1,4,48],instanc:[41,44],integ:[8,27,28,31],integr:2,interfac:46,interpret:1,intra:48,introduc:[1,8,15,16,25,27,31,34],introduct:[3,4,10,43],isn:[51,52],iter:[15,17,29],itertool:18,join:33,jupyt:[5,47],just:4,kei:[12,50],keyword:[14,37],languag:[1,5],learn:2,level:41,like:[46,51,52],linear:37,link:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50],linspac:33,list:[0,3,8,10,15,19,38,50],load:49,logic:[8,9,37],loop:[13,19,32],major:29,manag:48,manipul:27,map:12,margin:21,markdown:5,math:8,mathemat:[37,46],matplotlib:47,mean:[1,51,52],measur:36,merg:22,mess:3,method:[41,44,46],minor:22,mode:49,model:36,modul:[8,11,48,50,53,54,55,56,57,58,59],more:12,multi:37,multipl:[14,26,27],mutabl:26,mutat:8,name:[11,14,26,50],neg:27,nest:15,newaxi:[31,32],next:15,non:9,none:[8,50],notat:8,note:43,notebook:[5,47],noth:50,numba:6,number:[3,8,14,22],numer:[6,8,12],numpi:[6,31,33,37,49,50,56],object:[8,9,14,26,31,32,38,40,41,43,45,46,47,49,58],odd:59,offici:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50],ones:33,open:49,oper:[0,8,9,11,31,37,45,46],optim:[22,32,37],option:50,order:[12,29],orient:[38,43,45,58],other:5,out:[25,31],output:50,over:[15,29],overload:45,own:[15,48],packag:48,pairwis:32,palindrom:23,part:[10,11,12],path:49,pathlib:49,pep8:50,percentag:21,perform:31,pickl:49,pip:48,pitfal:13,place:[28,31],plai:[3,35],plot:47,plymi:[51,52],point:8,posit:14,potenti:13,precis:[8,12],problem:[22,35,55,57],produc:31,program:[1,38,43,45,58],pyplot:47,python:[0,1,3,4,6,8,16,18,33,48,49,50,51,52,53,54],pythonpath:48,quack:50,quick:7,radd:45,random:33,rang:15,read:[8,9,11,12,13,14,15,17,18,25,26,27,28,31,32,35,37,40,41,44,45,47,48,49,50],readabl:8,recommend:2,referenc:26,rel:48,relev:35,remark:6,represent:46,reshap:27,retriev:12,risk:31,row:29,rule:32,run:5,sampl:33,save:[47,49],scheme:28,scientif:8,scope:[16,24],script:1,self:44,sequenc:[8,25,33],sequenti:[10,33,37],server:5,set:[2,11,50],shadow:24,shop:38,shouldn:[51,52],simpl:[0,22,32],site:48,size:32,slice:[0,25,27,31],solut:[8,9,11,12,13,14,15,17,18,19,20,21,22,23,25,26,27,28,31,32,35,36,37,40,41,44,45,47,48,49,50],space:50,special:46,specifi:[14,31,33,37,49],start:53,statement:[8,9,14,48],store:[12,15],string:[0,3,8,20,46],structur:[10,11,12],style:50,subplot:47,summari:[1,6,8,39,42],suppli:27,tabl:51,term:39,terminolog:43,text:49,textbook:[51,52],than:27,thi:[4,51,52],time:12,tip:[23,35],togeth:33,too:[51,52],travers:29,trick:17,truth:9,tupl:[10,11,15,25,31,50],two:[22,27],type:[0,8,25,26,33,43,50],unari:37,underli:31,understand:[8,37],union:50,unoptim:32,unpack:17,unvector:[35,36],using:[15,19],util:32,valid:26,valu:[9,12,14,50],variabl:[24,26],variou:0,vector:[35,36,37],version:0,via:28,view:31,warn:12,what:[1,2,4,12,50,51,52],whitespac:16,why:1,within:21,word:12,work:[6,17,25,40,49],write:[49,50],you:[2,51,52],your:[15,48],yourself:5,zero:[22,27,33]}}) \ No newline at end of file +Search.setIndex({docnames:["Module1_GettingStartedWithPython/Exercises/Informal_Intro_Python","Module1_GettingStartedWithPython/GettingStartedWithPython","Module1_GettingStartedWithPython/Getting_Started_With_IDEs_and_Notebooks","Module1_GettingStartedWithPython/Informal_Intro_Python","Module1_GettingStartedWithPython/Installing_Python","Module1_GettingStartedWithPython/Jupyter_Notebooks","Module1_GettingStartedWithPython/Numerical_Work_In_Python","Module1_GettingStartedWithPython/SiteFormatting","Module2_EssentialsOfPython/Basic_Objects","Module2_EssentialsOfPython/ConditionalStatements","Module2_EssentialsOfPython/DataStructures","Module2_EssentialsOfPython/DataStructures_III_Sets_and_More","Module2_EssentialsOfPython/DataStructures_II_Dictionaries","Module2_EssentialsOfPython/ForLoops","Module2_EssentialsOfPython/Functions","Module2_EssentialsOfPython/Generators_and_Comprehensions","Module2_EssentialsOfPython/Introduction","Module2_EssentialsOfPython/Iterables","Module2_EssentialsOfPython/Itertools","Module2_EssentialsOfPython/Problems/DifferenceFanout","Module2_EssentialsOfPython/Problems/EncodeAsString","Module2_EssentialsOfPython/Problems/MarginPercentage","Module2_EssentialsOfPython/Problems/MergeMaxDicts","Module2_EssentialsOfPython/Problems/Palindrome","Module2_EssentialsOfPython/Scope","Module2_EssentialsOfPython/SequenceTypes","Module2_EssentialsOfPython/Variables_and_Assignment","Module3_IntroducingNumpy/AccessingDataAlongMultipleDimensions","Module3_IntroducingNumpy/AdvancedIndexing","Module3_IntroducingNumpy/ArrayTraversal","Module3_IntroducingNumpy/BasicArrayAttributes","Module3_IntroducingNumpy/BasicIndexing","Module3_IntroducingNumpy/Broadcasting","Module3_IntroducingNumpy/FunctionsForCreatingNumpyArrays","Module3_IntroducingNumpy/IntroducingTheNDarray","Module3_IntroducingNumpy/Problems/Approximating_pi","Module3_IntroducingNumpy/Problems/ComputeAccuracy","Module3_IntroducingNumpy/VectorizedOperations","Module4_OOP/Applications_of_OOP","Module4_OOP/Brief_Review","Module4_OOP/ClassDefinition","Module4_OOP/ClassInstances","Module4_OOP/Inheritance","Module4_OOP/Introduction_to_OOP","Module4_OOP/Methods","Module4_OOP/ObjectOrientedProgramming","Module4_OOP/Special_Methods","Module5_OddsAndEnds/Matplotlib","Module5_OddsAndEnds/Modules_and_Packages","Module5_OddsAndEnds/WorkingWithFiles","Module5_OddsAndEnds/Writing_Good_Code","Module6_Testing/Intro_to_Testing","Module6_Testing/Pytest","changes","index","intro","module_1","module_2","module_2_problems","module_3","module_3_problems","module_4","module_5","module_6"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,nbsphinx:1,sphinx:55},filenames:["Module1_GettingStartedWithPython\\Exercises\\Informal_Intro_Python.ipynb","Module1_GettingStartedWithPython\\GettingStartedWithPython.md","Module1_GettingStartedWithPython\\Getting_Started_With_IDEs_and_Notebooks.md","Module1_GettingStartedWithPython\\Informal_Intro_Python.md","Module1_GettingStartedWithPython\\Installing_Python.md","Module1_GettingStartedWithPython\\Jupyter_Notebooks.md","Module1_GettingStartedWithPython\\Numerical_Work_In_Python.md","Module1_GettingStartedWithPython\\SiteFormatting.md","Module2_EssentialsOfPython\\Basic_Objects.md","Module2_EssentialsOfPython\\ConditionalStatements.md","Module2_EssentialsOfPython\\DataStructures.md","Module2_EssentialsOfPython\\DataStructures_III_Sets_and_More.md","Module2_EssentialsOfPython\\DataStructures_II_Dictionaries.md","Module2_EssentialsOfPython\\ForLoops.md","Module2_EssentialsOfPython\\Functions.md","Module2_EssentialsOfPython\\Generators_and_Comprehensions.md","Module2_EssentialsOfPython\\Introduction.md","Module2_EssentialsOfPython\\Iterables.md","Module2_EssentialsOfPython\\Itertools.md","Module2_EssentialsOfPython\\Problems\\DifferenceFanout.md","Module2_EssentialsOfPython\\Problems\\EncodeAsString.md","Module2_EssentialsOfPython\\Problems\\MarginPercentage.md","Module2_EssentialsOfPython\\Problems\\MergeMaxDicts.md","Module2_EssentialsOfPython\\Problems\\Palindrome.md","Module2_EssentialsOfPython\\Scope.md","Module2_EssentialsOfPython\\SequenceTypes.md","Module2_EssentialsOfPython\\Variables_and_Assignment.md","Module3_IntroducingNumpy\\AccessingDataAlongMultipleDimensions.md","Module3_IntroducingNumpy\\AdvancedIndexing.md","Module3_IntroducingNumpy\\ArrayTraversal.md","Module3_IntroducingNumpy\\BasicArrayAttributes.md","Module3_IntroducingNumpy\\BasicIndexing.md","Module3_IntroducingNumpy\\Broadcasting.md","Module3_IntroducingNumpy\\FunctionsForCreatingNumpyArrays.md","Module3_IntroducingNumpy\\IntroducingTheNDarray.md","Module3_IntroducingNumpy\\Problems\\Approximating_pi.ipynb","Module3_IntroducingNumpy\\Problems\\ComputeAccuracy.md","Module3_IntroducingNumpy\\VectorizedOperations.md","Module4_OOP\\Applications_of_OOP.md","Module4_OOP\\Brief_Review.md","Module4_OOP\\ClassDefinition.md","Module4_OOP\\ClassInstances.md","Module4_OOP\\Inheritance.md","Module4_OOP\\Introduction_to_OOP.md","Module4_OOP\\Methods.md","Module4_OOP\\ObjectOrientedProgramming.md","Module4_OOP\\Special_Methods.md","Module5_OddsAndEnds\\Matplotlib.ipynb","Module5_OddsAndEnds\\Modules_and_Packages.md","Module5_OddsAndEnds\\WorkingWithFiles.md","Module5_OddsAndEnds\\Writing_Good_Code.md","Module6_Testing\\Intro_to_Testing.md","Module6_Testing\\Pytest.md","changes.rst","index.rst","intro.rst","module_1.rst","module_2.rst","module_2_problems.rst","module_3.rst","module_3_problems.rst","module_4.rst","module_5.rst","module_6.rst"],objects:{},objnames:{},objtypes:{},terms:{"**kwarg":14,"*arg":14,"04s":52,"07s":52,"0th":[8,29],"0x00000146ce118620":49,"0x000001b91b913708":52,"0x000001e768fe8a40":15,"0x000002a32898c6a8":14,"0x1d50de887b8":41,"0x1d50de896d8":41,"0x1d50de897b8":41,"0x1d50de89940":41,"0x1d50de899e8":41,"0x1d50de89a20":41,"0x1d50de89a58":41,"0x1d50de89a90":41,"0x1d50de89ac8":41,"0x1d50de89b00":41,"0x1d50de89b38":41,"0x20de1082608":18,"0x20de109ec18":18,"0x20de10a7728":18,"0x23e3557b3f0":18,"0x284f0008da0":44,"0x2ae8f65fcf8":41,"0x2ae8f666f60":41,"0x2ae8f68f2e8":41,"10000j":8,"10_000j":8,"10x10":47,"111111111111111e":8,"15x25":47,"16j":48,"1_000_000":8,"1e12":8,"1e3":8,"1e34":50,"1e9":8,"1st":[25,37],"1x10":8,"1x4":36,"207d18d18af2":27,"2246467991473532e":48,"2_3_4":8,"2cool":26,"2e10":8,"2eba8294859":51,"2f755f117ac9":27,"2mb":32,"2nd":12,"2x2":27,"2x3":[37,47],"2x3x4":33,"32301ff829e9":51,"32x32":[32,37],"3471672109ee":9,"38e":8,"3rd":[4,37,49,50,56],"3x4":[15,33],"48x48":32,"4th":31,"50x75x3":47,"51c17da13eaa":[],"551115123125783e":8,"5_6_7":8,"662_607_004":8,"6gb":32,"74c002a67890":12,"7th":25,"99ef0ca3d859":51,"\u0113z":27,"\u4e2d\u6587\u7248":[54,55],"\u4f60\u597d":8,"absolute import":48,"abstract method":44,"abstract":[27,28,42,45,50],"array iter":29,"basic index":31,"basic program":13,"best practic":50,"big-o":10,"binary fil":49,"boolean array index":28,"boolean":[12,20,26,35,36,37,50,51,57,59],"break":[3,4,8,17,23,24,26,50,51,52,57],"byte":[8,30,49],"c order":29,"c routin":37,"case":[1,3,4,5,9,10,12,13,14,15,17,19,20,21,22,23,25,27,31,32,36,37,40,45,47,49,50,51,52,57],"catch":[8,9,12,20,50,51],"char":[11,14,23,50,51],"class creat":41,"class definit":[39,40],"class funt":44,"class method":44,"class object":40,"class":[8,11,17,22,26,36,38,39,42,45,48,49,50,54,61,62],"clean directori":52,"close fil":49,"code block":7,"code styl":50,"column-major ord":29,"comparison oper":9,"console styl":7,"context manag":49,"control flow":[13,16,21],"copy index":28,"create arrai":33,"custom packag":48,"custom syntax":46,"data sci":[4,5],"default paramet":14,"default":[4,5,8,15,25,27,29,31,33,37,43,44,46,47,48,49,50,51,59],"dunder method":46,"export":4,"f order":29,"final":[5,8,19,20,26,31,32,35,42,47,48,50,51,52,53,57,59,62,63],"float":[3,12,15,20,21,26,27,28,31,33,36,37,43,44,46,47,50,51],"floating point precis":8,"for loop":19,"for-loop":[13,16],"function":[0,1,2,3,5,6,7,8,9,10,11,15,16,18,19,20,21,22,23,24,28,29,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,57,59,61,62,63],"generator comprehens":15,"get item":[12,25],"import":[0,3,4,5,6,8,10,11,12,14,15,17,18,19,20,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,41,44,47,49,50,51,52,54,55,57,61,62,63],"inline for-loop":15,"inline if":9,"int":[1,8,9,16,19,20,28,31,33,36,40,41,43,45,50,51,61],"integer array index":28,"interview prepar":[10,11,12],"is oper":9,"join directori":49,"jupyter lab":5,"linear algebra":37,"list comprehens":[15,19],"long":[2,4,8,10,12,15,19,20,23,31,37,43,47,48,50,51,57],"machine learn":36,"mismatched shap":32,"multidimensional arrai":31,"nd arrai":31,"negative index":[25,27],"nested comprehens":15,"new":[1,2,3,4,5,8,10,12,15,17,19,22,23,25,26,27,31,32,37,38,41,42,43,44,49,50,51,52,54,55,61,62],"no copy index":31,"null":8,"numpy arrai":[27,28,34],"object ori":[38,42,47],"ol\u00e1":8,"open fil":49,"operator overload":46,"practice problem":[19,20,21,22,23],"property-bas":[],"public":47,"python shopping list":38,"quick introduct":3,"read fil":49,"read lin":49,"relative import":48,"return":[3,4,5,6,7,8,9,10,11,12,13,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,32,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,57],"row-major ord":29,"short":[3,8,13,15,37,57],"special method":46,"static method":44,"static":[41,50,53,61],"sub class":42,"super":[42,45],"switch stat":9,"switch":4,"throw":[27,35],"true":[3,5,8,9,10,11,12,13,14,15,16,17,20,22,23,24,25,26,28,29,31,32,34,35,36,37,39,40,41,42,44,45,46,47,49,50,51,52],"try":[0,3,8,11,12,13,15,19,22,25,26,32,35,38,44,45,48,50,51,59],"type hint":50,"utf-8":49,"valid nam":26,"var":[13,14,15,26,37,41,49],"variable nam":26,"voil\u00e0":[1,32,48],"vowel count":14,"while":[0,3,4,5,16,17,19,22,24,26,27,30,31,32,47,50,52,54,57],"while-loop":13,Added:53,Adding:51,And:[4,5,11,14,20,36,51],Are:[8,15,32],Axes:[59,62],Being:25,But:[16,54,55],Doing:[26,32,38],For:[0,1,3,4,5,7,8,9,10,11,12,14,15,16,17,19,25,26,27,28,29,30,31,33,35,36,37,41,43,44,45,46,47,48,49,51,52,54,57],IDE:[1,2,5,48,50,53],IDEs:[1,16,48,50,51,52,56],IDs:36,Its:[5,8,16,37,41,45,47],Not:[5,27,36],One:[8,15,16,29,37,45,47,48,49,59],Such:[7,14],That:[1,2,4,5,8,9,10,11,12,13,14,15,17,19,20,24,25,26,27,29,31,32,35,36,40,41,42,43,44,45,46,48,49,50,51,52,54,55,61],The:[1,2,3,4,5,6,7,9,10,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,39,41,42,43,45,46,48,49,54,55,58,60,61,62,63],Their:[14,25],Then:[1,8,10,12,18,19,26,27,28,32,38,41],There:[1,2,3,4,5,8,9,10,13,14,15,18,19,22,25,26,31,32,33,34,36,37,43,44,47,48,49,50,51,52],These:[1,4,5,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,37,41,43,46,48,49,50,51,52,57,58,59,60],Tis:23,Use:[0,5,8,9,11,13,14,15,16,17,28,32,35,46,47,49,50,52],Uses:57,Using:[0,6,8,9,13,14,18,22,25,26,27,28,35,38,41,45,47,49,57,59],Will:[9,25,36,56],With:[4,11,41,49,51],Yes:4,____________________________:52,_____________________________:52,__add__:[44,45,46],__all__:48,__contains__:46,__div__:46,__eq__:45,__ge__:45,__getitem__:[17,46,50],__gt__:45,__init__:[38,39,42,43,44,45,46,48,50,52,61],__iter__:[17,46],__le__:45,__len__:[46,50],__lt__:45,__main__:[39,40,41,44],__mul__:[45,46],__ne__:45,__next__:46,__pow__:[45,46],__radd__:45,__repr__:[42,43,45,46],__rmul__:45,__rsub__:45,__rtruediv__:45,__setitem__:46,__str__:[45,46],__sub__:[45,46],__truediv__:[45,46],_data:46,_need:[38,46],_purchas:[38,46],_use_gpu:50,_var2:26,a858573fdc63:26,a_dir:48,a_list:51,a_long_list_nam:50,a_numb:51,a_poem:49,a_str:51,a_text_fil:52,abacus:32,abbrevi:[8,34,47],abc:[3,9,25,49,50],abcabcabc:9,abcd:[17,25,44],abcdef:[29,51],abcdefg:25,abcdefghij:13,abid:[22,50,62],abil:[2,8,9,14,16,25,26,27,29,41,43,44,46,50,51,52,57,62,63],abl:[1,3,4,5,8,12,14,22,25,26,27,29,31,32,37,44,45,47,48,52,54,55,59],about:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,19,22,29,32,33,35,37,38,41,43,44,45,46,47,49,50,52,57,61,62],abov:[4,5,8,14,22,27,31,32,35,36,39,41,48,50,51,52],abs:[8,15,21],abs_tol:8,absolut:[8,15,32,37,49],acceler:50,accept:[11,12,14,15,17,22,25,36,37,38,42,44,46,47,49,50],access:[1,3,8,9,10,11,15,17,18,19,20,22,24,25,28,29,31,32,33,34,40,41,43,44,48,49,52,54,59,61],accident:[4,5,48],accommod:[8,9,11,12,16,22,32,38,48,50],accomod:49,accompani:[58,60],accomplish:[0,1,3,12,14,48],accord:[1,8,9,10,12,14,20,27,29,30,31,32,35,37,41,44,47,49,50,52],accordingli:[1,35,46],account:[8,9,23,32,54,55],accru:50,accumul:[1,50,51],accuraci:[35,54,60],accustom:50,ace:25,aceg:25,achiev:[17,32,51,59],acquaint:[3,57],acquir:[54,55],across:[5,8,16,18,22,35,36,49,50,51,52],act:[37,57],action:[3,7,8,37,42,49,50],activ:[4,5,48,52],actual:[4,6,8,9,14,15,19,21,25,27,31,32,33,35,41,50,51,52,56,57,62],adam:8,add:[1,2,4,8,10,11,12,14,16,17,28,32,35,37,38,44,46,47,50,51,52,61],add_2:14,add_3:31,add_new_item:[38,46],added:[5,10,12,13,15,22,28,38,40,46,50,62],adding:[11,12,13,26,49,50,54,55,57],addit:[4,8,9,11,12,14,16,33,35,37,40,44,45,47,48,50,51,52],addition:[1,5,22,28,38,41,43,47,48,52],address:[14,15,22,32,41,44,52],adher:[16,29,50,51,52],adjust:[5,27,29],admittedli:51,ado:[4,52],adopt:[44,50],adorn:63,advanc:[2,4,6,12,15,27,29,34,52,54,59],advantag:[10,11,37,45],advis:[4,16,49],aeiou:[13,49],aeiouaeiou:[14,50,51],aesthet:50,affect:[3,16,26,31,41,43,46,47,52],afford:[27,51,52],afoot:22,aforement:[1,4,16,51,52],after:[3,4,8,11,12,13,14,15,19,22,24,27,32,40,50,51,52,58,60],afterward:[31,52],again:[3,10,15,24,31,32,43,50,51],against:[10,19,22,36],age:8,aggress:51,agre:27,aha:20,ahead:[19,51],aid:50,aim:[28,47],air:50,aka:50,akaclass:50,akin:[8,40],aks:27,alarm:51,albeit:32,albert:49,alert:50,alex:54,alexding123:[54,55],alfr:8,algebra:[10,11,59],algorithm:[12,17,21,22,50,57],alia:[4,41,48,50],alias:[48,50],alias_nam:48,alic:22,alien:[8,52],align:[8,32,47,50],alik:[5,7,15,56],all:[1,2,3,4,5,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,57,61,62,63],all_cap:50,all_fanout:19,allclos:[32,37],allevi:32,alloc:[8,31],allot:8,allow:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,19,21,23,25,27,28,29,31,32,33,34,36,38,40,41,42,45,46,47,48,49,50,52,56,57,62,63],almost:[8,10,12,27,32,50],alon:[49,51],along:[3,8,11,13,15,17,20,22,23,24,28,29,30,31,32,33,34,35,37,47,48,50,51,52,54,55,57,59],alongsid:[50,52,53,63],alpha:[35,47],alphabet:[8,27,38,50],alphanumer:[23,26],alreadi:[4,5,6,8,9,10,12,15,25,31,38,40,41,42,44,45,48,49,50,51],also:[2,3,4,6,8,9,10,11,12,14,15,17,20,21,22,23,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,58,59,60,62],altern:[5,8,9,51,52],although:[1,5,8,12,15,17,19,23,25,27,28,29,37,40,43,47,49,50,51,57],altogeth:14,alwai:[3,5,8,9,12,13,16,20,22,27,28,29,32,37,38,42,44,47,48,50,51,52],alyosha:50,ambigu:[27,59],amend:[26,33],among:[1,5,8,12,22,25,27,37,44,50,52,59,63],amort:10,amount:[8,29,33,37,38,45,47,49,51,57],amp:47,amplitud:47,anaconda3:4,anaconda:[3,5,6,47,48,56],analog:37,analysi:[8,10,35,43,53,54,55],analyt:48,analyz:[5,10,49,50,59],anatomi:63,anchor:50,anew:49,angi:18,angl:48,ani:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,22,24,25,26,29,30,31,32,35,37,40,41,43,44,45,46,48,49,51,52,56],anim:47,annabel:[54,55],annabellelew:[54,55],annot:[14,47,50,62],anoth:[1,5,8,9,11,12,15,22,25,28,29,31,32,35,41,42,43,46,47,48,50,52,61],another_long_nam:50,answer:[1,5,8,28,37,49,52],anticip:[21,44],anyon:[1,21,62],anyth:[1,8,9,12,14,44,45,47,49,50,51],anywher:[8,9,14,24,48,50],apart:5,api:[47,62],appar:51,appear:[1,3,5,7,8,15,19,25,26,45,47,48,52],append:[0,3,8,10,11,13,15,17,19,20,25,26,35,36,41,44,45,46,49,50],appendix:46,appendleft:11,appl:[3,8,11,12,14,15,18,22,25,38,39,40,46,50],applepie_yum_yum:26,appli:[19,27,28,32,35,37,41,50,51,52],applic:[4,5,6,11,27,29,37,47,52,54,55,57,59,61],apply_fanout:19,appreci:[15,22,35,46],approach:[32,36],appropri:[0,14,21,22,26,28,29,32,38,41,49,50,51,52],approv:50,approx:35,approxim:[8,14,35,37],arang:[6,27,28,29,35,37,47,59],arbitrari:[25,28,32,40,46,50,58],arbitrarili:[8,15,28],archaic:52,archiv:49,area:[35,43],area_:35,aren:22,arg1:50,arg2:50,arg3:50,arg4:50,arg5:50,arg6:50,arg:[14,22,24,46],argmax:[36,37],argmin:37,arguabl:[1,21],argument:[9,12,15,17,22,24,31,33,36,39,40,41,46,47,49,50,57],arguments_for_funct:52,aris:57,arithmet:[3,8,9,31,32,37],arm:[9,19,28,30,48,56,57,59,63],around:[8,34,41,43,50],arr:[27,31],arrai:[6,9,25,26,35,36,43,47,48,50,54,59,62],arrang:52,arriv:[12,59],arrow:[50,51],articl:6,artifact:46,as_integer_ratio:8,ascii:51,ascrib:[9,25,27],ashlei:[12,17,26,27],asid:2,ask:25,aspect:[8,19,24,28,46,47,52],assert:[45,63],assertionerror:[51,52],assess:23,assign:[0,1,3,5,7,9,13,14,17,22,25,27,39,40,41,48,54,57,59],associ:[4,8,9,10,12,36,37,45,47,48,50],assort:[27,32],assum:[1,4,8,9,10,12,19,21,24,25,35,36,44,49,50,52],assumpt:[47,50],assur:49,asterisk:14,astrophys:59,astropi:59,astyp:47,atrophi:50,attempt:[4,8,13,19,25,26,40,44,45,48],attent:[17,43,50,57,61],attr:[40,42],attract:6,attribut:[38,39,42,43,44,45,46,48,54,59,61],attribute_nam:40,attributeerror:[39,40,45],augment:[38,59],author:[48,52],auto:[43,48,52],autocomplet:[2,3,5],autom:[50,51,52,63],automat:[8,16,19,27,31,38,39,41,43,44,47,49,50,52],autoreload:48,avail:[3,5,7,8,10,11,12,25,27,33,37,40,45,47,48,49,50,52,53,54,55],averag:[32,35,37,57],avoid:[3,8,15,17,32,33,37,48,50],awai:[3,14,50,54,55],awar:[2,5,8,47,49],ax1:47,ax2:47,ax3:47,ax4:47,ax5:47,ax6:47,axes:[27,30,31,32,35,37,47],axi:[27,28,29,30,31,32,34,35,36,47],axs:47,b9d20096048c:15,b_attr:42,back:[4,5,13,29,50,51,52,54,55,63],background:[7,47],backtick:7,bad:[16,22,35,40,44,50,51,54,55],bad_dict:12,bad_f:14,bad_func1:14,bad_func2:14,bad_func3:14,bad_func4:14,bad_merge_max_map:22,bagel:49,balanc:57,banana:[12,18,22,50],bar:[16,47,51,52],bare:[48,52,59],barrier:51,base:[1,5,8,9,14,19,20,22,25,26,27,28,32,33,45,47,48,50,51,63],base_fanout:19,base_numb:19,bashrc:4,basic:[1,5,7,9,13,15,17,25,27,32,34,40,41,43,47,48,49,52,54,55,57,59,63],basic_funct:52,basic_math:48,basic_modul:48,basket:8,batch:36,batman:8,bcd:25,beauti:47,becaus:[1,4,8,9,10,11,12,13,14,15,17,22,25,27,28,29,31,33,35,36,37,44,45,48,49,51,52,54,55],becom:[1,5,6,9,11,13,15,17,18,27,33,37,40,48,50,51,52,54,55,56,57],bedrock:49,been:[1,4,5,8,10,12,15,20,25,27,31,32,35,37,38,40,43,45,48,50,52,54,55,57],beet:46,befor:[4,10,12,13,15,16,22,23,27,32,38,43,45,48,49,51,52],begin:[1,3,4,7,8,9,10,11,16,22,25,26,27,28,31,32,35,38,40,44,49,50,51,52,54,55,56,57,63],beginn:[4,5],behav:[8,11,12,13,14,19,20,22,25,28,31,35,36,37,41,43,44,45,46,50,51,61],behavior:[8,9,11,14,19,20,21,22,23,25,26,28,37,44,46,47,51,52],behind:[6,15,26,31,32,45,52],being:[1,2,4,5,7,8,9,12,13,14,15,17,20,22,26,27,28,29,31,32,35,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,61],believ:[],belong:[8,9,18,34,39,43],below:[4,5,11,35,40,49,52,57],belt:51,beneath:[5,13],benefit:[5,33,37,47,48,50,51],best:[6,8,22,26,28,37,47,49,54,55,62],better:[12,22,29,49,51],between:[1,3,4,5,7,8,15,16,19,25,27,31,32,35,37,41,42,47,50,51,59,61],beyond:[3,8,12,14,15,19,27,31,32,44,46,48,51,52,62],biff:50,big:[2,4,10,12,28,31],biggest:50,billion:8,bin:[4,47,48],binari:[4,19,49,50],bind:40,birthdai:52,bit:[8,14,15,18,29,30,33,37,47,49,51,63],bizarr:52,black:[50,52,57],blank:[14,16,47,50,52],blazingli:6,bloat:32,block:[5,7,8,9,13,16,24,36,49,51,52,57],blog:[52,54,55],blogospher:25,blue:[5,32,37,47],board:35,bob:[3,8,22],bodi:[9,11,13,14,16,20,40,41,44,51,52],bogus_path:49,bohm:11,bohr:11,boil:1,boiling_point:50,bokeh:47,bolster:[44,57],bone:48,bonu:0,book:[11,32,49,50,54,55],bookkeep:[27,29],bool:[8,12,13,14,15,17,20,23,28,37,41,50,51,57],bool_ind:28,bool_index:28,boope:25,boopeeboopeeboopeeboopeeboope:25,border:5,borrow:51,both:[5,6,8,9,10,11,13,14,25,26,27,28,29,31,32,37,39,42,43,44,45,47,48,49,50,51,52],bottleneck:[22,23,32],bottom:[1,5,8,9,13,14,15,25,26,37,47,48],bound:[19,27,35,40,43,47,48],box:[2,57],brace:[10,12,16],bracket:[8,10,12,16,25,46,49,50],brad:[17,27],branch:[9,16,57],brand:44,bread:38,brian:[18,26],brief:[7,37,48,50,53,54,56,61],briefli:[4,9,11,18,24,27,43,47,49],bring:[5,44],brittl:[],broadcast:[28,29,31,34,35,37,47,50,54,59],broadcast_to:[32,47],broadli:41,broken:[20,51,52],brought:61,browser:[5,47],bruce:[8,50],bud:50,bug:[8,9,12,17,22,31,50,51,52],buggi:58,buggy_merge_max_map:22,build:[3,4,16,27,29,32,37,42,48,56],built:[0,3,8,9,10,11,12,14,15,17,18,21,25,29,31,35,38,40,41,42,43,44,48,49,50,51,57],builtin:40,bullet:[6,46],bunch:[32,57],bundl:45,button:[4,51,52,63],bye:[8,14],c82711d5fe4d:51,cachedir:52,calcul:[0,6,19,32,34,37],calibr:48,call:[1,3,4,5,7,8,9,11,12,13,14,15,19,20,22,23,26,27,31,32,33,34,36,37,40,41,44,45,46,47,49,50,51,52,57,62],callabl:19,came:[4,6,12],camel:40,camelcas:50,camera:48,can:[0,1,2,3,4,5,6,7,9,10,11,13,14,15,16,17,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,61,62,63],cannot:[5,8,10,11,12,13,14,15,24,25,26,27,31,32,41,45,49,50,52,59],cap:63,capabl:[1,5,17,20,37,43,47,48,50,51,59],capit:[8,43,44,50],capsul:14,caption:7,captur:50,capword:50,care:[10,12,14,19,20,22,32,38,48,49,50,51,56],carefulli:[37,50,51],carpent:[54,55],carri:[1,29,38,43,48,52],carrot:12,cassi:[17,18,27],cast:[14,20],casual:40,cat:[3,8,11,14,18,24,25,36,40,41,43],cat_dog_goose_oth:36,catcatcat:25,categori:[27,50],catwoman:8,caught:[54,55],caus:[1,13,16,22,26,31,48,49,51,52],caution:[8,38],caveat:4,cavemen:32,cavewomen:32,cba:9,cdot4:32,cdot5:32,cdot6:32,cdot7:32,cdot:[32,37],ceaselessli:13,celin:50,cell:[22,36,51,56],celsiu:50,center:[8,32,35,42,43],center_of_mass:32,certain:[3,32,49],certainli:[12,51,52],chain:[9,18],challeng:[51,58],chanc:5,chang:[1,3,4,5,8,12,19,22,25,26,27,31,32,35,41,48,50,51,52,54,55],changelog:54,channel:[32,47,48,52],charact:[0,1,2,3,8,9,11,13,16,23,26,43,46,49,50,51,52,57],characterist:50,charli:40,chart:47,chdir:52,cheat:47,check:[2,3,8,9,10,11,12,15,20,22,25,27,31,32,37,40,41,46,48,49,50,51,52,57],chees:12,chines:[54,55],chocol:50,choic:[20,50,52],choos:[22,27,33,47,50],chosen:[50,54,55],chronolog:53,chunk:5,cindi:22,circl:[35,47],circuit:[13,57],circumst:[6,24,26,51],cite:50,civil:[33,40],clariti:16,class_:50,class_func:44,classa:11,classb:11,classif:[54,60],classifi:[36,50],classification_accuraci:36,classification_scor:36,classmethod:44,classnam:40,claus:[9,15,20,57],clean:[11,17,50,52,57],cleandir:52,cleaner:[8,36,50],cleanup:52,clear:[9,14,15,20,27,32,34,35,37,44,49,50,52,57],clearli:[19,50,51,52],clever:[20,22,25,32],click:[0,4,5,52],clockwis:43,close:[0,5,8,35,37,49,50,54,55],closur:50,cloth:46,cloud:48,cls:[44,50],clunki:52,cmap:47,cmath:8,cmd:[1,3,4],cnt:[7,40],cnt_div_by_3:16,code:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,31,32,34,35,36,37,38,39,40,41,42,45,47,48,49,53,54,55,56,57,58,59,60,62],coder:[],coerc:32,coexist:43,coffe:46,coher:[37,50],col:[15,28,47],collabor:50,collect:[1,4,8,9,10,12,13,17,25,27,32,37,40,43,48,49,50,51,52,54,57],colon:[9,11,13,14,25,50],color:[2,5,7,32,37,47],colormap:47,column:[27,28,30,31,32,34,35,36,37,47,59],com:[50,52],comb_l:18,combat:51,combin:[14,18,24,31,32,37,41,46,51,52,59],come:[1,3,4,6,7,8,10,14,17,25,37,49,50,52,57,61],comfort:[18,21,37],comma:[8,14,15,25,50,51],command:[1,4,5,9,15,22,36,47,48,50,51],commensur:47,comment:[7,51],common:[3,4,5,8,10,11,12,15,16,22,25,26,27,28,34,37,41,44,45,49,50,51,52,57],commonli:[8,9,14,29],commun:[2,5,50,62],commut:45,comp_var:24,compact:12,compani:50,compar:[5,6,8,9,10,11,12,15,22,23,24,27,32,36,37,50,51,52],comparison:[1,8,11,21,22,23,35,37,50,52,57],compat:[4,6,8,32,38,45,46,50],compet:[5,54,55],compil:[34,37,50],complac:[54,55],complain:44,complet:[2,4,5,6,8,9,10,11,12,13,20,21,27,29,33,35,36,46,48,49,50,51,52,54,55],complex32:30,complex64:33,complex:[11,26,33,48,50,57],complic:[12,15,35],compon:[6,31,48,52],compound:9,comprehens:[0,5,20,21,23,24,36,46,54,57,58,59,61,62,63],compris:[32,33],comput:[1,2,3,5,6,7,8,10,14,15,16,19,21,24,25,27,32,35,36,41,43,48,49,50,54,56,57,59],compute_area:[42,43],compute_corn:43,compute_exp:14,compute_student_stat:50,con:2,concat_to_str:20,concaten:[3,19,20,25,33,44],concept:[12,13,16,27,29,42,43,45,51,54,61],concern:[15,19,23,48,50,57],concert:52,concis:[9,17,19,23,32,35,47,50,51,57,59],conclud:[10,14,26,28,32,44,48,50,61],conclus:59,concret:[13,29,32,41,50],conda:[52,56,62],condens:9,condit:[0,8,12,13,15,16,20,22,28,32,50,54,57],condition:16,conduc:1,conduct:[5,13],confid:51,config:48,configur:[1,2,48,50,52],confirm:[0,44,51],conflict:[4,26,48,50],conform:1,conftest:[48,52],confus:[1,8,15],conjunct:[17,28,49,52],connect:[5,47],consecut:9,consid:[6,9,10,13,15,16,19,20,21,22,23,25,27,28,29,31,32,37,41,42,44,48,50,51,52,58,60,62,63],consider:[6,38,52,57],consist:[9,14,16,25,26,27,35,41,46,48,50,51],consol:[3,4,5,7,8,16,22,26,36,43,45,46,47,48,50,51,52],constant:[10,48,50,59],constitut:51,constraint:[22,36,50],construct:[8,10,11,15,16,17,23,25,27,28,33,44,47,48,49,52,57,61],constructor:[8,12,15],consult:[8,11,46,47,50],consum:[11,12,23,25,32],consumpt:[15,32],contact:61,contain:[0,1,2,3,4,5,8,9,10,11,12,14,15,16,17,18,22,24,25,26,27,28,30,31,32,33,34,35,37,38,40,41,45,47,48,49,50,51,52,57,61,62],content:[1,3,5,8,9,10,11,12,13,14,15,17,24,25,26,27,28,31,32,33,34,36,37,41,46,48,49,50,52,54,55,56,57,58,59,60,61,62,63],context:[2,3,13,14,17,24,28,30,31,37,41,45,46,49,51,52,62],context_manag:49,context_vari:49,continu:[22,26,27,57],continuum:48,contour:47,contract:[22,40],contrari:52,contrast:[24,37,40,44,50],contribut:[50,51,54,55],contributor:51,contriv:[18,51],control:[2,8,13,17,20,21,29,46,47,52,54,57],convei:[10,17,32,42,47,50],conveni:[1,3,8,9,10,15,27,32,37,44,46,47,48,49,51,52],convent:[40,44],convers:20,convert:[8,15,20,25,48,49],convinc:[22,28],convolut:[19,50],cook:[22,32],cool:12,coord:32,coordin:[11,12,32,35,38,47],copi:[22,23,26,27,28,31,32,41,46,48,51,54,55],core:[3,10,18,50,54,55,59],corner:[5,43],cornerston:[54,55,57],correct:[25,36,50,51,58],correctli:[9,22,36,50,51,52],correspond:[1,8,11,12,14,15,17,18,20,21,24,25,27,28,29,31,32,33,35,36,37,47],corrupt:[49,51],cos:[5,37,47],cosmic:51,cost:51,costli:5,could:[3,5,8,9,12,18,22,27,29,32,34,37,44,47,50,51,54,55],count:[3,8,10,11,12,14,16,17,18,21,25,35,36,41,45,50,51,52],count_even:14,count_valu:51,count_vowel:[14,50,51,52],counterpart:31,coupl:[8,20,51,52],cours:[1,2,3,4,5,6,14,16,26,27,49,51],courtnei:50,cout:1,cover:[8,12,14,17,37,49],cow:[12,14,17,18,24],cpython:[1,3,4,5,10,12,50],craft:62,creat:[0,1,2,3,4,8,9,12,17,18,20,22,23,25,26,27,28,29,31,32,34,35,37,38,39,40,42,43,44,45,48,49,50,51,54,55,56,57,59,61,62,63],creation:[11,32,33,40,41,43,49],creativ:25,creator:[48,50],credit:19,criterion:22,critic:[4,5,10,16,25,29,31,41,43,48,50,51,54,55,56,59,62,63],cross:[4,46],crowd:50,crucial:6,crude:35,crust:49,cryptic:8,ctrl:[0,5,51],cube:[9,48],cue:[3,27,37,52],cumbersom:[51,52],cumsum:35,cumul:35,curat:[36,48],curi:11,curli:[8,10,12,16],current:[5,8,15,35,44,48,50,52,54,55],current_num:17,cursor:5,curv:[2,5,35,47],custom:[6,8,43,47,48,49,50,61],custom_dot_product:50,custom_inherit:50,customiz:2,cut:[5,63],cute:20,cwd:52,cycl:47,d3_arrai:27,d5_arrai:27,d_sinc:5,dabbl:56,dai:[4,62],danger:[9,54,55],dangl:32,dart:[54,60],dart_posit:35,dash:[35,47,50],data1:49,data2:49,data:[2,3,4,5,15,22,25,28,29,30,32,34,36,37,43,45,47,48,49,50,54,55,56,57,59,61,62],databas:[48,50],datafram:43,dataset:[27,47],datatyp:33,date:[1,8,50,52,54,55],datum:36,davi:50,david:[11,12,18,49,54,55],deactiv:4,dead:[4,9],deal:[3,8,10,12,19,28,36,37,48],dear:63,debat:21,debug:[2,5,22,50,51],debugg:2,decid:35,decim:[3,8,12,32],decis:[50,51,52],decod:49,decor:44,dedic:[2,17,31],deduc:[35,51],deem:27,deep:[25,54,55],deepen:43,deeper:[15,47,48,51],deepli:[48,54,55],def:[5,6,7,10,12,16,19,20,21,22,23,24,26,31,32,36,38,39,40,41,42,43,44,45,46,48,50,51,52,57],defacto:44,defaultdict:[11,48],defin:[1,3,5,7,8,11,13,14,15,16,20,22,24,26,27,31,33,34,37,38,39,42,43,44,46,48,49,50,51,52,54,57,59,61],definit:[2,10,12,13,14,15,16,17,24,27,29,31,32,37,38,39,41,42,43,44,48,50,61],deg_to_rad:48,degre:[35,48,59],deleg:37,delet:[5,52],deliev:48,delimit:[8,9,13,14,46,49,50,57],deliv:48,deliveri:48,delv:[26,28,31,37],demand:[15,57],demarc:14,demo:3,demonin:45,demonstr:[7,8,9,11,12,13,18,19,22,24,25,26,28,29,31,32,33,37,40,41,44,46,47,48,49,50,51],denom:45,denot:[5,8,9,10,14,27,37,40,49,52],depend:[2,4,10,12,13,21,26,29,45,48,49,51,59],depict:[27,35],depth:52,deriv:5,describ:[1,11,20,30,37,41,42,43,48,50,51,52,57],descript:[8,10,11,14,22,28,29,48,50,51,52],deserv:17,design:[1,3,8,11,21,27,36,37,40,43,44,46,47,49,50,51,52,57,58,59,60],desir:[5,21,22,27,29,32,44,46,51],desktop:[48,49],despit:[22,48],destin:52,detail:[4,5,7,8,12,14,17,25,26,27,28,29,32,37,44,45,47,48,49,50,51,52,57],detect:[12,48],determin:[1,8,9,10,19,23,28,31,32,33,35,42,46,50],dev:[22,33,35,36],develop:[1,5,23,32,38,47,48,50,52,53,54,55,56,59],deviat:[21,35,37],devic:[8,54,55],devis:[22,51],diagnost:51,diagon:28,diagram:[25,27,32],dict1:[22,51,52],dict2:[22,51,52],dict:[11,12,17,22,41,44,51,52,61],dict_a0:52,dict_a1:52,dict_a2:52,dict_a3:52,dict_a:52,dict_b0:52,dict_b1:52,dict_b2:52,dict_b3:52,dict_b:52,dictat:[12,40,52],dictionari:[9,10,14,15,17,20,26,43,44,46,49,50,51,52,54,57,58],did:[3,8,10,13,19,20,22,35,38,44,56],didn:[29,35,44,51],diff:[32,52],differ:[2,3,5,6,8,9,10,11,12,14,15,16,20,22,23,24,25,29,31,32,34,43,44,45,47,48,50,52,54,57,58,59,61],difference_fanout:58,difference_upd:[38,46],differenti:[1,2,43],difficult:[28,50],digit:[8,20,32,37,54,55],dilig:[8,48,51],dimens:[28,29,30,31,33,34,35,37,54,59],dimension:[6,29,30,32,33,34,43,47,50,59],ding:54,dir:52,direct:[32,37,48,52],directli:[1,2,4,6,8,15,25,31,36,48,49,52],directori:[1,4,5,47,48,49,52],disabl:51,discard:8,discern:[12,30,50],discourag:23,discov:[40,52],discoveri:52,discret:47,discuss:[2,4,8,9,12,13,14,15,22,25,26,27,28,29,30,31,32,37,39,42,43,44,46,48,49,50,51,52,53,54,55,56,57,59,61],disk:49,dismai:8,dispatch:59,displai:[3,7,8,25,26,35,43,46,62],dispos:8,dissuad:51,dist:32,dist_from_origin:35,distanc:[35,50,52,59],distil:[47,51,54,55,57],distinct:[7,9,11,14,17,25,26,28,31,34,37,41,42,43,47,52],distinctli:7,distinguish:[2,7,11,34,43,44,49,57,61],distribut:[3,4,11,33,37,47,48,56],distutil:48,div:37,dive:[4,15,25,46,48,51,59],divers:[47,50],divid:[8,32,33,35,36,37,46,50],divide_func:48,divis:[8,9,16,32,37,46],divorc:31,dlib:50,doc2:9,doc:[14,35,50],docstr:[14,22,40,50,51,62],document:[1,2,3,5,45,54,55,57,59,61,62,63],doe:[3,5,8,9,10,11,12,14,15,20,22,23,25,26,27,28,31,33,37,41,42,44,45,47,48,50,51,52,56,57],doesn:[5,11,12,17,22,25,32,44,45,51,54,55],dog:[3,11,14,18,24,25,36,40,50],doing:[1,3,4,5,6,8,33,34,47,48,51,53,56,57,59,62],domain:[5,28,33,36,47],don:[5,8,9,12,19,27,31,45,49,50,51,52,54,55],done:[5,29,37,40,48],doom:32,dos:50,dot:[8,32,37,40,47,48,52],dot_index:9,doubl:[3,8,10,41,46,50],down:[1,20,27,37,48,49,51,54,55,62,63],downgrad:48,download:[1,2,4,48,52],downsid:[11,12,23],downstream:22,dpi:47,draw:[33,43,47,61],drawn:[10,18],dream:32,drill:48,drive:51,dropbox:50,dropdown:5,dtype:[28,30,33,34,37],duck:50,dude:3,due:[12,37,48],dummi:[40,41,44,48,52],dummy_email:52,dummy_inst:41,dump:49,dunder:[41,46],durat:52,dure:[1,15,35,48,50,51,52],dust:51,duti:51,dynam:47,dynload:48,e72fb36dc785:51,e7cf39509d06:12,each:[9,10,11,12,13,14,15,16,17,18,19,20,22,23,25,27,28,29,30,31,32,33,34,35,36,37,40,41,43,47,48,49,50,51,52,57,58,59,60],earli:[5,13],earlier:[8,12,15,19,27,35,41,50],easi:[2,4,17,22,37,45,48,49,50,51,52,57],easier:[29,35,38,46,50,51],easiest:48,easili:[2,5,7,14,19,22,32,35,54,55],echo:46,econom:15,ed60a54ccf0b:15,edg:[14,20,21,27,51],edit:[2,5,48,50,52,54,55,56],editor:[1,2,5,48,50],educ:56,edward:12,effect:[4,5,8,11,12,16,22,29,32,35,37,40,47,48,50,51,52,57,59,63],effici:[3,6,10,11,12,15,16,17,18,23,31,32,37,50,57,59],effort:5,egg:46,eigenvalu:37,eight:[9,16,20,52],einstein:11,either:[8,9,11,13,14,22,27,29,32,37,38,40,44,45,49,50,51],electr:8,electron:47,eleg:[2,6,9,17,28,35,42,46,47,62],elegantli:8,element:[10,11,12,15,18,19,25,26,27,28,29,30,31,32,34,35,37,38,44,45,46,50,57],elementwis:[35,37],elif:[14,16,17,20,22,26,57],elimin:[36,52],elppa:25,els:[14,15,16,17,20,21,22,24,26,35,36,44,45,46,49,50,57],elsewher:[16,26],elucid:48,email:[52,57],emb:[5,47],embark:[16,56],embed:47,embellish:50,embodi:[40,48],embrac:47,emerg:5,emit:23,emmi:[41,49],emphas:[8,20,32,54,55,58,60],emphasi:[50,54,55],empow:61,empti:[0,8,9,11,12,13,14,19,21,22,25,27,29,32,33,41,50,51,52],emul:[46,47],enabl:[2,4,5,19,43,46,47,48,49,50,52,57,59],encapsul:[14,16,24,31,39,41,43,45,50,51,57,61],enclos:13,encod:[36,49,54,58],encount:[4,8,11,13,15,17,24,25,27,41,43,44,49,50,51,52],encourag:[4,50],end:[1,3,4,5,8,9,10,11,13,14,15,16,17,18,19,25,26,28,29,32,34,35,37,40,49,50,51,52,54],endear:37,endeavor:57,endl:1,endors:2,endswith:8,enforc:50,engin:[1,8],english:[1,8,20,50],enhanc:[50,62,63],enjoi:35,enough:[5,8,29,51,54,55],enrol:11,ensur:[1,4,8,22,25,38,48,49,50,51,52],entail:[1,12,26,40,48],enter:[3,5,7,11,13,14,16,38,49],entertain:35,entir:[3,8,10,15,17,20,24,25,26,31,36,37,46,48,49,51,52],entireti:[10,37,58,60],entri:[3,8,10,11,14,17,25,26,27,28,29,31,32,33,34,37,38,41,47,48,50,51],enumer:[18,19,22,29,32,35,48],env:4,envelop:14,environ:[1,5,46,47,48,51,52,53,54,56],envis:32,eps:47,equal:[5,8,9,11,12,28,30,32,33,37,42,52],equat:[0,3,5,8,28,32,35,47],equip:57,equival:[8,9,11,13,14,15,19,20,21,22,23,25,27,28,31,32,33,37,41,42,44,46,50,51],eras:[5,49],err_low:47,err_upp:47,error:[1,2,5,8,9,12,13,14,19,21,25,26,27,36,44,45,47,49,50,51,52],error_messag:51,errorbar:47,esc:5,especi:[1,2,5,19,20,27,28,30,45,48,50,52],essenti:[1,5,11,12,13,15,17,18,28,37,42,43,47,48,52,54,55,56,58,60,61,62],establish:[32,61],estim:[8,54,60],etc:[2,4,22,25,31,35,37,40,50,51,54,55,61],euclidean:[32,50],euler:[11,41,48],evalu:[0,5,9,12,13,14,17,20,22,33,40,47,50,52],even:[5,6,7,8,9,10,12,13,14,15,16,17,19,20,24,28,32,34,38,40,41,44,48,49,50,51,52,54,55,63],even_gen:15,evenli:[5,8,33,47],event:[11,49],eventu:[49,50],ever:[3,5,9,13,14,15,17,32,51],everi:[4,5,13,15,16,22,25,31,35,37,41,49,50],everyon:[],everyth:5,everywher:[36,37],evid:51,evil:23,evolv:[35,51],exact:[8,15,28,32,41,50],exactli:[8,11,12,15,16,28,32,37,45],exagger:50,exam:[12,22,26,27,32],exam_1:22,exam_1_scor:18,exam_2:22,exam_2_scor:18,examin:45,exampl:[1,3,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,36,37,39,41,42,43,44,45,46,47,48,50,51,52,56,57,62],example_arrai:30,example_default_dict:11,example_dict:12,example_gen:15,example_scop:24,exce:[8,13,51],exceedingli:[14,50,52],excel:[2,3,5,11,46,50],except:[8,14,15,26,50,51],exception:1,excit:5,exclud:[14,15,25,33,46,48,52],exclus:[5,15,33,37],exe:[1,3,4],execut:[1,2,3,4,5,6,8,9,13,14,16,20,24,39,40,41,43,44,45,47,48,51,52,57],exemplifi:50,exercis:[20,51,52,57,58,60,62],exhaust:[8,11,15,28,37,45,46,54,55],exhibit:28,exist:[1,4,8,10,11,12,22,24,26,32,40,42,46,49,50,61],exit:[13,14,19,22],exorcis:51,exp:[8,31,37,47],expand:[9,16,43],expect:[1,4,7,10,14,15,35,37,40,44,45,47,48,49,50,51,52],expected_count:52,expected_merg:52,expected_merged0:52,expected_merged1:52,expected_merged2:52,expected_merged3:52,expedit:51,expel:20,expens:51,experi:[2,35,50],experienc:[54,55],experiment:8,explain:[5,8,25,44,48],explan:[10,46,49,58,60],explicit:[1,12,14,23,27,31,32,35,37,51],explicitli:[9,11,15,18,25,29,32,37,41,44,51],explor:[3,5,25,49,52],expon:8,exponenti:37,expos:[8,27,50],express:[0,8,10,12,13,14,19,20,22,23,31,36,37,40,46,48,50,51,54,57],expression_1:9,expression_2:9,expression_n:9,extend:[8,9,29,35,47,50,52,58],extens:[2,8,17,35,37,47,49,50,58],extent:[19,43,51],extern:44,extra:[19,32,58],extract:[9,11,15],extran:62,extraordinarili:49,extrapol:[20,27],extrem:[2,12,15,17,22,28,31,35,44,46,49,52,57],f8487d9d0863:[8,9],f89f8b6a7213:52,face:[44,48],face_detect:48,face_detector:48,facet:51,facial:48,facilit:[2,5,10,11,17,28,29,47,48,50,59],fact:[1,5,8,9,12,14,15,26,37,43,46,50,51,61],factor:[10,45,47],factori:[3,8,14,21],fail:[9,11,26,45,49,51,52],failur:[19,51,52],faithfulli:50,fall:[16,21,27,28,35,47],fallen:35,fals:[0,3,8,9,10,11,12,13,14,15,17,20,23,25,26,28,31,35,36,37,40,41,45,46,49,50,51,52],familiar:[1,2,3,4,8,9,10,11,17,20,21,31,34,35,37,45,47,50,51,56,57],fanci:[14,20,51],fancier:15,fanout:[54,58],fantast:[6,8,49,56],far:[6,8,17,25,27,29,31,39,41,43,46,47,48,50,51,52,57],farmer:8,fashion:[22,27,37],fast:[6,12,18,37],faster:[4,6,10,36,37,48,51],favor:8,featur:[1,2,3,5,11,15,16,17,33,34,43,47,48,50,52,53,54,55,59,62],fed:[3,11,12,15,22,37,47],federici:[54,55],feed:[11,14,15,33,36,37,41,51,52],feedback:[54,55],feel:[5,15,25,35,46,56,57],fell:[12,17,35,51],fermi:[11,41],few:[3,8,10,14,15,16,18,38,45,46,50,61],fewer:[19,31,51],feynman:11,fidel:50,field:[8,48],fig:[5,35,47],figsiz:47,figur:62,file12345:49,file1:49,file2:49,file3:49,file4:49,file:[1,2,4,5,9,24,26,45,47,48,51,52,54,62],file_cont:52,file_var:24,filefilefil:49,filenam:[2,9,47],fill:[29,31,32,33,37,47,52],fill_between:[35,47],filter:[9,11,15,21,23],filtered_str:23,find:[1,4,5,8,9,10,11,13,15,18,19,22,25,29,31,32,35,36,46,48,49,50,51,52,61,63],find_alpha:50,find_packag:[48,52],fine:[8,33],finish:[41,52],finit:[8,15,25],first:[1,2,3,4,5,8,9,11,12,13,14,15,16,17,19,20,22,23,25,27,29,31,32,35,36,37,41,43,44,45,46,48,49,50,52,53,59,61,62,63],first_item:9,fit:[49,51],five:[8,20,25,33,36,50],fix:[50,51,53],flag:50,flake8:50,flaw:22,fledgl:52,flesh:48,flexibl:[6,12,14,16,26,28,31,40,47,48,50],flip:[22,27],float16:33,float32:33,float64:30,float_kei:12,floor:8,flour:46,flow:[5,13,17,20,21,54,55,57],fly:50,focu:50,focus:47,folder:[1,5],folli:12,follow:[0,1,3,4,5,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,36,37,39,40,41,44,45,46,47,48,49,50,51,52,54,55],food:[12,46],foot:52,footprint:32,for_block:24,forai:43,forc:49,forego:3,foregon:18,foremost:[1,2,48,50],forese:14,forev:0,forg:52,forget:[49,52],forgiv:16,forgo:51,form:[3,8,9,11,15,17,18,20,23,25,26,28,31,32,33,37,41,44,46,48,49,50,51,52,61],formal:[5,8,9,10,13,16,27,28,32,36,40,50,51,53,57],format:[1,2,3,5,14,20,26,40,42,43,45,46,47,49,50,52,54,56],formatt:[50,52],former:[3,9,46,58,60],formul:32,formula:[0,35,48,50],forth:4,fortran:29,fortun:[6,15,19,32,49,50,52,54,55],forward:[13,28,32,43,62],found:[5,8,9,11,22,27,33,46,47,49,50,52],foundat:[1,52,54,55,59],four:[11,16,20,27,33,36,37,40,50,52],fourth:52,fowl:[],frac:[5,8,14,15,30,32,35,45],frac_correct:36,fraction:[8,21,35,36,47],framework:[48,54,63],free:[1,2,15,17,22,32,42,48,50,52,54,55],freeli:[4,31],frequent:[3,8,10,15,50],fresh:56,friend:35,friendli:[44,49],from:[1,2,3,5,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,35,36,37,38,40,41,43,44,45,46,47,48,49,50,51,52,54,55,57,59,61,62],fromkei:44,front:20,frozen:[11,12,26],frozenset:[11,12],fruit:12,fruit_or_veggi:12,frustrat:[51,52],fulfil:48,full:[3,9,15,27,29,32,37,46,47,48,50,51,52],fuller:61,fulli:[2,35,43,61],fun:[19,35,54,55],func:[14,24,44,50],func_a:50,func_b:50,func_block:24,func_c:50,func_d:50,func_nam:50,func_var:24,fundament:[6,8,31,50,59],funni:27,further:[4,6,9,22,27,43,52,61],furthermor:[5,8,9,10,14,17,25,28,29,31,32,35,41,47,50,51,52,54,55,63],fyi:27,gain:51,game:[9,37],gather:38,gaug:50,gauss:11,gaussian:[33,47],gcd:45,gen:15,gen_1:[15,18],gen_2:[15,18],gener:[3,5,8,9,11,12,13,14,17,18,19,20,21,23,25,26,27,29,32,33,35,36,37,42,43,46,47,48,49,50,51,52,54,56,57,58,59,61,62,63],genesi:[54,55],genexpr:15,genuin:51,get:[1,2,4,5,6,8,10,11,12,14,19,25,27,28,31,32,36,37,40,41,44,46,48,49,50,51,52,54,55],get_area:[42,45],get_first_and_last:50,get_max:12,get_zip:48,getattr:40,getcwd:52,getitem:46,getsitepackag:48,gfedcba:25,gheliabci:17,git:2,github:52,give:[0,4,6,16,24,25,27,35,36,41,45,46,48,51,52,59,62],given:[0,1,5,7,8,9,10,11,13,14,15,16,17,18,19,21,22,23,25,27,28,29,31,32,35,36,37,41,42,43,44,47,49,50,51,52,57],glad:57,glanc:[17,19,29,32,44,47],glare:32,glimps:3,glob:62,global:22,goal:[43,47],goe:[8,26,50],going:[3,41,45,48],good:[2,5,9,16,17,20,22,25,34,48,49,51,53,54,55,58,60,62],good_f:14,goodby:15,googl:[5,46,62],goos:[32,36],goosei:40,got:[54,55],gracefulli:38,grade:[11,12,17,26,27,32,49,50,57],grade_book:50,grade_lookup:50,gradebook:[11,27,50],graduat:[48,54,55],grai:47,grammar:[1,50,53],grammat:1,grape:[12,22,38,40,46],graph:[15,47],graphic:47,grasp:[25,41],grayscal:47,great:[3,5,8,11,12,14,15,17,25,37,50,51,54,55],greater:[0,8,9,15,22,28],greatest:[22,45],greatli:[17,36,43,44,46,50,57,62,63],green:[5,32,37,47,51,52],greet:63,grid:[5,32,33,35,37,47],grigg:[54,55],groceri:12,grocery_list:50,gross:[8,16],gross_merge_max_map:22,ground:51,group:[8,49,50],grow:[5,15,50,52,57],grumpi:1,guarante:[1,8,9,12,20,35,51],guess:[22,28,37],gui:14,guid:[47,54,55,56,62],guidelin:[50,62],gush:5,had:[5,8,12,19,20,21,24,32,35,37,48,51,54,55,59],half:47,hand:[5,8,12,15,29,50,51],handi:[25,49],handl:[4,5,9,14,20,21,29,38,46,49,50,51],hang:[37,50],haphazardli:[31,52],happen:[0,5,8,9,13,15,17,24,27,44,45,56],happi:[14,48,51,52],happili:50,hard:[8,16,18,20,22,31,50,54,55,59],hardboiled800:[54,55],harmon:15,has:[1,2,4,5,8,9,11,12,13,14,15,16,18,22,23,24,25,27,29,30,31,32,33,34,35,36,37,39,40,41,44,45,46,47,48,49,50,51,52,54,55,56,57,59],hasattr:[40,46],hash:[11,12],hashabl:[12,44,50],haskel:5,hasn:12,hat:[3,8,11,25],hatter:63,have:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,24,25,26,27,28,29,31,32,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,58,59,60,61],haven:51,header:[5,50],health:[9,51],healthi:51,hear:0,heart:63,heavi:[2,22,51],heavili:[1,43],heed:8,height:[42,43,45,47],heisenberg:11,held:51,hello:[1,3,8,13,14,15,17,20,25,40,41,43,46,50,52],hello_world:9,help:[1,2,5,8,9,13,14,15,17,19,22,25,26,32,35,38,41,48,49,50,51,52,54,55,59],helper:20,henc:45,her:[9,11,41],here:[1,2,5,6,7,8,10,11,12,13,17,18,20,21,22,23,24,26,27,28,29,31,32,35,36,37,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,58,60,62],herein:44,heterogen:[10,12],high:[5,6,27,33,36,37,46,47,50],higher:[8,27,29,32,47,50],highest:[10,36],highli:[2,4,8,9,12,17,37,47,49,51,59],highlight:[2,3,50,51],hijack:52,hill:49,him:18,hint:[3,8,25,53,62],his:[9,41],hist:47,histogram:[47,62],histor:43,historgram:47,histori:35,hit:[0,3,5,35,44,49,50,51],hline:35,hold:[3,8,11,13,14,50,51,57],hole:63,home:[4,48],homogen:[30,37],hood:[10,17,19,38,41,44,45,46,48,49,57],hope:57,hopefulli:[10,16,35,54,55],hopper:11,horizont:[32,33,35,37,50],horrai:36,host:48,hour:6,hous:[48,50,52],how:[1,3,4,5,8,10,12,14,15,16,21,22,25,26,27,32,35,37,41,43,44,46,47,48,49,50,51,52,54,55,57,59,62,63],howev:[6,8,9,10,12,14,15,17,20,22,25,27,31,33,36,37,38,40,43,45,48,49,51,52],hstack:33,html:50,http:50,huge:[1,2,5,6,31,50,54,55],human:[1,50],hundr:[6,15,35,54,55],hyperbol:37,hypothesi:[52,63],hypothet:[35,36],idea:[2,51],ideal:[12,27,47],ident:[5,8,9,26,47,48,52,61],identifi:[13,22,25,27,41,50,52],idiomat:50,if_block:24,ignor:[11,23,32,38],iii:[32,54,57],ill:25,illog:51,illustr:28,ilovepython:23,imag:[5,8,32,36,37,49,50,52,59,62],imagin:35,imaginari:8,imbal:22,immedi:[3,8,11,13,14,17,18,19,20,22,27,32,33,42,48,50],immut:[8,10,11,12,25,57],imort:48,impact:[12,22,32,50,59],implement:[1,10,12,16,17,22,25,32,37,38,43,44,45,46,49,50,52,59],impolit:3,importantli:51,impos:27,imposs:[14,25],imprecis:8,improv:[1,17,35,43,46,50,52,53,54,55,57,62],imread:47,imsav:47,imshow:47,in_arg1:24,in_arg2:24,in_circl:35,in_str:[14,50],inaccess:[2,46],inadmiss:32,inadvert:22,inch:47,incis:[51,52,63],includ:[1,3,4,7,8,9,11,12,13,14,15,16,17,22,25,26,27,33,35,37,38,40,41,42,43,47,48,49,50,51,52,53,56,57,58,59,60,62,63],include_i:[14,50,51,52],inclus:[11,15,33,50,51],incompat:[8,12,32,51],inconsequenti:17,inconsist:[16,50],incorrect:16,increas:[8,10,16,29,51],increasingli:[50,51,62],incred:[6,27,37,45],increment:[3,8,17],ind0:28,ind1:28,ind2:28,ind3:28,ind4:28,ind:28,ind_0:28,ind_1:28,ind_2:28,inde:[5,31,44,50,51],indel:59,indent:[9,13,14,16,40,49,52],indentationerror:16,independ:[4,5,9,15,17,22,28,33,35,36,41,52,62],index:[3,8,9,10,11,12,15,17,19,20,21,29,32,34,35,36,37,43,46,48,50,54,59],index_2d:28,indexerror:[9,25,27],indic:[0,3,7,8,11,14,15,19,28,30,31,32,37,44,47,48,49,50,51,52],individu:[3,8,11,25,27,31,34,35,37,41,43,46,48,49,52],ineffici:32,inequ:[8,22,51],inevit:[8,31],infer:[2,50],influenc:[54,55],info:8,inform:[1,8,10,14,26,31,37,43,44,47,48,50,51,52,54,56,63],inher:[12,29],inherit:[43,50,54,61],init:[35,39,41,45],initi:[4,11,15,17,19,22,26,27,32,33,39,41,44,45,48,50,57],inject:8,inlin:[15,20,21,22,47,57],inner:[19,33,51],innermost:19,input:[3,5,7,8,9,10,12,14,15,17,19,20,23,24,26,27,29,31,37,38,40,44,46,47,50,51,52],input_str:[23,40,52],insert:[8,27,29,31,52],insid:[12,16,24,45,49],insidi:[22,51],insight:[28,48,59,62],insofar:51,inspect:[2,5,8,15,25,30,35,40,43,46,49,50,62],inst:44,instal:[2,3,5,6,50,52,54,55,56,62],install_requir:52,instanc:[0,1,2,4,5,7,8,9,10,11,12,15,17,18,20,25,26,27,28,29,31,32,37,38,39,40,42,43,46,47,48,49,50,51,52,54,61],instanti:[39,41],instead:[2,3,4,5,8,9,10,11,15,19,25,27,29,33,34,35,36,37,38,42,44,47,48,49,50],instruct:[1,4,5,15,16,25,28,31,32,33,36,37,41,47,48,49,50,52],instrument:[6,52],instuct:1,int32:[30,33,34],int64:28,int_to_str:20,integ:[1,3,7,9,10,12,13,14,15,18,20,22,25,26,29,30,33,36,37,40,41,45,46,47,50,51,52,59],integer_flag:50,integr:[1,45,50,56],intellisens:2,intend:[31,50,51],intens:[47,50],intention:51,inter:[17,48],interact:[4,41,43,44,46,47,48,52,61],interchang:[8,27,50],interest:[6,15,32,43,51,54,55,62],interfac:[2,3,5,8,10,25,27,28,34,47,49,57,59,61],interim:51,intermedi:[19,31,32],intermediari:29,intern:[50,51],internet:5,interpet:1,interpret:[3,4,5,8,10,17,24,28,32,33,35,47,48,50,51,56],interrupt:[0,13],intersect:[10,11],interv:[10,16,33,35],intra:62,intro:43,introduc:[9,10,11,13,17,20,32,33,37,40,43,45,47,49,50,51,52,53,54,56,57,59,61,62,63],introduct:[2,16,34,41,42,48,54,56,57,61,63],introductori:[1,52],introspect:52,intuit:[1,8,15,17,23,27,28,29,32,37,38,51,56,59],invalid:[11,14,26],invalu:59,inventori:57,invers:[29,37,47,49],invert:[12,37],inverted_x:12,investig:26,invok:[4,11,14,15,28,31,32,37,39,41,44,45,46,47,49,57],involv:[8,10,12,15,17,29,31,49,57],iostream:1,ipynb:[5,49,52],ipython:[0,2,3,4,5,7,8,9,12,15,22,26,27,36,47,48,51,52],iron:52,irrat:[35,48],irrespect:[28,42,48],is_bound:14,is_equ:23,is_in:10,is_in_circl:35,is_in_slow:10,is_palindrom:23,isalnum:23,isalpha:11,isclos:[8,28],isdigit:8,isinst:[8,9,20,25,34,38,39,41,42,45,46,50,51],islow:15,isn:[1,5,6,8,11,14,24,25,50,51,52],isort:50,issu:[4,6,8,32,44,54,55,62],issubclass:[42,43],isupp:9,it_var:24,item1:[8,11],item2:[8,10,11],item3:8,item:[3,7,8,9,10,11,12,13,14,15,17,18,20,21,25,26,27,28,29,31,37,38,41,46,47,50,51,52],item_to_transcript:20,item_to_transcript_alt:20,itemn:8,items:30,items_to_pric:12,iter:[8,10,11,12,13,14,16,18,19,20,22,23,25,31,32,37,38,40,41,44,46,49,50,54,57,59,61],iter_3:18,iter_4:18,iter_cnt:17,itertool:[17,24,36,41,54,57],ith:10,its:[1,3,4,5,8,9,10,11,12,13,14,15,17,19,20,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,58,59,60,62],itself:[8,12,14,19,29,39,43,44,48,50,51,52],jack:8,jackenzi:8,jan:50,jane:8,jargon:8,java:[1,16],javascript:47,job:[10,20],join:[3,8,15,20,23,25,46,47,54,55,59],journei:51,jpg:47,judici:[9,19,27],julia:[5,59],jupyt:[0,2,4,7,13,16,22,36,46,48,49,51,52,53,54,56,62],just:[5,8,9,10,11,12,15,18,19,20,22,25,32,35,37,38,43,44,45,48,49,50,51,52,54,55,56],justif:[],jython:1,kamasi:41,keen:[4,22,32,36,50,51,52,59],keep:[2,8,11,12,15,17,19,20,22,27,31,32,35,38,45,46,50,51,53],kei:[3,10,11,14,22,37,44,46,47,51,52,57,61],kept:[54,55],kernel:[0,5,13,48],key1:12,key2:12,key3:12,keyboard:[5,46],keyerror:[11,12,22],keyword:[31,33,36,47,49],kick:[],kid:8,kill:5,kind:15,king:50,kit:[54,55],know:[1,4,5,10,13,14,15,17,19,25,28,33,35,36,37,40,41,43,44,45,48,50,51,52,54,55],knowledg:[19,38,48],known:[1,3,8,12,15,17,19,24,25,29,31,36,37,40,43,46,48,49,50,51,52,59],kwarg:[14,50],l_2:32,lab:[53,56],label:[5,27,35,36,47],labmat:[5,54,55],labor:50,lack:[25,54,55],ladi:49,laid:[5,29,37,47,51],lame:8,land:[4,35],landscap:59,languag:[2,3,4,6,8,10,14,16,24,25,26,29,37,43,50,51,54,55,56,57,59,61,62],laptop:2,larg:[1,2,5,6,8,15,20,21,32,43,47,48,50,51,52],large_int:8,large_num:8,larger:[8,10,22,32,48],largest:[12,17,22,27,32,36,51],lassi:50,last:[0,3,8,9,12,13,15,23,25,26,27,28,29,31,32,35,40,45,48,50,51,52],lastli:[7,8,12,31,37,38,43,47,48,49,50,56],late:49,later:[0,1,3,5,8,14,27,32,37,48,49,51,52],latest:[1,4,27,54,55],latex:[5,47],latter:[3,9,20,50,51],laundri:33,layout:[27,28,32,37,43,47,48],ldot:32,lead:[8,16,17,31,32,33,37,43,48,50,51,52,62],lean:[54,55],learn:[0,1,3,6,8,9,10,14,15,29,32,38,41,43,46,47,48,49,50,51,52,54,55,56,57,59,62],learning_python:[48,52],least:[8,13,25,27,28,31,50,51,54,55],leav:[8,9,14,19,22,31,32,40,41,49,52],left:[9,14,17,23,26,28,29,32,37,45,47,52],legend:[5,35,47],legibl:50,leisur:27,len:[0,3,8,9,10,12,14,15,18,19,21,22,23,25,36,46,50,51,52],length:[3,8,10,15,18,25,27,30,32,33,37,42,46,50,52],leq:37,less:[1,8,9,12,22,25,27,36,37,40,47,51],lesson:[8,17,22,52],let:[3,4,5,8,10,12,13,15,16,20,22,24,27,29,32,33,34,35,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52],letter:[8,11,13,15,17,25,40,49,51,52],level:[4,10,16,37,39,46,47,48,50,61],leverag:[4,8,9,35,36,37,41,42,43,46,47,48,49,50,52,59,62],lew:[54,55],lexicon:43,lib:[4,48],liber:[24,50],librari:[1,3,4,5,8,27,33,34,37,43,47,48,49,50,52,54,55,56,59,62,63],lie:51,lies:[9,44,54,55],lieu:[38,48,49],life:51,lifetim:50,lift:51,light:[8,32,37,42,44],lightweight:[2,50],like:[1,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,22,23,24,26,27,29,31,32,33,34,35,36,37,40,41,43,44,45,47,48,49,50,51,52,56,57,58,60,61,62],likewis:[9,43],limit:[6,8,12,19,37,45,48,49],limitless:[19,52],linalg:35,line:[3,5,7,8,9,14,15,16,20,32,35,36,45,47,49,50,51,52,62],linear:[10,47,59],linearli:[10,15,16,47],linestyl:[35,47],link:[35,57,58,59,60,61,62,63],linspac:[5,47,59],lint:50,linter:50,linux:[1,3,4,49],list1:26,list2:26,list:[4,5,9,11,12,13,14,17,18,20,21,22,23,24,25,26,27,28,29,31,33,34,35,37,40,41,43,44,45,46,47,48,49,51,52,53,56,57,58,61],list_famous_dog:50,list_of_ag:50,list_of_dummi:41,list_of_nam:50,list_of_peopl:41,list_of_stud:50,list_of_temperatur:50,list_purchased_item:38,list_unpurchased_item:38,listofstud:50,litani:51,liter:[8,53],littl:[45,49,51,52],live:[4,23,47,50],load:[47,62],load_databas:48,load_ext:48,loc:47,local:[5,48,50,52],locat:[4,25,31,43,47,48,49,52],log10:[8,37],log2:37,log:[8,17,26,31,33,35,37,47],log_:37,logarithm:[8,37,47],logic:[12,16,20,22,26,28,35,36,38,44,51,57,59],logical_and:28,logical_or:28,long_variable_nam:50,longer:[13,15,22,31,48,50,51,52],longev:50,look:[1,2,3,5,8,9,12,14,16,20,25,27,30,31,32,36,37,41,43,44,45,47,48,49,50,51,52,56],lookup:[11,12],loop:[0,7,12,14,15,16,17,20,21,22,23,34,35,36,37,40,41,50,54,57,58],loosei:40,lost:[8,27,51],lot:[14,51,52,54,55],love:[23,54,55],low:[36,37],lower:[8,10,11,12,14,15,23,32,35,40,47,51],lowercas:[3,8,11,15,49,50,51,52],luckili:49,luxuri:8,mac:[1,3,4],machin:[1,3,4,5,6,8,10,43,48,49,50,52,54,55,59,62],machineri:15,maco:49,mad:[9,63],made:[1,8,18,20,22,31,32,35,45,48,50,52,54,55],magic:[6,22,47,48],magnitud:47,mai:[1,2,7,8,9,10,14,15,17,19,20,22,23,26,27,28,29,31,32,37,40,44,45,46,49,50,51,52],mail:48,main:[1,38],maintain:[1,4,12,48,50,52],major:[4,5,6,8,16,18,25,28,32,33,34,36,37,49,50,52,54,55,59],make:[2,3,4,5,6,8,9,11,12,14,15,16,17,19,20,22,23,25,27,28,29,31,32,34,35,36,37,38,41,43,44,45,46,47,48,49,50,51,52,54,55,57,58,60],manag:[4,5,12,19,44,49,50,51,52,62],mangl:23,mani:[1,2,3,4,5,6,8,10,11,14,15,16,18,19,25,27,29,31,33,35,37,47,48,49,50,52,54,55,57,59,62],manifest:[3,29,57],manifestli:[8,27],manipul:[3,41,43,47,57,59,61],manner:50,manual:[4,15,17,22,49,51,52],manufactur:21,map:[1,10,11,14,20,22,37,44,50,51],march:50,margin:[54,58],mari:49,mark:[1,3,5,8,38,46,47,50,51,52,59],mark_purchased_item:[38,46],marker:47,mascharka:[54,55],mask:51,mass:32,massiv:[5,32,37,47,49,51],master:41,match:[14,22,27,28,32,36,37,47,49,50,52],materi:[12,15,31,37,48,50,51,52,54,55,58,60,62],math:[3,5,14,37,48],mathcal:[10,11,12],mathemat:[3,5,6,8,9,10,31,32,33,34,50,59,61],matlab:[37,59],matmul:32,matplotib:47,matplotlib:[4,5,35,51,54,56,59,62],matric:[37,47],matrix:[6,15,32,37,47],matter:[3,5,8,12,14,20,25,27,29,32,44,51,57],matur:[5,43,50,62],max:[12,14,17,22,32,36,37],max_kei:12,max_key_optim:12,max_num:50,max_or_min:14,max_red_quad:37,max_val:[12,32],maximum:[12,22,37],mean:[2,3,4,5,8,9,10,12,13,14,15,17,19,22,23,24,25,26,27,31,32,33,34,35,36,37,39,42,43,45,46,48,49,50,51,52,56,57,58,59,60,61,62],mean_exam_scor:32,mean_i:32,mean_imag:37,mean_in_circl:35,mean_x:32,meaning:24,meaningfulli:10,meant:[7,8,9,13,14,15,20,25,26,44,46,50,51,58,60],measur:[8,54,60],meaur:47,mechan:[8,11,19,25,26,31,32,41,50,52,59,61],median:[37,50],melon:46,member:[8,10,11,13,14,15,17,19,25,48,50],membership:[9,10,11,12,15,25,46,50,57],memor:[10,37],memori:[1,8,12,14,15,17,18,23,25,26,30,31,32,41,44,50,57],mention:48,menu:[3,5],mere:[3,7,10,20,22,32,40,41,43,47,48,50],merg:[20,46,50,51,54,58],merge_max_map:[22,51,52],mess:[48,56],messag:[44,45,51,52],messi:9,met:[16,20,28,57],method:[0,8,10,15,17,20,28,29,30,31,32,33,34,38,39,40,42,43,45,47,48,49,50,54,61],methodolog:[29,51,63],metric:21,microsecond:37,microsoft:[1,2,48,50],middl:[3,11,47],might:[3,17,22,27,32,45,48,50,51,52],milk:[12,38,46],mill:1,million:52,min:[14,17,19,37],min_blu:37,mind:[8,11,19,22,26,31,32,35,50,51],mine:[58,60],miniconda3:48,minimalist:47,minimum:[37,48],minor:[44,58],minut:4,mirror:[10,12,15],mis:[46,49],misapprehens:50,misbehav:51,misdirect:51,mislead:15,miss:[11,14,32,54,55],misspel:2,mistak:[1,2,22,31,50,54,55],mistakenli:[14,38,50],mix:[3,7,14,25,37],mkdir:49,mkl:[6,37,48],mobil:[54,55],mock:52,mod:[8,37],mode:[5,14,26,48,50,51,52],model:[24,32,48,54,60],moder:2,modern:[16,43,47,56,61],modif:49,modifi:[2,8,41,44,48,49,50],modul:[2,3,4,9,12,14,15,16,17,18,26,27,34,37,41,42,43,45,49,51,52,53,54],modular:[16,57],module5_oddsandend:[48,49],module6_test:52,module_nam:48,modulo:[8,37],moment:[1,4,16,38,51],momentarili:41,monitor:[32,37],montalcini:11,month:[5,51,52],moo:[3,8,10,11,12,14,18,25,44,52],moon:52,more:[1,2,3,4,5,6,8,9,10,11,13,14,15,16,17,20,21,22,23,25,27,28,29,31,32,33,35,36,37,38,39,40,41,43,46,47,48,49,50,51,52,54,55,56,57,59,61,62],moreov:[36,54,55],most:[1,5,8,9,11,12,15,16,17,24,26,27,32,45,46,47,48,49,50,51,52,56,59],most_common:11,motiv:[4,10,49,51,63],move:[13,19,32,41,43,62],moveabl:5,movi:8,much:[0,1,2,3,5,8,12,16,22,32,33,35,36,45,46,49,51,52,54,55,57,61],muli:9,multi:[8,27,33,34,49,50,52],multidimension:[27,29,30,33,37],multipl:[3,5,8,12,18,19,20,25,31,32,34,37,38,43,46,47,48,49,51,52,54,57,59],multipli:[32,34,35,37,46],must:[3,8,9,10,11,12,13,14,15,16,22,23,25,26,27,28,29,31,32,36,37,41,44,48,49,50,51,52],mutabl:[8,10,11,12,22,25,57],mutat:[10,11,22,25,26,51],mxnet:43,my_arch:49,my_archive_fil:49,my_arrai:49,my_cod:[1,51],my_cub:48,my_dequ:11,my_dict:12,my_dir:48,my_fil:[9,49],my_fold:49,my_func:[7,16,24],my_imag:47,my_list:[3,9,10,14,17,24,38],my_loaded_grad:49,my_modul:48,my_open_fil:49,my_script:1,my_squar:[42,45],my_text:1,mygrad:[43,53,59],mygui:40,mylist:46,mypi:[50,53],n_circl:35,n_total:35,naiv:44,name1:52,name2:52,name:[2,3,4,5,8,9,12,17,18,22,24,25,27,37,38,40,41,44,45,46,48,49,52,57,61],name_to_scor:12,namedtupl:11,nameerror:[8,13,24],namen:52,namespac:[5,24,51,52],nano:1,nanosecond:10,napolean:50,narrow:50,nativ:[2,4,5,37,47,50],natur:[3,8,19,25,27,32,37,49,51,62],navig:[4,5,48,50,52],ncircl:35,ncol:47,ndarrai:[25,28,30,31,32,33,34,36,50,61],ndenumer:29,ndim:[30,43],nearest:25,nearli:[5,13,25,37,47,57],necessari:[9,10,16,17,28,32,48,49,50,51],necessarili:[12,15,32,47],necromanc:4,need:[1,2,4,5,8,10,14,15,17,18,19,20,22,27,29,32,34,35,36,41,42,44,47,48,49,50,51,52,54,55,57],neg:[0,3,8,9,20,23,25,28,31,37,51,52],neg_index:25,negat:[8,9,50],neighbor:19,neither:14,nest:[9,10,19,32,33,48],nestl:9,network:43,neural:43,never:[0,5,8,9,10,11,13,14,22,29,37,50,51],new_dict:44,new_fold:49,new_kei:12,new_list:46,new_subarrai:31,new_valu:[12,44],newaxi:[28,59],newcom:2,newfound:[3,9,57],newlin:8,next:[3,5,8,12,13,19,23,29,31,33,36,38,41,42,43,44,46,48,49,50,51,56,57,59,61,62,63],ngrid:47,nice:[2,3,5,8,10,11,12,14,20,25,31,35,47,48,50],nicer:2,niceti:[17,57],nick:12,niel:41,nimbl:[4,5],nine:20,njit:6,nlog:10,noether:[11,41],noisi:35,non:[6,8,11,15,17,19,23,27,32,37,45,48,50,51,52,57],none:[9,10,11,14,17,20,22,24,25,31,32,41,44,46,48,51,57],none_indic:17,nonetheless:[52,62],nonetyp:8,nonsens:46,nontrivi:28,nonzero:[9,13],nor:[9,11,14,22,24,47],norm:35,normal:[11,12,23,32,33,37],normed_imag:32,nose2:52,nose:52,notat:[10,28,31,37],note:[0,1,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,27,29,31,32,35,37,41,44,45,46,47,48,49,50,51,52,61],notebook:[0,2,4,7,13,16,22,35,36,46,48,49,51,52,53,54,56,62],notepad:1,noth:[1,2,8,15,24,44,49],notic:[5,20,23,37,38,45,50],notifi:8,notimpl:45,novic:31,now:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,17,19,22,25,26,27,30,31,32,35,37,41,42,45,46,47,48,49,51,52,53,54,55,57],npy:49,npz:49,nrow:47,nthi:49,nuanc:[10,27,31,44,57],nucleu:63,num:[9,13,14,16,17,45],num_correct:36,num_health:9,num_in_circl:35,num_loop:13,num_thrown:35,num_vowel:14,numba_result:6,number:[0,1,2,4,5,6,9,10,11,12,13,15,16,17,19,25,26,27,28,29,30,31,32,33,34,35,36,37,41,43,44,45,46,47,48,49,50,51,52,56,57,58,59],number_of_arg:14,numer:[1,5,9,14,26,27,32,34,35,37,43,46,54,55,59],numpi:[1,4,5,9,25,26,27,28,29,30,32,34,35,36,43,47,48,52,54,55,56,60,61,62],numpy_funct:52,numpy_result:6,numpydoc:50,nwai:49,nwhat:3,obei:[1,8],obj1:12,obj2:12,obj:[10,11,12,25,40],object:[3,10,11,12,13,15,17,19,20,22,25,28,30,33,34,37,39,42,44,48,50,51,52,54,57,59,62],obscur:[8,19,33,50],observ:[37,45,51],obtain:[6,20,46],obviou:[8,44,46,51,52],obvious:49,occas:[49,51,52],occur:[3,4,8,25,44,45,47],occurr:[10,25,28],odd:[8,13,15,16,49,54],odd_numb:50,off:[3,5,11,13,32,42,50,51,57],office_suppli:46,offici:[1,57,59,61,62,63],offload:6,offset:32,often:[2,8,16,27,32,33,41,45,51,52,63],ok_func:14,okai:[5,9,16,32],old:[5,8,51],old_dir:52,omit:[14,25,52],onc:[1,3,4,5,8,9,12,13,14,15,17,22,24,25,26,28,32,35,38,39,40,41,47,49,50,51,52],one:[0,1,2,3,5,6,8,9,11,12,14,15,16,17,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,38,41,42,43,44,46,47,48,49,50,51,52,54,55,59,61,62],ones:[8,52,59],onion:12,onli:[2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,22,23,24,25,27,28,29,30,31,32,33,36,37,38,41,42,43,44,46,47,48,49,50,51,52,57,62],onlin:47,onto:1,oop:45,opaqu:[47,50],open:[1,2,3,4,5,8,26,47,48,50,52,62,63],opencv:59,opened_fil:[26,49],oper:[1,4,5,6,10,12,15,19,21,22,26,27,29,32,34,35,36,41,43,44,49,50,54,57,59,61],operand:[32,37,45],opportun:[35,51,57],oppos:62,opt_merge_max_map:22,optim:[1,4,6,10,11,12,14,23,36,48,51,52,54,58,59],option:[4,5,8,14,15,29,31,43,44,48,51,52],orang:[3,18,47],orchestr:20,order:[5,8,9,10,11,14,15,16,17,18,22,23,25,26,27,28,31,32,35,36,37,38,48,50,51,52,53,54,55,59],ordereddict:12,org:[1,48],organ:[3,35,48,50,51],orient:[5,8,17,41,42,47,54,62],origin:[8,17,21,22,26,27,29,31,35,51,52],other:[0,1,2,3,4,6,8,10,11,12,14,15,16,17,19,20,22,24,25,26,28,29,31,33,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,59],otherwis:[8,9,11,13,19,32,33,35,46,50,59],ought:[9,12,37,38,42,45,51],ould:3,our:[1,2,3,5,8,9,10,11,12,14,15,17,19,20,22,23,24,25,26,27,28,30,31,32,34,35,36,38,40,41,42,43,44,45,46,47,48,49,50,53,54,55,56,57,61,62,63],ourselv:[3,34,44,48,51,57,61],out0:49,out1:49,out2:49,out:[0,1,2,3,5,8,9,11,12,13,15,17,20,21,23,26,27,28,29,32,35,36,37,38,44,46,47,48,49,50,52,54,55,59,63],outcom:[8,37,50],outdat:52,outer:[19,25],outermost:19,output:[0,3,5,7,14,15,19,22,27,28,29,37,47,49,51,52],outright:[12,13,15,48],outset:51,outsid:[13,16,19,21,24,35,40,48],over:[1,4,8,10,11,12,13,14,16,17,18,19,20,21,22,32,34,35,36,37,41,45,46,47,49,50,51,54,57,59],overal:[22,32],overhead:52,overli:[10,50],overload:46,overlook:[32,51,63],overrid:[14,24,49],overridden:[14,24],oversight:[19,50,51],overst:[18,50,59],overview:[7,8,16,34,37,39,43,48],overwhelm:[2,54,55],overwrit:[31,42,49],overwritten:37,overwrot:42,own:[4,6,8,10,14,16,17,26,29,38,40,41,42,43,45,46,49,50,51,52,57,62],pack:[12,14,22,31,50],packag:[1,3,4,6,34,47,54,62,63],package_nam:48,pad:8,page:[4,5,8,9,13,14,15,25,26,50,54,55],pai:[48,50,57],painstakingli:37,pair:[11,12,14,17,18,19,21,32,37,41,47,50],pairwis:[37,50,52,59],pairwise_dist:[32,50,52],pairwise_dists_crud:32,pairwise_dists_loop:32,palindrom:[54,58],paltri:15,pan:47,panda:[43,54,55,59],pane:5,paradigm:[5,13,37,57],parallel:52,param1:52,param2:52,param:52,paramet:[12,14,15,19,20,21,22,23,32,35,36,38,43,44,45,46,50,51,52],parameterless:50,parametr:[51,52],paramn:52,paramount:[50,57],parent:[28,31,42,45,52],parenthes:[8,14,15,25,50],parenthesi:[14,50],parenthet:15,pars:[1,50],part:[1,3,4,8,19,20,21,22,24,26,43,48,49,50,51,54,57,59],parti:[4,49,50,56,59],particip:1,particular:[4,11,22,28,36,40,41,43,44,50,57],particularli:[6,17,28,54,55,57],pass:[1,12,13,14,15,16,19,21,22,24,26,27,31,33,36,39,41,42,43,44,45,46,49,50,51,52],past:[5,13,46,53],path:[4,27,48,51,62],path_to_data1:49,path_to_fil:49,pathet:35,pathlib:62,pattern:[9,17,20,34,47,48,49,50,52],pdf:[9,47],peach:38,pear:[18,22],peculiar:[20,41,46],pedant:51,peek:[16,34,43],pen:46,pencil:46,peopl:[1,4,14,43,50,51,54,55,62],pep8:62,pep:50,per:[22,36,47],percentag:[54,58],perceptu:47,perfect:[4,5,8,11],perfectli:8,perform:[1,3,4,5,6,8,9,10,13,15,17,19,22,23,27,28,29,32,34,35,36,37,45,47,48,50,51],perhap:[8,9,35,47,50,51],period:[3,8,9,47],permiss:28,permit:[5,8,9,10,17,19,20,25,26,27,28,29,31,32,40,42,43,47,48,49,50,57,61,62],persist:[3,7,12,13],person:[41,54,55],pertin:50,perus:[5,8,11],pessimist:10,pet:23,petar:[54,55],petarmhg:[54,55],phone:3,phrase:[37,40],phrase_of_the_dai:48,physic:[27,54,55],pick:[3,32,50,52,54,55],pickl:62,pictur:[36,48],pie:[15,47],piec:[3,13,16,25,36,45,54,55,58,60],pillow:14,pineappl:38,pip:[4,52,53,62],pitfal:[],pixel:[32,37,47],pixel_std_dev:37,pizza:[12,40],pizzashop:40,pkl:49,place:[1,4,8,12,14,20,25,27,32,37,38,40,46,48,50,52,54,55,59],placehold:[8,26,32,37],plai:[19,20,32,52,54,56,60],plain:[1,7,51],plan:50,platform:[4,52,62],player:47,pleas:[3,8,9,11,33,37,48,49,52,54,55],pleasantli:37,plenti:[3,51],plot:[5,35,59,62],plotli:47,plt:[5,35,47],plu:49,plug:43,pluggi:52,plymi:[35,49,50,52,58,60],plymi_mod6:52,plymi_mod6_src:52,plymi_root_dir:52,plymi_us:52,png:[47,49],point:[3,4,5,9,12,15,16,19,20,22,23,26,27,28,29,32,33,35,36,37,46,47,49,50,51,52,54,55,62],point_to_region:12,pointer:26,polish:[2,5],polyglot:2,ponder:51,pop:[8,10,25],popul:[22,28,33,41,46,47,49,63],popular:[1,4,5,15,43,48,50,56,59,62],portabl:[38,49],portion:[5,9,37],pos_index:25,pose:25,posit:[0,3,8,9,10,11,13,17,19,25,27,28,32,35,37,43,44,48,50],posixpath:49,poss:30,possess:[8,10,31,32,37,39,40,43,47,48,61],possibl:[8,13,17,19,21,26,27,28,32,38,40,49,50,52],post:[54,55],poster:12,potenti:[19,23,29,50,51,52],potpourri:47,power:[2,4,5,6,8,9,19,25,28,31,34,35,37,42,45,46,47,48,49,50,51,52,56,57,59,62,63],practic:[1,5,8,9,13,14,15,25,26,28,36,37,43,49,51,54,55,58,60,62],pre:[1,10,37],prece:46,preced:[1,8,9,11,12,17,20,24,25,28,29,30,31,32,33,37,46,50],preceed:25,precis:[1,27,31,37,51],preclud:52,pred_label:36,predict:[0,26,28,36,52],prefer:[9,15,20,22,38,50],prefix:3,prematur:[13,23],premier:[5,34,54,55],premium:2,prepar:[32,47,48],prepend:4,prescrib:[34,37,59],prescript:20,presenc:3,present:[5,12,22,33,46,47,48,49,52,54,55,56,58,59,60,62],preserv:29,press:[5,32,49,51,63],pressur:50,presum:49,presumpt:22,pretti:45,prev_num:17,prevent:[15,50,51],previou:[4,8,14,19,22,27,32,35,47,51,52,53],previous:[13,50],price:12,primari:50,primer:52,print:[0,1,3,7,8,9,12,13,14,15,16,17,24,26,35,41,45,46,48,49,51],print_kwarg:14,printabl:[43,46],prior:[5,12,19,50],priorit:[4,47],pro:2,probabl:[18,35,50],problem:[4,10,19,20,21,23,32,36,37,51,52,54,55],problemat:[9,12,31,50,51],proce:[5,15,19,25,29,32,40,42,44,47,48,49,57],proceed:[8,27,43,52],process:[1,2,3,4,5,9,11,13,26,29,32,34,35,36,37,41,44,46,48,49,50,51,52,54,55,56,57,59,63],produc:[8,9,11,12,13,15,17,21,22,23,24,25,26,27,28,29,32,33,35,36,37,39,41,44,46,47,48,49,50,52,59],product:[8,19,30,32,37,41],profession:2,program:[5,6,8,16,17,41,42,54,55,56,57],programm:[2,6,8],programmat:[8,30],progress:[48,52],project:[4,5,36,48,50,51,52,54,55,62,63],project_dir:52,prolif:50,promin:[5,62],promis:[22,50],prompt:[46,49,52],prone:[36,49],pronounc:[27,41],proper:[14,51,52],properli:[5,22,49,52],properti:[42,43,44,51,52,63],propos:50,protocol:[49,50,61],prototyp:[1,2,4,5],proud:35,provid:[1,2,3,4,5,6,7,8,10,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,35,37,38,41,42,43,45,46,47,48,49,50,51,52,54,55,57,59],prudent:50,pseudo:[9,15],pts:32,publish:[47,50],punctuat:[11,15],purchas:[38,46],purchased_item:46,pure:[6,7,23,37,43],purpl:[40,47],purpos:[7,8,14,19,32,41,45,48,50,52],push:51,put:[3,8,9,13,14,15,16,25,26,37,43,52],py27:4,pycharm:[2,50,52,56],pyformat:8,pypi:48,pyplot:[5,35,62],pyright:[50,53],pytest:[48,54,63],pytest_cach:52,python36:48,python3:48,python:[2,5,7,9,10,11,12,13,14,15,17,19,20,23,24,25,26,27,29,31,34,37,38,39,40,41,42,43,44,45,46,47,51,53,58,59,60,61,62,63],python_requir:[48,52],pythonlikeyoumeanit:50,pythonoptim:51,pytorch:[43,48,51,54,55],quadrant:37,quadrat:[0,3,10],qualiti:[5,47,50],queri:15,question:[3,5,8,25,50,51,52,54,55],quick:[3,39,47,54,56],quickli:[4,11,12,27,50,51,52],quintessenti:16,quirk:[8,49],quit:[1,6,8,9,12,15,16,17,24,25,27,50,52,54,55],quot:[3,8,49],quotat:[1,3,8],quotient:8,rabbit:63,racecar:23,radian:[5,47,48],radiu:35,rai:51,rais:[1,8,9,11,12,13,14,15,16,19,21,22,24,25,26,34,40,44,49,50,51,52],raiton:45,ram:32,ramp:47,ran:[5,52],rand:[32,33,35,36,37,47],randint:36,randn:[33,47],random:[11,32,35,36,37,47,59],randomli:[10,18,33,35],rang:[6,7,11,12,14,16,18,21,22,23,25,28,33,36,40,41,47,48,49,52],rank:59,rapidli:[1,5,34,52],rare:[1,50,51],rat:45,rather:[1,3,8,10,15,20,22,26,28,31,35,37,41,44,46,47,48,51],ratio:35,ration:[8,45],rationa:45,rbg:[32,37],reach:[9,13,14,19,29,35,46],read:[1,4,5,6,21,22,23,33,54,55,57,58,59,60,61,62,63],readabl:[1,9,11,15,17,22,23,46,50,52],reader:[8,11,23,32,46,54,55,56,57,58,60,62],readi:[48,56],readili:[15,57],readlin:49,real:[8,11,27,32,37,48,52],realiz:35,realli:[5,16,22,32,33,44,45,50,51,52],reap:51,reason:[12,14,15,20,22,27,31,43,47,57,59],recal:[3,5,8,9,10,12,14,15,16,17,19,20,22,23,27,28,29,30,31,33,35,36,37,40,41,44,45,46,48,49,50,51,52],recast:32,receiv:[22,33,38,44],recent:[5,8,9,12,15,26,27,45,51,52,53],recogn:[27,32,42],recognit:48,recoil:32,recommend:[4,5,8,11,12,17,18,35,38,46,47,48,49,50],recomput:5,record:[17,21,53],recreat:12,rect1:43,rect:45,rectangl:[41,42,43,45],red:[5,32,37,40,47,51],redefin:[5,15,46],redraw:5,reduc:[38,40],redund:[11,20,28,38,44,50,51,52],redundantli:32,refactor:[21,32,44],refer:[2,3,5,8,9,11,12,13,14,19,22,24,25,26,27,28,29,31,33,34,35,37,40,41,42,43,45,46,48,49,50,51,52,57],referenc:[5,7,10,11,31,41,50,57],refin:47,reflect:[22,26,31,32,48,50,53],refresh:37,regard:[22,52],regardless:[12,29,32,50,52],region:[12,28,35,40,47],regrett:32,regular:[4,28,48],regularli:[48,50],reimplement:12,reiniti:31,reinstal:48,reiter:[22,49],rel:[1,3,8,10,14,16,20,22,25,32,33,37,44,49,54,55,62],relat:[4,11,48,49,54,55,56,59,62],relationship:[8,25,31,41,42,45],relative_po:32,releas:[51,53],relev:[37,52,58,60],reli:[1,7,8,12,37,43,50,51,57],reliabl:[2,8,35],relic:[8,43],reload:48,remain:[9,17,31,48],remaind:[8,16,37],remaining_item:46,remedi:[31,52],rememb:[8,22,29,41,51],remind:[8,49,51],remov:[4,8,10,11,19,26,37,38,52],renam:5,render:[5,8,46,47,48,50],reorgan:52,repeat:[11,13,20,25,27,28,33,37,51],repeatedli:[3,13,14,28,51,52,57],repertoir:57,replac:[3,8,10,17,26,27,28,31,37,46,52],replic:[15,32],report:[5,52],repositori:52,repr:[45,46],repres:[6,8,9,10,12,14,21,24,26,30,31,32,37,41,46,47,48],represent:[8,20,43,49,61],reproduc:[1,47,50],repurpos:26,request:[13,15,38],requir:[2,4,5,6,8,9,12,15,21,23,25,27,28,29,31,32,37,46,48,50,52,54,55],reread:52,rerun:[35,51,52],rescu:52,research:[1,5,54,55,56,59],resembl:32,reserv:[8,14,15,25,26,32,43,44,46,47,50,51,61],reset:29,reshap:[28,29,31,32,33,34,37],resid:[27,41,47,48,52],resolut:[32,47],resolv:[9,24,27,28,41,45,57],resourc:[2,8,15,46,47,50,54,55],respect:[5,8,9,13,14,17,20,24,27,28,29,32,33,35,37,40,44,47,49,51,52,62],respons:[20,38,47,48,50,52],rest:[5,7,17],restart:[5,13,48],restor:[51,52],restore_default:48,restrict:[6,8,9,24,37,48,50],result:[1,3,5,6,7,8,11,12,15,20,22,26,27,28,29,31,32,33,35,36,37,40,41,45,47,48,49,50,52,61],resum:49,retain:[8,22,51],retriev:[10,11,15,25,27,47,50],reus:57,reveal:[5,14,47],reveres:25,revers:[9,23,25,26,27,31,41,53],review:[5,8,16,25,27,31,50,62],revisit:[5,13,42,49,50],revolutionari:56,revolv:34,rewit:44,rewrit:[0,19,22,32,44,50,52],rewritten:[8,14,31,52],rgb:[32,37,47],rgba:47,rich:[2,5,46,50,52],richer:50,rid:28,right:[3,5,9,12,19,22,23,26,28,29,32,37,43,45,47,57],rightarrow:[8,9,11,12,19,20,25,28,32],rigor:[32,46,50,54,55],rival:37,road:[54,55,62],roadblock:6,roar:0,robot:3,robust:[2,5,51],roll:[19,49],root:[0,3,4,32,35,37,49,52],root_dir:49,rootdir:52,roster:11,rotate_imag:50,rotateimag:50,roughli:[12,36,52],round:[12,20,32],rout:5,routin:[27,29,32,37,48],row:[8,15,25,27,28,30,31,32,33,35,36,37,47,50,59],row_i:32,row_x:32,rsokl:[54,55],rubi:5,rudimentari:[50,51,63],rug:48,rule:[1,8,12,15,16,24,27,28,29,31,37,41,47,50,51,52,59],run:[0,1,2,4,10,12,13,15,22,34,35,36,48,49,50,51,56,63],rundown:[10,11,12,25,31,39,49],runner:[48,52],running_estim:35,runtim:50,ryan:[8,11,12,14,48,50,54,55],safe:[32,49],safeti:21,sai:[5,6,8,10,15,26,27,37,45,50,51],said:[2,4,5,8,9,13,20,24,27,29,31,32,35,40,41,42,43,48,50,51,52,54,55],sake:[1,12,16,23,32,37,46,50,51,52],salient:[17,41,50],salt:46,sam:[54,55],same:[1,5,6,8,9,10,12,15,16,19,20,22,23,24,25,26,27,28,29,31,32,35,37,40,41,43,45,47,48,50,51,52,57,61],sampl:59,sane:4,sash:3,satisfactori:20,satisfi:[8,28,31,32,48],save:[1,5,15,50,51,62],savefig:47,savez:49,saw:[5,8,15,25,31,41,50,52],scalar:[27,37],scale:[10,33,35,47,48,50],scatter:[47,62],scenario:[9,10,21,32,45,51],scene:[6,15,31,32],schema:27,scheme:[11,12,25,27,31,49,59],school:[54,55],sci:[54,55],scienc:[4,5,29,47,54,55,57,59],scientif:6,scientist:[1,56],scikit:59,scipi:4,scope:[8,12,22,40,41,50,51,52,54,57],score:[12,22,26,27,32,36,57],score_offset:32,scores_per_stud:32,scratch:[8,33,42,44,52,54,55],scratchwork:3,screen:[1,3],script:[2,3,4,8,17,24,48,52,56],search:[4,49,50,54,55,62],second:[5,6,8,10,15,17,20,22,25,27,29,36,44,47,49,50,51,52,62],secretli:6,section:[1,2,4,5,7,8,9,10,13,14,15,16,17,25,27,28,29,31,32,33,37,38,40,41,42,45,46,47,48,49,50,51,52,58,60,62],see:[3,4,5,7,8,9,11,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,31,32,33,34,35,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,61],seek:51,seem:[15,17,29,32,40,44],seen:[8,15,16,24,25,31,37,47,48,50,61],segment:[14,35,47],sel:27,seldom:[33,41],select:[5,27,28,30,51],self:[27,38,39,41,42,43,45,46,50],selina:8,semant:17,semi:[35,47],semicolon:47,send:[1,5],send_mail:48,sens:[8,15,34,38,44,54,55],sensibl:[25,29,44,46],sensit:23,sentenc:[3,8,11],separ:[3,5,8,10,14,15,16,17,20,22,25,26,47,49,50,51,52],seq1:25,seq2:25,seq3:25,seq:[10,14,23,25],sequenc:[3,9,10,12,13,14,15,16,17,18,19,20,23,26,27,28,29,34,35,37,41,43,49,50,51,54,57,59,61],sequenti:[3,8,11,17,25,32,36,57,59],seri:[14,15,36,51],serial:49,seriou:[6,8],serv:[7,16,26,41,48,49,50,51,52,54,55,63],server:56,servic:4,session:[3,4,48,52],set:[1,5,8,9,10,12,14,15,17,18,22,26,27,28,36,37,38,40,41,43,44,46,47,48,49,51,53,54,56,57,61],set_1:11,set_2:11,set_titl:[5,47],set_xlabel:[5,35,47],set_xscal:35,set_ylabel:[35,47],set_yscal:47,setattr:[40,46],setup:[48,52],setuptool:[48,52],seven:[8,20],sever:[3,5,6,8,14,16,18,25,33,35,38,41,45,48,49,50,52],shade:[35,47],shadow:[50,57],shallow:22,shameless:43,shampoo:50,shape:[27,28,29,30,31,32,33,35,36,37,43,46,47,50,59],share:[5,16,24,25,31,41,48,51,52],shares_memori:[28,31],sheet:[27,28,29,30,32,37,47],shelf:51,shell:[0,2,47],shift:5,shine:[9,10,12,32,37,52],shirt:46,shmangela:50,shmonathan:50,shock:8,shockingli:40,shop:[40,46,61],shoppinglist:[38,46,50],short_gen:15,shortcom:52,shortcut:[5,8],shorten:14,shorthand:[25,26,27,31,34,51],shortli:[47,50],should:[3,4,5,7,8,9,10,12,13,14,15,16,17,19,20,22,23,25,26,28,31,32,33,34,35,36,37,38,40,41,42,44,45,46,47,48,49,50,52,53,54,55,63],shouldn:38,show:[5,11,16,26,27,32,34,45,47,51,52],showcas:18,shown:[22,50],shrewdli:32,side:[3,4,9,42,45,47,48],sidewai:47,sift:52,sigh:14,sight:32,sign:[9,20],signal:[13,14,15,16,31,42],signatur:[14,22,44,46,50,52],signifi:[10,14,16,49],signific:[8,31,44,54,55],significantli:[4,6,28],silent:[1,12,51],silli:[46,50],sillyclass:46,similar:[1,5,14,15,22,25,27,32,33,37,40,41,44,47,50,51,52],similarli:[8,9,22,24,25,27,28,29,32,37,40,44,46,49],simpl:[1,2,3,4,5,8,9,12,14,15,16,17,20,25,26,27,29,35,36,37,38,39,40,43,45,46,48,49,50,51,52,58,59],simple_arrai:27,simple_merge_max_map:22,simpler:[0,36,47],simplest:[9,23,28,50],simpli:[1,2,3,4,5,8,10,12,14,15,16,19,21,22,25,26,27,29,31,32,34,35,36,37,40,44,45,46,47,48,49,50,51,52,54,55],simplic:[1,35,50],simplifi:[8,15,17,19,36,52],simul:35,simultan:[14,19,28,37],sin:[5,37,47],sinc:[5,8,12,15,16,19,20,25,27,36,37,40,43,45,48,49],sine:[33,47],sine_wav:47,sinewave_plt:47,sing:47,singl:[3,5,8,9,11,12,14,15,16,18,20,22,23,25,27,28,31,32,33,35,36,37,38,41,42,47,48,49,50,52,57,63],singular:[40,41],site:[54,55],situat:24,six:[9,20,37,54,55],size:[10,12,15,22,25,27,30,31,33,35,36,37,42,47,52,59],skill:61,skip:[9,13,15,35,51],sky:8,slate:52,sleek:[15,17,28,46,47],slice:[3,8,9,10,11,19,23,26,28,34,37,46,50],slick:[20,35],slightli:[15,41,47,49],slot:29,slow:[6,32,37],slower:6,small:[3,5,6,8,22],smaller:[22,47,51],smallest:[17,27],smart:52,snake:40,snake_cas:50,sneak:[16,34,43],snippet:[3,5,34,50,54,55],sock:46,softwar:[1,2,48],soil:49,soklaski:[48,50,54,55],sole:[8,10,14,15,38,41,44],solid:[47,54,55,59],solut:[0,4,54,55,57,58,59,60,61,62,63],solv:[4,19,21,37,44],solver:48,some:[3,4,5,7,8,10,11,12,17,18,19,20,26,27,29,35,36,37,38,39,41,45,47,48,49,50,51,52,54,55,56,57,59,61,62,63],some_dict:14,some_iterable_of_str:20,some_list:[14,48],some_long_function_nam:50,some_text:49,some_util_func:48,someon:[38,54,55,62],someth:[5,9,14,16,22,33,36,44,50],sometim:[20,49,50],somewhat:[19,27,28,46],soon:[9,15,40,43,50,51],sophist:[1,2,4,31,46,51,61],sort:[2,8,9,10,11,17,25,38,41,45,49,50,51,54,55],sound:[51,54,55],sourc:[1,2,8,25,48,50],space:[5,8,11,12,16,27,33,40,47,49],space_time_coord:11,span:14,sparingli:[14,15,20,50],speak:[40,52],spec:50,special:[1,3,8,9,15,17,19,20,22,29,32,34,38,39,41,42,43,44,45,48,49,50,51,54,61],specif:[1,4,8,10,12,15,21,25,27,28,31,32,36,37,39,40,41,43,44,47,48,49,50,52,56,62],specifi:[1,3,4,8,9,11,12,15,16,18,25,27,28,29,32,35,36,39,40,41,42,44,47,48,50,51,52,57,59],speed:6,speedup:[10,22,37],spell:[1,20,26],spend:[7,50],spent:38,sphinx:50,split:[8,11,15,33,47],spot:[54,55],spreadsheet:[32,43],spuriou:32,sqrt:[3,8,32,35,37,47],squar:[0,3,8,9,10,12,15,25,31,32,34,35,37,42,45,46,47,48,49],stack:[27,29,32,33,36,50,51,57],stagnat:[54,55],stand:[5,8,41,50,51,59],standalon:[27,50],standard:[1,3,4,8,11,12,14,16,33,35,37,47,48,49,50,52,59],stapl:46,star:[8,12,34],stark:[22,37,50],starkli:61,start:[3,4,5,8,12,13,15,16,18,25,26,27,29,31,32,33,34,35,43,45,49,51,52,54,55],startswith:[8,49],stat:50,stat_func:50,stat_funct:50,state:[8,14,15,22,26,31,46,48],statement:[13,15,16,17,20,21,22,24,40,50,52,54,57,62,63],static_func:44,staticmethod:44,statist:[17,33,35,37,50],statment:[13,14],statu:[9,26],std:[1,22,33,35,36,37],std_in_circl:35,stdin:45,stdlib:52,stem:[43,54,55,56,57,59],step:[10,13,15,23,25,27,29,32,33,37,50,51,52,56,63],stew:8,stick:[6,10,50],still:[5,8,13,14,26,28,31,32,38,40,41,44,45,48,50,53,57],stock:51,stomp:22,stop:[15,19,25,27,33,54,55],stopiter:[13,15],store:[3,4,6,8,9,11,14,17,18,19,22,25,26,27,30,31,32,34,35,36,37,38,41,43,46,47,48,49,50,57,59],str:[8,9,14,15,20,23,25,38,40,41,43,44,45,46,49,50,51,52,61],strage:45,straight:[14,28,32],straightforward:[22,27,32,37],strang:44,strategi:63,stream:47,streamlin:63,strength:47,stretch:47,strict:[1,50],strictli:[9,48,49,50],strike:[46,52],string:[2,5,9,11,12,13,14,15,17,19,22,23,25,26,27,37,38,40,41,43,44,45,48,49,50,51,52,54,56,57,58,61],string_of_num:15,stringent:6,strip:[8,47],strive:[35,49,50],strongli:[16,18,35,46,49,50],struck:57,structur:[27,30,32,33,48,49,51,52,54,57,63],struggl:[5,50],student:[11,12,17,22,26,27,32,50,56,57,58,60],student_grad:26,student_list:50,studi:[11,16,32,35,37,43,50,56,57,61,62,63],studio:[2,50,56],stuff:32,style:[5,7,16,40,47,48,54,55,62],stylist:[20,22],styliz:5,sub:[25,27,34,48],subarrai:31,subclass:42,subdirectori:[5,48,49],subfield:51,subject:28,sublist:50,submit:[50,58,60],submodul:47,subpackag:48,subplot:[5,35,62],subscript:15,subsect:[5,9,15,25,26,28,31,32,50],subsequ:[8,10,13,14,15,16,20,22,24,25,26,27,28,34,37,49,52,61],subset:[6,11,49],substanti:[32,35,37,48,54,55],subtl:[20,22],subtract:[19,32,35,37,45,46],succe:46,success:[19,50],successfulli:[32,52],succinct:[22,36,50],succinctli:31,suffic:[13,44],suffici:[8,10,16,37,50,54,55],suffix:[1,2,5,48,49],suggest:[9,50],suit:[1,11,20,28,32,37,47,48,50,51,63],sum:[1,6,8,13,14,15,17,19,21,32,35,36,37,43,44,50,51],sum_:[15,32],sum_func:[6,48],summar:[7,8,10,25,32,43,48,49,51],summari:[10,12,16,38,47,50,54,56,57,61],summed_row:32,superior:[21,46],superset:11,suppli:[25,28,31,33,37,49],support:[1,2,8,9,11,12,25,26,27,47,48,50],suppos:[8,9,10,11,14,17,19,22,26,27,28,29,32,36,37,38,41,42,48,49,50,51,52],suppress:47,suprem:[8,15,17],sure:[9,14,32,34,45,50,51,52],surfac:[8,33,42,52],surpris:[15,27,31,37,40,50],surprisingli:51,surround:[5,50],survei:[10,24,37,44,56],susan:11,suspect:52,suss:51,swap:[4,27],sweep:48,swept:48,swoop:51,symbol:[7,8,11,14,26,46,48],symmetr:11,symmetric_differ:11,synonym:[41,43],syntact:[16,17],syntax:[1,2,5,6,8,9,11,12,13,14,15,16,17,19,20,21,22,25,26,27,31,38,40,41,48,49,50,56,61],syntaxerror:14,sys:[0,48],system:[4,25,26,31,43,48,49,50,52,62],tab:[3,5,8,16,50],tabl:[27,29,37],tabular:59,tac:25,tackl:19,tag:44,tailor:[6,32],take:[0,1,4,6,7,8,10,11,12,14,15,16,17,18,19,20,22,25,27,28,29,31,32,34,35,36,37,38,40,44,45,46,47,48,49,50,51,52,54,55,56,57,61,63],takeawai:[2,4,9,10,11,12,15,17,22,24,25,27,28,31,32,37,40,43,48,49,50,51,52,57],taken:[12,20,27,32,49,50,54,55],talent:50,talk:[3,7],talli:[3,11,13,21,35,36,37],tan:37,target:[10,47,48],task:[1,8,20,25,28,37,57],taylor:14,teach:[49,54,55],technic:[16,48,50,62],techniqu:[12,28,59],technolog:47,tediou:[27,29,44,49,50,51],tell:[1,5,14,49,50,54,55],temp:52,temperatur:50,tempfil:52,templat:[9,52],temporari:[51,52],temporarili:[32,51,52],temporarydirectori:52,ten:[10,35,37,41],tend:43,tensor:[37,43],tensorflow:[43,48,54,55],term:[3,8,10,16,17,19,22,25,32,37,43,47,48,49,50,51,54,59,61],termin:[0,1,2,3,4,5,48,52],terminolog:[15,41,61],terrancewasabi:[48,49],terribl:[10,54,55],terrif:5,ters:28,tertiari:50,test:[1,2,5,9,10,11,12,14,21,22,25,36,41,48,49,50,54],test_0:49,test_1:49,test_:52,test_all_combin:52,test_appl:49,test_basic_funct:52,test_basic_numpi:52,test_broken_funct:52,test_calibr:48,test_config:48,test_count_vowels_bas:[51,52],test_databas:48,test_email1:52,test_email2:52,test_email3:52,test_funct:52,test_inequ:52,test_inequality_unparameter:52,test_merge_max_map:[51,52],test_model:48,test_numpy_funct:52,test_range_length:52,test_range_length_unparameter:52,test_using_fixtur:52,test_util:48,test_vers:52,test_writing_a_fil:52,testabl:51,tests_requir:52,text:[1,2,3,5,7,8,9,11,13,14,15,25,26,46,48,50,54,55,57,62],text_1:11,text_2:11,textbook:8,textedit:1,than:[0,1,4,6,8,9,10,11,12,13,14,15,19,20,21,22,25,28,29,31,32,35,36,37,41,44,46,47,48,49,50,51,52,57],thank:51,the_decor:52,the_function_being_decor:52,thefollow:47,thei:[1,4,5,6,8,10,12,13,15,16,17,18,20,22,24,25,26,27,29,30,31,32,37,41,43,44,45,47,48,49,50,51,52,54,55,58,59,60],them:[2,3,4,5,8,11,15,18,19,20,22,26,29,32,35,37,38,43,44,45,46,47,48,49,50,51,52,53,57],themselv:50,theoret:11,theori:50,therefor:[30,32,37],therein:[5,9,54,55],thi:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,61,62,63],thing1:48,thing2:48,thing:[3,8,14,15,27,37,43,45,49,50,52,61],thingth:50,think:[1,16,25,27,37,45,50,51,54,55],third:[5,15,26,32,49,50,52,59],thorough:[28,37],those:[4,8,11,14,15,21,24,25,26,28,31,35,37,42,48,50,51,54,55,59],though:[32,41,50],thought:[3,22,50],thousand:[6,8,10,35,52],three:[3,8,9,14,17,18,20,25,27,28,31,32,33,34,36,37,41,44,46,47,49,52],threshold:28,through:[4,5,15,17,22,27,31,32,45,46,47,48,49,50,51,52,56,58,60,61],throughout:[1,2,6,7,8,9,13,14,15,25,26,34,50,52,54,55],thrown:35,thu:[1,2,4,5,6,8,9,10,11,12,13,14,15,17,18,19,20,22,23,25,26,27,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,59],thusli:8,tick:[47,50],tightli:35,time:[3,4,5,6,7,8,10,11,13,15,17,18,22,23,25,28,29,31,32,34,35,36,37,38,41,45,47,49,50,51,52,56,61],timeit:[22,36],times10:8,tinker:5,tip:[20,36,58,60],titl:47,tmp:[41,52],tmpdirnam:52,togeth:[3,8,12,15,18,20,22,32,36,44,45,57,59],token:11,toler:8,too:[8,12,14,15,20,23,27,37,50,51,52],took:48,tool:[1,2,3,5,6,8,11,12,15,16,17,18,29,37,47,50,51,52,53,54,55,56,57,59,62],toolkit:57,toothpast:50,top:[0,1,5,11,13,37,43,47,48,50],topic:[28,37,42,48,59],topmost:[22,36,48],torch:52,total:[3,10,13,14,15,19,20,21,27,30,32,35,36,37],total_even:14,touch:[8,31,50],tough:12,tour:[48,61],tover:8,toward:[5,8,37,50,51,52],town:47,toyplot:47,trace:[50,51],traceback:[8,9,12,15,26,27,45,51,52],track:[2,8,11,12,15,17,27,38,45,46,48,50],trade:57,tradit:[8,37,57],tradition:[1,8,37],trail:[3,8,25,27,31,32,49,50],train:43,trait:50,transcript:20,transform:52,transit:[29,46],translat:[1,6,15],transpar:[35,47],transpir:[26,32],transpos:[27,32],travers:[25,28,36,37,50,54,59],treacher:31,treat:[3,8,27,28,32,37,40,43,44,48,49,50,52],treatment:[8,28,29,46,47,48,54,55,57],tree:[11,52],tremend:[1,5,6,34,37,59],tri:[22,36,45],trial:[8,35],triangl:47,triangular:47,tribul:51,trick:[20,57],trigger:[14,31,51,52],trigonometr:[8,37],trillion:8,tripl:[8,49],triplet:29,triu:47,trivial:[28,32,35,41,44,51,52],troubl:[50,52],troubleshoot:62,true_label:36,truli:[10,31],truth:[36,57],tupl:[8,9,12,13,14,17,18,22,26,27,28,30,33,37,38,41,43,47,51,57,61],tuple_of_dummi:41,turn:[31,47],tutori:[2,4,8,11,12,15,38,40,42,43,47,48,49,52],twelv:32,twice:[10,12,17,20,38],twitter:[54,55],two:[0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,18,19,20,25,26,28,29,31,32,33,34,35,37,38,40,41,43,44,45,46,47,48,50,51,52,54,56,58,59,62],txt:[1,26,49,52],type:[1,2,3,5,9,10,11,12,13,15,17,20,22,24,28,30,31,34,37,38,39,40,41,42,44,45,46,47,48,49,53,54,57,59,61,62],typeerror:[12,14,15,25,26,44,45],typic:[2,7,8,11,14,28,37,47],typo:[2,53],u0336:46,ubiquit:25,uint8:47,ultim:[8,20,27,49,50,51,52,61],umbrella:14,unabl:[37,45],unachiev:59,unaffect:[26,31],unambigu:[1,9,37],unanticip:22,unchang:[22,27,31,35,44],uncommon:[4,57],uncompromis:50,undefin:[2,40],under:[10,17,19,38,41,44,45,46,48,50,51,57],undergo:32,underli:[9,27,28,34,59],underneath:49,underscor:[8,26,40,41,46,50],underst:13,understand:[1,3,7,9,10,15,16,17,20,22,25,26,27,28,29,30,31,32,41,43,44,47,48,50,51,54,55,57,58,60],understat:57,understood:[7,8,14,61],undo:[29,51],unequ:[32,33,52],unevalu:9,unexpect:[44,51],unfamiliar:[],unfortun:[45,54,55],unhash:12,unicod:[8,26,46,49],unifi:43,uniform:[16,30,33,47],uninstal:[4,48],union:[10,11,38],uniqu:[11,12,25,27,28,29,38,46,47],unit:51,unittest:52,univers:[1,8],unknown:27,unless:[12,31,33,48,51],unlik:[11,12,25,28,37],unnecessari:[27,50],unnecessarili:[15,32],unord:[10,11,12],unpack:[14,22,28,47],unpattern:28,unpickl:49,unpopul:22,unpurchas:[38,46],unrecogn:45,unrestrict:37,unruli:50,unsign:47,unsorted_index:17,unsuccessfulli:45,unsupport:45,until:[0,12,13,15,16,24,29,45],untitl:5,untitled1:52,unus:50,unusu:48,unvector:60,unvectorized_accuraci:36,unwieldi:[27,51,52],unwittingli:[22,31,51],updat:[3,4,7,8,9,10,11,12,22,26,28,31,34,35,38,41,46,48,49,50,51,52,53,59],upgrad:48,upload:48,upon:[15,17,39,51],upper:[8,14,35,47],uppercas:[9,51,52],upward:47,usabl:51,usag:[11,15,17,32],use:[0,1,2,3,4,5,6,8,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,57,59],use_gpu:50,used:[1,3,5,6,7,8,9,10,11,12,13,14,15,17,20,25,26,27,28,29,31,32,33,34,37,39,40,41,43,44,45,46,47,48,49,50,51,52,57],usefixtur:52,useful:[1,2,3,4,5,8,10,11,12,14,15,16,17,18,27,28,31,32,35,36,37,38,45,46,47,48,49,50,51,52,57],usefulness:27,useless:9,user:[2,3,4,5,7,8,11,12,14,25,27,31,33,37,43,44,47,48,49,50,51,52,54,55,57,58,59,60,61,62],uses:[4,8,10,11,16,20,25,27,29,32,35,37,47,50],using:[0,1,2,4,5,6,8,9,10,11,12,14,17,18,20,21,22,23,25,27,28,29,30,31,32,33,34,35,37,40,41,42,43,46,47,48,49,50,52,54,55,57,58,59,62],usr:48,utf:[8,49],util:[1,3,4,8,9,10,11,13,14,16,17,18,26,28,29,31,34,37,38,42,43,44,46,47,48,49,50,62],val1:52,val2:52,val:[14,52],valid:[1,3,9,12,13,14,15,23,25,27,29,31,37,44,47,50,57],valj:52,valu:[0,1,3,5,8,10,11,13,15,17,18,19,20,21,22,24,25,26,27,28,31,32,33,34,35,36,37,40,41,43,44,46,47,51,52,57],valuabl:[11,17,18,22,24,27,29,52,54,55],value1:12,value2:12,value3:12,valueerror:[25,27,32],vanilla:[4,6,11,48],var_nam:14,vari:[27,31,33,51,52],variabl:[0,1,2,3,4,5,7,8,9,13,14,17,22,25,31,37,38,39,40,41,43,48,49,50,51,54,57],varianc:[33,37],variant:4,variat:48,varieti:[8,12,25,28,33,37,41,44,46,47,50],variou:[3,5,9,10,11,12,16,24,27,28,31,37,40,43,46,47,48,50,51,53,57,61],vast:49,vastli:16,vector:[1,32,34,50,54,59,60],veget:12,veggi:12,vein:[37,48],venu:48,verbos:[12,50,52],veri:[2,4,5,6,8,9,12,14,15,16,20,22,25,27,32,33,34,35,37,41,44,47,50,51],verifi:[8,15,32,37,41,42,44,47,49,51],versa:[3,22,50],versatil:[12,47,59],version:[2,4,6,8,9,10,11,12,20,24,32,43,44,48,50,51,52,54,55],versu:[26,31,35,47,52],vert:37,vertic:[32,33,37,47,50],via:[0,4,5,7,8,9,11,12,13,15,20,22,25,27,31,32,35,37,39,42,47,48,49,50,51,52,59],vice:[3,22,50],video:[5,9,52,59],view:[5,12,27,28,32,38,50,52,54,55,59],violat:[1,50,51],viridi:47,visibl:24,visit:[14,20,29,54,55],visual:[2,8,35,47,50,56,62],vogu:8,vowel:[13,14,49,50,51],vowel_count:51,vscode:[2,50,52,53],vstack:33,vulner:49,wai:[0,1,3,4,5,8,9,11,12,14,15,16,20,25,27,28,29,31,32,33,35,37,38,40,43,44,45,46,47,48,49,50,51,52,59,62],wait:63,walk:[45,50,54,55],want:[1,2,3,5,8,9,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,32,33,35,36,37,38,40,41,42,44,48,49,50,51,52,54,55],warn:[0,1,8,13,14,25,33,50,57],warrant:[8,25,29],wasi:47,wasn:[14,50],wast:32,watch:[8,49],wave:47,wayn:8,weak:47,wealth:10,web:[5,47],websit:[5,54,55],week:51,weirdo:8,welcom:63,well:[1,2,5,8,12,14,17,19,22,23,25,31,32,33,37,46,47,48,50,51,56,59],went:53,were:[3,5,8,9,12,16,20,31,37,38,44,48,49,50,51,52,53,54,55,58,60],weren:38,what:[3,5,7,8,9,11,14,15,16,17,18,20,21,22,24,25,26,27,28,29,30,31,32,33,34,37,41,44,45,48,49,51,52,53,56,57,59,62],whatev:[4,5,10,11,22,47,50,51],when:[1,3,5,6,8,9,10,11,12,13,14,15,16,17,21,22,24,25,26,27,28,29,31,32,33,37,38,41,44,45,46,47,48,49,50,51,52,56,57],whenev:[4,8,11,15,17,28,29,31,37,39,40,44,46,49],where:[1,6,8,9,10,13,14,15,16,17,21,22,23,25,27,28,29,31,32,35,38,40,41,43,45,46,47,48,49,50,51,52,56,63],wherea:[3,5,8,9,10,11,14,15,23,24,25,26,28,32,33,44,46,48,50],whereas:9,wherein:39,wherev:[7,8,15,28,36,48,51],whether:[1,12,21,23,26,32,35,36,45,51,59],which:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,56,57,58,59,60,61,62,63],while_block:24,white:16,whitespac:[8,9,13,14,23,50,57],who:[3,4,15,21,32,50,54,55,62],whole:[1,8,15,34,37,48,57],wholesal:48,whom:[32,50],whose:[8,10,11,12,15,25,26,28,35,36,42,43,44,46,47,48,49,50,51,52],why:[0,3,6,8,9,15,20,25,26,27,29,31,32,34,44,46,48,50,56,59,63],wide:[8,12,33,37,44,47,48,49,50],wider:48,width:[42,43,45,47],wildcard:49,wildli:10,win32:52,win:1,window:[1,3,4,5,47,49],windowspath:49,wisdom:50,wise:[32,37],withhold:27,within:[3,5,7,8,9,10,13,14,15,16,19,22,24,25,27,28,29,31,32,33,35,36,37,40,42,43,44,47,48,49,50,51,54,57,58,62],within_margin_percentag:21,without:[0,4,5,7,8,9,13,14,15,16,19,22,28,31,32,34,35,47,48,49,50,51,52,57,59],won:[45,50],wonder:[3,8,46],wont:46,woof:40,word:[1,2,8,11,14,15,20,43,48,52],word_collect:15,word_distr:11,words_with_o:15,work:[2,3,4,5,8,10,12,14,15,23,24,26,27,28,31,32,34,36,37,38,42,44,45,46,47,48,50,52,54,55,56,57,58,59,60,61,62,63],workflow:50,world:[1,8,32,41,43,46,48,51,52],worldwid:48,worri:[4,8,11,12,19,29,37,41,49,52],worst:[10,12],worth:50,worthwhil:[6,26,43,47,50],would:[3,5,6,8,9,10,11,12,13,14,17,18,19,20,21,22,24,25,29,31,32,35,36,37,40,44,45,46,47,48,49,50,51,52,54,55,58,60],wow:25,wrap:[3,50,52],write:[1,2,3,5,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,25,26,29,32,34,35,36,38,41,42,43,45,48,52,53,54,55,56,57,59,62,63],writelin:49,written:[1,3,4,5,6,8,9,10,15,16,22,37,45,48,49,50,51,54,55,58,60],wrong:[1,9,12,14,22],wrote:[10,22,42,45,46,51,52],www:50,x_0:32,x_1:32,x_1d:32,x_i:37,x_it:15,x_left:47,x_norm:32,x_right:47,x_sqrd_sum:32,x_val:18,x_y_prod:32,x_y_sqrd:32,xarrai:[27,59],xmax:35,xmin:35,y_0:32,y_1:32,y_gen:18,y_sqrd_sum:32,year:[5,8,51,54,55],yerr:47,yes:50,yet:[1,8,10,22,25,41,52],yield:[12,15,18,26,36,49,50,52],you:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,26,27,28,29,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47,48,49,50,51,52,56,57,58,59,60,62],your:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,16,17,19,20,21,22,25,26,27,31,35,36,38,40,41,43,45,46,47,49,50,51,52,54,56,57,62],your_usernam:4,yourself:[1,2,4,6,8,22,28,35,47,49,50,56],zero:[8,9,14,15,20,25,45,47,50,51,59],zerodivisionerror:[8,9,21],zeros_lik:32,zip:[12,18,22,36,48],zoe:12,zone:[54,55],zoom:47,zordon:8},titles:["Exercises","Introducing the Python Programming Language","Setting Up a Development Environment","An Informal Introduction to Python","Installing Python","Jupyter Notebooks","Doing Numerical Work in Python","A Quick Guide to Formatting","Basic Object Types","Conditional Statements","Data Structures (Part I): Introduction","Data Structures (Part III): Sets & the Collections Module","Data Structures (Part II): Dictionaries","For-Loops and While-Loops","Basics of Functions","Generators & Comprehension Expressions","Introducing Control Flow","Iterables","Python\u2019s \u201cItertools\u201d","Difference Fanout","Encode as String","Within Margin Percentage","Merging Two Dictionaries","Is Palindrome","Scope","Sequence Types","Variables & Assignment","Accessing Data Along Multiple Dimensions in an Array","Advanced Indexing","Iterating Over Arrays & Array-Traversal Order","Basic Array Attributes","Introducing Basic and Advanced Indexing","Array Broadcasting","Functions for Creating NumPy Arrays","Introducing the ND-array","Playing Darts and Estimating Pi","Measuring the Accuracy of a Classification Model","\u201cVectorized\u201d Operations: Optimized Computations on NumPy Arrays","Applications of Object Oriented Programming","A Brief Summary of Terms and Concepts","Defining a New Class of Object","Instances of a Class","Inheritance","Introduction to Object Oriented Programming","Methods","Object Oriented Programming","Special Methods","Matplotlib","Import: Modules and Packages","Working with Files","Writing Good Code","Introduction to Testing","The pytest Framework","Changelog","Python Like You Mean It","Python Like You Mean It","Module 1: Getting Started with Python","Module 2: The Essentials of Python","Module 2: Problems","Module 3: The Essentials of NumPy","Module 3: Problems","Module 4: Object Oriented Programming","Module 5: Odds and Ends","Module 6: Testing Your Code"],titleterms:{"boolean":[8,9,28],"break":13,"class":[40,41,43,44,46],"default":[11,14],"float":8,"function":[12,14,17,27,33,37],"import":[43,48],"new":[40,53],"return":14,"short":9,"static":44,"while":13,Adding:12,Are:12,Axes:[32,47],Being:50,Doing:[0,6],For:[13,32,50],IDE:52,IDEs:2,One:[22,27],The:[8,11,14,15,32,40,44,47,50,51,52,57,59],Uses:16,Using:[5,15,31,32,33,37,50],Will:2,__init__:41,about:[54,55],absolut:[48,50],access:27,accommod:14,accuraci:36,act:17,add:45,advanc:[28,31,32],algebra:37,algorithm:10,along:27,anaconda:4,anatomi:51,ani:50,applic:[32,38],arang:33,arbitrari:[14,22],arg:50,argument:[14,37,44],arithmet:0,arrai:[27,28,29,30,31,32,33,34,37,49],assert:[51,52],assign:[8,26,28,31],attribut:[30,40,41],augment:[8,28,31],axi:37,basic:[8,12,14,28,30,31,37,51],benefit:31,beyond:47,binari:37,bool:9,bound:25,brief:[4,39],broadcast:32,buggi:22,callabl:50,can:[8,12],cell:5,chain:15,challeng:22,changelog:53,check:0,circuit:9,classif:36,claus:13,code:[5,50,51,52,63],collect:11,column:29,combin:28,comparison:9,complex:[8,10,12],comprehens:[8,9,11,12,13,14,15,17,18,19,25,26,27,28,31,32,37,40,41,44,45,47,48,49,50,51,52],comput:[4,37],concept:39,conclus:37,conda:[4,48],condit:9,constant:33,construct:[0,12],consum:15,contain:46,content:53,continu:13,contributor:[54,55],control:16,convent:50,correct:22,counter:11,creat:[5,11,15,33,41,46,47,52],cut:51,dabbl:3,dart:35,data:[0,10,11,12,27,31,33],decor:52,def:14,defin:[40,41,45],definit:40,delimit:16,dequ:11,describ:10,develop:2,dict:50,dictionari:[11,12,22],did:4,differ:19,difference_fanout:19,dimens:[27,32],dimension:[27,28,31,37],displai:47,distanc:32,document:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50,51,52],doe:1,easi:[54,55],elif:9,ellipsi:31,els:[9,13],encod:20,end:[6,62],enhanc:52,enrich:52,enumer:17,environ:[2,4],essenti:[8,57,59],estim:35,exampl:[5,49],exercis:[0,8,9,13,14,15,17,25,26,47,48],express:[9,15],extend:22,extens:19,extra:22,familiar:5,fanout:19,fewer:27,figur:47,file:49,first:51,fixtur:52,flow:16,fly:15,form:40,format:[7,8],framework:52,from:33,gener:[15,22,40],get:56,github:[54,55],given:12,glob:49,good:50,googl:50,grade:0,guid:[7,50],handl:[22,25],hint:50,how:29,ident:41,iii:11,imag:47,immut:26,improv:8,indent:50,index:[25,27,28,31],indic:[25,27,54],inform:3,inherit:[42,45],inlin:[9,14],input:22,insert:32,inspect:12,instal:[1,4,48],instanc:[41,44],integ:[8,27,28,31],integr:2,interfac:46,interpret:1,intra:48,introduc:[1,8,15,16,25,27,31,34],introduct:[3,4,10,43,51],isn:[54,55],iter:[15,17,29],itertool:18,join:33,jupyt:[5,47],just:4,kei:[12,50],keyword:[14,37],lab:5,languag:[1,5],learn:2,level:41,like:[46,54,55],linear:37,link:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50,51,52],linspac:33,list:[0,3,8,10,15,19,38,50],liter:50,load:49,logic:[8,9,37],loop:[13,19,32],major:29,manag:48,manipul:27,map:12,margin:21,markdown:5,math:8,mathemat:[37,46],matplotlib:47,mean:[1,54,55],measur:36,merg:22,mess:3,method:[41,44,46],minor:22,mode:49,model:36,modul:[8,11,48,50,56,57,58,59,60,61,62,63],more:12,multi:37,multipl:[14,26,27],mutabl:26,mutat:8,name:[11,14,26,50],neg:27,nest:15,newaxi:[31,32],next:15,non:9,none:[8,50],notat:8,note:43,notebook:[5,47],noth:50,numba:6,number:[3,8,14,22],numer:[6,8,12],numpi:[6,31,33,37,49,50,59],object:[8,9,14,26,31,32,38,40,41,43,45,46,47,49,61],odd:62,offici:[8,9,11,12,13,14,15,17,18,24,25,27,28,29,30,31,32,33,34,37,40,42,43,46,47,48,49,50,51,52],ones:33,open:49,oper:[0,8,9,11,31,37,45,46],optim:[22,32,37],option:50,order:[12,29],organ:52,orient:[38,43,45,61],other:5,our:[51,52],out:[25,31,51],output:50,over:[15,29],overload:45,own:[15,48],packag:[48,52],pairwis:32,palindrom:23,parameter:52,part:[10,11,12],path:49,pathlib:49,pep8:50,percentag:21,perform:31,pickl:49,pip:48,pitfal:13,place:[28,31],plai:[3,35],plot:47,plymi:[54,55],point:8,popul:52,posit:14,potenti:13,precis:[8,12],problem:[22,35,58,60],produc:31,program:[1,38,43,45,61],purpos:[],pyplot:47,pytest:52,python:[0,1,3,4,6,8,16,18,33,48,49,50,52,54,55,56,57],pythonpath:48,quack:50,quick:7,radd:45,random:33,rang:15,read:[8,9,11,12,13,14,15,17,18,25,26,27,28,31,32,35,37,40,41,44,45,47,48,49,50,51,52],readabl:8,recommend:2,referenc:26,rel:48,relev:35,remark:6,represent:46,reshap:27,retriev:12,risk:31,row:29,rule:32,run:[5,52],sampl:33,save:[47,49],scheme:28,scientif:8,scope:[16,24],scratch:[],script:1,self:44,sequenc:[8,25,33],sequenti:[10,33,37],server:5,set:[2,11,50],shadow:24,shop:38,should:51,shouldn:[54,55],simpl:[0,22,32],site:48,size:32,slice:[0,25,27,31],solut:[8,9,11,12,13,14,15,17,18,19,20,21,22,23,25,26,27,28,31,32,35,36,37,40,41,44,45,47,48,49,50,51,52],sourc:[51,52],space:50,special:46,specifi:[14,31,33,37,49],start:56,statement:[8,9,14,48,51],store:[12,15],string:[0,3,8,20,46],structur:[10,11,12],studio:5,style:50,subplot:47,suit:52,summari:[1,6,8,39,42],suppli:27,support:5,syntax:52,tabl:54,term:39,terminolog:43,test:[51,52,63],text:49,textbook:[54,55],than:27,thi:[4,54,55],time:12,tip:[23,35],togeth:33,too:[54,55],travers:29,trick:17,truth:9,tupl:[10,11,15,25,31,50],two:[22,27],type:[0,8,25,26,33,43,50],unari:37,underli:31,understand:[8,37],union:50,unoptim:32,unpack:17,unvector:[35,36],using:[15,19],util:[32,52],valid:26,valu:[9,12,14,50],variabl:[24,26],variou:0,vector:[35,36,37],version:0,via:28,view:31,visual:5,warn:12,what:[1,2,4,12,50,54,55],whitespac:16,why:[1,51],within:[21,52],word:12,work:[6,17,25,40,49,51],write:[49,50,51],you:[2,54,55],your:[15,48,63],yourself:5,zero:[22,27,33]}}) \ No newline at end of file