primeiro commit com exercicios de Exercism realizados até esta data
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"authors": [
|
||||
"BethanyG"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lasagna.py"
|
||||
],
|
||||
"test": [
|
||||
"lasagna_test.py"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.py"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"csharp/lucians-luscious-lasagna",
|
||||
"ruby/lasagna"
|
||||
],
|
||||
"icon": "lasagna",
|
||||
"blurb": "Learn the basics of Python by cooking Guido's Gorgeous Lasagna."
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"track":"python","exercise":"guidos-gorgeous-lasagna","id":"f936c8fd62ae46d19a8298f527f1298b","url":"https://exercism.org/tracks/python/exercises/guidos-gorgeous-lasagna","handle":"sanctushck","is_requester":true,"auto_approve":false}
|
||||
@@ -0,0 +1,130 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
We use [pytest][pytest: Getting Started Guide] as our website test runner.
|
||||
You will need to install `pytest` on your development machine if you want to run tests for the Python track locally.
|
||||
You should also install the following `pytest` plugins:
|
||||
|
||||
- [pytest-cache][pytest-cache]
|
||||
- [pytest-subtests][pytest-subtests]
|
||||
|
||||
Extended information can be found in our website [Python testing guide][Python track tests page].
|
||||
|
||||
|
||||
### Running Tests
|
||||
|
||||
To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_).
|
||||
Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded.
|
||||
|
||||
Linux/MacOS
|
||||
```bash
|
||||
$ cd {path/to/exercise-folder-location}
|
||||
```
|
||||
|
||||
Windows
|
||||
```powershell
|
||||
PS C:\Users\foobar> cd {path\to\exercise-folder-location}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file:
|
||||
|
||||
Linux/MacOS
|
||||
```bash
|
||||
$ python3 -m pytest -o markers=task {exercise_test.py}
|
||||
==================== 7 passed in 0.08s ====================
|
||||
```
|
||||
|
||||
Windows
|
||||
```powershell
|
||||
PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py}
|
||||
==================== 7 passed in 0.08s ====================
|
||||
```
|
||||
|
||||
|
||||
### Common options
|
||||
- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_)
|
||||
- `-v` : enable verbose output.
|
||||
- `-x` : stop running tests on first failure.
|
||||
- `--ff` : run failures from previous test before running other test cases.
|
||||
|
||||
For additional options, use `python3 -m pytest -h` or `py -m pytest -h`.
|
||||
|
||||
|
||||
### Fixing warnings
|
||||
|
||||
If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax:
|
||||
|
||||
```bash
|
||||
PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html
|
||||
```
|
||||
|
||||
To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file.
|
||||
We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini].
|
||||
|
||||
You can also create your own `pytest.ini` file with the following content:
|
||||
|
||||
```ini
|
||||
[pytest]
|
||||
markers =
|
||||
task: A concept exercise task.
|
||||
```
|
||||
|
||||
Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings.
|
||||
More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers].
|
||||
|
||||
Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats].
|
||||
|
||||
|
||||
### Extending your IDE or Code Editor
|
||||
|
||||
Many IDEs and code editors have built-in support for using `pytest` and other code quality tools.
|
||||
Some community-sourced options can be found on our [Python track tools page][Python track tools page].
|
||||
|
||||
[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html
|
||||
[Python track tools page]: https://exercism.org/docs/tracks/python/tools
|
||||
[Python track tests page]: https://exercism.org/docs/tracks/python/tests
|
||||
[pytest-cache]:http://pythonhosted.org/pytest-cache/
|
||||
[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests
|
||||
[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini
|
||||
[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats
|
||||
[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks
|
||||
[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit lasagna.py` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Python track's documentation](https://exercism.org/docs/tracks/python)
|
||||
- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Below are some resources for getting help if you run into trouble:
|
||||
|
||||
- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources.
|
||||
- [The Exercism Community on Discord](https://exercism.org/r/discord)
|
||||
- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community.
|
||||
- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners.
|
||||
- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done.
|
||||
- [Python Community Forums](https://discuss.python.org/)
|
||||
- [Free Code Camp Community Forums](https://forum.freecodecamp.org/)
|
||||
- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help)
|
||||
- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually.
|
||||
|
||||
Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already.
|
||||
If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- [The Python Tutorial][the python tutorial] can be a great introduction.
|
||||
- [PEP 8][pep8] is the Python code style guide.
|
||||
- [PEP 257][PEP257] details Python docstring conventions.
|
||||
- [Numbers][numbers] in Python can be integers, floats, or complex.
|
||||
|
||||
|
||||
## 1. Define expected bake time in minutes
|
||||
|
||||
- You need to [name][naming] a [constant][constants], and [assign][assignment] it an [integer][numbers] value.
|
||||
This constant should be the first thing after the docstring that is at the top of the file.
|
||||
Remember to remove the #TODO comment after defining the constant.
|
||||
|
||||
## 2. Calculate remaining bake time in minutes
|
||||
|
||||
- You need to define a [function][defining functions] with a single parameter representing the time elapsed so far.
|
||||
- Use the [mathematical operator for subtraction][numbers] to subtract values.
|
||||
- This function should [return a value][return].
|
||||
|
||||
## 3. Calculate preparation time in minutes
|
||||
|
||||
- You need to define a [function][defining functions] with a single parameter representing the number of layers.
|
||||
- Use the [mathematical operator for multiplication][numbers] to multiply values.
|
||||
- You could define an extra _constant_ for the time in minutes per layer rather than using a "magic number" in your code.
|
||||
- This function should [return a value][return].
|
||||
|
||||
## 4. Calculate total elapsed cooking time (prep + bake) in minutes
|
||||
|
||||
- You need to define a [function][defining functions] with two parameters.
|
||||
- Remember: you can always _call_ a function you've defined previously.
|
||||
- You can use the [mathematical operator for addition][python as a calculator] to sum values.
|
||||
- This function should [return a value][return].
|
||||
|
||||
## 5. Update the recipe with notes
|
||||
|
||||
- Clearly [commenting][comments] and [documenting][docstrings] your code according to [PEP257][pep257] is always recommended.
|
||||
|
||||
[assignment]: https://docs.python.org/3/reference/simple_stmts.html#grammar-token-assignment-stmt
|
||||
[comments]: https://realpython.com/python-comments-guide/
|
||||
[constants]: https://stackoverflow.com/a/2682752
|
||||
[defining functions]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions
|
||||
[docstrings]: https://docs.python.org/3/tutorial/controlflow.html#tut-docstrings
|
||||
[naming]: https://realpython.com/python-variables/
|
||||
[numbers]: https://docs.python.org/3/tutorial/introduction.html#numbers
|
||||
[pep257]: https://www.python.org/dev/peps/pep-0257/
|
||||
[python as a calculator]: https://docs.python.org/3/tutorial/introduction.html#using-python-as-a-calculator
|
||||
[return]: https://docs.python.org/3/reference/simple_stmts.html#return
|
||||
[the python tutorial]: https://docs.python.org/3/tutorial/introduction.html
|
||||
@@ -0,0 +1,359 @@
|
||||
# Guido's Gorgeous Lasagna
|
||||
|
||||
Welcome to Guido's Gorgeous Lasagna on Exercism's Python Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
Python is a [dynamic and strongly][dynamic typing in python] typed programming language.
|
||||
It employs both [duck typing][duck typing] and [gradual typing][gradual typing] via [type hints][type hints].
|
||||
|
||||
While Python supports many different programming _styles_, internally **everything in Python is an [object][everythings an object]**.
|
||||
This includes numbers, strings, lists, and even functions.
|
||||
|
||||
We'll dig more into what all of that means as we continue through the track.
|
||||
|
||||
This first exercise introduces 4 major Python language features:
|
||||
1. Name Assignment (_variables and constants_),
|
||||
2. Functions (_the `def` keyword and the `return` keyword_),
|
||||
3. Comments, and
|
||||
4. Docstrings.
|
||||
|
||||
<br>
|
||||
|
||||
~~~~exercism/note
|
||||
|
||||
In general, content, tests, and analyzer tooling for the Python track follow the style conventions outlined in [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/) for Python code style, with the additional (strong) suggestion that there be no single letter variable names.
|
||||
|
||||
On the Python track, [variables][variables] are always written in [`snake_case`][snake case], and constants in `SCREAMING_SNAKE_CASE`.
|
||||
|
||||
[variables]: https://realpython.com/python-variables/
|
||||
[snake case]: https://en.wikipedia.org/wiki/Snake_case
|
||||
~~~~
|
||||
|
||||
<br>
|
||||
|
||||
## Name Assignment (Variables & Constants)
|
||||
|
||||
Programmers can bind [_names_][facts-and-myths-about-python-names] (also called _variables_) to any type of object using the assignment `=` operator: `<name> = <value>`.
|
||||
A name can be reassigned (or re-bound) to different values (different object types) over its lifetime.
|
||||
|
||||
|
||||
```python
|
||||
>>> my_first_variable = 1 #<-- my_first_variable bound to an integer object of value one.
|
||||
>>> my_first_variable = 2 #<-- my_first_variable re-assigned to integer value 2.
|
||||
|
||||
>>> print(type(my_first_variable))
|
||||
<class 'int'>
|
||||
|
||||
>>> print(my_first_variable)
|
||||
2
|
||||
|
||||
>>> my_first_variable = "Now, I'm a string." #<-- You may re-bind a name to a different object type and value.
|
||||
>>> print(type(my_first_variable))
|
||||
<class 'str'>
|
||||
|
||||
>>> print(my_first_variable)
|
||||
"Now, I'm a string." #<-- Strings can be declared using single or double quote marks.
|
||||
```
|
||||
|
||||
|
||||
### Constants
|
||||
|
||||
Constants are names meant to be assigned only once in a program.
|
||||
They should be defined at a [module][module] (file) level, and are typically visible to all functions and classes in the program.
|
||||
Using `SCREAMING_SNAKE_CASE` signals that the name should not be re-assigned, or its value mutated.
|
||||
|
||||
|
||||
## Functions
|
||||
|
||||
The `def` keyword begins a [function definition][function definition].
|
||||
Each function can have zero or more formal [parameters][parameters] in `()` parenthesis, followed by a `:` colon.
|
||||
Statements for the _body_ of the function begin on the line following `def` and must be _indented in a block_.
|
||||
|
||||
|
||||
```python
|
||||
# The body of a function is indented by 2 spaces, & prints the sum of the numbers.
|
||||
def add_two_numbers(number_one, number_two):
|
||||
total = number_one + number_two
|
||||
print(total)
|
||||
|
||||
>>> add_two_numbers(3, 4)
|
||||
7
|
||||
|
||||
|
||||
# Inconsistent indentation in your code blocks will raise an error.
|
||||
>>> def add_three_numbers_misformatted(number_one, number_two, number_three):
|
||||
... result = number_one + number_two + number_three # This was indented by 4 spaces.
|
||||
... print(result) #this was only indented by 3 spaces
|
||||
...
|
||||
...
|
||||
File "<stdin>", line 3
|
||||
print(result)
|
||||
^
|
||||
IndentationError: unindent does not match any outer indentation level
|
||||
```
|
||||
|
||||
|
||||
Functions _explicitly_ return a value or object via the [`return`][return] keyword:
|
||||
|
||||
|
||||
```python
|
||||
# Function definition on first line, explicit return used on final line.
|
||||
>>> def add_two_numbers(number_one, number_two):
|
||||
return number_one + number_two
|
||||
|
||||
|
||||
# Calling the function in the Python terminal returns the sum of the numbers.
|
||||
>>> add_two_numbers(3, 4)
|
||||
7
|
||||
|
||||
# Assigning the function call to a variable and printing it
|
||||
# will also return the value.
|
||||
>>> sum_with_return = add_two_numbers(5, 6)
|
||||
>>> print(sum_with_return)
|
||||
11
|
||||
```
|
||||
|
||||
|
||||
Functions that do not have an _explicit_ `return` expression will _implicitly_ return the [`None`][none] object.
|
||||
This means that if you do not use `return` in a function, Python will return the `None` object for you.
|
||||
The details of `None` will be covered in a later exercise.
|
||||
For the purposes of this exercise and explanation, `None` is a placeholder that represents nothing, or null:
|
||||
|
||||
|
||||
```python
|
||||
# This function does not have an explicit return.
|
||||
def add_two_numbers(number_one, number_two):
|
||||
result = number_one + number_two
|
||||
|
||||
|
||||
# Calling the function in the Python terminal appears
|
||||
# to not return anything at all.
|
||||
>>> add_two_numbers(5, 7)
|
||||
>>>
|
||||
|
||||
|
||||
# Using print() with the function call shows that
|
||||
# the function is actually returning the **None** object.
|
||||
>>> print(add_two_numbers(5, 7))
|
||||
None
|
||||
|
||||
|
||||
# Assigning the function call to a variable and printing
|
||||
# the variable will also show None.
|
||||
>>> sum_without_return = add_two_numbers(5, 6)
|
||||
>>> print(sum_without_return)
|
||||
None
|
||||
```
|
||||
|
||||
|
||||
### Calling Functions
|
||||
|
||||
Functions are [_called_][calls] or invoked using their name followed by `()`.
|
||||
Dot (`.`) notation is used for calling functions defined inside a class or module.
|
||||
|
||||
```python
|
||||
>>> def number_to_the_power_of(number_one, number_two):
|
||||
return number_one ** number_two
|
||||
...
|
||||
|
||||
>>> number_to_the_power_of(3,3) # Invoking the function with the arguments 3 and 3.
|
||||
27
|
||||
|
||||
|
||||
# A mismatch between the number of parameters and the number of arguments will raise an error.
|
||||
>>> number_to_the_power_of(4,)
|
||||
...
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: number_to_the_power_of() missing 1 required positional argument: 'number_two'
|
||||
|
||||
|
||||
# Calling methods or functions in classes and modules.
|
||||
>>> start_text = "my silly sentence for examples."
|
||||
>>> str.upper(start_text) # Calling the upper() method for the built-in str class.
|
||||
"MY SILLY SENTENCE FOR EXAMPLES."
|
||||
|
||||
# Importing the math module
|
||||
import math
|
||||
|
||||
>>> math.pow(2,4) # Calling the pow() function from the math module
|
||||
>>> 16.0
|
||||
```
|
||||
|
||||
|
||||
## Comments
|
||||
|
||||
[Comments][comments] in Python start with a `#` that is not part of a string, and end at line termination.
|
||||
Unlike many other programming languages, Python **does not support** multi-line comment marks.
|
||||
Each line of a comment block must start with the `#` character.
|
||||
|
||||
|
||||
## Docstrings
|
||||
|
||||
The first statement of a function body can optionally be a [_docstring_][docstring], which concisely summarizes the function or object's purpose.
|
||||
Docstrings are declared using triple double quotes (""") indented at the same level as the code block:
|
||||
|
||||
|
||||
```python
|
||||
|
||||
# An example from PEP257 of a multi-line docstring.
|
||||
def complex(real=0.0, imag=0.0):
|
||||
"""Form a complex number.
|
||||
|
||||
Keyword arguments:
|
||||
real -- the real part (default 0.0)
|
||||
imag -- the imaginary part (default 0.0)
|
||||
"""
|
||||
|
||||
if imag == 0.0 and real == 0.0:
|
||||
return complex_zero
|
||||
|
||||
```
|
||||
|
||||
|
||||
Docstrings are read by automated documentation tools and are returned by calling the special attribute `.__doc__` on the function, method, or class name.
|
||||
Docstring conventions are laid out in [PEP257][pep257].
|
||||
|
||||
Docstrings can also function as [lightweight unit tests][doctests], which will be covered in a later exercise.
|
||||
|
||||
|
||||
```python
|
||||
# An example on a user-defined function.
|
||||
>>> def number_to_the_power_of(number_one, number_two):
|
||||
"""Raise a number to an arbitrary power.
|
||||
|
||||
:param number_one: int the base number.
|
||||
:param number_two: int the power to raise the base number to.
|
||||
:return: int - number raised to power of second number
|
||||
|
||||
Takes number_one and raises it to the power of number_two, returning the result.
|
||||
"""
|
||||
|
||||
return number_one ** number_two
|
||||
...
|
||||
|
||||
# Calling the .__doc__ attribute of the function and printing the result.
|
||||
>>> print(number_to_the_power_of.__doc__)
|
||||
Raise a number to an arbitrary power.
|
||||
|
||||
:param number_one: int the base number.
|
||||
:param number_two: int the power to raise the base number to.
|
||||
:return: int - number raised to power of second number
|
||||
|
||||
Takes number_one and raises it to the power of number_two, returning the result.
|
||||
```
|
||||
|
||||
[calls]: https://docs.python.org/3/reference/expressions.html#calls
|
||||
[comments]: https://realpython.com/python-comments-guide/#python-commenting-basics
|
||||
[docstring]: https://docs.python.org/3/tutorial/controlflow.html#tut-docstrings
|
||||
[doctests]: https://docs.python.org/3/library/doctest.html
|
||||
[duck typing]: https://en.wikipedia.org/wiki/Duck_typing
|
||||
[dynamic typing in python]: https://stackoverflow.com/questions/11328920/is-python-strongly-typed
|
||||
[everythings an object]: https://docs.python.org/3/reference/datamodel.html
|
||||
[facts-and-myths-about-python-names]: https://nedbatchelder.com/text/names.html
|
||||
[function definition]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions
|
||||
[gradual typing]: https://en.wikipedia.org/wiki/Gradual_typing
|
||||
[module]: https://docs.python.org/3/tutorial/modules.html
|
||||
[none]: https://docs.python.org/3/library/constants.html
|
||||
[parameters]: https://docs.python.org/3/glossary.html#term-parameter
|
||||
[pep257]: https://www.python.org/dev/peps/pep-0257/
|
||||
[return]: https://docs.python.org/3/reference/simple_stmts.html#return
|
||||
[type hints]: https://docs.python.org/3/library/typing.html
|
||||
|
||||
## Instructions
|
||||
|
||||
You're going to write some code to help you cook a gorgeous lasagna from your favorite cookbook.
|
||||
|
||||
You have five tasks, all related to cooking your recipe.
|
||||
|
||||
<br>
|
||||
|
||||
~~~~exercism/note
|
||||
We have started the first function definition for you in the stub file, but you will need to write the remaining function definitions yourself.
|
||||
You will also need to define any constants yourself.
|
||||
Read the #TODO comment lines in the stub file carefully.
|
||||
Once you are done with a task, remove the TODO comment.
|
||||
~~~~
|
||||
|
||||
<br>
|
||||
|
||||
## 1. Define expected bake time in minutes as a constant
|
||||
|
||||
Define the `EXPECTED_BAKE_TIME` [constant][constants] that represents how many minutes the lasagna should bake in the oven.
|
||||
According to your cookbook, the Lasagna should be in the oven for 40 minutes:
|
||||
|
||||
```python
|
||||
>>> print(EXPECTED_BAKE_TIME)
|
||||
40
|
||||
```
|
||||
|
||||
## 2. Calculate remaining bake time in minutes
|
||||
|
||||
Complete the `bake_time_remaining()` function that takes the actual minutes the lasagna has been in the oven as an argument and returns how many minutes the lasagna still needs to bake based on the `EXPECTED_BAKE_TIME` constant.
|
||||
|
||||
```python
|
||||
>>> bake_time_remaining(30)
|
||||
10
|
||||
```
|
||||
|
||||
|
||||
## 3. Calculate preparation time in minutes
|
||||
|
||||
Define the `preparation_time_in_minutes()` [function][functions] that takes the `number_of_layers` you want to add to the lasagna as an argument and returns how many minutes you would spend making them.
|
||||
Assume each layer takes 2 minutes to prepare.
|
||||
|
||||
```python
|
||||
>>> def preparation_time_in_minutes(number_of_layers):
|
||||
...
|
||||
...
|
||||
|
||||
>>> preparation_time_in_minutes(2)
|
||||
4
|
||||
```
|
||||
|
||||
|
||||
## 4. Calculate total elapsed cooking time (prep + bake) in minutes
|
||||
|
||||
Define the `elapsed_time_in_minutes()` function that takes two parameters as arguments: `number_of_layers` (_the number of layers added to the lasagna_) and `elapsed_bake_time` (_the number of minutes the lasagna has been baking in the oven_).
|
||||
This function should return the total number of minutes you have been cooking, or the sum of your preparation time and the time the lasagna has already spent baking in the oven.
|
||||
|
||||
```python
|
||||
>>> def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time):
|
||||
...
|
||||
...
|
||||
|
||||
>>> elapsed_time_in_minutes(3, 20)
|
||||
26
|
||||
```
|
||||
|
||||
|
||||
## 5. Update the recipe with notes
|
||||
|
||||
Go back through the recipe, adding "notes" in the form of [function docstrings][function-docstrings].
|
||||
|
||||
```python
|
||||
def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time):
|
||||
"""Calculate the elapsed cooking time.
|
||||
|
||||
:param number_of_layers: int - the number of layers in the lasagna.
|
||||
:param elapsed_bake_time: int - elapsed cooking time.
|
||||
:return: int - total time elapsed (in minutes) preparing and cooking.
|
||||
|
||||
This function takes two integers representing the number of lasagna layers and the
|
||||
time already spent baking and calculates the total elapsed minutes spent cooking the
|
||||
lasagna.
|
||||
"""
|
||||
```
|
||||
|
||||
[constants]: https://stackoverflow.com/a/2682752
|
||||
[functions]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions
|
||||
[function-docstrings]: https://docs.python.org/3/tutorial/controlflow.html#documentation-strings
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @BethanyG
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,67 @@
|
||||
"""Functions used in preparing Guido's gorgeous lasagna.
|
||||
|
||||
Learn about Guido, the creator of the Python language:
|
||||
https://en.wikipedia.org/wiki/Guido_van_Rossum
|
||||
|
||||
This is a module docstring, used to describe the functionality
|
||||
of a module and its functions and/or classes.
|
||||
"""
|
||||
|
||||
# TODO: define the 'EXPECTED_BAKE_TIME' constant below.
|
||||
EXPECTED_BAKE_TIME = 40
|
||||
PREPARATION_TIME = 2
|
||||
|
||||
# TODO: Remove 'pass' and complete the 'bake_time_remaining()' function below.
|
||||
|
||||
|
||||
def bake_time_remaining(elapsed_bake_time: int) -> int:
|
||||
"""Calculate the bake time remaining.
|
||||
|
||||
:param elapsed_bake_time: int - baking time already elapsed.
|
||||
:return: int - remaining bake time (in minutes) derived from 'EXPECTED_BAKE_TIME'.
|
||||
|
||||
Function that takes the actual minutes the lasagna has been in the oven as
|
||||
an argument and returns how many minutes the lasagna still needs to bake
|
||||
based on the `EXPECTED_BAKE_TIME`.
|
||||
"""
|
||||
return EXPECTED_BAKE_TIME - elapsed_bake_time
|
||||
|
||||
|
||||
# TODO: Define the 'preparation_time_in_minutes()' function below.
|
||||
# You might also consider defining a 'PREPARATION_TIME' constant.
|
||||
# You can do that on the line below the 'EXPECTED_BAKE_TIME' constant.
|
||||
# This will make it easier to do calculations.
|
||||
def preparation_time_in_minutes(number_of_layers: int) -> int:
|
||||
"""Calculate how long will take in minutes to prepare a lasagna with
|
||||
number_of_layers
|
||||
|
||||
:param number_of_layers: int - number of layers in the lasagna
|
||||
:return int - time to make (in minutes) a lasagna with number_of_layers
|
||||
|
||||
Function that takes the number_of_layers you want to add to the lasagna as
|
||||
an argument and returns how many minutes you would spend making them.
|
||||
Assume each layer takes 2 minutes to prepare.
|
||||
"""
|
||||
return number_of_layers * PREPARATION_TIME
|
||||
|
||||
|
||||
# TODO: define the 'elapsed_time_in_minutes()' function below.
|
||||
def elapsed_time_in_minutes(number_of_layers: int, elapsed_bake_time: int) -> int:
|
||||
"""Calculate the total number of minutes you have been cooking (or the sum
|
||||
of your preparation time and the time the lasagna has already spent baking
|
||||
in the oven).
|
||||
|
||||
:param number_of_layers: int - the number of layers added to the lasagna
|
||||
:param elapsed_bake_time: int - the number of minutes the lasagna has been baking in the oven
|
||||
:return: int - total number of minutes you have been cooking
|
||||
|
||||
Function that takes two parameters as arguments: number_of_layers (you want
|
||||
to add to the lasagna) and elapsed_bake_time (number of minutes the lasagna
|
||||
has been baking in the oven). This function returns the total number of
|
||||
minutes you have been cooking
|
||||
"""
|
||||
return preparation_time_in_minutes(number_of_layers) + elapsed_bake_time
|
||||
|
||||
|
||||
# TODO: Remember to go back and add docstrings to all your functions
|
||||
# (you can copy and then alter the one from bake_time_remaining.)
|
||||
@@ -0,0 +1,97 @@
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
# For this first exercise, it is really important to be clear about how we are importing names for tests.
|
||||
# To that end, we are putting a try/catch around imports and throwing specific messages to help students
|
||||
# decode that they need to create and title their constants and functions in a specific way.
|
||||
try:
|
||||
from lasagna import (EXPECTED_BAKE_TIME,
|
||||
bake_time_remaining,
|
||||
preparation_time_in_minutes,
|
||||
elapsed_time_in_minutes)
|
||||
|
||||
# Here, we are separating the constant import errors from the function name import errors
|
||||
except ImportError as import_fail:
|
||||
message = import_fail.args[0].split('(', maxsplit=1)
|
||||
item_name = import_fail.args[0].split()[3]
|
||||
|
||||
if 'EXPECTED_BAKE_TIME' in item_name:
|
||||
# pylint: disable=raise-missing-from
|
||||
raise ImportError(f'\n\nMISSING CONSTANT --> \nWe can not find or import the constant {item_name} in your'
|
||||
" 'lasagna.py' file.\nDid you misname or forget to define it?") from None
|
||||
else:
|
||||
item_name = item_name[:-1] + "()'"
|
||||
# pylint: disable=raise-missing-from
|
||||
raise ImportError("\n\nMISSING FUNCTION --> In your 'lasagna.py' file, we can not find or import the"
|
||||
f' function named {item_name}. \nDid you misname or forget to define it?') from None
|
||||
|
||||
|
||||
# Here begins the formal test cases for the exercise.
|
||||
class LasagnaTest(unittest.TestCase):
|
||||
|
||||
@pytest.mark.task(taskno=1)
|
||||
def test_EXPECTED_BAKE_TIME(self):
|
||||
failure_msg = 'Expected a constant of EXPECTED_BAKE_TIME with a value of 40.'
|
||||
self.assertEqual(EXPECTED_BAKE_TIME, 40, msg=failure_msg)
|
||||
|
||||
@pytest.mark.task(taskno=2)
|
||||
def test_bake_time_remaining(self):
|
||||
input_data = [1, 2, 5, 10, 15, 23, 33, 39]
|
||||
result_data = [39, 38, 35, 30, 25, 17, 7, 1]
|
||||
|
||||
for variant, (time, expected) in enumerate(zip(input_data, result_data), start=1):
|
||||
with self.subTest(f'variation #{variant}', time=time, expected=expected):
|
||||
actual_result = bake_time_remaining(time)
|
||||
failure_msg = (f'Called bake_time_remaining({time}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected} as the remaining bake time.')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=failure_msg)
|
||||
|
||||
@pytest.mark.task(taskno=3)
|
||||
def test_preparation_time_in_minutes(self):
|
||||
input_data = [1, 2, 5, 8, 11, 15]
|
||||
result_data = [2, 4, 10, 16, 22, 30]
|
||||
|
||||
for variant, (layers, expected) in enumerate(zip(input_data, result_data), start=1):
|
||||
with self.subTest(f'variation #{variant}', layers=layers, expected=expected):
|
||||
actual_result = preparation_time_in_minutes(layers)
|
||||
failure_msg = (f'Called preparation_time_in_minutes({layers}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected} as the preparation time.')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=failure_msg)
|
||||
|
||||
@pytest.mark.task(taskno=4)
|
||||
def test_elapsed_time_in_minutes(self):
|
||||
layer_data = (1, 2, 5, 8, 11, 15)
|
||||
time_data = (3, 7, 8, 4, 15, 20)
|
||||
result_data = [5, 11, 18, 20, 37, 50]
|
||||
|
||||
for variant, (layers, time, expected) in enumerate(zip(layer_data, time_data, result_data), start=1):
|
||||
with self.subTest(f'variation #{variant}', layers=layers, time=time, expected=expected):
|
||||
actual_result = elapsed_time_in_minutes(layers, time)
|
||||
failure_msg = (f'Called elapsed_time_in_minutes({layers}, {time}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected} as the elapsed time.')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=failure_msg)
|
||||
|
||||
@pytest.mark.task(taskno=5)
|
||||
def test_docstrings_were_written(self):
|
||||
"""Validate function.__doc__ exists for each function.
|
||||
Check the attribute dictionary of each listed function
|
||||
for the presence of a __doc__ key.
|
||||
|
||||
:return: unexpectedly None error when __doc__ key is missing.
|
||||
"""
|
||||
functions = [bake_time_remaining, preparation_time_in_minutes, elapsed_time_in_minutes]
|
||||
|
||||
for variant, function in enumerate(functions, start=1):
|
||||
with self.subTest(f'variation #{variant}', function=function):
|
||||
actual_result = function.__doc__
|
||||
failure_msg = (f'Called {function.__name__}.__doc__. {actual_result} was returned, '
|
||||
f'but the tests expected a docstring for the {function.__name__} function.')
|
||||
|
||||
# Check that the __doc__ key is populated for the function.
|
||||
self.assertIsNotNone(actual_result, msg=failure_msg)
|
||||
Reference in New Issue
Block a user