async def test_find_flat_success(flat_repository: FlatRepository, connection: Connection, flats: List[Record], geolocations: List[Record]): record = await flat_repository._find_record( # noqa connection, Flat(url='xx2', geolocation={'point': (38.0000345, 33.0023)}, area=100, kitchen_area=58.9, living_area=19, rooms=3, floor=8, total_floor=9)) assert record['id'] == flats[1]['id'] assert record['price'] == Decimal('50000.000') assert record['geolocation_id'] == geolocations[1]['id'] record = await flat_repository._find_record( # noqa connection, Flat(url='xx11', geolocation={'point': (44.29099, 32.05321)}, area=71.1, kitchen_area=18.3, rooms=2, floor=7, total_floor=9, avatar='ava11')) assert record['id'] == flats[0]['id'] assert record['price'] == Decimal('35000.000') assert record['geolocation_id'] == geolocations[0]['id'] record = await flat_repository._find_record( # noqa connection, Flat(url='xx1', geolocation={'point': (0, 0)})) assert record['id'] == flats[0]['id'] assert record['price'] == Decimal('35000.000') assert record['geolocation_id'] == geolocations[0]['id']
async def test_find_flat_failure( flat_repository: FlatRepository, connection: Connection, flats: List[Record], geolocations: List[Record] # noqa ): assert None is await flat_repository._find_record( # noqa connection, Flat(url='xx3', geolocation={'point': (34.23, 35.0765)}, area=50, kitchen_area=15.7, rooms=2, floor=4, total_floor=9)) assert None is await flat_repository._find_record( # noqa connection, Flat(url='xx4', geolocation={'point': (51.3, 52.97)}, area=70, kitchen_area=24.9, rooms=2, floor=7, total_floor=9)) assert None is await flat_repository._find_record( # noqa connection, Flat(url='xx5', geolocation={'point': (44.290986, 32.0532)}, area=58, kitchen_area=18, rooms=2, floor=7, total_floor=9)) assert None is await flat_repository._find_record( # noqa connection, Flat(url='xx6', geolocation={'point': (44.290986, 32.0532)}, area=70, kitchen_area=18, rooms=2, floor=3, total_floor=9)) assert None is await flat_repository._find_record( # noqa connection, Flat(url='xx7', geolocation={'point': (44.3043, 32.09542)}, area=69.5, rooms=2, floor=7, total_floor=9))
async def test_update_flat_success(flat_repository: FlatRepository, connection: Connection, flats: List[Record]): await flat_repository._update_record( # noqa connection, flats[1], Flat(url='url2', published=date(2019, 4, 30), geolocation={'point': (48.98765, 51.0987)}, price=Decimal('36480.000'), rate=Decimal('570.000'), area=64, living_area=43, kitchen_area=14.5, rooms=2, floor=4, total_floor=9, ceiling_height=2.7, details=['v3'])) record = await connection.fetchrow(''' SELECT f.id, price FROM flats f JOIN flats_details fd ON f.id = fd.flat_id JOIN details d ON fd.detail_id = d.id JOIN geolocations g ON f.geolocation_id = g.id WHERE locality = 'Cherkasy' AND feature = 'f3' AND value = 'v3' AND url = 'url2' AND rooms = 2 AND floor = 4 AND total_floor = 9 AND area = 64 AND living_area = 43 AND kitchen_area = 14.5 AND ceiling_height = 2.7 AND price = 36480 AND rate = 570 ''') assert record['id'] == flats[1]['id']
def test_validate(flat_validator: FlatValidator): assert flat_validator.validate( Flat(url='x1', published=date.today(), area=45.8, rooms=2, floor=6, total_floor=9)) assert flat_validator.validate( Flat(url='x2', published=date.today(), area=245, kitchen_area=18, living_area=139, rooms=4, floor=16, total_floor=16, ceiling_height=3))
async def test_create_flat_and_new_geolocation(flat_repository: FlatRepository, connection: Connection): await flat_repository.create( Flat(url='url5', published=date(2019, 5, 11), geolocation={ 'point': (51.342123403, 47.345045433), 'state': 'Одеська область', 'locality': 'Одеса', 'county': 'Приморський район', 'neighbourhood': 'Ланжерон', 'road': None, 'house_number': None }, price=Decimal('35000.000'), rate=Decimal('500.000'), area=70, living_area=51, kitchen_area=12, rooms=2, floor=8, total_floor=9, ceiling_height=2.75, details=['brick'])) assert None is not await connection.fetchrow(''' SELECT f.id FROM flats f JOIN geolocations g on f.geolocation_id = g.id JOIN flats_details fd on fd.flat_id = f.id JOIN details d on d.id = fd.detail_id WHERE locality = 'Одеса' AND county = 'Приморський район' AND state = 'Одеська область' AND neighbourhood = 'Ланжерон' AND point = st_setsrid( st_point(51.342123403, 47.345045433), 4326 ) AND url = 'url5' AND price = 35000 AND rate = 500 AND area = 70 AND living_area = 51 AND kitchen_area = 12 AND rooms = 2 AND floor = 8 AND total_floor = 9 AND value IN ('brick') ''')
def _parse_offer(self, url: str, soup: BeautifulSoup, **kwargs: Any) -> Flat: pairs = self._parse_pairs(soup) params = self.__parse_parameters(pairs) return Flat(url=url, avatar=self._parse_avatar(soup, kwargs['avatar']), published=self._parse_published(soup), geolocation=self._parse_geolocation(soup), price=self._parse_price(soup), area=kwargs['area'], living_area=kwargs['living_area'], kitchen_area=kwargs['kitchen_area'], rooms=params['rooms'], floor=params['floor'], total_floor=params['total_floor'], ceiling_height=params['ceiling_height'], details=self._parse_details(pairs))
def _parse_offer(self, url: str, soup: BeautifulSoup, **kwargs: Any) -> Flat: shapes = self._parse_shapes(soup) pairs = self._parse_pairs(soup) params = self.__parse_parameters(pairs) return Flat(url=url, avatar=self._parse_avatar(soup), published=self._parse_published(soup), geolocation=self._parse_geolocation(soup), price=shapes['price'], currency=shapes['currency'], area=params['area'], kitchen_area=params['kitchen_area'], rooms=params['rooms'], floor=params['floor'], total_floor=params['total_floor'], details=self._parse_details(pairs))
async def test_create_failure(flat_repository: FlatRepository, connection: Connection): await flat_repository.create( Flat(url='url1', avatar='outstanding duplicate', geolocation={ 'point': (44.0672520115, 43.0985213187), 'state': None, 'locality': None, 'county': None, 'neighbourhood': None, 'road': None, 'house_number': None })) assert None is await connection.fetchrow(''' SELECT id FROM flats WHERE url = 'outstanding duplicate' ''')
async def test_create_flat_and_reuse_geolocation( flat_repository: FlatRepository, connection: Connection): await flat_repository.create( Flat(url='url4', avatar='ava4', published=date(2019, 5, 11), geolocation={ 'point': (44.0672520115, 43.0985213187), 'state': None, 'locality': None, 'county': None, 'neighbourhood': None, 'road': None, 'house_number': None }, price=Decimal('56000.000'), rate=Decimal('800.000'), area=70, living_area=58, kitchen_area=10, rooms=2, floor=4, total_floor=5, details=['3 passenger elevators', '2 bathrooms'])) assert None is not await connection.fetchrow(''' SELECT f.id FROM flats f JOIN geolocations g on f.geolocation_id = g.id JOIN flats_details fd on fd.flat_id = f.id JOIN details d on d.id = fd.detail_id WHERE point = st_setsrid( st_point(44.0672520115, 43.0985213187), 4326 ) AND url = 'url4' AND price = 56000 AND rate = 800 AND area = 70 AND living_area = 58 AND kitchen_area = 10 AND rooms = 2 AND floor = 4 AND total_floor = 5 AND value IN ('2 bathrooms') ''')
async def test_find_flat_almost_found( flat_repository: FlatRepository, connection: Connection, flats: List[Record], geolocations: List[Record] # noqa ): assert None is await flat_repository._find_record( # noqa connection, Flat(url='copy1', avatar='avax', published=date(2019, 9, 5), geolocation={'point': (38.0000345, 33.0023001)}, price=Decimal('50500.000'), rate=Decimal('505.000'), area=100, living_area=60, kitchen_area=19, rooms=3, floor=9, total_floor=9))
async def test_update_flat_no_update(flat_repository: FlatRepository, connection: Connection, flats: List[Record]): await flat_repository._update_record( # noqa connection, flats[0], Flat(url='durl1', published=date(2019, 5, 17), geolocation={'point': (48.0987, 53.5098)}, price=Decimal('37400.000'), rate=Decimal('534.290'), area=70, rooms=3, floor=7, total_floor=10)) record = await connection.fetchrow(''' SELECT f.id, price FROM flats f JOIN flats_details fd ON f.id = fd.flat_id JOIN details d ON fd.detail_id = d.id JOIN geolocations g ON f.geolocation_id = g.id WHERE locality = 'Kyiv' AND feature = 'f1' AND value = 'v1' AND url = 'url1' AND rooms = 3 AND floor = 7 AND total_floor = 10 AND price = 35000 AND rate = 500 ''') assert record['id'] == flats[0]['id']
def test_parse_offer_dom_ria_flat(dom_ria_flat_parser: DomRiaFlatParser): assert dom_ria_flat_parser.parse_offer({ 'url': 'https://dom.ria.com/uk/realty-perevireno-prodaja-kvartira-' 'odessa-primorskiy-italyanskiy-bulvar-15546830.html', 'markup': read('fixtures/test_parse_offer/dom_ria_flat0.html'), 'avatar': 'https://cdn.riastatic.com/photosnew/dom/photo/perevireno-prodaja' '-kvartira-odessa-primorskiy-italyanskiy-bulvar__97597766fl.jpg', 'area': 47.7, 'living_area': 22.0, 'kitchen_area': 15.0 }) == Flat( url='https://dom.ria.com/uk/realty-perevireno-prodaja-kvartira' '-odessa-primorskiy-italyanskiy-bulvar-15546830.html', avatar='https://cdn.riastatic.com/photosnew/dom/photo/perevireno-' 'prodaja-kvartira-odessa-primorskiy-italyanskiy-bulvar' '__97597766fl.jpg', published=date(2019, 4, 15), geolocation={'point': (30.75220862914432, 46.46768691411673)}, price=Decimal('78000.000'), area=47.7, living_area=22.0, kitchen_area=15.0, rooms=1, floor=13, total_floor=14, details=[ 'Цегла', 'Індивідуальне опалення', 'Роздільне планування', 'Авторський проект', 'Зовнішнє й внутрішнє утеплення', 'Газ відсутній', 'Броньовані двері', 'Суміжний санвузол', '1 пасажирський ліфт', 'Вторинне житло' ]) assert dom_ria_flat_parser.parse_offer({ 'url': 'https://dom.ria.com/uk/realty-perevireno-prodaja-kvartira-' 'vinnitsa-staryiy-gorod-pokryishkina-ulitsa-15223903.html', 'markup': read('fixtures/test_parse_offer/dom_ria_flat2.html'), 'avatar': 'https://cdn.riastatic.com/photosnew/dom/photo/perevireno-' 'prodaja-kvartira-vinnitsa-staryiy-gorod-pokryishkina-ulit' 'sa__94899036fl.jpg', 'area': 52, 'living_area': 32, 'kitchen_area': 14 }) == Flat( url='https://dom.ria.com/uk/realty-perevireno-prodaja-kvartira' '-vinnitsa-staryiy-gorod-pokryishkina-ulitsa-15223903.html', avatar='https://cdn.riastatic.com/photosnew/dom/photo/perevireno' '-prodaja-kvartira-vinnitsa-staryiy-gorod-pokryishkina-' 'ulitsa__94899036fl.jpg', published=date(2019, 4, 10), geolocation={'address': 'Вінниця, Старе місто, Покришкіна вулиця'}, price=Decimal('19900.000'), area=52, living_area=32, kitchen_area=14, rooms=2, floor=4, total_floor=12, ceiling_height=2.71, details=[ 'Цегла', 'Опалення відсутнє', 'Роздільне планування', 'Потребує ремонту', 'Внутрішнє утеплення', 'Газ є', 'Металопластикові вікна', 'Суміжний санвузол', '1 пасажирський ліфт', 'Вторинне житло' ]) assert dom_ria_flat_parser.parse_offer({ 'url': 'https://dom.ria.com/uk/realty-perevireno-prodaja-kvartira-' 'odessa-primorskiy-italyanskiy-bulvar-15591101.html', 'markup': read('fixtures/test_parse_offer/dom_ria_flat3.html'), 'avatar': 'https://cdn.riastatic.com/photosnew/dom/photo/' 'perevireno-prodaja-kvartira-odessa-primorskiy-italyanskiy' '-bulvar__97910469fl.jpg', 'area': 65, 'living_area': None, 'kitchen_area': None }) == Flat( url='https://dom.ria.com/uk/realty-perevireno-prodaja-' 'kvartira-odessa-primorskiy-italyanskiy-bulvar-15591101.html', avatar= 'https://cdn.riastatic.com/photosnew/dom/photo/perevireno-prodaja-' 'kvartira-odessa-primorskiy-italyanskiy-bulvar__97910469fl.jpg', published=date(2019, 4, 25), geolocation={'point': (30.752294459832797, 46.467716472633796)}, price=Decimal('96000.000'), area=65, rooms=2, floor=12, total_floor=15, details=[ 'Цегла', 'Індивідуальне опалення', 'Роздільне планування', 'Потребує ремонту', 'Газ відсутній', 'Броньовані двері', 'Металопластикові вікна', 'Роздільний санвузол', '1 пасажирський ліфт', 'Вторинне житло' ]) assert dom_ria_flat_parser.parse_offer({ 'url': 'https://dom.ria.com/uk/realty-perevireno-prodaja-kvartira-' 'kiev-dneprovskiy-prajskaya-ulitsa-15581555.html', 'markup': read('fixtures/test_parse_offer/dom_ria_flat4.html'), 'avatar': 'https://cdn.riastatic.com/photosnew/dom/photo/perevireno' '-prodaja-kvartira-kiev-dneprovskiy-prajskaya-ulitsa' '__97897725fl.jpg', 'area': 44.9, 'living_area': 29.5, 'kitchen_area': 7.8 }) == Flat( url='https://dom.ria.com/uk/realty-perevireno-prodaja-' 'kvartira-kiev-dneprovskiy-prajskaya-ulitsa-15581555.html', avatar='https://cdn.riastatic.com/photosnew/dom/photo/perevireno-' 'prodaja-kvartira-kiev-dneprovskiy-prajskaya-ulitsa' '__97897725fl.jpg', published=date(2019, 4, 22), geolocation={'point': (30.643568070947254, 50.43808004773596)}, price=Decimal('45000.000'), area=44.9, living_area=29.5, kitchen_area=7.8, rooms=2, floor=1, total_floor=5, details=[ 'Панель', 'Централізоване опалення', 'Суміжно-роздільне планування', 'Євроремонт', 'Зовнішнє утеплення', 'Газ є', 'Металеві двері', 'Металопластикові вікна', 'Суміжний санвузол', 'Вторинне житло' ]) assert dom_ria_flat_parser.parse_offer({ 'url': 'https://dom.ria.com/uk/realty-prodaja-kvartira-' 'ochakov-ochakov-pervomayskaya-13179860.html', 'markup': read('fixtures/test_parse_offer/dom_ria_flat6.html'), 'avatar': 'https://cdn.riastatic.com/photosnew/dom/photo/prodaja-' 'kvartira-ochakov-ochakov-pervomayskaya__74444903fl.jpg', 'area': 35, 'living_area': 19, 'kitchen_area': 8 }) == Flat(url='https://dom.ria.com/uk/realty-prodaja-kvartira-ochakov' '-ochakov-pervomayskaya-13179860.html', avatar='https://cdn.riastatic.com/photosnew/dom/photo/prodaja' '-kvartira-ochakov-ochakov-pervomayskaya__74444903fl.jpg', published=date(2019, 5, 23), geolocation={'point': (31.52812112850194, 46.62593951428682)}, price=Decimal('11500.000'), area=35, living_area=19, kitchen_area=8, rooms=1, floor=8, total_floor=9, ceiling_height=2.7, details=[ 'Цегла', 'Побудовано у 1990-2000', 'Централізоване опалення', 'Роздільне планування', 'Хороший стан', 'Газ є', 'Металопластикові вікна', 'Суміжний санвузол', 'Без пасажирських ліфтів', 'Вторинне житло' ]) assert dom_ria_flat_parser.parse_offer({ 'url': 'https://dom.ria.com/uk/realty-perevireno-prodaja-kvarti' 'ra-vinnitsa-blijnee-zamoste-vyacheslava-chernovola-' 'ulitsa-14797413.html', 'markup': read('fixtures/test_parse_offer/dom_ria_flat7.html'), 'avatar': 'https://cdn.riastatic.com/photosnewr/dom/photo/' 'realty__98129585-300x200x80.webp', 'area': 73.5, 'living_area': None, 'kitchen_area': 25 }) == Flat(url='https://dom.ria.com/uk/realty-perevireno-prodaja-kvart' 'ira-vinnitsa-blijnee-zamoste-vyacheslava-chernovola-uli' 'tsa-14797413.html', avatar='https://cdn.riastatic.com/photosnewr/dom/photo' '/realty__98129585-300x200x80.webp', published=date(2019, 5, 6), geolocation={'point': (28.477062352423104, 49.24405425158156)}, price=Decimal('47000.000'), area=73.5, kitchen_area=25, rooms=2, floor=6, total_floor=12, ceiling_height=2.8, details=[ 'Цегла', 'Здача у 2019', 'Індивідуальне опалення', 'Роздільне планування', 'Чорнові роботи', 'Зовнішнє утеплення', 'Газ є', 'Металеві двері', 'Металопластикові вікна', 'Суміжний санвузол', '1 пасажирський ліфт', 'Первинне житло' ])
def test_parse_offer_olx_flat(olx_flat_parser: OlxFlatParser): assert olx_flat_parser.parse_offer({ 'url': 'https://www.olx.ua/obyavlenie/prodam-2k-' 'kvartiru-v-tsentre-1000-melochey-IDDqNsA.html', 'markup': read('fixtures/test_parse_offer/olx_flat0.html') }) == Flat(url='https://www.olx.ua/obyavlenie/prodam-2k' '-kvartiru-v-tsentre-1000-melochey-IDDqNsA.html', avatar='https://apollo-ireland.akamaized.net:443/v1' '/files/atbs10v8fzy43-UA/image;s=644x461', published=date(2019, 2, 25), geolocation={'point': (37.56492189, 47.13203091)}, price=Decimal('18200.000'), area=46.0, kitchen_area=6.0, rooms=2, floor=5, total_floor=5, details=[]) assert olx_flat_parser.parse_offer({ 'url': 'https://www.olx.ua/obyavlenie/2-komnatnaya-kvartira-74-met' 'ra-v-novopecherskoy-vezhe-po-ul-kikvidze-41-IDCqiKk.html', 'markup': read('fixtures/test_parse_offer/olx_flat1.html') }) == Flat( url='https://www.olx.ua/obyavlenie/2-komnatnaya-kvartira-74-metra-v-' 'novopecherskoy-vezhe-po-ul-kikvidze-41-IDCqiKk.html', avatar='https://apollo-ireland.akamaized.net:443/' 'v1/files/nyj7wonmwpf9-UA/image;s=644x461', published=date(2019, 2, 27), geolocation={'point': (30.55172926, 50.4070917)}, price=Decimal('1850000.000'), currency='грн.', area=74.0, kitchen_area=28.0, rooms=2, floor=8, total_floor=26, details=[ 'На етапі будівництва', 'Моноліт', 'Роздільне планування', 'Роздільний санвузол', 'Власна котельня', 'Щойно споруджено', 'Меблі відсутні' ]) assert olx_flat_parser.parse_offer({ 'url': 'https://www.olx.ua/obyavlenie/bolshaya-kvartira' '-v-samom-tsentre-irpenya-IDDJbxi.html', 'markup': read('fixtures/test_parse_offer/olx_flat2.html') }) == Flat(url='https://www.olx.ua/obyavlenie/bolshaya-kvartira' '-v-samom-tsentre-irpenya-IDDJbxi.html', avatar='https://apollo-ireland.akamaized.net:443/v1/' 'files/37oo82mm73sv3-UA/image;s=644x461', published=date(2019, 3, 23), geolocation={'point': (30.2593, 50.51752)}, price=Decimal('30500.000'), area=75.0, kitchen_area=16.0, rooms=1, floor=9, total_floor=10, details=[ 'Царський будинок', 'Цегла', 'Суміжне, прохідне планування', 'Суміжний санвузол', 'Власна котельня' ]) assert olx_flat_parser.parse_offer({ 'url': 'https://www.olx.ua/obyavlenie/prodam-2-komnatnuyu-kvartir' 'u-v-32-zhemchuzhine-arkadiya-dom-sdan-IDBbRIG.html', 'markup': read('fixtures/test_parse_offer/olx_flat3.html') }) == Flat(url='https://www.olx.ua/obyavlenie/prodam-2-komnatnuyu-kvartiru' '-v-32-zhemchuzhine-arkadiya-dom-sdan-IDBbRIG.html', avatar='https://apollo-ireland.akamaized.net:443/v1/' 'files/p5fbluxbefad3-UA/image;s=644x461', published=date(2019, 3, 12), geolocation={'point': (30.76142585, 46.42438896)}, price=Decimal('50000.000'), area=52.0, kitchen_area=9.0, rooms=2, floor=4, total_floor=24, details=[ 'На етапі будівництва', 'Вільне планування', 'Роздільний санвузол', 'Власна котельня', 'Щойно споруджено' ]) assert olx_flat_parser.parse_offer({ 'url': 'https://www.olx.ua/obyavlenie/prodam-3-k-' 'kvartiru-ul-uzhviy-10-podolskiy-r-n-IDDIwaX.html', 'markup': read('fixtures/test_parse_offer/olx_flat4.html') }) == Flat(url='https://www.olx.ua/obyavlenie/prodam-3-k-kvartiru-ul-' 'uzhviy-10-podolskiy-r-n-IDDIwaX.html', avatar='https://apollo-ireland.akamaized.net:443/v1/files/' 'b45v2qziwxkp3-UA/image;s=644x461', published=date(2019, 3, 22), geolocation={'point': (30.43441159, 50.50743121)}, price=Decimal('60000.000'), area=74.0, kitchen_area=9.0, rooms=3, floor=5, total_floor=9, details=[ 'Роздільне планування', 'Роздільний санвузол', 'Євроремонт', 'Є меблі' ]) assert olx_flat_parser.parse_offer({ 'url': 'https://www.olx.ua/obyavlenie/prodazha-obmen-nedvizhimosti' '-v-kieve-na-nedvizhimost-v-sankt-peterburge-IDypRFA.html', 'markup': read('fixtures/test_parse_offer/olx_flat5.html') }) == Flat(url='https://www.olx.ua/obyavlenie/prodazha-obmen-nedvizhimosti' '-v-kieve-na-nedvizhimost-v-sankt-peterburge-IDypRFA.html', avatar='https://apollo-ireland.akamaized.net:443/v1/' 'files/34mlkr9opvr2-UA/image;s=644x461', published=date(2019, 5, 20), geolocation={'point': (30.50188948, 50.39525513)}, price=Decimal('71051.200'), area=62.1, kitchen_area=7.2, rooms=3, floor=2, total_floor=5, details=[])
def test_validate_emptiness(flat_validator: FlatValidator): assert not flat_validator.validate(None) assert not flat_validator.validate({'area': 54}) assert not flat_validator.validate( Flat(published=date.today(), area=2, kitchen_area=18, rooms=2, floor=5, total_floor=9)) assert not flat_validator.validate( Flat(published=date.today(), rooms=3, floor=5)) assert not flat_validator.validate( Flat(published=date.today(), kitchen_area=1.1, living_area=23, rooms=2, floor=1, total_floor=5)) assert not flat_validator.validate( Flat(published=date.today(), area=9876563, kitchen_area=784309, rooms=1, floor=12, total_floor=16)) assert not flat_validator.validate( Flat(published=date.today(), area=0.345543, kitchen_area=0.11, living_area=0.23, rooms=1, floor=13, total_floor=16)) assert not flat_validator.validate( Flat(published=date.today(), area=25, kitchen_area=25, living_area=25, rooms=1, floor=1, total_floor=1)) assert not flat_validator.validate( Flat(published=date.today(), area=98, kitchen_area=1.02, rooms=2, floor=7, total_floor=12)) assert not flat_validator.validate( Flat(published=date.today(), area=98, kitchen_area=1.02, rooms=3, floor=6, total_floor=9)) assert not flat_validator.validate( Flat(published=date.today(), area=325, kitchen_area=45, living_area=225, rooms=1, floor=12, total_floor=16)) assert not flat_validator.validate( Flat(published=date.today(), area=98, kitchen_area=21, rooms=9, floor=7, total_floor=16)) assert not flat_validator.validate( Flat(published=date.today(), area=48, kitchen_area=17.6, rooms=6, floor=7, total_floor=9)) assert not flat_validator.validate( Flat(published=date.today(), area=325, kitchen_area=45, living_area=225, rooms=1, floor=12, total_floor=16)) assert not flat_validator.validate( Flat(published=date.today(), area=170, kitchen_area=33, living_area=110, rooms=3, floor=12, total_floor=55)) assert not flat_validator.validate( Flat(published=date.today(), area=48, kitchen_area=13.6, rooms=2, floor=17, total_floor=9)) assert not flat_validator.validate( Flat(published=date.today(), area=170, kitchen_area=33, living_area=110, rooms=3, floor=12, total_floor=55)) assert not flat_validator.validate( Flat(published=date.today(), area=81, kitchen_area=26, living_area=51, rooms=3, floor=12, total_floor=16, ceiling_height=8.1)) assert not flat_validator.validate( Flat(published=date.today(), area=81, kitchen_area=26, living_area=51, rooms=3, floor=12, total_floor=16, ceiling_height=0.27))