Skip to content

Commit

Permalink
v0.1.383
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 588813547
  • Loading branch information
Google Earth Engine Authors authored and jgarcia525 committed Dec 7, 2023
1 parent a113ecf commit 2d7f73c
Show file tree
Hide file tree
Showing 15 changed files with 451 additions and 202 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/ci-type-verification.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: ci-type-verification
on:
# Triggers the workflow when new code is pushed to the master branch.
push:
branches: [ master ]
# Enables running this workflow manually from the Actions tab.
workflow_dispatch:
jobs:
build:
name: "Type verification"
runs-on: ubuntu-latest
steps:
- name: Cancel previous
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}
if: ${{github.ref != 'refs/head/master'}}
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.11
- name: Install EE API
run: |
pip install -e ./python
pip install pyright
- name: ee type verification
run: |
pyright --verifytypes ee
- name: ee.cli type verification
run: |
pyright --verifytypes ee.cli
32 changes: 16 additions & 16 deletions javascript/build/ee_api_js.js

Large diffs are not rendered by default.

187 changes: 109 additions & 78 deletions javascript/build/ee_api_js_debug.js

Large diffs are not rendered by default.

231 changes: 131 additions & 100 deletions javascript/build/ee_api_js_npm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion javascript/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@google/earthengine",
"version": "0.1.382",
"version": "0.1.383",
"description": "JavaScript client for Google Earth Engine API.",
"author": "Google LLC",
"license": "Apache-2.0",
Expand Down
2 changes: 1 addition & 1 deletion javascript/src/apiclient.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const {trustedResourceUrl} = goog.require('safevalues');
/** @namespace */
const apiclient = {};

const API_CLIENT_VERSION = '0.1.382';
const API_CLIENT_VERSION = '0.1.383';

exports.VERSION = apiVersion.VERSION;
exports.API_CLIENT_VERSION = API_CLIENT_VERSION;
Expand Down
19 changes: 19 additions & 0 deletions javascript/src/batch.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ Export.table = {};
/** @const */
Export.video = {};

/** @const */
Export.classifier = {};

/**
* ExportTask
*/
Expand Down Expand Up @@ -393,6 +396,22 @@ Export.video.toDrive = function(
return ExportTask.create(serverConfig);
};

/**
* @param {!ComputedObject} classifier
* @param {string=} opt_description
* @param {string=} opt_assetId
* @return {!ExportTask}
* @export
*/
Export.classifier.toAsset = function(classifier, opt_description, opt_assetId) {
const clientConfig =
eeArguments.extractFromFunction(Export.classifier.toAsset, arguments);
const serverConfig = Export.convertToServerParams(
clientConfig, ExportDestination.ASSET, ExportType.CLASSIFIER);
return ExportTask.create(serverConfig);
};


////////////////////////////////////////////////////////////////////////////////
// Internal validation. //
////////////////////////////////////////////////////////////////////////////////
Expand Down
47 changes: 47 additions & 0 deletions javascript/src/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ goog.provide('ee.data.AuthPrivateKey');
goog.provide('ee.data.Band');
goog.provide('ee.data.BandDescription');
goog.provide('ee.data.BigQueryTaskConfig');
goog.provide('ee.data.ClassifierTaskConfig');
goog.provide('ee.data.DownloadId');
goog.provide('ee.data.ExportDestination');
goog.provide('ee.data.ExportState');
Expand Down Expand Up @@ -1296,6 +1297,11 @@ ee.data.startProcessing = function(taskId, params, opt_callback) {
case ee.data.ExportType.MAP:
const mapRequest = ee.data.prepareExportMapRequest_(params, metadata);
return handle(call.map().export(call.projectsPath(), mapRequest));
case ee.data.ExportType.CLASSIFIER:
const classifierRequest =
ee.data.prepareExportClassifierRequest_(params, metadata);
return handle(
call.classifier().export(call.projectsPath(), classifierRequest));
default:
throw new Error(
`Unable to start processing for task of type ${taskType}`);
Expand Down Expand Up @@ -1379,6 +1385,27 @@ ee.data.prepareExportMapRequest_ = function(taskConfig, metadata) {
return mapRequest;
};


/**
* Creates an ExportClassifierRequest for a given ClassifierTaskConfig.
*
* @param {!Object} taskConfig classifier task configuration params.
* @param {!Object} metadata associated with the export request.
* @return {!ee.api.ExportClassifierRequest}
* @private
*/
ee.data.prepareExportClassifierRequest_ = function(taskConfig, metadata) {
const classifierRequest =
ee.rpc_convert_batch.taskToExportClassifierRequest(taskConfig);
classifierRequest.expression =
ee.data.expressionAugmenter_(classifierRequest.expression, metadata);
if (taskConfig['workloadTag']) {
classifierRequest.workloadTag = taskConfig['workloadTag'];
}
return classifierRequest;
};


/**
* Creates an image asset ingestion task.
*
Expand Down Expand Up @@ -2195,6 +2222,7 @@ ee.data.resetWorkloadTag = function(opt_resetDefault) {
*/
ee.data.AssetType = {
ALGORITHM: 'Algorithm',
CLASSIFIER: 'Classifier',
FEATURE_VIEW: 'FeatureView',
FOLDER: 'Folder',
FEATURE_COLLECTION: 'FeatureCollection',
Expand All @@ -2211,6 +2239,7 @@ ee.data.ExportType = {
MAP: 'EXPORT_TILES',
TABLE: 'EXPORT_FEATURES',
VIDEO: 'EXPORT_VIDEO',
CLASSIFIER: 'EXPORT_CLASSIFIER'
};

/** @enum {string} The status of the export. */
Expand Down Expand Up @@ -3419,6 +3448,24 @@ ee.data.ImageExportFormatConfig;
*/
ee.data.MapTaskConfig;

/**
* An object for specifying configuration of a task to export a classifier
* as an asset.
*
* @typedef {{
* id: string,
* type: string,
* sourceUrl: (undefined|string),
* description: (undefined|string),
* element: (undefined|!ee.ComputedObject),
* assetId: (undefined|string),
* maxWorkers: (undefined|number),
* workloadTag: (undefined|string),
* }}
*/
ee.data.ClassifierTaskConfig;


/**
* An object for specifying configuration of a task to export feature
* collections to a FeatureView.
Expand Down
2 changes: 1 addition & 1 deletion python/ee/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""The EE Python library."""

__version__ = '0.1.382'
__version__ = '0.1.383'

# Using lowercase function naming to match the JavaScript names.
# pylint: disable=g-bad-name
Expand Down
52 changes: 52 additions & 0 deletions python/ee/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Type(str, enum.Enum):
EXPORT_MAP = 'EXPORT_TILES'
EXPORT_TABLE = 'EXPORT_FEATURES'
EXPORT_VIDEO = 'EXPORT_VIDEO'
EXPORT_CLASSIFIER = 'EXPORT_CLASSIFIER'

class State(str, enum.Enum):
"""The state of a Task."""
Expand Down Expand Up @@ -129,6 +130,8 @@ def start(self) -> None:
result = data.exportTable(self._request_id, self.config)
elif self.task_type == Task.Type.EXPORT_VIDEO:
result = data.exportVideo(self._request_id, self.config)
elif self.task_type == Task.Type.EXPORT_CLASSIFIER:
result = data.exportClassifier(self._request_id, self.config)
else:
raise ee_exception.EEException(
'Unknown Task type "{}"'.format(self.task_type))
Expand Down Expand Up @@ -959,6 +962,55 @@ def toDrive(collection, description='myExportVideoTask',
Task.ExportDestination.DRIVE)
return _create_export_task(config, Task.Type.EXPORT_VIDEO)

class classifier:
"""A class with static methods to start classifier export tasks."""

def __init__(self):
"""Forbids class instantiation."""
raise AssertionError('This class cannot be instantiated.')

def __new__(cls,
classifier,
description='myExportClassifierTask',
config=None):
"""Export an EE Classifier.
Args:
classifier: The feature collection to be exported.
description: Human-readable name of the task.
config: A dictionary that will be copied and used as parameters
for the task:
- assetId: The destination asset ID.
Returns:
An unstarted Task that exports the table.
"""
config = (config or {}).copy()
return Export.classifier.toAsset(classifier, description, **config)

# Disable argument usage check; arguments are accessed using locals().
# pylint: disable=unused-argument
@staticmethod
def toAsset(classifier,
description='myExportClassifierTask',
assetId=None,
overwrite=False,
**kwargs):
"""Creates a task to export an EE Image to an EE Asset.
Args:
classifier: The classifier to be exported.
description: Human-readable name of the task.
assetId: The destination asset ID.
overwrite: If an existing asset can be overwritten by this export.
**kwargs: Holds other keyword arguments.
Returns:
An unstarted Task that exports the image as an Earth Engine Asset.
"""
config = _capture_parameters(locals(), ['classifier'])
config = _prepare_classifier_export_config(classifier, config,
Task.ExportDestination.ASSET)
return _create_export_task(config, Task.Type.EXPORT_CLASSIFIER)

# Mapping from file formats to prefixes attached to format specific config.
FORMAT_PREFIX_MAP = {'GEOTIFF': 'tiff', 'TFRECORD': 'tfrecord'}

Expand Down
27 changes: 27 additions & 0 deletions python/ee/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,33 @@ def exportMap(request_id: str, params: Dict[str, Any]) -> Any:
)


def exportClassifier(request_id: str, params: Dict[str, Any]) -> Any:
"""Starts a classifier export task.
This is a low-level method. The higher-level ee.batch.Export.classifier
object is generally preferred for initiating classifier exports.
Args:
request_id (string): A unique ID for the task, from newTaskId. If you are
using the cloud API, this does not need to be from newTaskId, (though
that's a good idea, as it's a good source of unique strings). It can also
be empty, but in that case the request is more likely to fail as it cannot
be safely retried.
params: The object that describes the export task. If you are using the
cloud API, this should be an ExportClassifierRequest. However, the
"expression" parameter can be the actual Classifier to be exported, not
its serialized form.
Returns:
A dict with information about the created task.
If you are using the cloud API, this will be an Operation.
"""
params = params.copy()
return _prepare_and_run_export(
request_id, params, _get_cloud_projects().classifier().export
)


def _prepare_and_run_export(
request_id: str, params: Dict[str, Any], export_endpoint: Any
) -> Any:
Expand Down
11 changes: 7 additions & 4 deletions python/ee/oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import google.auth.transport.requests

from ee import data as ee_data
from ee.ee_exception import EEException
from ee import ee_exception


# Optional imports used for specific shells.
Expand Down Expand Up @@ -94,7 +94,7 @@ def _valid_credentials_exist() -> bool:
creds = ee_data.get_persistent_credentials()
creds.refresh(google.auth.transport.requests.Request())
return True
except (EEException, google.auth.exceptions.RefreshError):
except (ee_exception.EEException, google.auth.exceptions.RefreshError):
return False


Expand Down Expand Up @@ -213,7 +213,9 @@ def _obtain_and_write_token(
fetched_info = json.loads(
urllib.request.urlopen(fetch_client).read().decode())
if 'error' in fetched_info:
raise EEException('Cannot authenticate: %s' % fetched_info['error'])
raise ee_exception.EEException(
'Cannot authenticate: %s' % fetched_info['error']
)
client_info = {k: fetched_info[k] for k in ['client_id', 'client_secret']}
scopes = fetched_info.get('scopes') or scopes
token = request_token(auth_code.strip(), code_verifier, **client_info)
Expand Down Expand Up @@ -524,7 +526,8 @@ def __init__(
scopes=urllib.parse.quote(' '.join(self.scopes)), **request_info)
self.code_verifier = ':'.join(request_info[k] for k in nonces)
else:
raise EEException('Unknown auth_mode "%s"' % auth_mode) # pylint:disable=broad-exception-raised
# pylint:disable-next=broad-exception-raised
raise ee_exception.EEException('Unknown auth_mode "%s"' % auth_mode)

def save_code(self, code: Optional[str] = None) -> None:
"""Fetches auth code if not given, and saves the generated credentials."""
Expand Down
Empty file added python/ee/py.typed
Empty file.
6 changes: 6 additions & 0 deletions python/ee/tests/algorithms.json
Original file line number Diff line number Diff line change
Expand Up @@ -15289,6 +15289,12 @@
"description": "The prediction payload size limit in bytes. Defaults to 1.5MB (1500000 bytes)",
"optional": true,
"defaultValue": null
}, {
"argumentName": "payloadFormat",
"type": "String",
"description": "The payload format of entries in prediction requests and responses. One of: [\u0027SERIALIZED_TF_TENSORS, \u0027RAW_JSON\u0027, \u0027ND_ARRAYS\u0027]. Defaults to \u0027SERIALIZED_TF_TENSORS\u0027.",
"optional": true,
"defaultValue": null
}]
}, {
"name": "algorithms/Model.predictImage",
Expand Down
3 changes: 2 additions & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "earthengine-api"
version = "0.1.382"
version = "0.1.383"
description = "Earth Engine Python API"
requires-python = ">=3.7"
keywords = [
Expand Down Expand Up @@ -63,6 +63,7 @@ packages = [

[tool.setuptools.package-data]
ee = [
"py.typed",
"tests/*.py",
"tests/*.json",
]

0 comments on commit 2d7f73c

Please sign in to comment.