Skip to content

Commit

Permalink
Merge branch 'master' into DEVEX-2431
Browse files Browse the repository at this point in the history
  • Loading branch information
wormsik authored Dec 4, 2024
2 parents bffd767 + b8a6549 commit b98680e
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 13 deletions.
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,27 @@ Categories for each release: Added, Changed, Deprecated, Removed, Fixed, Securit

## Unreleased

## [385.0] - beta
## [387.0] - beta

### Added

* `--name-mode` parameter for `dx find data`

### Fixed

* Nonce generation for python 3

## [386.0] - 2024.12.2

### Added

* `--database-results-restricted` `--unset-database-results-restricted` for `dx new project`

### Fixed

* Remove pipes import for Python 3.13 compatibility

## [385.0] - 2024.11.8

### Added

Expand Down
2 changes: 1 addition & 1 deletion src/R/dxR/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: dxR
Type: Package
Title: DNAnexus R Client Library
Version: 0.385.0
Version: 0.387.0
Author: Katherine Lai
Maintainer: Katherine Lai <klai@dnanexus.com>
Description: dxR is an R extension containing API wrapper functions for
Expand Down
2 changes: 1 addition & 1 deletion src/R/dxR/R/dxR-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
##' the new DNAnexus platform.
##'
##' \tabular{ll}{ Package: \tab dxR\cr Type: \tab Package\cr Version: \tab
##' 0.385.0\cr License: \tab Apache License (== 2.0)\cr
##' 0.387.0\cr License: \tab Apache License (== 2.0)\cr
##' }
##'
##' @name dxR-package
Expand Down
2 changes: 1 addition & 1 deletion src/R/dxR/man/dxR-package.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
}
\details{
\tabular{ll}{ Package: \tab dxR\cr Type: \tab Package\cr
Version: \tab 0.385.0\cr License: \tab Apache License (==
Version: \tab 0.387.0\cr License: \tab Apache License (==
2.0)\cr }
}
\author{
Expand Down
19 changes: 18 additions & 1 deletion src/python/dxpy/bindings/dxproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ def new(self, name, summary=None, description=None, region=None, protected=None,
restricted=None, download_restricted=None, contains_phi=None,
tags=None, properties=None, bill_to=None, database_ui_view_only=None,
external_upload_restricted=None, default_symlink=None,
database_results_restricted=None,
**kwargs):
"""
:param name: The name of the project
Expand Down Expand Up @@ -313,6 +314,8 @@ def new(self, name, summary=None, description=None, region=None, protected=None,
:type database_ui_view_only: boolean
:param external_upload_restricted: If provided, whether project members can upload data to project from external sources, e.g. outside of job
:type external_upload_restricted: boolean
:param database_results_restricted: If provided, minimum amount of data that project members with VIEW access can see from databases in the project
:type database_results_restricted: int
:param default_symlink: If provided, the details needed to have writable symlinks in the project. Dict must include drive, container, and optional prefix.
:type default_symlink: dict
Expand Down Expand Up @@ -346,6 +349,8 @@ def new(self, name, summary=None, description=None, region=None, protected=None,
input_hash["databaseUIViewOnly"] = database_ui_view_only
if external_upload_restricted is not None:
input_hash["externalUploadRestricted"] = external_upload_restricted
if database_results_restricted is not None:
input_hash["databaseResultsRestricted"] = database_results_restricted
if tags is not None:
input_hash["tags"] = tags
if properties is not None:
Expand All @@ -360,7 +365,9 @@ def new(self, name, summary=None, description=None, region=None, protected=None,
def update(self, name=None, summary=None, description=None, protected=None,
restricted=None, download_restricted=None, version=None,
allowed_executables=None, unset_allowed_executables=None,
database_ui_view_only=None, external_upload_restricted=None, **kwargs):
database_ui_view_only=None, external_upload_restricted=None,
database_results_restricted=None, unset_database_results_restricted=None,
**kwargs):
"""
:param name: If provided, the new project name
:type name: string
Expand All @@ -376,10 +383,16 @@ def update(self, name=None, summary=None, description=None, protected=None,
:type download_restricted: boolean
:param allowed_executables: If provided, these are the only executable ID(s) allowed to run as root executions in this project
:type allowed_executables: list
:param unset_allowed_executables: If provided, removes any restrictions set by allowed_executables
:type unset_allowed_executables: boolean
:param database_ui_view_only: If provided, whether the viewers on the project can access the database data directly
:type database_ui_view_only: boolean
:param external_upload_restricted: If provided, whether project members can upload data to project from external sources, e.g. outside of job
:type external_upload_restricted: boolean
:param database_results_restricted: If provided, minimum amount of data that project members with VIEW access can see from databases in the project
:type database_results_restricted: int
:param unset_database_results_restricted: If provided, removes any restrictions set by database_results_restricted
:type unset_database_results_restricted: boolean
:param version: If provided, the update will only occur if the value matches the current project's version number
:type version: int
Expand Down Expand Up @@ -413,6 +426,10 @@ def update(self, name=None, summary=None, description=None, protected=None,
update_hash["databaseUIViewOnly"] = database_ui_view_only
if external_upload_restricted is not None:
update_hash["externalUploadRestricted"] = external_upload_restricted
if database_results_restricted is not None:
update_hash["databaseResultsRestricted"] = database_results_restricted
if unset_database_results_restricted is not None:
update_hash["databaseResultsRestricted"] = None
dxpy.api.project_update(self._dxid, update_hash, **kwargs)

def invite(self, invitee, level, send_email=True, **kwargs):
Expand Down
4 changes: 4 additions & 0 deletions src/python/dxpy/cli/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,10 @@ def get_update_project_args(args):
input_params['allowedExecutables'] = args.allowed_executables
if args.unset_allowed_executables:
input_params['allowedExecutables'] = None
if args.database_results_restricted is not None:
input_params['databaseResultsRestricted'] = args.database_results_restricted
if args.unset_database_results_restricted:
input_params['databaseResultsRestricted'] = None
if args.external_upload_restricted is not None:
input_params['externalUploadRestricted'] = args.external_upload_restricted == 'true'
return input_params
Expand Down
11 changes: 9 additions & 2 deletions src/python/dxpy/scripts/dx.py
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,8 @@ def new_project(args):
inputs["containsPHI"] = True
if args.database_ui_view_only:
inputs["databaseUIViewOnly"] = True
if args.database_results_restricted is not None:
inputs["databaseResultsRestricted"] = args.database_results_restricted
if args.monthly_compute_limit is not None:
inputs["monthlyComputeLimit"] = args.monthly_compute_limit
if args.monthly_egress_bytes_limit is not None:
Expand Down Expand Up @@ -2479,7 +2481,7 @@ def find_data(args):
visibility=args.visibility,
properties=args.properties,
name=args.name,
name_mode='glob',
name_mode=args.name_mode,
typename=args.type,
tags=args.tag, link=args.link,
project=args.project,
Expand Down Expand Up @@ -5427,6 +5429,9 @@ def positive_number(value):
allowed_executables_group = parser_update_project.add_mutually_exclusive_group()
allowed_executables_group.add_argument('--allowed-executables', help='Executable ID(s) this project is allowed to run. This operation overrides any existing list of executables.', type=str, nargs="+")
allowed_executables_group.add_argument('--unset-allowed-executables', help='Removes any restriction to run executables as set by --allowed-executables', action='store_true')
database_results_restricted_group = parser_update_project.add_mutually_exclusive_group()
database_results_restricted_group.add_argument('--database-results-restricted', help='Viewers on the project can access only more than specified size of visual data from databases', type=positive_integer)
database_results_restricted_group.add_argument('--unset-database-results-restricted', help='Removes any restriction to return data from databases as set by --database-results-restricted', action='store_true')

parser_update_project.set_defaults(func=update_project)
register_parser(parser_update_project, subparsers_action=subparsers_update, categories="metadata")
Expand Down Expand Up @@ -5813,6 +5818,7 @@ def __call__(self, parser, namespace, values, option_string=None):
action='store_true')
parser_new_project.add_argument('--database-ui-view-only', help='Viewers on the project cannot access database data directly', default=False,
action='store_true')
parser_new_project.add_argument('--database-results-restricted', help='Viewers on the project can access only more than specified size of visual data from databases', type=positive_integer)
parser_new_project.add_argument('--monthly-compute-limit', type=positive_integer, help='Monthly project spending limit for compute')
parser_new_project.add_argument('--monthly-egress-bytes-limit', type=positive_integer, help='Monthly project spending limit for egress (in Bytes)')
parser_new_project.add_argument('--monthly-storage-limit', type=positive_number, help='Monthly project spending limit for storage')
Expand Down Expand Up @@ -6137,7 +6143,8 @@ def __call__(self, parser, namespace, values, option_string=None):
)
parser_find_data.add_argument('--state', choices=['open', 'closing', 'closed', 'any'], help='State of the object')
parser_find_data.add_argument('--visibility', choices=['hidden', 'visible', 'either'], default='visible', help='Whether the object is hidden or not')
parser_find_data.add_argument('--name', help='Name of the object')
parser_find_data.add_argument('--name', help='Search criteria for the object name, interpreted according to the --name-mode')
parser_find_data.add_argument('--name-mode', default='glob', help='Name mode to use for searching', choices=['glob', 'exact', 'regexp'])
parser_find_data.add_argument('--type', help='Type of the data object')
parser_find_data.add_argument('--link', help='Object ID that the data object links to')
parser_find_data.add_argument('--all-projects', '--allprojects', help='Extend search to all projects (excluding public projects)', action='store_true')
Expand Down
2 changes: 1 addition & 1 deletion src/python/dxpy/toolkit_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = '0.385.0'
version = '0.387.0'
4 changes: 2 additions & 2 deletions src/python/dxpy/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,10 @@ class Nonce:
'''
def __init__(self):
try:
self.nonce = "%s%f" % (str(binascii.hexlify(os.urandom(32))), time.time())
self.nonce = "%s%f" % (binascii.hexlify(os.urandom(32)).decode('utf-8'), time.time())
except:
random.seed(time.time())
self.nonce = "%s%f" % (str(random.getrandbits(8*26)), time.time())
self.nonce = "%s%f" % (random.getrandbits(8*26), time.time())

def __str__(self):
return self.nonce
Expand Down
4 changes: 3 additions & 1 deletion src/python/dxpy/utils/describe.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def print_project_desc(desc, verbose=False):
'containsPHI', 'databaseUIViewOnly', 'externalUploadRestricted', 'region', 'storageCost', 'pendingTransfer',
'atSpendingLimit', 'currentMonthComputeAvailableBudget', 'currentMonthEgressBytesAvailableBudget',
'currentMonthStorageAvailableBudget', 'currentMonthComputeUsage', 'currentMonthEgressBytesUsage',
'currentMonthExpectedStorageUsage', 'defaultSymlink'
'currentMonthExpectedStorageUsage', 'defaultSymlink', 'databaseResultsRestricted',
# Following are app container-specific
'destroyAt', 'project', 'type', 'app', 'appName'
]
Expand Down Expand Up @@ -455,6 +455,8 @@ def print_project_desc(desc, verbose=False):
print_json_field('External Upload Restricted', desc['externalUploadRestricted'])
if 'defaultSymlink' in desc and verbose:
print_json_field('Default Symlink', desc['defaultSymlink'])
if 'databaseResultsRestricted' in desc and desc['databaseResultsRestricted']:
print_json_field('Database Results Restricted', desc['databaseResultsRestricted'])

# Usage
print_field("Created", render_timestamp(desc['created']))
Expand Down
8 changes: 6 additions & 2 deletions src/python/test/test_dxpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ def test_new(self):
self.assertEqual(desc["databaseUIViewOnly"], False)
self.assertEqual(desc["externalUploadRestricted"], False)
self.assertEqual(desc["tags"], [])
self.assertEqual(desc["databaseResultsRestricted"], None)
prop = dxpy.api.project_describe(dxproject.get_id(),
{'fields': {'properties': True}})
self.assertEqual(prop['properties'], {})
Expand Down Expand Up @@ -192,6 +193,7 @@ def test_update_describe(self):
download_restricted=True,
external_upload_restricted=False,
allowed_executables=["applet-abcdefghijklmnopqrstuzwx"],
database_results_restricted=10,
description="new description")
desc = dxproject.describe()
self.assertEqual(desc["id"], self.proj_id)
Expand All @@ -203,13 +205,15 @@ def test_update_describe(self):
self.assertEqual(desc["externalUploadRestricted"], False)
self.assertEqual(desc["description"], "new description")
self.assertEqual(desc["allowedExecutables"][0], "applet-abcdefghijklmnopqrstuzwx")
self.assertEqual(desc["databaseResultsRestricted"], 10)
self.assertTrue("created" in desc)

dxproject.update(restricted=False, download_restricted=False, unset_allowed_executables=True)
dxproject.update(restricted=False, download_restricted=False, unset_allowed_executables=True, unset_database_results_restricted=True)
desc = dxproject.describe()
self.assertEqual(desc["restricted"], False)
self.assertEqual(desc["downloadRestricted"], False)
self.assertTrue("allowedExecutables" not in desc)
self.assertEqual(desc["allowedExecutables"], None)
self.assertEqual(desc["databaseResultsRestricted"], None)

def test_new_list_remove_folders(self):
dxproject = dxpy.DXProject()
Expand Down

0 comments on commit b98680e

Please sign in to comment.