pyfunda 2.4.0__tar.gz → 2.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ .venv
2
+ .git
3
+ dist
4
+ __pycache__
5
+ *.egg-info
6
+ .claude
@@ -0,0 +1,13 @@
1
+ FROM ghcr.io/astral-sh/uv:0.6.6-python3.12-bookworm-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY pyproject.toml uv.lock ./
6
+ RUN uv sync --frozen --no-install-project --no-cache
7
+
8
+ COPY . .
9
+ RUN uv sync --frozen --no-cache
10
+
11
+ ENV PATH="/app/.venv/bin:$PATH"
12
+
13
+ CMD ["bash"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyfunda
3
- Version: 2.4.0
3
+ Version: 2.6.0
4
4
  Summary: Python API for Funda.nl real estate listings
5
5
  Project-URL: Homepage, https://github.com/0xMH/pyfunda
6
6
  Project-URL: Repository, https://github.com/0xMH/pyfunda
@@ -324,6 +324,9 @@ class Funda:
324
324
  plot_max: int | None = None,
325
325
  object_type: list[str] | None = None,
326
326
  energy_label: list[str] | None = None,
327
+ construction_type: str | list[str] | None = None,
328
+ construction_year_min: int | None = None,
329
+ construction_year_max: int | None = None,
327
330
  radius_km: int | None = None,
328
331
  sort: str | None = None,
329
332
  page: int = 0,
@@ -343,6 +346,9 @@ class Funda:
343
346
  plot_max: Maximum plot area in m²
344
347
  object_type: Property types (e.g. ["house", "apartment"])
345
348
  energy_label: Energy labels (e.g. ["A", "A+", "A++"])
349
+ construction_type: "resale" or "newly_built", or a list of both
350
+ construction_year_min: Minimum construction year (maps to Funda periods)
351
+ construction_year_max: Maximum construction year (maps to Funda periods)
346
352
  radius_km: Search radius in km (use with single location/postcode)
347
353
  sort: Sort order - "newest", "oldest", "price_asc", "price_desc",
348
354
  "area_asc", "area_desc", "plot_desc", "city", "postcode", or None
@@ -449,6 +455,41 @@ class Funda:
449
455
  if energy_label:
450
456
  params["energy_label"] = energy_label
451
457
 
458
+ # Construction type filter
459
+ if construction_type:
460
+ if isinstance(construction_type, str):
461
+ params["construction_type"] = [construction_type]
462
+ else:
463
+ params["construction_type"] = list(construction_type)
464
+
465
+ # Construction year filter (mapped to Funda's predefined periods)
466
+ if construction_year_min is not None or construction_year_max is not None:
467
+ period_boundaries = [1906, 1931, 1945, 1960, 1971, 1981, 1991, 2001, 2011, 2021]
468
+ all_periods = (
469
+ ["before_1906"]
470
+ + [f"from_{period_boundaries[i]}_to_{period_boundaries[i+1]-1}" for i in range(len(period_boundaries) - 1)]
471
+ + ["after_2020"]
472
+ )
473
+ # Map each period to its year range for filtering
474
+ period_ranges = {
475
+ "before_1906": (0, 1905),
476
+ "from_1906_to_1930": (1906, 1930),
477
+ "from_1931_to_1944": (1931, 1944),
478
+ "from_1945_to_1959": (1945, 1959),
479
+ "from_1960_to_1970": (1960, 1970),
480
+ "from_1971_to_1980": (1971, 1980),
481
+ "from_1981_to_1990": (1981, 1990),
482
+ "from_1991_to_2000": (1991, 2000),
483
+ "from_2001_to_2010": (2001, 2010),
484
+ "from_2011_to_2020": (2011, 2020),
485
+ "after_2020": (2021, 9999),
486
+ }
487
+ year_min = construction_year_min or 0
488
+ year_max = construction_year_max or 9999
489
+ selected = [p for p in all_periods if period_ranges[p][1] >= year_min and period_ranges[p][0] <= year_max]
490
+ if selected:
491
+ params["construction_period"] = selected
492
+
452
493
  # Build NDJSON query
453
494
  index_line = json.dumps({"index": "listings-wonen-searcher-alias-prod"})
454
495
  query_line = json.dumps({"id": "search_result_20250805", "params": params})
@@ -771,23 +812,42 @@ class Funda:
771
812
  price = price_data.get("selling_price", [None])[0]
772
813
  if not price:
773
814
  price = price_data.get("rent_price", [None])[0] if price_data.get("rent_price") else None
815
+ price_condition = price_data.get("selling_price_condition") or price_data.get("rent_price_condition")
774
816
  else:
775
817
  price = price_data
818
+ price_condition = None
819
+
820
+ offering_types = source.get("offering_type", [])
821
+ offering_type = offering_types[0] if offering_types else None
822
+
823
+ agents = source.get("agent", [])
824
+ agent = agents[0] if agents else {}
776
825
 
777
826
  listing_data = {
778
827
  "global_id": int(hit.get("_id", 0)),
779
828
  "title": f"{address.get('street_name', '')} {address.get('house_number', '')}".strip(),
829
+ "street_name": address.get("street_name"),
830
+ "house_number": address.get("house_number"),
831
+ "house_number_suffix": address.get("house_number_suffix"),
780
832
  "city": address.get("city"),
781
833
  "postcode": address.get("postal_code"),
782
834
  "province": address.get("province"),
783
835
  "neighbourhood": address.get("neighbourhood"),
784
836
  "price": price,
837
+ "price_condition": price_condition,
785
838
  "living_area": source.get("floor_area", [None])[0] if source.get("floor_area") else None,
786
839
  "plot_area": source.get("plot_area_range", {}).get("gte"),
787
840
  "bedrooms": source.get("number_of_bedrooms"),
841
+ "rooms": source.get("number_of_rooms"),
788
842
  "energy_label": source.get("energy_label"),
789
843
  "object_type": source.get("object_type"),
844
+ "offering_type": offering_type,
790
845
  "construction_type": source.get("construction_type"),
846
+ "publish_date": source.get("publish_date"),
847
+ "detail_url": source.get("object_detail_page_relative_url"),
848
+ "broker_id": agent.get("id"),
849
+ "broker_name": agent.get("name"),
850
+ "broker_association": agent.get("association"),
791
851
  "photos": source.get("thumbnail_id", [])[:5],
792
852
  }
793
853
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyfunda"
7
- version = "2.4.0"
7
+ version = "2.6.0"
8
8
  description = "Python API for Funda.nl real estate listings"
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-or-later"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes