Repository: planetlabs/planet-client-python

Issue:
Fix broken CLI code examples
_Base URL:_ https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-guide/

**General issue:**

- [x]  Most code examples have some prefix from the console (i.e., a "`$`" before the command), which makes copying and pasting the command a nuicence. I highly recommend finding all console prefixes and removing them.

_For example:_ On https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-intro/#collecting-results-with-planet-collect
`$ planet data filter | planet data search PSScene - | planet collect -`

**Data Client:**  https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-data/
- [x] 1. `search` function needs the `--filter` flag.
**Solution:** Add the `--filter` flag before the filter (`filter.json` or STDIN).
_For example:_
`planet data search PSScene filter.json` ➡️ `planet data search PSScene --filter filter.json`
`planet data filter | planet data search PSScene -` ➡️ `planet data filter | planet data search PSScene --filter -`

- [x] 2. `search-quick` function is not supported.
**Solution:** Either change to `search` or remove example.
__For example:_
`planet data filter --range cloud_percent lt 10 | planet data search-quick PSScene -` ➡️ `planet data filter --range cloud_percent lt 10 | planet data search PSScene --filter -`

- [x] 3. `permission` option no longer needs an input.
**Solution:** Remove input to `--permission` flag.
_For example:_ `planet data filter --permission false --asset ortho_analytic_8b_sr | planet data search PSScene -` ➡️ `planet data filter --permission --asset ortho_analytic_8b_sr | planet data search PSScene --filter -` 

**Orders Client:** https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-orders/
- [x] 1. Broken command for `orders list`
**Solution:** `planet** orders --state running` ➡️ `planet orders list --state running`
- [x] 2. STAC output with the composite tool is not currently supported (https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-orders/#clip-composite):
```console
curl -s https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-clip-composite.json \
| planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Streaming Clip & Composite' \
 20220605_124027_64_242b,20220605_124025_34_242b --tools - | planet orders create - 

Error: {"field":null,"general":[{"message":"Unable to accept order: STAC output with the composite tool is not currently supported."}]}
```
- [x] 3. Missing options flags and unneeded ID flag:
`planet orders request PSScene visual --name 'No STAC' --no-stac --id 20220605_124027_64_242b` ➡️  `planet orders request --item-type PSScene --bundle visual --name 'No STAC' --no-stac 20220605_124027_64_242b`

**Extra tips:** https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-tips-tricks/
- [x] 1. Advanced `jq` example returns nothing and needs syntax highlighting
```console
planet orders list | jq -rs '.[] | "(.id) (.created_on) (.state) (.products[0].item_type)"'

(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
(.id) (.created_on) (.state) (.products[0].item_type)
```

**_Note:_** 
- Issues with `planet data filter` piping into `planet data search` are found on:
    - [CLI intro](https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-intro/)
    - [Data API](https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-data/)
    - [Orders API](https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-orders/)
    - [extra tips](https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-tips-tricks/)
- Issues with the `--permission` flag are found on:
    - [Data API](https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-data/)
    - [extra tips](https://planet-sdk-for-python-v2.readthedocs.io/en/latest/cli/cli-tips-tricks/)

Discussion:

Patch:
diff --git a/CHANGES.txt b/CHANGES.txt
index 4963823..fd17000 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -9,7 +9,13 @@ Changed:
 Added:
 - The Session class can now construct clients by name with its client method
   (#858).
+
+Changed:
 - Updated product bundle spec to 2/24/23 version.
+- `planet.subscription_request.catalog_source` and 
+  `planet subscriptions source-catalog` now simplify geojson given in
+  `geometry` parameter/option to just the geometry, the form required by the
+   subscriptions api (#880).
 
 
 2.0.0-rc.1 (2023-03-06)
diff --git a/docs/cli/cli-intro.md b/docs/cli/cli-intro.md
index 6100876..91bb052 100644
--- a/docs/cli/cli-intro.md
+++ b/docs/cli/cli-intro.md
@@ -173,7 +173,7 @@ represent GeoJSON features, the JSON blob is a GeoJSON FeatureCollection.
 Otherwise, the JSON blob is a list of the individual results.
 
 ```console
-$ planet data search PSScene | planet collect -
+planet data search PSScene | planet collect -
 ```
 
 This gives you a fully compliant GeoJSON FeatureCollection, which is 
diff --git a/docs/cli/cli-orders.md b/docs/cli/cli-orders.md
index ab47780..bf5049f 100644
--- a/docs/cli/cli-orders.md
+++ b/docs/cli/cli-orders.md
@@ -36,7 +36,7 @@ You can also filter orders by their `state`, which can be useful to just see ord
 progress:
 
 ```console
-planet orders --state running
+planet orders list --state running
 ```
 
 The other options are queued, failed, success, partial and cancelled.
@@ -100,7 +100,7 @@ To create an order you need a name, a [bundle](https://developers.planet.com/api
 First lets get the ID of an item you have download access to, using the Data API: 
 
 ```
-planet data filter | planet data search PSScene --limit 1 - | jq -r .id
+planet data filter | planet data search PSScene --limit 1 --filter - | jq -r .id 
 ```
 
 If you don't have access to PlanetScope data then replace PSScene with SkySatCollect.
@@ -515,7 +515,7 @@ One cool little trick is that you can even stream in the JSON directly with `cur
 
 ```console
 curl -s https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-clip-composite.json \
-| planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Streaming Clip & Composite' \
+| planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Streaming Clip & Composite' --no-stac \
  20220605_124027_64_242b,20220605_124025_34_242b --tools - | planet orders create - 
 ```
 
@@ -550,7 +550,7 @@ STAC metadata by default, as the STAC files are small and often more useful than
 You can easily turn off STAC output request with the `--no-stac` command:
 
 ```
-planet orders request PSScene visual --name 'No STAC' --no-stac --id 20220605_124027_64_242b 
+planet orders request --item-type PSScene --bundle visual --name 'No STAC' --no-stac 20220605_124027_64_242b
 ```
 
 Currently this needs to be done for any 'composite' operation, as STAC output from composites is not yet 
@@ -672,7 +672,7 @@ image that was published:
 
 ```console
 planet orders request --item-type SkySatCollect --bundle analytic --name 'SkySat Latest' \
- `planet data filter | planet data search SkySatCollect --sort 'acquired desc' --limit 1 - | jq -r .id` \
+ `planet data filter | planet data search SkySatCollect --sort 'acquired desc' --limit 1 --filter - | jq -r .id` \
 | planet orders create - 
 ```
 
@@ -681,7 +681,7 @@ Or get the 5 latest cloud free images in an area and create an order that clips
 
 ```console
 ids=`planet data filter --geom geometry.geojson --range clear_percent gt 90 | planet data \
-search PSScene --limit 5 - | jq -r .id | tr '\n' , | sed 's/.$//'`
+search PSScene --limit 5 --filter - | jq -r .id | tr '\n' , | sed 's/.$//'`
 planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Clipped Scenes'  \
  $ids --clip geometry.geojson | planet orders create -
 ```
diff --git a/docs/cli/cli-tips-tricks.md b/docs/cli/cli-tips-tricks.md
index 4da63c3..bae4fcd 100644
--- a/docs/cli/cli-tips-tricks.md
+++ b/docs/cli/cli-tips-tricks.md
@@ -301,9 +301,11 @@ planet orders list | jq -rs '.[3] | "\(.id) \(.created_on) \(.name) \(.state)"'
 
 * Use jq to show just orders that have a given item type, like just skysat.
 
-planet orders list | jq -rs '.[] | "\(.id) \(.created_on) \(.state) \(.products[0].item_type)"'  will show the item type
+```console
+planet orders list | jq -rs '.[] | "\(.id) \(.created_on) \(.state) \(.products[0].item_type)"'
+```
 
-https://gist.github.com/ipbastola/2c955d8bf2e96f9b1077b15f995bdae3 has ideas for contains, but haven't got it right yet
+will show the item type https://gist.github.com/ipbastola/2c955d8bf2e96f9b1077b15f995bdae3 has ideas for contains, but haven't got it right yet
 
 * use jq to get the id of the an order by it's name
 
diff --git a/planet/cli/data.py b/planet/cli/data.py
index 46a9603..cbca75e 100644
--- a/planet/cli/data.py
+++ b/planet/cli/data.py
@@ -283,8 +283,7 @@ def filter(ctx,
                 callback=check_item_types)
 @click.option('--filter',
               type=types.JSON(),
-              help="""Apply specified filter to search. Can be a json string,
-              filename, or '-' for stdin.""")
+              help='Apply specified filter to search.')
 @limit
 @click.option('--name', type=str, help='Name of the saved search.')
 @click.option('--sort',
@@ -322,35 +321,32 @@ async def search(ctx, item_types, filter, limit, name, sort, pretty):
 @click.pass_context
 @translate_exceptions
 @coro
+@click.argument('name')
 @click.argument("item_types",
                 type=types.CommaSeparatedString(),
                 callback=check_item_types)
-@click.option(
-    '--filter',
-    type=types.JSON(),
-    required=True,
-    help="""Filter to apply to search. Can be a json string, filename,
-         or '-' for stdin.""")
-@click.option('--name',
-              type=str,
-              required=True,
-              help='Name of the saved search.')
+@click.argument("filter", type=types.JSON())
 @click.option('--daily-email',
               is_flag=True,
               help='Send a daily email when new results are added.')
 @pretty
-async def search_create(ctx, item_types, filter, name, daily_email, pretty):
+async def search_create(ctx, name, item_types, filter, daily_email, pretty):
     """Create a new saved structured item search.
 
     This function outputs a full JSON description of the created search,
     optionally pretty-printed.
 
+    NAME is the name to give the search.
+
     ITEM_TYPES is a comma-separated list of item-types to search.
+
+    FILTER must be JSON and can be specified a json string, filename, or '-'
+    for stdin.
     """
     async with data_client(ctx) as cl:
-        items = await cl.create_search(item_types=item_types,
+        items = await cl.create_search(name=name,
+                                       item_types=item_types,
                                        search_filter=filter,
-                                       name=name,
                                        enable_email=daily_email)
         echo_json(items, pretty)
 
diff --git a/planet/clients/data.py b/planet/clients/data.py
index 2e80dd0..82c22c2 100644
--- a/planet/clients/data.py
+++ b/planet/clients/data.py
@@ -167,9 +167,9 @@ class DataClient:
             yield i
 
     async def create_search(self,
+                            name: str,
                             item_types: List[str],
                             search_filter: dict,
-                            name: str,
                             enable_email: bool = False) -> dict:
         """Create a new saved structured item search.
 
@@ -190,9 +190,9 @@ class DataClient:
 
 
         Parameters:
+            name: The name of the saved search.
             item_types: The item types to include in the search.
             search_filter: Structured search criteria.
-            name: The name of the saved search.
             enable_email: Send a daily email when new results are added.
 
         Returns:


Test patch:
diff --git a/tests/integration/test_data_api.py b/tests/integration/test_data_api.py
index 8a2c500..736d751 100644
--- a/tests/integration/test_data_api.py
+++ b/tests/integration/test_data_api.py
@@ -245,9 +245,7 @@ async def test_create_search_basic(search_filter, session):
     respx.post(TEST_SEARCHES_URL).return_value = mock_resp
 
     cl = DataClient(session, base_url=TEST_URL)
-    search = await cl.create_search(['PSScene'],
-                                    search_filter=search_filter,
-                                    name='test')
+    search = await cl.create_search('test', ['PSScene'], search_filter)
 
     # check that request is correct
     expected_request = {
@@ -283,9 +281,8 @@ async def test_create_search_email(search_filter, session):
     respx.post(TEST_SEARCHES_URL).return_value = mock_resp
 
     cl = DataClient(session, base_url=TEST_URL)
-    search = await cl.create_search(['PSScene'],
-                                    search_filter=search_filter,
-                                    name='test',
+    search = await cl.create_search('test', ['PSScene'],
+                                    search_filter,
                                     enable_email=True)
 
     # check that request is correct
diff --git a/tests/integration/test_data_cli.py b/tests/integration/test_data_cli.py
index 47265bd..6150d25 100644
--- a/tests/integration/test_data_cli.py
+++ b/tests/integration/test_data_cli.py
@@ -572,13 +572,7 @@ def test_data_search_create_filter_invalid_json(invoke, item_types, filter):
     name = "temp"
 
     runner = CliRunner()
-    result = invoke([
-        "search-create",
-        item_types,
-        f'--name={name}',
-        f'--filter={json.dumps(filter)}'
-    ],
-                    runner=runner)
+    result = invoke(["search-create", name, item_types, filter], runner=runner)
     assert result.exit_code == 2
 
 
@@ -605,12 +599,7 @@ def test_data_search_create_filter_success(invoke, item_types):
     respx.post(TEST_SEARCHES_URL).return_value = mock_resp
 
     runner = CliRunner()
-    result = invoke([
-        "search-create",
-        item_types,
-        f'--filter={json.dumps(filter)}',
-        f'--name={name}'
-    ],
+    result = invoke(["search-create", name, item_types, json.dumps(filter)],
                     runner=runner)
 
     assert result.exit_code == 0
@@ -632,9 +621,9 @@ def test_data_search_create_daily_email(invoke, search_result):
 
     result = invoke([
         'search-create',
+        'temp',
         'SkySatScene',
-        '--name=temp',
-        f'--filter={json.dumps(filter)}',
+        json.dumps(filter),
         '--daily-email'
     ])