Skip to content

Commit 0b51fcd

Browse files
committed
feat: settings sketch
1 parent 345847d commit 0b51fcd

File tree

6 files changed

+405
-0
lines changed

6 files changed

+405
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"base_url": "https://www.otodom.pl",
3+
"price": {
4+
"min": 1000,
5+
"max": 5000
6+
},
7+
"province" : "kujawsko-pomorskie",
8+
"city": "torun",
9+
"property_type": "flat",
10+
"sale_or_rent": "rent",
11+
"_comments": {
12+
"property_type": "Can be: 'flat', 'studio', 'house', 'investment', 'room', 'plot', 'venue', 'magazine', 'garage'",
13+
"sale_or_rent": "Can be: 'sale', 'rent'"
14+
}
15+
}

otodom/task_2/sebastian_rydz/src/main.py

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from settings import Settings # noqa: F401
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from enum import Enum
2+
3+
4+
class Defaults:
5+
"""
6+
A class that provides default values for the settings used by the application.
7+
8+
Attributes:
9+
DEFAULT_URL (str): The default base URL for the Otodom website.
10+
DEFAULT_PRICE_MIN (int): The default minimum price for the property.
11+
DEFAULT_PRICE_MAX (int): The default maximum price for the property.
12+
DEFAULT_PROVINCE (str): The default province where the property is located.
13+
DEFAULT_CITY (str): The default city where the property is located.
14+
DEFAULT_DISTRICT (str, optional): The default district of the city.
15+
Defaults to `None`.
16+
DEFAULT_PROPERTY_TYPE (str): The default type of property.
17+
DEFAULT_AUCTION_TYPE (str): The default type of auction.
18+
"""
19+
20+
DEFAULT_URL = "https://www.otodom.pl"
21+
DEFAULT_PRICE_MIN = 0
22+
DEFAULT_PRICE_MAX = 10000000
23+
DEFAULT_PROVINCE = "mazowieckie"
24+
DEFAULT_CITY = "warszawa"
25+
DEFAULT_DISTRICT = None
26+
DEFAULT_PROPERTY_TYPE = "mieszkanie"
27+
DEFAULT_AUCTION_TYPE = "sprzedaz"
28+
29+
30+
class PropertyType(Enum):
31+
FLAT = "mieszkanie"
32+
STUDIO = "kawalerka"
33+
HOUSE = "dom"
34+
INVESTMENT = "inwestycja"
35+
ROOM = "pokoj"
36+
PLOT = "dzialka"
37+
VENUE = "lokal"
38+
MAGAZINE = "haleimagazyny"
39+
GARAGE = "garaz"
40+
41+
42+
class AuctionType(Enum):
43+
SALE = "sprzedaz"
44+
RENT = "wynajem"
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
import json
2+
import logging
3+
4+
from s_types import AuctionType
5+
from s_types import Defaults
6+
from s_types import PropertyType
7+
from utils import get_auction_type
8+
from utils import get_property_type
9+
from utils import replace_polish_characters
10+
11+
AVAILABLE_PROVINCES = [
12+
"dolnoslaskie",
13+
"kujawsko-pomorskie",
14+
"lubelskie",
15+
"lubuskie",
16+
"lodzkie",
17+
"malopolskie",
18+
"mazowieckie",
19+
"opolskie",
20+
"podkarpackie",
21+
"podlaskie",
22+
"pomorskie",
23+
"slaskie",
24+
"swietokrzyskie",
25+
"warminsko-mazurskie",
26+
"wielkopolskie",
27+
"zachodniopomorskie",
28+
]
29+
30+
31+
class Settings:
32+
"""
33+
This class represents the settings for a property search application.
34+
35+
The settings include parameters such as the base URL for web scraping,
36+
price filters, selected province, city, district, and property type.
37+
38+
Attributes:
39+
base_url (str): The base URL for web scraping.
40+
Defaults to the otodom.pl website.
41+
price_min (int): The minimum property price filter. Defaults to 0.
42+
price_max (int): The maximum property price filter. Defaults to 10,000,000.
43+
province (str): The selected province for property search.
44+
Defaults to "mazowieckie".
45+
city (str): The selected city for property search. Defaults to "warszawa".
46+
district (str): The selected district for property search. Defaults to None.
47+
property_type (str): The selected property type for filtering.
48+
Defaults to "mieszkanie".
49+
50+
These default values are defined in the Defaults class.
51+
52+
Example:
53+
To create a Settings object with default values:
54+
>>> settings = Settings()
55+
56+
To access a specific setting:
57+
>>> print(settings.base_url)
58+
"https://www.otodom.pl"
59+
"""
60+
61+
def __init__(self):
62+
"""
63+
Initialize the Settings object by loading the settings from a JSON file.
64+
65+
If the file cannot be loaded, the settings are set to default values.
66+
"""
67+
logging.info("Loading settings")
68+
try:
69+
with open("settings.json", "r", encoding="utf-8") as f:
70+
settings = json.load(f)
71+
self.base_url = self.__init_base_url(settings)
72+
self.price_min, self.price_max = self.__init_price(settings)
73+
self.province = self.__init_province(settings)
74+
self.city = self.__init_city(settings)
75+
self.district = self.__init_district(settings)
76+
self.property_type = self.__init_property_type(settings)
77+
self.auction_type = self.__init_auction_type(settings)
78+
79+
except Exception as e:
80+
logging.warning(
81+
"Settings file not found. Settings are set to default. Error info: %s",
82+
e,
83+
)
84+
self.set_default()
85+
86+
@staticmethod
87+
def __init_base_url(settings: dict) -> str:
88+
"""
89+
Initialize the base URL from the settings dictionary.
90+
91+
If the base URL is not a string or does not start with "https://www.otodom.pl",
92+
a warning message is logged and the default base URL is returned.
93+
94+
:param settings: A dictionary containing the settings
95+
:return: The base URL
96+
"""
97+
base_url = settings.get("base_url")
98+
if not isinstance(base_url, str) or not base_url.startswith(
99+
"https://www.otodom.pl"
100+
):
101+
logging.warning("Base url is not correct. Base url is set to default")
102+
return Defaults.DEFAULT_URL
103+
return base_url
104+
105+
@staticmethod
106+
def __init_price(settings: dict) -> (int, int):
107+
"""
108+
Initialize the minimum and maximum price from the settings dictionary.
109+
110+
If the price is not a dictionary or the minimum and maximum prices
111+
are not integers or are less than 0, a warning message is logged
112+
and the default prices are returned.
113+
114+
:param settings: A dictionary containing the settings
115+
:return: A tuple containing the minimum and maximum price
116+
"""
117+
price = settings.get("price")
118+
logging.info(price)
119+
if not isinstance(price, dict):
120+
logging.warning("Prices is not of dict type. Price is set to default")
121+
return Defaults.DEFAULT_PRICE_MIN, Defaults.DEFAULT_PRICE_MAX
122+
123+
price_min = price.get("min")
124+
price_max = price.get("max")
125+
126+
if not isinstance(price_min, int):
127+
logging.warning("Min price is not of int type. Min price is set to default")
128+
price_min = Defaults.DEFAULT_PRICE_MIN
129+
if not isinstance(price_max, int):
130+
logging.warning("Max price is not of int type. Max price is set to default")
131+
price_max = Defaults.DEFAULT_PRICE_MAX
132+
if price_min < 0 or price_max < 0:
133+
logging.warning("Prices cannot be negative. Prices are set to default")
134+
return Defaults.DEFAULT_PRICE_MIN, Defaults.DEFAULT_PRICE_MAX
135+
if price_min > price_max:
136+
logging.warning(
137+
"Min price cannot be greater than max price. Prices are set to default"
138+
)
139+
return Defaults.DEFAULT_PRICE_MIN, Defaults.DEFAULT_PRICE_MAX
140+
141+
return price_min, price_max
142+
143+
@staticmethod
144+
def __init_province(settings: dict) -> str:
145+
"""
146+
Initialize the province from the settings dictionary.
147+
148+
If the province is not a string or is not in the list of available provinces,
149+
a warning message is logged and the default province is returned.
150+
151+
:param settings: A dictionary containing the settings
152+
:return: The province
153+
"""
154+
province = settings.get("province")
155+
if not isinstance(province, str):
156+
logging.warning("Province is not correct. Province is set to default")
157+
return Defaults.DEFAULT_PROVINCE
158+
province = replace_polish_characters(province)
159+
if province not in AVAILABLE_PROVINCES:
160+
logging.warning("Province is not correct. Province is set to default")
161+
return Defaults.DEFAULT_PROVINCE
162+
return province
163+
164+
@staticmethod
165+
def __init_city(settings: dict) -> str:
166+
"""
167+
Initialize the city from the settings dictionary.
168+
169+
If the city is not a string,
170+
a warning message is logged and the default city is returned.
171+
172+
:param settings: A dictionary containing the settings
173+
:return: The city
174+
"""
175+
city = settings.get("city")
176+
if not isinstance(city, str):
177+
logging.warning("City is not correct. City is set to default")
178+
return Defaults.DEFAULT_CITY
179+
return replace_polish_characters(city)
180+
181+
@staticmethod
182+
def __init_district(settings: dict) -> str:
183+
"""
184+
Initialize the district from the settings dictionary.
185+
186+
If the district is not a string,
187+
a warning message is logged and the default district is returned.
188+
189+
:param settings: A dictionary containing the settings
190+
:return: The district
191+
"""
192+
district = settings.get("district")
193+
if not isinstance(district, str):
194+
logging.warning("District is not correct. District is set to default")
195+
return Defaults.DEFAULT_DISTRICT
196+
return replace_polish_characters(district)
197+
198+
@staticmethod
199+
def __init_property_type(settings: dict) -> PropertyType:
200+
"""
201+
Initialize the property type from the settings dictionary.
202+
203+
If the property type is not a string or is not recognized,
204+
a warning message is logged and the default property type is returned.
205+
206+
:param settings: A dictionary containing the settings
207+
:return: The property type
208+
"""
209+
property_type_str = settings.get("property_type")
210+
if not isinstance(property_type_str, str):
211+
logging.warning(
212+
"Property type is not a string. Property type is set to default"
213+
)
214+
return Defaults.DEFAULT_PROPERTY_TYPE
215+
216+
property_type = get_property_type(property_type_str)
217+
if property_type is None:
218+
logging.warning(
219+
"Property type is not correct. Property type is set to default"
220+
)
221+
return Defaults.DEFAULT_PROPERTY_TYPE
222+
223+
return property_type
224+
225+
@staticmethod
226+
def __init_auction_type(settings: dict) -> AuctionType:
227+
"""
228+
Initialize the auction type from the settings dictionary.
229+
230+
If the auction type is not a string or is not recognized,
231+
a warning message is logged and the default auction type is returned.
232+
233+
:param settings: A dictionary containing the settings
234+
:return: The auction type
235+
"""
236+
auction_type_str = settings.get("auction_type")
237+
if not isinstance(auction_type_str, str):
238+
logging.warning(
239+
"Auction type is not correct. Auction type is set to default"
240+
)
241+
return Defaults.DEFAULT_AUCTION_TYPE
242+
243+
auction_type = get_auction_type(auction_type_str)
244+
if auction_type is None:
245+
logging.warning(
246+
"Auction type is not correct. Auction type is set to default"
247+
)
248+
return Defaults.DEFAULT_AUCTION_TYPE
249+
return auction_type
250+
251+
def set_default(self):
252+
"""
253+
Set the settings to their default values.
254+
255+
These default values are defined in the Defaults class.
256+
"""
257+
self.base_url = Defaults.DEFAULT_URL
258+
self.price_min = Defaults.DEFAULT_PRICE_MIN
259+
self.price_max = Defaults.DEFAULT_PRICE_MAX
260+
self.province = Defaults.DEFAULT_PROVINCE
261+
self.city = Defaults.DEFAULT_CITY
262+
self.district = Defaults.DEFAULT_DISTRICT
263+
self.property_type = Defaults.DEFAULT_PROPERTY_TYPE
264+
self.auction_type = Defaults.DEFAULT_AUCTION_TYPE
265+
266+
267+
if __name__ == "__main__":
268+
settings = Settings()
269+
print(settings.__dict__)

0 commit comments

Comments
 (0)