code: def cli(
      user,
      password,
      geometry,
      start,
      end,
      uuid,
      name,
      download,
      fail_fast,
      quicklook,
      sentinel,
      producttype,
      instrument,
      cloud,
      footprints,
      path,
      query,
      url,
      order_by,
      location,
      limit,
      timeout,
      debug,
      include_pattern,
      exclude_pattern,
      gnss,
      fmt,
      info,
  ):
      """Search for Sentinel products and, optionally, download all the results
      and/or create a GeoJSON file with the search result footprints.
      Beyond your Copernicus Open Access Hub user and password, you will typically want to pass a GeoJSON file
      containing the geometry of the area you want to search for and the relevant time range.
      """
  
      if footprints and footprints.name == "-":
          _set_logger_handler("WARNING")
      elif debug:
          _set_logger_handler("DEBUG")
      else:
          _set_logger_handler("INFO")
  
      if info:
          api = SentinelAPI(None, None, url, timeout=timeout)
          ctx = click.get_current_context()
          click.echo("DHuS version: " + api.dhus_version)
          ctx.exit()
  
      if include_pattern is not None and exclude_pattern is not None:
          raise click.UsageError(
              "--include-pattern and --exclude-pattern cannot be specified together."
          )
      elif include_pattern is not None:
          nodefilter = make_path_filter(include_pattern)
      elif exclude_pattern is not None:
          nodefilter = make_path_filter(exclude_pattern, exclude=True)
      else:
          nodefilter = None
  
      if gnss:
          url = "https://scihub.copernicus.eu/gnss/"
          user = "gnssguest"
          password = "gnssguest"
  
      if user is None or password is None:
          try:
              user, password = requests.utils.get_netrc_auth(url)
          except TypeError:
              pass
  
      if user is None or password is None:
          raise click.UsageError(
              "Missing --user and --password. Please see docs "
              "for environment variables and .netrc support."
          )
  
      api = SentinelAPI(user, password, url, timeout=timeout)
  
      search_kwargs = {}
      if sentinel:
          search_kwargs["platformname"] = "Sentinel-" + sentinel
  
      if instrument:
          search_kwargs["instrumentshortname"] = instrument
  
      if producttype:
          search_kwargs["producttype"] = producttype
  
      if cloud:
          if sentinel not in ["2", "3"]:
              logger.error(
                  "Cloud cover is only supported for Sentinel 2 and 3."
              )
              exit(1)
          search_kwargs["cloudcoverpercentage"] = (0, cloud)
  
      if len(name) > 0:
          search_kwargs["identifier"] = set(name)
  
      if len(uuid) > 0:
          search_kwargs["uuid"] = set(uuid)
  
      if len(query) > 0:
          for kwarg in query:
              key, value = kwarg.split("=", 1)
              if key in search_kwargs:
                  if isinstance(search_kwargs[key], set):
                      search_kwargs[key].add(value)
                  else:
                      search_kwargs[key] = {search_kwargs[key], value}
              else:
                  search_kwargs[key] = value
  
      if location is not None:
          wkt, info = placename_to_wkt(location)
          minX, minY, maxX, maxY = info["bbox"]
          r = 6371  # average radius, km
          extent_east = (
              r
              * math.radians(maxX - minX)
              * math.cos(math.radians((minY + maxY) / 2))
          )
          extent_north = r * math.radians(maxY - minY)
          logger.info(
              "Querying location: '%s' with %.1f x %.1f km, %f, %f to %f, %f bounding box",
              info["display_name"],
              extent_north,
              extent_east,
              minY,
              minX,
              maxY,
              maxX,
          )
          search_kwargs["area"] = wkt
  
      if geometry is not None:
          # check if the value is an existing path
          if os.path.exists(geometry):
              search_kwargs["area"] = geojson_to_wkt(
                  read_geojson(geometry)
              )
          # check if the value is a GeoJSON
          else:
              if geometry.startswith("{"):
                  try:
                      geometry = json.loads(geometry)
                      search_kwargs["area"] = geojson_to_wkt(geometry)
                  except json_parse_exception:
                      raise click.UsageError(
                          "geometry string starts with '{' but is not a valid GeoJSON."
                      )
              # check if the value is a WKT
              elif is_wkt(geometry):
                  search_kwargs["area"] = geometry
              else:
                  raise click.UsageError(
                      "The geometry input is neither a GeoJSON file with a valid path, "
                      "a GeoJSON String nor a WKT string."
                  )
  
      products = api.query(
          date=(start, end),
          order_by=order_by,
          limit=limit,
          **search_kwargs,
      )
  
      if footprints is not None:
          footprints_geojson = api.to_geojson(products)
          gj.dump(footprints_geojson, footprints)
          footprints.close()
  
      if quicklook:
          (
              downloaded_quicklooks,
              failed_quicklooks,
          ) = api.download_all_quicklooks(products, path)
          if failed_quicklooks:
              api.logger.warning(
                  "Some quicklooks failed: %s out of %s",
                  len(failed_quicklooks),
                  len(products),
              )
  
      if download:
          downloaded, triggered, failed_downloads = api.download_all(
              products, path, nodefilter=nodefilter, fail_fast=fail_fast
          )
          retcode = 0
          if len(failed_downloads) > 0:
              retcode = 1
              with open(
                  os.path.join(path, "corrupt_scenes.txt"), "w"
              ) as outfile:
                  for failed_id in failed_downloads:
                      outfile.write(
                          "{} : {}\n".format(
                              failed_id, products[failed_id]["title"]
                          )
                      )
          logger.info(
              "Successfully downloaded %d/%d products.",
              len(downloaded),
              len(products),
          )
          exit(retcode)
      else:
          for product_id, props in products.items():
              logger.info(fmt.format(**props))
          logger.info("---")
          logger.info(
              "%s scenes found with a total size of %.2f GB",
              len(products),
              api.get_products_size(products),
          )
  
file_path: sentinelsat/sentinelsat/scripts/cli.py
imports: import json
  import logging
  import math
  import os
  import re
  import click
  import geojson
  import requests.utils
  from tqdm.auto import tqdm
  from sentinelsat import __version__, make_path_filter
  from sentinelsat.sentinel import SentinelAPI, geojson_to_wkt, is_wkt, placename_to_wkt, read_geojson
label_desc: Use image node_id 3 for calling a global function with example usage: cli(user, password, geometry, start, end, uuid, name, download, fail_fast, quicklook, sentinel, producttype, instrument, cloud, footprints, path, query, url, order_by, location, limit, timeout, debug, include_pattern, exclude_pattern, gnss, fmt, info) without return types