Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a title #1757

Open
wants to merge 14 commits into
base: add_timeout
Choose a base branch
from
5 changes: 3 additions & 2 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[flake8]
ignore = E203, E266
inline-quotes = "
ignore = E203, E266, W503, ANN002, ANN003, ANN101, ANN102, ANN401, N807, N818
max-line-length = 79
max-complexity = 18
select = B,C,E,F,W,T4,B9
select = B,C,E,F,W,T4,B9,ANN,Q0,N8,VNE
exclude = venv, tests
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v2

- name: Set Up Python 3.8
- name: Set Up Python 3.10
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: "3.10"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the specified Python version is compatible with your project's dependencies. If your project supports multiple Python versions, consider testing against all of them.


- name: Install pytest and flake8
run: |
Expand Down
86 changes: 77 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# Washing Station

- Read [the guideline](https://github.com/mate-academy/py-task-guideline/blob/main/README.md) before start
Read [the guideline](https://github.com/mate-academy/py-task-guideline/blob/main/README.md) before starting.

You own a car washing station. Washing cost calculation
takes a lot of time, and you decide to automate this
calculation. The washing cost will depend on car comfort
class, car cleanness degree, wash station average rating
and wash station distance from the center of the city.

Create class `Car`, its constructor takes and stores
Create class `Car`, its `__init__` method takes and stores
3 arguments:
1. `comfort_class` - comfort class of a car, from 1 to 7
2. `clean_mark` - car cleanness mark, from very
dirty - 1 to absolutely clean - 10
3. `brand` - brand of the car

Create class `CarWashStation`, its constructor takes and
Create class `CarWashStation`, its `__init__` method takes and
stores 4 arguments:
1. `distance_from_city_center` - how far station from
the city center, from 1.0 to 10.0
Expand All @@ -28,19 +28,85 @@ from 1.0 to 5.0, rounded to 1 decimal
`CarWashStation` should have such methods:
1. `serve_cars` - method, that takes a list of `Car`'s, washes only
cars with `clean_mark` < `clean_power` of wash station
and returns income of CarWashStation for serving this list of Car's,
rounded to 1 decimal
and returns income of `CarWashStation` for serving this list of Car's,
rounded to 1 decimal:

```python
bmw = Car(comfort_class=3, clean_mark=3, brand='BMW')
audi = Car(comfort_class=4, clean_mark=9, brand='Audi')

print(bmw.clean_mark) # 3

wash_station = CarWashStation(
distance_from_city_center=5,
clean_power=6,
average_rating=3.5,
count_of_ratings=6
)

income = wash_station.serve_cars([bmw, audi])

print(income) # 6.3
print(bmw.clean_mark) # 6
```

So, only bmw was washed, because `audi.clean_mark` > `wash_station.clean_power`,
and `bmw.clean_mark` has changed, because we washed it.

If `audi.clean_mark` was below `wash_station.clean_power` then `audi` would have been washed as well
and the income would have raised:

```python
bmw = Car(comfort_class=3, clean_mark=3, brand='BMW')
audi = Car(comfort_class=4, clean_mark=2, brand='Audi')

print(bmw.clean_mark) # 3
print(audi.clean_mark) # 2

wash_station = CarWashStation(
distance_from_city_center=5,
clean_power=6,
average_rating=3.5,
count_of_ratings=6
)

income = wash_station.serve_cars([bmw, audi])

print(income) # 17.5

print(bmw.clean_mark) # 6
print(audi.clean_mark) # 6
```

2. `calculate_washing_price` - method, that calculates cost for a
single car wash,
cost is calculated as: car's comfort class * difference between
wash station's clean power and car's clean mark * car wash station
rating / car wash station
distance to the center of the city, returns number rounded
to 1 decimal
to 1 decimal;
3. `wash_single_car` - method, that washes a single car, so it should
have `clean_mark` equals wash station's `clean_power`, if
`wash_station.clean_power` is greater than `car.clean_mark`
4. `rate_service` - method to add a single rate.
`wash_station.clean_power` is greater than `car.clean_mark`;
4. `rate_service` - method that adds a single rate to the wash station, and based on this single rate
`average_rating` and `count_of_ratings` should be changed:

```python
wash_station = CarWashStation(
distance_from_city_center=6,
clean_power=8,
average_rating=3.9,
count_of_ratings=11
)

print(wash_station.average_rating) # 3.9
print(wash_station.count_of_ratings) # 11

wash_station.rate_service(5)

print(wash_station.average_rating) # 4.0
print(wash_station.count_of_ratings) # 12
```

You can add own methods if you need.

Expand Down Expand Up @@ -76,4 +142,6 @@ ws.rate_service(5)

ws.count_of_ratings == 12
ws.average_rating == 4.0
```
```

### Note: Check your code using this [checklist](checklist.md) before pushing your solution.
80 changes: 80 additions & 0 deletions checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Check Your Code Against the Following Points

## Code Style

1. If you have some long math, you can split it onto additional variables,
or break after binary operations (not before - it cause the W504 errors)

Good example:

```python
fuel_consumption = max_fuel_consumption * height_fuel_consumption_coeficient
estimated_speed = plan_max_speed - wind_awerage_speed * wind_angle_coefisient
estimated_time = distance_to_the_destinatoin / estimated_speed
how_much_fuel_needed = fuel_consumption * estimated_time * overlap_coeficient
```

Good example:

```python
how_much_fuel_needed = (max_fuel_consumption
* height_fuel_consumption_coeficient
* distance_to_the_destinatoin
/ (plan_max_speed
- wind_awerage_speed
* wind_angle_coefisient)
* overlap_coeficient)
```

Bad example:

```python
how_much_fuel_needed = max_fuel_consumption \
* height_fuel_consumption_coeficient \
* distance_to_the_destinatoin / (
plan_max_speed
- wind_awerage_speed
* wind_angle_coefisient
) * overlap_coeficient
```

2. Use descriptive and correct variable names.

Good example:

```python
def get_full_name(first_name: str, last_name: str) -> str:
return f"{first_name} {last_name}"
```

Bad example:
```python
def get_full_name(x: str, y: str) -> str:
return f"{x} {y}"
```

## Clean Code

1. You can avoid else when have return statement.

Good example:

```python
def is_adult(age: int) -> str:
if age >= 18:
return "adult"
return "not an adult"
```

Bad example:

```python
def is_adult(age: int) -> str:
if age >= 18:
return "adult"
else:
return "not an adult"
```

2. Add comments, prints, and functions to check your solution when you write your code.
Don't forget to delete them when you are ready to commit and push your code.
8 changes: 6 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
pytest==6.2.5
flake8==4.0.1
flake8==5.0.4
flake8-annotations==2.9.1
flake8-quotes==3.3.1
flake8-variables-names==0.0.5
pep8-naming==0.13.2
pytest==7.1.3
22 changes: 22 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from unittest.mock import patch
import pytest
import os

from app.main import Car, CarWashStation

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the app.main module exists and contains the Car and CarWashStation classes. If the module or classes are missing, the tests will fail.


Expand Down Expand Up @@ -37,6 +39,12 @@ def test_car_wash_station(cars, wash_station, total_cost):
income = wash_station.serve_cars(cars)
assert income == total_cost, f"Income should equal to {total_cost}"

def test_wash_single_car_is_called():
with patch.object(CarWashStation, 'wash_single_car') as mock_method:
CarWashStation(3, 9, 4, 11).serve_cars([Car(2, 1, "Ford")])
ProgrammerYaroslav marked this conversation as resolved.
Show resolved Hide resolved
assert mock_method.called, "Expected 'wash_single_car' to have " \
"been called inside 'serve_cars' method"


@pytest.mark.parametrize(
"cars,wash_station,cars_clean_marks",
Expand Down Expand Up @@ -101,3 +109,17 @@ def test_rate_service(
f"'count_of_ratings' should equal to {result_num_ratings}, "
f"when initial 'count_of_ratings' was {init_num_ratings}"
)


def test_unnecessary_comment():
if os.path.exists(os.path.join(os.pardir, "app", "main.py")):
main_path = os.path.join(os.pardir, "app", "main.py")
else:
main_path = os.path.join("app", "main.py")

with open(main_path, "r") as main:
main_content = main.read()

assert (
"# write your code here" not in main_content
), "Remove unnecessary comment"
Comment on lines +115 to +125

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test checks for an unnecessary comment in the main.py file. Ensure that the comment # write your code here is not present in the file, as this test will fail if it is.