def test_center_to_centerdict(): center = CenterInfo( "28", "Delphine ROUSSEAU", "https://patient.avecmondoc.com/fiche/structure/delphine-rousseau-159" ) center.metadata = { "address": "21 Rue Nicole 28000 Chartres", "phone_number": "0033143987678", "business_hours": { "Lundi": "08:30-12:30 13:30-17:00", "Mardi": "08:30-12:30 13:30-17:00", "Mercredi": "08:30-12:30 13:30-17:00", "Jeudi": "08:30-12:30 13:30-17:00", "Vendredi": "08:30-12:30 13:30-17:00", "Samedi": "", "Dimanche": "", } } center.location = CenterLocation(1.481373, 48.447586, "Chartres", "28000") center.internal_id = "amd159" data_file = Path("tests/fixtures/avecmondoc/centerdict.json") data = json.loads(data_file.read_text(encoding='utf8')) assert avecmondoc.center_to_centerdict(center) == data
def test_get_last_scans(): center_info1 = CenterInfo("01", "Centre 1", "https://example1.fr") center_info2 = CenterInfo("01", "Centre 2", "https://example2.fr") center_info2.prochain_rdv = "2021-06-06T00:00:00" centres_cherchés = [center_info1, center_info2] fake_now = dt.datetime(2021, 5, 5) with mock_datetime_now(fake_now): centres_cherchés = get_last_scans(centres_cherchés) assert centres_cherchés[0].last_scan_with_availabilities == None assert centres_cherchés[1].last_scan_with_availabilities == "2021-05-05T00:00:00"
def test_get_appointments(): """get_appointments should return first available appointment date""" center_data = dict() center_data = json.load(io.open(TEST_CENTRE_INFO, "r", encoding="utf-8-sig")) center_info = CenterInfo.from_csv_data(center_data) # This center has availabilities and should return a date, non null appointment_count and vaccines request = ScraperRequest( "https://server.bimedoc.com/vmd/pharmacy-with-slots/9cf46288-0080-4a8d-8856-8e9998ced9f7?start_date=2021-08-10&end_date=2021-08-17", "2021-08-10", center_info, "Bimedoc9cf46288-0080-4a8d-8856-8e9998ced9f", ) center_with_availability = bimedoc.BimedocSlots() slots = json.load(io.open(Path("tests", "fixtures", "bimedoc", "slots_available.json"), "r", encoding="utf-8-sig")) assert center_with_availability.get_appointments(request, slots_api=slots) == "2021-08-11T08:15:00Z" assert request.appointment_count == 133 assert request.vaccine_type == [Vaccine.PFIZER] # This one should return no date, neither appointment_count nor vaccine. request = ScraperRequest( "https://server.bimedoc.com/vmd/pharmacy-with-slots/9cf46288-0080-4a8d-8856-8e9998ced9f7?start_date=2021-08-10&end_date=2021-08-17", "2021-08-10", center_info, ) center_without_availability = bimedoc.BimedocSlots() slots = json.load( io.open(Path("tests", "fixtures", "bimedoc", "slots_unavailable.json"), "r", encoding="utf-8-sig") ) assert center_without_availability.get_appointments(request, slots_api=slots) == None assert request.appointment_count == 0 assert request.vaccine_type == None
def test_fetch(): mesoigner.PLATFORM_ENABLED = True center_data = dict() center_data = json.load( io.open(TEST_CENTRE_INFO, "r", encoding="utf-8-sig")) center_info = CenterInfo.from_csv_data(center_data) # This center has availabilities and should return a date, non null appointment_count and vaccines request = ScraperRequest( "https://pharmacie-des-pyrenees.pharmaxv.fr/rendez-vous/vaccination/269-vaccination-covid-19/pre-inscription", "2021-06-16", center_info, ) slots = json.load( io.open(Path("tests", "fixtures", "mesoigner", "slots_available.json"), "r", encoding="utf-8-sig")) def app(requested: httpx.Request) -> httpx.Response: assert "User-Agent" in requested.headers return httpx.Response(200, json=slots) client = httpx.Client(transport=httpx.MockTransport(app)) center_with_availability = mesoigner.MesoignerSlots(client=client) response = center_with_availability.fetch(request) assert response == "2021-06-16T14:50:00+02:00"
def test_fetch(): def app(requested: httpx.Request) -> httpx.Response: assert "User-Agent" in requested.headers return httpx.Response(responsecode, json=slots) bimedoc.PLATFORM_ENABLED = True center_data = dict() center_data = json.load(io.open(TEST_CENTRE_INFO, "r", encoding="utf-8-sig")) center_info = CenterInfo.from_csv_data(center_data) # This center has availabilities and should return a date, non null appointment_count and vaccines request = ScraperRequest( "https://server.bimedoc.com/vmd/pharmacy-with-slots/9cf46288-0080-4a8d-8856-8e9998ced9f7?start_date=2021-08-10&end_date=2021-08-17", "2021-08-10", center_info, ) slots = json.load(io.open(Path("tests", "fixtures", "bimedoc", "slots_available.json"), "r", encoding="utf-8-sig")) # Response 200 responsecode = 200 client = httpx.Client(transport=httpx.MockTransport(app)) center_with_availability = bimedoc.BimedocSlots(client=client) response = center_with_availability.fetch(request) assert response == "2021-08-11T08:15:00Z" # Response 403 responsecode = 403 client = httpx.Client(transport=httpx.MockTransport(app)) center_with_availability = bimedoc.BimedocSlots(client=client) with pytest.raises(Exception): response = center_with_availability.fetch(request) assert response == None
def test_doctolib_next_slot(): # Cas de repli : c'est surprenant, mais parfois la liste des dispos # est vide, mais il y a un champ 'next_slot' qui contient la date de # la prochaine visite, que l'on utilise dans ce cas. start_date = "2021-04-03" base_url = "https://partners.doctolib.fr/centre-de-vaccinations-internationales/ville1/centre1?pid=practice-165752&enable_cookies_consent=1" # noqa center_info = CenterInfo(departement="07", nom="Mon Super Centre", url=base_url) scrap_request = ScraperRequest(base_url, start_date, center_info) def app(request: httpx.Request) -> httpx.Response: assert "User-Agent" in request.headers if request.url.path == "/booking/centre1.json": path = Path("tests", "fixtures", "doctolib", "next-slot-booking.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) assert request.url.path == "/availabilities.json" path = Path("tests", "fixtures", "doctolib", "next-slot-availabilities.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) client = httpx.Client(transport=httpx.MockTransport(app)) slots = DoctolibSlots(client=client, cooldown_interval=0) next_date = slots.fetch(scrap_request) # Next slot should not be used assert next_date is None
def test_doctolib_motive_categories(): # Certains centres opèrent une distinction de motifs pour les professionnels de santé / # non professionnels de santé. # On doit gérer ces cas-là. start_date = "2021-04-03" base_url = "https://partners.doctolib.fr/centre-de-vaccinations-internationales/ville1/centre1?pid=practice-165752&enable_cookies_consent=1" # noqa center_info = CenterInfo(departement="07", nom="Mon Super Centre", url=base_url) scrap_request = ScraperRequest(base_url, start_date, center_info) def app(request: httpx.Request) -> httpx.Response: assert "User-Agent" in request.headers if request.url.path == "/booking/centre1.json": path = Path("tests", "fixtures", "doctolib", "category-booking.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) assert request.url.path == "/availabilities.json" path = Path("tests", "fixtures", "doctolib", "category-availabilities.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) client = httpx.Client(transport=httpx.MockTransport(app)) slots = DoctolibSlots(client=client, cooldown_interval=0) next_date = slots.fetch(scrap_request) assert next_date == "2021-04-10"
def test_blocked_by_doctolib_par_availabilities(): # Cas de base. start_date = "2021-04-03" base_url = "https://partners.doctolib.fr/centre-de-vaccinations-internationales/ville1/centre1?pid=practice-165752&enable_cookies_consent=1" # noqa center_info = CenterInfo(departement="07", nom="Mon Super Centre", url=base_url) scrap_request = ScraperRequest(base_url, start_date, center_info) def app(request: httpx.Request) -> httpx.Response: assert "User-Agent" in request.headers if request.url.path == "/booking/centre1.json": path = Path("tests", "fixtures", "doctolib", "basic-booking.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) return httpx.Response(403, text="Anti dDos") client = httpx.Client(transport=httpx.MockTransport(app)) slots = DoctolibSlots(client=client, cooldown_interval=0) with pytest.raises(Blocked403): slots.fetch(scrap_request)
def test_fetch(): def app(requested: httpx.Request) -> httpx.Response: assert "User-Agent" in requested.headers return httpx.Response(responsecode, json=slots) valwin.PLATFORM_ENABLED = True center_data = dict() center_data = json.load(io.open(TEST_CENTRE_INFO, "r", encoding="utf-8-sig")) center_info = CenterInfo.from_csv_data(center_data) # This center has availabilities and should return a date, non null appointment_count and vaccines request = ScraperRequest( "https://pharma-api.epharmacie.pro/global/api/meetings/v2/pharmabest75-plateau-lyon/slots", "2021-08-10", center_info, ) slots = json.load(io.open(Path("tests", "fixtures", "valwin", "slots_available.json"), "r", encoding="utf-8-sig")) # Response 200 responsecode = 200 client = httpx.Client(transport=httpx.MockTransport(app)) center_with_availability = valwin.Slots(client=client) response = center_with_availability.fetch(request) assert response == "2021-09-17T10:00:00" # Response 403 responsecode = 403 client = httpx.Client(transport=httpx.MockTransport(app)) center_with_availability = valwin.Slots(client=client) with pytest.raises(Exception): response = center_with_availability.fetch(request) assert response == None
def test_no_center_data(): path_centerinfo = Path("tests", "fixtures", "keldoc", "cabinet-16913-centerinfo.json") centerinfo_1 = json.loads(path_centerinfo.read_text(encoding="utf-8")) center_info = CenterInfo.from_csv_data(centerinfo_1) center1_url = "https://www.keldoc.com/centre-hospitalier-regional/lorient-56100/groupe-hospitalier-bretagne-sud-lorient-hopital-du-scorff?specialty=144" request = ScraperRequest(center1_url, "2020-04-04", center_info=center_info) def app(request: httpx.Request) -> httpx.Response: if (request.url.path == "/centre-hospitalier-regional/lorient-56100/groupe-hospitalier-bretagne-sud-lorient-hopital-du-scorff" ): return httpx.Response( 302, headers={ "Location": "https://vaccination-covid.keldoc.com/redirect/?dom=centre-hospitalier-regional&inst=lorient-56100&user=groupe-hospitalier-bretagne-sud-lorient-hopital-du-scorff&specialty=144 " }, ) if request.url.path == "/redirect/": return httpx.Response(200, json={}) return httpx.Response(403, json={}) keldoc.session = httpx.Client(transport=httpx.MockTransport(app)) date = fetch_slots(request) assert not date
def test_center_info_next_availability(): center = CenterInfo("Paris", "Centre 1", "https://.../centre") center.prochain_rdv = "TEST" data = center.handle_next_availability() assert not data center.prochain_rdv = "2021-06-06" data = center.handle_next_availability() assert center.prochain_rdv == "2021-06-06" center.prochain_rdv = "2042-04-10T00:00:00" data = center.handle_next_availability() assert center.prochain_rdv is None
def organization_to_center(organization) -> Optional[CenterInfo]: if organization is None: return None url = AVECMONDOC_CONF.get("patient_url", "").format(slug=organization.get("slug")) id = organization["id"] zip = organization["zipCode"] dept = departementUtils.to_departement_number(departementUtils.cp_to_insee(zip)) reasons = organization["consultationReasons"] if reasons is None: logger.warning(f"no reasons found in organization") return None if get_valid_reasons(reasons) == []: return None center = CenterInfo(dept, organization["name"], url) location = CenterLocation(0, 0, organization["city"], organization["zipCode"]) if organization.get("coordinates") is not None: location.longitude = organization["coordinates"].get("lng", 0.0) location.latitude = organization["coordinates"].get("lat", 0.0) center.metadata = { "address": organization["address"], "phone_number": organization["phone"], } center.location = location center.internal_id = f"amd{id}" if "schedules" not in organization: return center business_hours = {} for day, day_name in AVECMONDOC_SCRAPER.get("business_days", {}).items(): value = "" if organization["schedules"][day]["enabled"]: value = " ".join(f'{sc["start"]}-{sc["end"]}' for sc in organization["schedules"][day]["schedules"]) business_hours[day_name] = value center.metadata["business_hours"] = business_hours return center
def test_fetch_slots(): def app(request: httpx.Request) -> httpx.Response: try: with open(Path("tests", "fixtures", "mapharma", "slots.json"), encoding="utf8") as f: return httpx.Response(200, content=f.read()) except IOError: return httpx.Response(404, content="") client = httpx.Client(transport=httpx.MockTransport(app)) center_info = CenterInfo( departement="49", nom="Pharmacie Grand Maine", url="https://mapharma.net/49100-3?c=257&l=0", location=CenterLocation(longitude=-0.595416, latitude=47.468377, city="ANGERS", cp="49100"), metadata={ "address": "CENTRE CIAL GRAND MAINE RUE DU GRAND LAUNAY, 49100 ANGERS", "business_hours": { "lundi": "09:30 – 20:00", "mardi": "09:30 – 20:00", "mercredi": "09:30 – 20:00", "jeudi": "09:30 – 20:00", "vendredi": "09:30 – 20:00", "samedi": "09:30 – 20:00", "dimanche": "Fermé", }, }, ) request = ScraperRequest(url="https://mapharma.net/97200?c=60&l=1", start_date="2021-04-14", center_info=center_info) first_availability = fetch_slots(request, creneau_q=DummyQueue(), client=client, opendata_file=TEST_OPEN_DATA_FILE) assert first_availability == "2021-04-19T17:15:00" # test campagne["total_libres"]: 0 request = ScraperRequest("https://mapharma.net/88400?c=92&l=1", "2021-04-14", center_info=center_info) first_availability = fetch_slots(request, client=client, opendata_file=TEST_OPEN_DATA_FILE) assert first_availability == None
def test_fetch_slots(): valwin.PLATFORM_ENABLED = False center_data = dict() center_data = json.load(io.open(TEST_CENTRE_INFO, "r", encoding="utf-8-sig")) center_info = CenterInfo.from_csv_data(center_data) request = ScraperRequest( "https://pharma-api.epharmacie.pro/global/api/meetings/v2/pharmabest75-plateau-lyon/slots", "2021-08-10", center_info, ) response = valwin.fetch_slots(request) # On devrait trouver None puisque la plateforme est désactivée assert response == None
def test_fetch_slots(): bimedoc.PLATFORM_ENABLED = False center_data = dict() center_data = json.load(io.open(TEST_CENTRE_INFO, "r", encoding="utf-8-sig")) center_info = CenterInfo.from_csv_data(center_data) request = ScraperRequest( "https://server.bimedoc.com/vmd/pharmacy-with-slots/9cf46288-0080-4a8d-8856-8e9998ced9f7?start_date=2021-08-10&end_date=2021-08-17", "2021-08-10", center_info, ) response = bimedoc.fetch_slots(request) # On devrait trouver None puisque la plateforme est désactivée assert response == None
def test_doctolib_sends_creneau(): # Given start_date = "2021-04-03" base_url = "https://partners.doctolib.fr/centre-de-vaccinations-internationales/ville1/centre1?pid=practice-165752&enable_cookies_consent=1" # noqa center_info = CenterInfo(departement="07", nom="Mon Super Centre", url=base_url) scrap_request = ScraperRequest(base_url, start_date, center_info) def app(request: httpx.Request) -> httpx.Response: assert "User-Agent" in request.headers if request.url.path == "/booking/centre1.json": path = Path("tests", "fixtures", "doctolib", "basic-booking.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) assert request.url.path == "/availabilities.json" path = Path("tests", "fixtures", "doctolib", "basic-availabilities.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) client = httpx.Client(transport=httpx.MockTransport(app)) q = SimpleQueue() slots = DoctolibSlots(client=client, cooldown_interval=0, creneau_q=q) # When slots.fetch(scrap_request) actual = [] while not q.empty(): actual.append(q.get()) # Then assert len(actual) == 1 assert actual[0] == Creneau( reservation_url=base_url, horaire=dateutil.parser.parse("2021-04-10T21:45:00.000+02:00"), type_vaccin=[Vaccine.PFIZER], lieu=Lieu( departement="07", plateforme=Plateforme.DOCTOLIB, url=base_url, nom="Mon Super Centre", internal_id="doctolib123456789pid165752", lieu_type="vaccination-center", ), dose=["1"], )
def online_keldoc_test(): path_centerinfo = Path("tests", "fixtures", "keldoc", "cabinet-16913-centerinfo.json") centerinfo_1 = json.loads(path_centerinfo.read_text(encoding="utf-8")) center_info = CenterInfo.from_csv_data(centerinfo_1) request = ScraperRequest( "https://www.keldoc.com/cabinet-medical/grenoble-38000/centre-de-vaccination-universite-inter-age-du-dauphine-uiad", "2021-04-13", center_info=center_info, ) fetch_slots(request)
def cherche_prochain_rdv_dans_centre( centre: dict) -> CenterInfo: # pragma: no cover center_data = CenterInfo.from_csv_data(centre) start_date = get_start_date() has_error = None result = None try: result = fetch_centre_slots(centre["rdv_site_web"], start_date, input_data=centre.get("booking")) center_data.fill_result(result) except ScrapeError as scrape_error: logger.error( f"erreur lors du traitement de la ligne avec le gid {centre['gid']} {str(scrape_error)}" ) has_error = scrape_error except CircuitBreakerOffException as error: logger.error( f"circuit '{error.name}' désactivé lors du traîtement de la ligne avec le gid {centre['gid']}: {str(error)}" ) has_error = error except Exception: logger.error( f"erreur lors du traitement de la ligne avec le gid {centre['gid']}" ) traceback.print_exc() if has_error is None: logger.info( f'{centre.get("gid", "")!s:>8} {center_data.plateforme!s:16} {center_data.prochain_rdv or ""!s:32} {center_data.departement!s:6}' ) else: logger.info( f'{centre.get("gid", "")!s:>8} {center_data.plateforme!s:16} {"Erreur" or ""!s:32} {center_data.departement!s:6}' ) if result is not None and result.request.url is not None: center_data.url = result.request.url.lower() if result.request.internal_id is None: center_data.internal_id = f'{result.platform.lower()}{centre.get("gid", "")}' if "type" in centre: center_data.type = centre["type"] if not center_data.type: center_data.type = VACCINATION_CENTER center_data.gid = centre.get("gid", "") logger.debug(center_data.default()) return center_data
def centre(self, lieu: Lieu): return CenterInfo( departement=lieu.departement, nom=lieu.nom, url=lieu.url, location=self.location_to_dict(lieu.location), metadata=lieu.metadata, prochain_rdv=None, plateforme=lieu.plateforme.value, type=lieu.lieu_type, appointment_count=0, internal_id=lieu.internal_id, vaccine_type=[], erreur=None, atlas_gid=lieu.atlas_gid, )
def test_fetch_slots(): def app(request: httpx.Request) -> httpx.Response: if request.url.path == "/api/BusinessHours/availabilitiesPerDay": path = Path("tests/fixtures/avecmondoc/get_availabilities.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf8"))) if request.url.path == "/api/Organizations/slug/delphine-rousseau-159": path = Path("tests/fixtures/avecmondoc/get_organization_slug.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf8"))) return httpx.Response(404) center_info = CenterInfo( departement="69", nom="Pharmacie AVENUE (Picard)", url= "https://patient.avecmondoc.com/fiche/structure/pharmacie-avenue-picard-583", location=CenterLocation(longitude=4.77231, latitude=45.742216, city="Francheville", cp="69340"), metadata={ "address": "29 avenue du Chater, 69340 Francheville", "business_hours": { "Lundi": "08:45-12:15 15:00-19:15", "Mardi": "08:45-12:15 15:00-19:15", "Mercredi": "08:45-12:15 15:00-19:15", "Jeudi": "08:45-12:15 15:00-19:15", "Vendredi": "08:45-12:15 15:00-19:15", "Samedi": "08:45-12:15", "Dimanche": "", }, "phone_number": "+33478342931", }, plateforme="Avecmondoc", type="drugstore", internal_id="amd583", ) client = httpx.Client(transport=httpx.MockTransport(app)) url = "https://patient.avecmondoc.com/fiche/structure/delphine-rousseau-159" request = ScraperRequest(url, "2021-05-20", center_info=center_info) first_availability = fetch_slots(request, client=client) assert first_availability == "2021-05-20T09:00:00+00:00" assert request.vaccine_type == ["Pfizer-BioNTech", "Janssen"]
def test_get_first_availability(): request = ScraperRequest( url= "https://www.maiia.com/centre-de-vaccination/42400-saint-chamond/centre-de-vaccination-covid---hopital-du-gier-?centerid=5ffc744c68dedf073a5b87a2", start_date="2021-07-17", center_info=CenterInfo( departement="42", nom="Centre de vaccination COVID - Hôpital du Gier ", url= "https://www.maiia.com/centre-de-vaccination/42400-saint-chamond/centre-de-vaccination-covid---hopital-du-gier-?centerid=5ffc744c68dedf073a5b87a2", location=CenterLocation(longitude=4.50184989506, latitude=45.4698319517, city="Saint-Chamond", cp="42400"), metadata={ "address": "19 rue victor hugo 42400 Saint-Chamond", "business_hours": { "Lundi": "08:15-17:15", "Mardi": "08:15-17:15", "Mercredi": "08:15-17:15", "Jeudi": "08:15-17:15", "Vendredi": "08:15-17:15", "Samedi": "08:15-17:15", "Dimanche": "08:15-17:15", }, }, type="vaccination-center", internal_id="5ffc744c", ), ) reasons = get_reasons("5ffc744c68dedf073a5b87a2", limit=MAIIA_LIMIT, client=client) instance = MaiiaSlots(creneau_q=DummyQueue, client=None) fake_now = dt.datetime(2021, 4, 29, 18, 20) with mock_datetime_now(fake_now): first_availability, slots_count = instance.get_first_availability( "5ffc744c68dedf073a5b87a2", "2021-04-29", reasons, client=client, request=request) assert slots_count == 7182 assert first_availability.isoformat() == "2021-05-13T13:40:00+00:00"
def test_convert_ordoclic(): center = CenterInfo("Paris", "Centre 1", "https://.../centre") data = { "location": { "coordinates": { "lon": 1.1281, "lat": 93.182, }, "city": "Foobar", "address": "12 Avenue de la ville", "zip": "22000", }, "phone_number": "06 06 06 06 06", } center = convert_ordoclic_to_center_info(data, center) assert center.metadata["address"] == "12 Avenue de la ville, 22000 Foobar" assert center.metadata["phone_number"] == "+33606060606" assert center.metadata["business_hours"] is None
def test_convert_ordoclic(): center = CenterInfo("Paris", "Centre 1", "https://.../centre") data = { 'location': { 'coordinates': { 'lon': 1.1281, 'lat': 93.182, }, 'city': 'Foobar', 'address': '12 Avenue de la ville', 'zip': '22000' }, 'phone_number': '06 06 06 06 06' } center = convert_ordoclic_to_center_info(data, center) assert center.metadata['address'] == '12 Avenue de la ville, 22000 Foobar' assert center.metadata['phone_number'] == '+33606060606' assert center.metadata['business_hours'] is None
def test_center_info_fill(): center = CenterInfo("Paris", "Centre 1", "https://.../centre") newloc = CenterLocation(1.122, 2.391, "Ok", "Cp") request = ScraperRequest(center.url, "2021-05-04") result = ScraperResult(request, "Doctolib", "2021-05-06") center.fill_localization(newloc) request.update_appointment_count(42) request.add_vaccine_type(Vaccine.PFIZER) request.add_vaccine_type(Vaccine.ASTRAZENECA) request.add_vaccine_type(Vaccine.MODERNA) request.update_internal_id("doctolibcentre1") request.update_practitioner_type(DRUG_STORE) request.set_appointments_only_by_phone(False) center.fill_result(result) assert center.location == newloc assert center.prochain_rdv == "2021-05-06" assert center.plateforme == "Doctolib" assert center.type == "drugstore" assert center.appointment_count == 42 assert center.internal_id == "doctolibcentre1" assert center.vaccine_type == ["Pfizer-BioNTech", "AstraZeneca", "Moderna"] assert not center.appointment_by_phone_only assert center.default() == { "departement": "Paris", "nom": "Centre 1", "url": "https://.../centre", "location": { "longitude": 1.122, "latitude": 2.391, "city": "Ok", "cp": "Cp" }, "metadata": None, "prochain_rdv": "2021-05-06", "plateforme": "Doctolib", "type": "drugstore", "appointment_count": 42, "internal_id": "doctolibcentre1", "vaccine_type": ["Pfizer-BioNTech", "AstraZeneca", "Moderna"], "appointment_by_phone_only": False, "erreur": None, "last_scan_with_availabilities": None, "appointment_schedules": None, "request_counts": None, }
def test_center_info_fill(): center = CenterInfo("Paris", "Centre 1", "https://.../centre") newloc = CenterLocation(1.122, 2.391, "Ok") request = ScraperRequest(center.url, "2021-05-04") result = ScraperResult(request, "Doctolib", "2021-05-06") center.fill_localization(newloc) request.update_appointment_count(42) request.add_vaccine_type(Vaccine.PFIZER) request.add_vaccine_type(Vaccine.ASTRAZENECA) request.add_vaccine_type(Vaccine.MODERNA) request.update_internal_id("doctolibcentre1") request.update_practitioner_type(DRUG_STORE) request.set_appointments_only_by_phone(False) center.fill_result(result) assert center.location == newloc assert center.prochain_rdv == "2021-05-06" assert center.plateforme == "Doctolib" assert center.type == "drugstore" assert center.appointment_count == 42 assert center.internal_id == "doctolibcentre1" assert center.vaccine_type == ["Pfizer-BioNTech", "AstraZeneca", "Moderna"] assert not center.appointment_by_phone_only assert center.default() == { 'departement': 'Paris', 'nom': 'Centre 1', 'url': 'https://.../centre', 'location': { 'longitude': 1.122, 'latitude': 2.391, 'city': 'Ok' }, 'metadata': None, 'prochain_rdv': '2021-05-06', 'plateforme': 'Doctolib', 'type': 'drugstore', 'appointment_count': 42, 'internal_id': 'doctolibcentre1', 'vaccine_type': ['Pfizer-BioNTech', 'AstraZeneca', 'Moderna'], 'appointment_by_phone_only': False, 'erreur': None, 'last_scan_with_availabilities': None, 'appointment_schedules': None }
def test_keldoc_scrape_nodate(): center1_url = ( "https://www.keldoc.com/centre-hospitalier-regional/lorient-56100/groupe-hospitalier" "-bretagne-sud-lorient-hopital-du-scorff?specialty=144 ") keldoc.KELDOC_ENABLED = True def app_center2(request: httpx.Request) -> httpx.Response: if "timetables/" in request.url.path: return httpx.Response(200, json={}) if (request.url.path == "/centre-hospitalier-regional/lorient-56100/groupe-hospitalier-bretagne-sud-lorient-hopital-du-scorff" ): return httpx.Response( 302, headers={ "Location": "https://vaccination-covid.keldoc.com/redirect/?dom=centre-hospitalier-regional&inst=lorient-56100&user=groupe-hospitalier-bretagne-sud-lorient-hopital-du-scorff&specialty=144 " }, ) for path in CENTER1_KELDOC: if request.url.path == path: return httpx.Response(200, json=get_test_data(CENTER1_KELDOC[path])) return httpx.Response(200, json={}) path_centerinfo = Path("tests", "fixtures", "keldoc", "cabinet-16913-centerinfo.json") centerinfo_1 = json.loads(path_centerinfo.read_text(encoding="utf-8")) center_info = CenterInfo.from_csv_data(centerinfo_1) request = ScraperRequest(center1_url, "2099-12-12", center_info=center_info) keldoc.session = httpx.Client(transport=httpx.MockTransport(app_center2)) date = fetch_slots(request) assert not date
def test_blocked_by_doctolib_par_centre(): # Cas de base. start_date = "2021-04-03" base_url = "https://partners.doctolib.fr/centre-de-vaccinations-internationales/ville1/centre1?pid=practice-165752&enable_cookies_consent=1" # noqa center_info = CenterInfo(departement="07", nom="Mon Super Centre", url=base_url) scrap_request = ScraperRequest(base_url, start_date, center_info) def app(request: httpx.Request) -> httpx.Response: assert "User-Agent" in request.headers if request.url.path == "/booking/centre1.json": path = Path("tests", "fixtures", "doctolib", "basic-booking.json") return httpx.Response(403, text="Anti dDos") assert request.url.path == "/availabilities.json" params = dict(httpx.QueryParams(request.url.query)) assert params == { "start_date": start_date, "visit_motives_ids": "2", "agenda_ids": "3", "insurance_sector": "public", "practice_ids": "4", "destroy_temporary": "true", "limit": str(DOCTOLIB_CONF.pagination["pages"]), } path = Path("tests", "fixtures", "doctolib", "basic-availabilities.json") return httpx.Response(200, json=json.loads( path.read_text(encoding="utf-8"))) client = httpx.Client(transport=httpx.MockTransport(app)) slots = DoctolibSlots(client=client, cooldown_interval=0) with pytest.raises(Blocked403): slots.fetch(scrap_request)
def test_convert_ordoclic_second(): data = { "nom": "Centre 2", "com_insee": "35238", "rdv_site_web": "https://site.fr/", "iterator": "ordoclic", "location": { "coordinates": { "lon": 1.1281, "lat": 93.182, }, "city": "Foobar", "address": "12 Avenue de la ville", "zip": "22000", }, "phone_number": "06 06 06 06 06", } center = CenterInfo.from_csv_data(data) assert center.nom == "Centre 2" assert center.metadata["address"] == "12 Avenue de la ville, 22000 Foobar" assert center.metadata["phone_number"] == "+33606060606" assert center.metadata["business_hours"] is None
def test_export_reserved_centers(tmp_path): centres_cherchés_dict = [{ "departement": "01", "nom": "Bugey Sud - Réservé aux médecins du groupe hospitalier", "url": "https://example.com/bugey-sud", "plateforme": "Doctolib", "prochain_rdv": "2021-04-10T00:00:00", "location": None, "metadata": None, "type": None, "appointment_by_phone_only": False, "appointment_count": 1, "internal_id": None, }] centres_cherchés = [ CenterInfo.from_dict(center) for center in centres_cherchés_dict ] out_dir = tmp_path / "out" out_dir.mkdir() outpath_format = str(out_dir / "{}.json") fake_now = dt.datetime(2021, 4, 4) get_start_date() with mock_datetime_now(fake_now): export_data(centres_cherchés, [], outpath_format=outpath_format) # Departements 01 and 59 should contain expected data. content = json.loads((out_dir / "01.json").read_text()) assert content == { "version": 1, "centres_disponibles": [], "centres_indisponibles": [], "last_scrap": [], "last_updated": "2021-04-04T00:00:00", }
def test_convert_centerinfo_invalid(): data = { "nom": "Centre 1", "gid": "d001", "rdv_site_web": "https://site.fr", "com_insee": "0095238", "rdv_tel": "06 06 06 06 06", "phone_number": "06 06 06 06 07", "adr_num": "1", "adr_voie": "Rue de la Fraise", "com_cp": "75016", "com_nom": "Paris", "business_hours": { "lundi": "09:50-10:10", "mardi": "09:10-10:10", "mercredi": "10:00-10:10", "jeudi": "10:20-10:40", "vendredi": "09:50-10:10", "samedi": "09:00-10:20", "dimanche": "Fermé", }, } center = CenterInfo.from_csv_data(data) assert center.departement == "" assert center.url == "https://site.fr" assert center.metadata["address"] == "1 Rue de la Fraise, 75016 Paris" assert center.metadata["phone_number"] == "+33606060607" assert center.metadata["business_hours"] == { "lundi": "09:50-10:10", "mardi": "09:10-10:10", "mercredi": "10:00-10:10", "jeudi": "10:20-10:40", "vendredi": "09:50-10:10", "samedi": "09:00-10:20", "dimanche": "Fermé", }