codecov[bot]: # [Codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=h1) Report
> Merging [#302](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=desc) into [master](https://codecov.io/gh/googlemaps/google-maps-services-python/commit/5439986a94b8f372fd1f697d5dafa9eef7dfe61e?src=pr&el=desc) will **increase** coverage by `1.35%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/graphs/tree.svg?width=650&token=VgQ96jQ3z0&height=150&src=pr)](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #302      +/-   ##
==========================================
+ Coverage   88.22%   89.57%   +1.35%     
==========================================
  Files          12       12              
  Lines         620      614       -6     
==========================================
+ Hits          547      550       +3     
+ Misses         73       64       -9
```


| [Impacted Files](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [googlemaps/places.py](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/diff?src=pr&el=tree#diff-Z29vZ2xlbWFwcy9wbGFjZXMucHk=) | `95.28% <ø> (-0.26%)` | :arrow_down: |
| [googlemaps/convert.py](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/diff?src=pr&el=tree#diff-Z29vZ2xlbWFwcy9jb252ZXJ0LnB5) | `97.39% <0%> (+0.86%)` | :arrow_up: |
| [googlemaps/client.py](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/diff?src=pr&el=tree#diff-Z29vZ2xlbWFwcy9jbGllbnQucHk=) | `95.67% <0%> (+4.32%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=footer). Last update [5439986...d807276](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov[bot]: # [Codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=h1) Report
> Merging [#302](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=desc) into [master](https://codecov.io/gh/googlemaps/google-maps-services-python/commit/5439986a94b8f372fd1f697d5dafa9eef7dfe61e?src=pr&el=desc) will **increase** coverage by `1.35%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/graphs/tree.svg?width=650&token=VgQ96jQ3z0&height=150&src=pr)](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #302      +/-   ##
==========================================
+ Coverage   88.22%   89.57%   +1.35%     
==========================================
  Files          12       12              
  Lines         620      614       -6     
==========================================
+ Hits          547      550       +3     
+ Misses         73       64       -9
```


| [Impacted Files](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [googlemaps/places.py](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/diff?src=pr&el=tree#diff-Z29vZ2xlbWFwcy9wbGFjZXMucHk=) | `95.28% <ø> (-0.26%)` | :arrow_down: |
| [googlemaps/convert.py](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/diff?src=pr&el=tree#diff-Z29vZ2xlbWFwcy9jb252ZXJ0LnB5) | `97.39% <0%> (+0.86%)` | :arrow_up: |
| [googlemaps/client.py](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302/diff?src=pr&el=tree#diff-Z29vZ2xlbWFwcy9jbGllbnQucHk=) | `95.67% <0%> (+4.32%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=footer). Last update [5439986...d807276](https://codecov.io/gh/googlemaps/google-maps-services-python/pull/302?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

jpoehnelt: @amuramoto sorry for all the formatting in the diff. only changes were the list of values and the tests with a subfield
diff --git a/googlemaps/places.py b/googlemaps/places.py
index 53ca388..a77f2d8 100644
--- a/googlemaps/places.py
+++ b/googlemaps/places.py
@@ -20,44 +20,92 @@
 from googlemaps import convert
 
 
-PLACES_FIND_FIELDS_BASIC = set([
-    "formatted_address", "geometry", "icon", "id", "name",
-    "permanently_closed", "photos", "place_id", "plus_code", "scope",
-    "types",
-])
-
-PLACES_FIND_FIELDS_CONTACT = set(["opening_hours",])
-
-PLACES_FIND_FIELDS_ATMOSPHERE = set([
-    "price_level", "rating", "user_ratings_total",
-])
-
-PLACES_FIND_FIELDS = (PLACES_FIND_FIELDS_BASIC ^
-                      PLACES_FIND_FIELDS_CONTACT ^
-                      PLACES_FIND_FIELDS_ATMOSPHERE)
-
-PLACES_DETAIL_FIELDS_BASIC = set([
-    "address_component", "adr_address", "alt_id", "formatted_address",
-    "geometry", "icon", "id", "name", "permanently_closed", "photo",
-    "place_id", "plus_code", "scope", "type", "url", "utc_offset", "vicinity",
-])
-
-PLACES_DETAIL_FIELDS_CONTACT = set([
-    "formatted_phone_number", "international_phone_number", "opening_hours",
-    "website",
-])
-
-PLACES_DETAIL_FIELDS_ATMOSPHERE = set([
-    "price_level", "rating", "review", "user_ratings_total",
-])
-
-PLACES_DETAIL_FIELDS = (PLACES_DETAIL_FIELDS_BASIC ^
-                        PLACES_DETAIL_FIELDS_CONTACT ^
-                        PLACES_DETAIL_FIELDS_ATMOSPHERE)
-
-
-def find_place(client, input, input_type, fields=None, location_bias=None,
-                language=None):
+PLACES_FIND_FIELDS_BASIC = set(
+    [
+        "formatted_address",
+        "geometry",
+        "geometry/location",
+        "geometry/location/lat",
+        "geometry/location/lng",
+        "geometry/viewport",
+        "geometry/viewport/northeast",
+        "geometry/viewport/northeast/lat",
+        "geometry/viewport/northeast/lng",
+        "geometry/viewport/southwest",
+        "geometry/viewport/southwest/lat",
+        "geometry/viewport/southwest/lng",
+        "icon",
+        "id",
+        "name",
+        "permanently_closed",
+        "photos",
+        "place_id",
+        "plus_code",
+        "scope",
+        "types",
+    ]
+)
+
+PLACES_FIND_FIELDS_CONTACT = set(["opening_hours"])
+
+PLACES_FIND_FIELDS_ATMOSPHERE = set(["price_level", "rating", "user_ratings_total"])
+
+PLACES_FIND_FIELDS = (
+    PLACES_FIND_FIELDS_BASIC
+    ^ PLACES_FIND_FIELDS_CONTACT
+    ^ PLACES_FIND_FIELDS_ATMOSPHERE
+)
+
+PLACES_DETAIL_FIELDS_BASIC = set(
+    [
+        "address_component",
+        "adr_address",
+        "alt_id",
+        "formatted_address",
+        "geometry",
+        "geometry/location",
+        "geometry/location/lat",
+        "geometry/location/lng",
+        "geometry/viewport",
+        "geometry/viewport/northeast",
+        "geometry/viewport/northeast/lat",
+        "geometry/viewport/northeast/lng",
+        "geometry/viewport/southwest",
+        "geometry/viewport/southwest/lat",
+        "geometry/viewport/southwest/lng",
+        "icon",
+        "id",
+        "name",
+        "permanently_closed",
+        "photo",
+        "place_id",
+        "plus_code",
+        "scope",
+        "type",
+        "url",
+        "utc_offset",
+        "vicinity",
+    ]
+)
+
+PLACES_DETAIL_FIELDS_CONTACT = set(
+    ["formatted_phone_number", "international_phone_number", "opening_hours", "website"]
+)
+
+PLACES_DETAIL_FIELDS_ATMOSPHERE = set(
+    ["price_level", "rating", "review", "user_ratings_total"]
+)
+
+PLACES_DETAIL_FIELDS = (
+    PLACES_DETAIL_FIELDS_BASIC
+    ^ PLACES_DETAIL_FIELDS_CONTACT
+    ^ PLACES_DETAIL_FIELDS_ATMOSPHERE
+)
+
+
+def find_place(
+    client, input, input_type, fields=None, location_bias=None, language=None
+):
     """
     A Find Place request takes a text input, and returns a place.
     The text input can be any kind of Places data, for example,
@@ -92,25 +140,27 @@ def find_place(client, input, input_type, fields=None, location_bias=None,
     params = {"input": input, "inputtype": input_type}
 
     if input_type != "textquery" and input_type != "phonenumber":
-        raise ValueError("Valid values for the `input_type` param for "
-                         "`find_place` are 'textquery' or 'phonenumber', "
-                         "the given value is invalid: '%s'" % input_type)
+        raise ValueError(
+            "Valid values for the `input_type` param for "
+            "`find_place` are 'textquery' or 'phonenumber', "
+            "the given value is invalid: '%s'" % input_type
+        )
 
     if fields:
         invalid_fields = set(fields) - PLACES_FIND_FIELDS
         if invalid_fields:
-            raise ValueError("Valid values for the `fields` param for "
-                             "`find_place` are '%s', these given field(s) "
-                             "are invalid: '%s'" % (
-                                "', '".join(PLACES_FIND_FIELDS),
-                                "', '".join(invalid_fields)))
+            raise ValueError(
+                "Valid values for the `fields` param for "
+                "`find_place` are '%s', these given field(s) "
+                "are invalid: '%s'"
+                % ("', '".join(PLACES_FIND_FIELDS), "', '".join(invalid_fields))
+            )
         params["fields"] = convert.join_list(",", fields)
 
     if location_bias:
         valid = ["ipbias", "point", "circle", "rectangle"]
         if location_bias.split(":")[0] not in valid:
-            raise ValueError("location_bias should be prefixed with one of: %s"
-                             % valid)
+            raise ValueError("location_bias should be prefixed with one of: %s" % valid)
         params["locationbias"] = location_bias
     if language:
         params["language"] = language
@@ -118,9 +168,19 @@ def find_place(client, input, input_type, fields=None, location_bias=None,
     return client._request("/maps/api/place/findplacefromtext/json", params)
 
 
-def places(client, query, location=None, radius=None, language=None,
-           min_price=None, max_price=None, open_now=False, type=None, region=None,
-           page_token=None):
+def places(
+    client,
+    query,
+    location=None,
+    radius=None,
+    language=None,
+    min_price=None,
+    max_price=None,
+    open_now=False,
+    type=None,
+    region=None,
+    page_token=None,
+):
     """
     Places search.
 
@@ -169,15 +229,36 @@ def places(client, query, location=None, radius=None, language=None,
         html_attributions: set of attributions which must be displayed
         next_page_token: token for retrieving the next page of results
     """
-    return _places(client, "text", query=query, location=location,
-                   radius=radius, language=language, min_price=min_price,
-                   max_price=max_price, open_now=open_now, type=type, region=region,
-                   page_token=page_token)
-
-
-def places_nearby(client, location=None, radius=None, keyword=None,
-                  language=None, min_price=None, max_price=None, name=None,
-                  open_now=False, rank_by=None, type=None, page_token=None):
+    return _places(
+        client,
+        "text",
+        query=query,
+        location=location,
+        radius=radius,
+        language=language,
+        min_price=min_price,
+        max_price=max_price,
+        open_now=open_now,
+        type=type,
+        region=region,
+        page_token=page_token,
+    )
+
+
+def places_nearby(
+    client,
+    location=None,
+    radius=None,
+    keyword=None,
+    language=None,
+    min_price=None,
+    max_price=None,
+    name=None,
+    open_now=False,
+    rank_by=None,
+    type=None,
+    page_token=None,
+):
     """
     Performs nearby search for places.
 
@@ -240,21 +321,49 @@ def places_nearby(client, location=None, radius=None, keyword=None,
         raise ValueError("either a location or page_token arg is required")
     if rank_by == "distance":
         if not (keyword or name or type):
-            raise ValueError("either a keyword, name, or type arg is required "
-                             "when rank_by is set to distance")
+            raise ValueError(
+                "either a keyword, name, or type arg is required "
+                "when rank_by is set to distance"
+            )
         elif radius is not None:
-            raise ValueError("radius cannot be specified when rank_by is set to "
-                             "distance")
-
-    return _places(client, "nearby", location=location, radius=radius,
-                   keyword=keyword, language=language, min_price=min_price,
-                   max_price=max_price, name=name, open_now=open_now,
-                   rank_by=rank_by, type=type, page_token=page_token)
-
-
-def _places(client, url_part, query=None, location=None, radius=None,
-            keyword=None, language=None, min_price=0, max_price=4, name=None,
-            open_now=False, rank_by=None, type=None, region=None, page_token=None):
+            raise ValueError(
+                "radius cannot be specified when rank_by is set to " "distance"
+            )
+
+    return _places(
+        client,
+        "nearby",
+        location=location,
+        radius=radius,
+        keyword=keyword,
+        language=language,
+        min_price=min_price,
+        max_price=max_price,
+        name=name,
+        open_now=open_now,
+        rank_by=rank_by,
+        type=type,
+        page_token=page_token,
+    )
+
+
+def _places(
+    client,
+    url_part,
+    query=None,
+    location=None,
+    radius=None,
+    keyword=None,
+    language=None,
+    min_price=0,
+    max_price=4,
+    name=None,
+    open_now=False,
+    rank_by=None,
+    type=None,
+    region=None,
+    page_token=None,
+):
     """
     Internal handler for ``places`` and ``places_nearby``.
     See each method's docs for arg details.
@@ -318,11 +427,12 @@ def place(client, place_id, session_token=None, fields=None, language=None):
     if fields:
         invalid_fields = set(fields) - PLACES_DETAIL_FIELDS
         if invalid_fields:
-            raise ValueError("Valid values for the `fields` param for "
-                             "`place` are '%s', these given field(s) "
-                             "are invalid: '%s'" % (
-                                "', '".join(PLACES_DETAIL_FIELDS),
-                                "', '".join(invalid_fields)))
+            raise ValueError(
+                "Valid values for the `fields` param for "
+                "`place` are '%s', these given field(s) "
+                "are invalid: '%s'"
+                % ("', '".join(PLACES_DETAIL_FIELDS), "', '".join(invalid_fields))
+            )
         params["fields"] = convert.join_list(",", fields)
 
     if language:
@@ -372,15 +482,27 @@ def places_photo(client, photo_reference, max_width=None, max_height=None):
     # "extract_body" and "stream" args here are used to return an iterable
     # response containing the image file data, rather than converting from
     # json.
-    response = client._request("/maps/api/place/photo", params,
-                           extract_body=lambda response: response,
-                           requests_kwargs={"stream": True})
+    response = client._request(
+        "/maps/api/place/photo",
+        params,
+        extract_body=lambda response: response,
+        requests_kwargs={"stream": True},
+    )
     return response.iter_content()
 
 
-def places_autocomplete(client, input_text, session_token=None, offset=None,
-                        location=None, radius=None, language=None, types=None,
-                        components=None, strict_bounds=False):
+def places_autocomplete(
+    client,
+    input_text,
+    session_token=None,
+    offset=None,
+    location=None,
+    radius=None,
+    language=None,
+    types=None,
+    components=None,
+    strict_bounds=False,
+):
     """
     Returns Place predictions given a textual search string and optional
     geographic bounds.
@@ -425,14 +547,24 @@ def places_autocomplete(client, input_text, session_token=None, offset=None,
     :rtype: list of predictions
 
     """
-    return _autocomplete(client, "", input_text, session_token=session_token,
-                         offset=offset, location=location, radius=radius,
-                         language=language, types=types, components=components,
-                         strict_bounds=strict_bounds)
-
-
-def places_autocomplete_query(client, input_text, offset=None, location=None,
-                              radius=None, language=None):
+    return _autocomplete(
+        client,
+        "",
+        input_text,
+        session_token=session_token,
+        offset=offset,
+        location=location,
+        radius=radius,
+        language=language,
+        types=types,
+        components=components,
+        strict_bounds=strict_bounds,
+    )
+
+
+def places_autocomplete_query(
+    client, input_text, offset=None, location=None, radius=None, language=None
+):
     """
     Returns Place predictions given a textual search query, such as
     "pizza near New York", and optional geographic bounds.
@@ -457,13 +589,30 @@ def places_autocomplete_query(client, input_text, offset=None, location=None,
 
     :rtype: list of predictions
     """
-    return _autocomplete(client, "query", input_text, offset=offset,
-                         location=location, radius=radius, language=language)
-
-
-def _autocomplete(client, url_part, input_text, session_token=None,
-                  offset=None, location=None, radius=None, language=None,
-                  types=None, components=None, strict_bounds=False):
+    return _autocomplete(
+        client,
+        "query",
+        input_text,
+        offset=offset,
+        location=location,
+        radius=radius,
+        language=language,
+    )
+
+
+def _autocomplete(
+    client,
+    url_part,
+    input_text,
+    session_token=None,
+    offset=None,
+    location=None,
+    radius=None,
+    language=None,
+    types=None,
+    components=None,
+    strict_bounds=False,
+):
     """
     Internal handler for ``autocomplete`` and ``autocomplete_query``.
     See each method's docs for arg details.

Sub fields not supported by place 
Sub fields like `geometry/location` give an error when they are supported by the places API.


eg.
```
GMAPS.place(
  place_id=place_id, fields=['geometry/location']
)
```
diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py
index 17bf03e..f6fa9f8 100644
--- a/googlemaps/test/test_places.py
+++ b/googlemaps/test/test_places.py
@@ -47,14 +47,14 @@ class PlacesTest(_test.TestCase):
                       status=200, content_type='application/json')
 
         self.client.find_place('restaurant', 'textquery',
-                                fields=['geometry', 'id'],
+                                fields=['geometry/location', 'id'],
                                 location_bias='point:90,90',
                                 language=self.language)
 
         self.assertEqual(1, len(responses.calls))
         self.assertURLEqual('%s?language=en-AU&inputtype=textquery&'
                             'locationbias=point:90,90&input=restaurant'
-                            '&fields=geometry,id&key=%s'
+                            '&fields=geometry/location,id&key=%s'
                             % (url, self.key), responses.calls[0].request.url)
 
         with self.assertRaises(ValueError):
@@ -119,11 +119,11 @@ class PlacesTest(_test.TestCase):
                       status=200, content_type='application/json')
 
         self.client.place('ChIJN1t_tDeuEmsRUsoyG83frY4',
-                          fields=['geometry', 'id'], language=self.language)
+                          fields=['geometry/location', 'id'], language=self.language)
 
         self.assertEqual(1, len(responses.calls))
         self.assertURLEqual('%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4'
-                            '&key=%s&fields=geometry,id'
+                            '&key=%s&fields=geometry/location,id'
                             % (url, self.key), responses.calls[0].request.url)
 
         with self.assertRaises(ValueError):

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov responses mock
3.7
test_requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi @ file:///croot/certifi_1671487769961/work/certifi
charset-normalizer==3.4.1
coverage==7.2.7
exceptiongroup==1.2.2
-e git+https://github.com/googlemaps/google-maps-services-python.git@3afe6586698523ff96272d01c4845e150abe0e53#egg=googlemaps
idna==3.10
importlib-metadata==6.7.0
iniconfig==2.0.0
mock==5.2.0
packaging==24.0
pluggy==1.2.0
pytest==7.4.4
pytest-cov==4.1.0
PyYAML==6.0.1
requests==2.31.0
responses==0.23.3
tomli==2.0.1
types-PyYAML==6.0.12.12
typing_extensions==4.7.1
urllib3==2.0.7
zipp==3.15.0

name: google-maps-services-python
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - charset-normalizer==3.4.1
      - coverage==7.2.7
      - exceptiongroup==1.2.2
      - idna==3.10
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - mock==5.2.0
      - packaging==24.0
      - pluggy==1.2.0
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pyyaml==6.0.1
      - requests==2.31.0
      - responses==0.23.3
      - tomli==2.0.1
      - types-pyyaml==6.0.12.12
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - zipp==3.15.0
prefix: /opt/conda/envs/google-maps-services-python

googlemaps/test/test_places.py::PlacesTest::test_place_detail googlemaps/test/test_places.py::PlacesTest::test_places_find
googlemaps/test/test_places.py::PlacesTest::test_autocomplete googlemaps/test/test_places.py::PlacesTest::test_autocomplete_query googlemaps/test/test_places.py::PlacesTest::test_photo googlemaps/test/test_places.py::PlacesTest::test_places_nearby_search googlemaps/test/test_places.py::PlacesTest::test_places_text_search
googlemaps/places.py
googlemaps/places.py