pyfunda 3.1.0__tar.gz → 3.1.1__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.
Files changed (55) hide show
  1. {pyfunda-3.1.0 → pyfunda-3.1.1}/PKG-INFO +13 -5
  2. {pyfunda-3.1.0 → pyfunda-3.1.1}/README.md +10 -2
  3. pyfunda-3.1.0/funda/autocomplete.py → pyfunda-3.1.1/funda/_autocomplete.py +2 -2
  4. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/funda.py +4 -4
  5. {pyfunda-3.1.0 → pyfunda-3.1.1}/pyproject.toml +22 -3
  6. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_autocomplete.py +5 -5
  7. {pyfunda-3.1.0 → pyfunda-3.1.1}/.dockerignore +0 -0
  8. {pyfunda-3.1.0 → pyfunda-3.1.1}/.github/FUNDING.yml +0 -0
  9. {pyfunda-3.1.0 → pyfunda-3.1.1}/.github/workflows/publish.yml +0 -0
  10. {pyfunda-3.1.0 → pyfunda-3.1.1}/.gitignore +0 -0
  11. {pyfunda-3.1.0 → pyfunda-3.1.1}/Dockerfile +0 -0
  12. {pyfunda-3.1.0 → pyfunda-3.1.1}/LICENSE +0 -0
  13. {pyfunda-3.1.0 → pyfunda-3.1.1}/docs/API.md +0 -0
  14. {pyfunda-3.1.0 → pyfunda-3.1.1}/docs/ARCHITECTURE.md +0 -0
  15. {pyfunda-3.1.0 → pyfunda-3.1.1}/docs/DEVELOPMENT.md +0 -0
  16. {pyfunda-3.1.0 → pyfunda-3.1.1}/docs/EXAMPLES.md +0 -0
  17. {pyfunda-3.1.0 → pyfunda-3.1.1}/docs/README.md +0 -0
  18. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/almere_age_rank.py +0 -0
  19. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/analysis.ipynb +0 -0
  20. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/batch_details.py +0 -0
  21. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/broker_due_diligence.py +0 -0
  22. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/enrichment_export.py +0 -0
  23. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/export_to_csv.py +0 -0
  24. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/full_api_walkthrough.py +0 -0
  25. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/neighborhood_market_snapshot.py +0 -0
  26. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/new_listings_alert.py +0 -0
  27. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/poll_new_listings.py +0 -0
  28. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/price_history.py +0 -0
  29. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/price_tracker.py +0 -0
  30. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/search_sold.py +0 -0
  31. {pyfunda-3.1.0 → pyfunda-3.1.1}/examples/similar_sales_comp.py +0 -0
  32. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/__init__.py +0 -0
  33. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_autocomplete_parser.py +0 -0
  34. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_detail_parser.py +0 -0
  35. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_enrichment_parser.py +0 -0
  36. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_parallel.py +0 -0
  37. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_parse_helpers.py +0 -0
  38. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_price_history_parser.py +0 -0
  39. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_search_parser.py +0 -0
  40. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/_transport.py +0 -0
  41. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/constants.py +0 -0
  42. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/exceptions.py +0 -0
  43. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/headers.py +0 -0
  44. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/listing.py +0 -0
  45. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/models.py +0 -0
  46. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/parsing.py +0 -0
  47. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/py.typed +0 -0
  48. {pyfunda-3.1.0 → pyfunda-3.1.1}/funda/search.py +0 -0
  49. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/__init__.py +0 -0
  50. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_client.py +0 -0
  51. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_enrichment_parser.py +0 -0
  52. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_live.py +0 -0
  53. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_models.py +0 -0
  54. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_search.py +0 -0
  55. {pyfunda-3.1.0 → pyfunda-3.1.1}/tests/test_transport_parallel.py +0 -0
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyfunda
3
- Version: 3.1.0
4
- Summary: Python API for Funda.nl real estate listings
3
+ Version: 3.1.1
4
+ Summary: Python API wrapper for Funda.nl, the Dutch real estate platform. Reverse-engineered mobile API client, no scraping, no Selenium, no CAPTCHA.
5
5
  Project-URL: Homepage, https://github.com/0xMH/pyfunda
6
6
  Project-URL: Repository, https://github.com/0xMH/pyfunda
7
7
  Project-URL: Issues, https://github.com/0xMH/pyfunda/issues
8
8
  Author: 0xMH
9
9
  License-Expression: AGPL-3.0-or-later
10
10
  License-File: LICENSE
11
- Keywords: api,funda,housing,netherlands,real-estate,scraper
11
+ Keywords: api,api-wrapper,client,dutch,funda,funda-api,funda-nl,funda-scraper,housing,housing-api,mobile-api,netherlands,real-estate,real-estate-api,rest-api,reverse-engineering,scraper,sdk
12
12
  Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
@@ -29,9 +29,17 @@ Description-Content-Type: text/markdown
29
29
  [![Python versions](https://img.shields.io/pypi/pyversions/pyfunda)](https://pypi.org/project/pyfunda/)
30
30
  [![License](https://img.shields.io/pypi/l/pyfunda)](https://github.com/0xMH/pyfunda/blob/main/LICENSE)
31
31
 
32
- The only working real Python API for Funda ([funda.nl](https://www.funda.nl)) -- the Netherlands' largest real estate platform.
32
+ **pyfunda** is a Python API wrapper for [Funda.nl](https://www.funda.nl), the Netherlands' largest Dutch real estate platform. It talks to Funda's reverse engineered mobile JSON API, so you get clean typed objects for listings, prices, media, brokers, and price history without HTML scraping, Selenium, a headless browser, or CAPTCHA solving.
33
33
 
34
- > If you find this useful, consider giving it a star -- it helps others discover the project.
34
+ Funda has no public developer API. pyfunda is the only working opensource Python client that hits Funda's app facing `*.funda.io` endpoints directly, the same ones the official Android app uses.
35
+
36
+ ```bash
37
+ pip install pyfunda
38
+ ```
39
+
40
+ Use pyfunda as a Funda API client or Funda Python SDK to fetch Dutch property listings, run search queries by city and price, pull listing detail and media, get broker info and reviews, read price history, and stream new listings. If you have been looking for a working fundascraper alternative or a Netherlands housing API, this is the only Python wrapper hitting the same `*.funda.io` endpoints the Funda Android app uses.
41
+
42
+ > If you find this useful, consider giving it a star, it helps others discover the project.
35
43
 
36
44
  [![Star History Chart](https://api.star-history.com/svg?repos=0xMH/pyfunda&type=Date)](https://star-history.com/#0xMH/pyfunda&Date)
37
45
 
@@ -4,9 +4,17 @@
4
4
  [![Python versions](https://img.shields.io/pypi/pyversions/pyfunda)](https://pypi.org/project/pyfunda/)
5
5
  [![License](https://img.shields.io/pypi/l/pyfunda)](https://github.com/0xMH/pyfunda/blob/main/LICENSE)
6
6
 
7
- The only working real Python API for Funda ([funda.nl](https://www.funda.nl)) -- the Netherlands' largest real estate platform.
7
+ **pyfunda** is a Python API wrapper for [Funda.nl](https://www.funda.nl), the Netherlands' largest Dutch real estate platform. It talks to Funda's reverse engineered mobile JSON API, so you get clean typed objects for listings, prices, media, brokers, and price history without HTML scraping, Selenium, a headless browser, or CAPTCHA solving.
8
8
 
9
- > If you find this useful, consider giving it a star -- it helps others discover the project.
9
+ Funda has no public developer API. pyfunda is the only working opensource Python client that hits Funda's app facing `*.funda.io` endpoints directly, the same ones the official Android app uses.
10
+
11
+ ```bash
12
+ pip install pyfunda
13
+ ```
14
+
15
+ Use pyfunda as a Funda API client or Funda Python SDK to fetch Dutch property listings, run search queries by city and price, pull listing detail and media, get broker info and reviews, read price history, and stream new listings. If you have been looking for a working fundascraper alternative or a Netherlands housing API, this is the only Python wrapper hitting the same `*.funda.io` endpoints the Funda Android app uses.
16
+
17
+ > If you find this useful, consider giving it a star, it helps others discover the project.
10
18
 
11
19
  [![Star History Chart](https://api.star-history.com/svg?repos=0xMH/pyfunda&type=Date)](https://star-history.com/#0xMH/pyfunda&Date)
12
20
 
@@ -1,4 +1,4 @@
1
- """Autocomplete payload construction."""
1
+ """Internal autocomplete payload construction."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -14,7 +14,7 @@ from funda.models import JsonDict
14
14
 
15
15
 
16
16
  @dataclass(frozen=True, slots=True)
17
- class _LocationAutocomplete:
17
+ class LocationAutocomplete:
18
18
  value: str
19
19
  timeout: str = "3s"
20
20
  size: int = 10
@@ -28,7 +28,7 @@ from funda.constants import (
28
28
  PAGE_SIZE,
29
29
  )
30
30
  from funda.exceptions import FundaRequestError, ListingNotFound, PriceHistoryError, SearchError
31
- from funda.autocomplete import _LocationAutocomplete
31
+ from funda._autocomplete import LocationAutocomplete
32
32
  from funda.listing import Listing, LocationSuggestion, PriceHistory
33
33
  from funda.models import JsonDict
34
34
  from funda.parsing import (
@@ -84,7 +84,7 @@ class Funda:
84
84
  def __enter__(self) -> "Funda":
85
85
  return self
86
86
 
87
- def __exit__(self, *args) -> None:
87
+ def __exit__(self, *_) -> None:
88
88
  self.close()
89
89
 
90
90
  def listing(self, listing_id: int | str) -> Listing:
@@ -130,7 +130,7 @@ class Funda:
130
130
  sort: Sequence[Any] | None = None,
131
131
  ) -> list[LocationSuggestion]:
132
132
  """Suggest Funda location identifiers for search-box text."""
133
- autocomplete = _LocationAutocomplete(
133
+ autocomplete = LocationAutocomplete(
134
134
  value=value,
135
135
  size=size,
136
136
  timeout=timeout,
@@ -434,7 +434,7 @@ class Funda:
434
434
 
435
435
  raise SearchError("Search failed without a response")
436
436
 
437
- def _autocomplete(self, autocomplete: _LocationAutocomplete) -> JsonDict:
437
+ def _autocomplete(self, autocomplete: LocationAutocomplete) -> JsonDict:
438
438
  payload = autocomplete.to_payload()
439
439
  for attempt in range(3):
440
440
  response = self._transport.post(
@@ -4,15 +4,34 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyfunda"
7
- version = "3.1.0"
8
- description = "Python API for Funda.nl real estate listings"
7
+ version = "3.1.1"
8
+ description = "Python API wrapper for Funda.nl, the Dutch real estate platform. Reverse-engineered mobile API client, no scraping, no Selenium, no CAPTCHA."
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-or-later"
11
11
  requires-python = ">=3.10"
12
12
  authors = [
13
13
  { name = "0xMH" }
14
14
  ]
15
- keywords = ["funda", "real-estate", "netherlands", "housing", "api", "scraper"]
15
+ keywords = [
16
+ "funda",
17
+ "funda-api",
18
+ "funda-nl",
19
+ "funda-scraper",
20
+ "real-estate",
21
+ "real-estate-api",
22
+ "netherlands",
23
+ "dutch",
24
+ "housing",
25
+ "housing-api",
26
+ "api",
27
+ "api-wrapper",
28
+ "rest-api",
29
+ "client",
30
+ "sdk",
31
+ "mobile-api",
32
+ "reverse-engineering",
33
+ "scraper",
34
+ ]
16
35
  classifiers = [
17
36
  "Development Status :: 4 - Beta",
18
37
  "Intended Audience :: Developers",
@@ -1,6 +1,6 @@
1
1
  import unittest
2
2
 
3
- from funda.autocomplete import _LocationAutocomplete
3
+ from funda._autocomplete import LocationAutocomplete
4
4
  from funda.constants import (
5
5
  LOCATION_AUTOCOMPLETE_AREA_TYPES,
6
6
  LOCATION_AUTOCOMPLETE_TEMPLATE_ID,
@@ -45,7 +45,7 @@ AUTOCOMPLETE_RESPONSE = {
45
45
 
46
46
  class AutocompleteTests(unittest.TestCase):
47
47
  def test_payload_matches_funda_searchbox_template(self) -> None:
48
- payload = _LocationAutocomplete("almere poor").to_payload()
48
+ payload = LocationAutocomplete("almere poor").to_payload()
49
49
 
50
50
  self.assertEqual(payload["id"], LOCATION_AUTOCOMPLETE_TEMPLATE_ID)
51
51
  self.assertEqual(payload["params"]["value"], "almere poor")
@@ -60,7 +60,7 @@ class AutocompleteTests(unittest.TestCase):
60
60
  )
61
61
 
62
62
  def test_payload_can_limit_area_types_for_vague_area_searches(self) -> None:
63
- payload = _LocationAutocomplete(
63
+ payload = LocationAutocomplete(
64
64
  "amsterdam west",
65
65
  area_types=("city", "municipality", "neighborhood", "wijk"),
66
66
  size=5,
@@ -74,9 +74,9 @@ class AutocompleteTests(unittest.TestCase):
74
74
 
75
75
  def test_invalid_payload_values_fail_before_network(self) -> None:
76
76
  with self.assertRaises(ValueError):
77
- _LocationAutocomplete("").to_payload()
77
+ LocationAutocomplete("").to_payload()
78
78
  with self.assertRaises(ValueError):
79
- _LocationAutocomplete("amsterdam", size=0).to_payload()
79
+ LocationAutocomplete("amsterdam", size=0).to_payload()
80
80
 
81
81
  def test_parse_location_suggestions_maps_geo_hits(self) -> None:
82
82
  suggestions = parse_location_suggestions(AUTOCOMPLETE_RESPONSE)
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
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
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
File without changes