Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ruff for linting #1257

Merged
merged 2 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ jobs:
steps:
- checkout
- tox:
env: docs,flake8,lintclient
env: docs,lint,lintclient
- store_artifacts:
path: build/docs
- persist_to_workspace:
Expand Down
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
497ddf38b1461da47d1d542003172603e2166b5f
# PR 1148: Lint the client tests
23ab7f011abaa71d0a4904a9da599174c38f64c3
# PR 1257: Use ruff for linting
dcda95e659a4eaa73cae85ab02f1b89059e63c32
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
- Add an endpoint to make it easier to replace thumbnails ([#1253](../../pull/1253))
- Presets from Large Image Configuration file ([#1248](../../pull/1248))

### Changes
- Minor code changes based on suggestions from ruff linting ([#1257](../../pull/1257))

### Bug Fixes
- Guard against ICC profiles that won't parse ([#1245](../../pull/1245))
- Fix filter button on item lists ([#1251](../../pull/1251))
Expand Down
6 changes: 3 additions & 3 deletions docs/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ By default, instead of storing test environments in a ``.tox`` directory, they a
nodejs and npm for Girder Tests or Development
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``nodejs`` version 12.x and a corresponding version of ``npm`` are required to build and test Girder client code. See `nodejs <https://nodejs.org/en/download/>`_ for how to download and install it. Remember to get version 12 or earlier.
``nodejs`` version 14.x and a corresponding version of ``npm`` are required to build and test Girder client code. See `nodejs <https://nodejs.org/en/download/>`_ for how to download and install it. Remember to get version 12 or 14.

Mongo for Girder Tests or Development
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -33,13 +33,13 @@ Tests are run via tox environments:

.. code-block:: bash
tox -e test-py39,flake8,lintclient
tox -e test-py39,lint,lintclient
Or, without Girder:

.. code-block:: bash
tox -e core-py39,flake8
tox -e core-py39,lint
You can build the docs. They are created in the ``docs/build`` directory:

Expand Down
9 changes: 5 additions & 4 deletions examples/algorithm_progression.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def apply_algorithm(algorithm, input_filename, output_dir, params, param_space,
filepath = Path(output_dir, filename)

desc = dict(
**{'path': filename},
**{VARIABLE_LAYERS[i]: v for i, v in enumerate(iteration_id)}
path=filename,
**{VARIABLE_LAYERS[i]: v for i, v in enumerate(iteration_id)},
)

source = large_image.open(input_filename)
Expand Down Expand Up @@ -145,15 +145,16 @@ def sweep_algorithm(algorithm, input_filename, input_params, param_oder, output_
input_params = {}
input_params = {
key: np.linspace(
float(value[0]), float(value[1]), int(value[2]), endpoint=len(value) > 3
float(value[0]), float(value[1]), int(value[2]), endpoint=len(value) > 3,
)
for key, value in input_params.items()
if len(value) >= 3
}
param_order = list(input_params.keys())

if not Path(input_filename).exists():
raise ValueError(f'Cannot locate file {input_filename}.')
msg = f'Cannot locate file {input_filename}.'
raise ValueError(msg)

algorithm = algorithms.ALGORITHM_CODES[algorithm_code]
sig = inspect.signature(algorithm)
Expand Down
8 changes: 3 additions & 5 deletions examples/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ def rgb_to_hsi(im):
"""
im = np.moveaxis(im, -1, 0)
if len(im) not in (3, 4):
raise ValueError(
'Expected 3-channel RGB or 4-channel RGBA image; '
'received a {}-channel image'.format(len(im))
)
msg = f'Expected 3-channel RGB or 4-channel RGBA image; received a {len(im)}-channel image'
raise ValueError(msg)
im = im[:3]
hues = (
np.arctan2(3**0.5 * (im[1] - im[2]), 2 * im[0] - im[1] - im[2]) / (2 * np.pi)
) % 1
intensities = im.mean(0)
saturations = np.where(
intensities, 1 - im.min(0) / np.maximum(intensities, 1e-10), 0
intensities, 1 - im.min(0) / np.maximum(intensities, 1e-10), 0,
)
return np.stack([hues, saturations, intensities], -1)

Expand Down
6 changes: 3 additions & 3 deletions examples/average_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import argparse

import numpy
import numpy as np

import large_image

Expand Down Expand Up @@ -36,13 +36,13 @@ def average_color(imagePath, magnification=None):
resample=True):
# The tile image data is in tile['tile'] and is a numpy
# multi-dimensional array
mean = numpy.mean(tile['tile'], axis=(0, 1))
mean = np.mean(tile['tile'], axis=(0, 1))
tileMeans.append(mean)
tileWeights.append(tile['width'] * tile['height'])
print('x: %d y: %d w: %d h: %d mag: %g color: %g %g %g' % (
tile['x'], tile['y'], tile['width'], tile['height'],
tile['magnification'], mean[0], mean[1], mean[2]))
mean = numpy.average(tileMeans, axis=0, weights=tileWeights)
mean = np.average(tileMeans, axis=0, weights=tileWeights)
print('Average color: %g %g %g' % (mean[0], mean[1], mean[2]))
return mean

Expand Down
6 changes: 3 additions & 3 deletions examples/sumsquare_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import argparse

import numpy
import numpy as np

import large_image

Expand Down Expand Up @@ -33,12 +33,12 @@ def sum_squares(imagePath, magnification=None, **kwargs):
tile['tile_overlap']['left']:
data.shape[1] - tile['tile_overlap']['right'],
:]
sumsq = numpy.sum(data**2, axis=(0, 1))
sumsq = np.sum(data**2, axis=(0, 1))
tileSumSquares.append(sumsq)
print('x: %d y: %d w: %d h: %d mag: %g sums: %d %d %d' % (
tile['x'], tile['y'], tile['width'], tile['height'],
tile['magnification'], sumsq[0], sumsq[1], sumsq[2]))
sumsq = numpy.sum(tileSumSquares, axis=0)
sumsq = np.sum(tileSumSquares, axis=0)
print('Sum of squares: %d %d %d' % (sumsq[0], sumsq[1], sumsq[2]))
return sumsq

Expand Down
9 changes: 5 additions & 4 deletions girder/girder_large_image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def _updateJob(event):
'job_id': job['_id'],
'item_id': item['_id'],
'success': status == JobStatus.SUCCESS,
'status': status
'status': status,
},
user={'_id': job.get('userId')},
expires=datetime.datetime.utcnow() + datetime.timedelta(seconds=30))
Expand Down Expand Up @@ -294,7 +294,8 @@ def metadataSearchHandler( # noqa
if any(typ not in models for typ in types):
raise RestException('The metadata search is only able to search in %r.' % models)
if not isinstance(query, str):
raise RestException('The search query must be a string.')
msg = 'The search query must be a string.'
raise RestException(msg)
# If we have the beginning of the field specifier, don't do a search
if re.match(r'^(k|ke|key|key:)$', query.strip()):
return {k: [] for k in types}
Expand All @@ -307,7 +308,7 @@ def metadataSearchHandler( # noqa
pipeline = [
{'$project': {'arrayofkeyvalue': {'$objectToArray': '$$ROOT.%s' % metakey}}},
{'$unwind': '$arrayofkeyvalue'},
{'$group': {'_id': None, 'allkeys': {'$addToSet': '$arrayofkeyvalue.k'}}}
{'$group': {'_id': None, 'allkeys': {'$addToSet': '$arrayofkeyvalue.k'}}},
]
for model in (searchModels or types):
modelInst = ModelImporter.model(*model if isinstance(model, tuple) else [model])
Expand Down Expand Up @@ -588,7 +589,7 @@ def validateNonnegativeInteger(doc):


@setting_utilities.validator({
constants.PluginSettings.LARGE_IMAGE_DEFAULT_VIEWER
constants.PluginSettings.LARGE_IMAGE_DEFAULT_VIEWER,
})
def validateDefaultViewer(doc):
doc['value'] = str(doc['value']).strip()
Expand Down
2 changes: 1 addition & 1 deletion girder/girder_large_image/loadmodelcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ def loadModel(resource, model, plugin='_core', id=None, allowCookie=False,
'tokenId': tokenStr,
'expiry': time.time() + LoadModelCacheExpiryDuration,
'result': entry,
'hits': 0
'hits': 0,
}
return entry
28 changes: 15 additions & 13 deletions girder/girder_large_image/models/image_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ def createImageItem(self, item, fileObj, user=None, token=None,
logger.info('createImageItem called on item %s (%s)', item['_id'], item['name'])
# Using setdefault ensures that 'largeImage' is in the item
if 'fileId' in item.setdefault('largeImage', {}):
raise TileGeneralError('Item already has largeImage set.')
msg = 'Item already has largeImage set.'
raise TileGeneralError(msg)
if fileObj['itemId'] != item['_id']:
raise TileGeneralError(
'The provided file must be in the provided item.')
msg = 'The provided file must be in the provided item.'
raise TileGeneralError(msg)
if (item['largeImage'].get('expected') is True and
'jobId' in item['largeImage']):
raise TileGeneralError(
'Item is scheduled to generate a largeImage.')
msg = 'Item is scheduled to generate a largeImage.'
raise TileGeneralError(msg)

item['largeImage'].pop('expected', None)
item['largeImage'].pop('sourceName', None)
Expand All @@ -90,8 +91,8 @@ def createImageItem(self, item, fileObj, user=None, token=None,
logger.info(
'createImageItem will not use item %s (%s) as a largeImage',
item['_id'], item['name'])
raise TileGeneralError(
'A job must be used to generate a largeImage.')
msg = 'A job must be used to generate a largeImage.'
raise TileGeneralError(msg)
logger.debug(
'createImageItem creating a job to generate a largeImage for item %s (%s)',
item['_id'], item['name'])
Expand Down Expand Up @@ -175,8 +176,8 @@ def _createLargeImageLocalJob(

def convertImage(self, item, fileObj, user=None, token=None, localJob=True, **kwargs):
if fileObj['itemId'] != item['_id']:
raise TileGeneralError(
'The provided file must be in the provided item.')
msg = 'The provided file must be in the provided item.'
raise TileGeneralError(msg)
if not localJob:
return self._createLargeImageJob(item, fileObj, user, token, toFolder=True, **kwargs)
return self._createLargeImageLocalJob(item, fileObj, user, toFolder=True, **kwargs)
Expand Down Expand Up @@ -220,10 +221,11 @@ def _tileFromHash(cls, item, x, y, z, mayRedirect=False, **kwargs):
@classmethod
def _loadTileSource(cls, item, **kwargs):
if 'largeImage' not in item:
raise TileSourceError('No large image file in this item.')
msg = 'No large image file in this item.'
raise TileSourceError(msg)
if item['largeImage'].get('expected'):
raise TileSourceError('The large image file for this item is '
'still pending creation.')
msg = 'The large image file for this item is still pending creation.'
raise TileSourceError(msg)

sourceName = item['largeImage']['sourceName']
try:
Expand Down Expand Up @@ -374,7 +376,7 @@ def _getAndCacheImageOrData(
if not hasattr(self, '_getAndCacheImageOrDataLock'):
self._getAndCacheImageOrDataLock = {
'keys': {},
'lock': threading.Lock()
'lock': threading.Lock(),
}
keylock = None
with self._getAndCacheImageOrDataLock['lock']:
Expand Down
10 changes: 5 additions & 5 deletions girder/girder_large_image/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,16 @@ def _itemFindRecursive(self, origItemFind, folderId, text, name, limit, offset,
'connectToField': 'parentId',
'depthField': '_depth',
'as': '_folder',
'startWith': '$_id'
'startWith': '$_id',
}},
{'$group': {'_id': '$_folder._id'}}
{'$group': {'_id': '$_folder._id'}},
]
children = [ObjectId(folderId)] + next(Folder().collection.aggregate(pipeline))['_id']
if len(children) > 1:
filters = (filters.copy() if filters else {})
if text:
filters['$text'] = {
'$search': text
'$search': text,
}
if name:
filters['name'] = name
Expand Down Expand Up @@ -121,7 +121,7 @@ def _itemFindRecursive(self, origItemFind, folderId, text, name, limit, offset,
'for admins).')
.modelParam('id', model=Folder, level=AccessType.READ)
.param('name', 'The name of the file.', paramType='path')
.errorResponse()
.errorResponse(),
)
@boundHandler()
def getYAMLConfigFile(self, folder, name):
Expand All @@ -142,7 +142,7 @@ def getYAMLConfigFile(self, folder, name):
.modelParam('id', model=Folder, level=AccessType.WRITE)
.param('name', 'The name of the file.', paramType='path')
.param('config', 'The contents of yaml config file to validate.',
paramType='body')
paramType='body'),
)
@boundHandler()
def putYAMLConfigFile(self, folder, name, config):
Expand Down
14 changes: 7 additions & 7 deletions girder/girder_large_image/rest/item_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ class InternalMetadataItemResource(Item):
def __init__(self, apiRoot):
super().__init__()
apiRoot.item.route(
'GET', (':itemId', 'internal_metadata', ':key'), self.getMetadataKey
'GET', (':itemId', 'internal_metadata', ':key'), self.getMetadataKey,
)
apiRoot.item.route(
'PUT', (':itemId', 'internal_metadata', ':key'), self.updateMetadataKey
'PUT', (':itemId', 'internal_metadata', ':key'), self.updateMetadataKey,
)
apiRoot.item.route(
'DELETE', (':itemId', 'internal_metadata', ':key'), self.deleteMetadataKey
'DELETE', (':itemId', 'internal_metadata', ':key'), self.deleteMetadataKey,
)

@describeRoute(
Expand All @@ -44,7 +44,7 @@ def __init__(self, apiRoot):
default='meta',
)
.errorResponse('ID was invalid.')
.errorResponse('Read access was denied for the item.', 403)
.errorResponse('Read access was denied for the item.', 403),
)
@access.user(scope=TokenScope.DATA_READ)
@loadmodel(model='item', map={'itemId': 'item'}, level=AccessType.READ)
Expand All @@ -55,7 +55,7 @@ def getMetadataKey(self, item, key, params):

@describeRoute(
Description(
'Overwrite the value for a single internal metadata key on this item.'
'Overwrite the value for a single internal metadata key on this item.',
)
.param('itemId', 'The ID of the item.', paramType='path')
.param(
Expand All @@ -72,7 +72,7 @@ def getMetadataKey(self, item, key, params):
paramType='body',
)
.errorResponse('ID was invalid.')
.errorResponse('Write access was denied for the item.', 403)
.errorResponse('Write access was denied for the item.', 403),
)
@access.user(scope=TokenScope.DATA_WRITE)
@loadmodel(model='item', map={'itemId': 'item'}, level=AccessType.WRITE)
Expand All @@ -90,7 +90,7 @@ def updateMetadataKey(self, item, key, params):
default='meta',
)
.errorResponse('ID was invalid.')
.errorResponse('Write access was denied for the item.', 403)
.errorResponse('Write access was denied for the item.', 403),
)
@access.user(scope=TokenScope.DATA_WRITE)
@loadmodel(model='item', map={'itemId': 'item'}, level=AccessType.READ)
Expand Down
Loading