Skip to content

Commit

Permalink
add debug option
Browse files Browse the repository at this point in the history
  • Loading branch information
soraros committed Jan 19, 2021
1 parent 46542f8 commit 9139dfb
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
- name: Test
env:
LD_LIBRARY_PATH: ${{ steps.get-lib-dir.outputs.libdir }}
NUTILS_DEBUG: all
run: |
mkdir testenv
cp -r examples docs tests .coveragerc testenv
Expand Down Expand Up @@ -168,7 +169,7 @@ jobs:
- name: Run unit tests
env:
_image: ${{ steps.build.outputs.id }}
run: podman run --pull=never --rm -v "$PWD/tests:/app/tests:ro" -v "$PWD/examples:/app/examples:ro" "$_image" -m unittest -bq
run: podman run --pull=never --rm -v "$PWD/tests:/app/tests:ro" -v "$PWD/examples:/app/examples:ro" --env NUTILS_DEBUG=all "$_image" -m unittest -bq
- name: Push image to container registry
if: ${{ github.event_name == 'push' }}
env:
Expand Down
31 changes: 31 additions & 0 deletions nutils/debug_flags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (c) 2020 Evalf
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import os, warnings

_env = dict.fromkeys(filter(None, os.getenv('NUTILS_DEBUG', '').lower().split(':')), True)
_all = _env.pop('all', False)

sparse = _env.pop('sparse', _all or __debug__) # check sparse chunks in evaluable
lower = _env.pop('lower', _all or __debug__) # check lowered shape, dtype in function
evalf = _env.pop('evalf', _all) # check evaluated arrays in evaluable

if _env:
warnings.warn('unused debug flags: {}'.format(', '.join(_env)))
20 changes: 11 additions & 9 deletions nutils/evaluable.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
else:
Protocol = object

from . import util, types, numeric, cache, transform, expression, warnings, parallel, sparse
from . import debug_flags, util, types, numeric, cache, transform, expression, warnings, parallel, sparse
from ._graph import Node, RegularNode, DuplicatedLeafNode, InvisibleNode, Subgraph
import numpy, sys, itertools, functools, operator, inspect, numbers, builtins, re, types as builtin_types, abc, collections.abc, math, treelog as log, weakref, time, contextlib, subprocess
_ = numpy.newaxis
Expand Down Expand Up @@ -733,8 +733,9 @@ def as_axis_property(value):

# ARRAYS

if __debug__:
_ArrayMeta = type(Evaluable)

if debug_flags.sparse:
def _chunked_assparse_checker(orig):
assert isinstance(orig, property)
@property
Expand All @@ -757,6 +758,13 @@ def _assparse(self):
return chunks
return _assparse

class _ArrayMeta(_ArrayMeta):
def __new__(mcls, name, bases, namespace):
if '_assparse' in namespace:
namespace['_assparse'] = _chunked_assparse_checker(namespace['_assparse'])
return super().__new__(mcls, name, bases, namespace)

if debug_flags.evalf:
class _evalf_checker:
def __init__(self, orig):
self.evalf_obj = getattr(orig, '__get__', lambda *args: orig)
Expand All @@ -771,18 +779,12 @@ def evalf_with_check(*args, **kwargs):
return res
return evalf_with_check

class _ArrayMeta(type(Evaluable)):
class _ArrayMeta(_ArrayMeta):
def __new__(mcls, name, bases, namespace):
if '_assparse' in namespace:
namespace['_assparse'] = _chunked_assparse_checker(namespace['_assparse'])
if 'evalf' in namespace:
namespace['evalf'] = _evalf_checker(namespace['evalf'])
return super().__new__(mcls, name, bases, namespace)

else:

_ArrayMeta = type(Evaluable)

class AsEvaluableArray(Protocol):
'Protocol for conversion into an :class:`Array`.'

Expand Down
15 changes: 7 additions & 8 deletions nutils/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
Protocol = object

from typing import Tuple, Union, Type, Callable, Sequence, Any, Optional, Iterator, Dict, Mapping, overload, List, Set
from . import evaluable, numeric, util, expression, types, warnings
from . import evaluable, numeric, util, expression, types, warnings, debug_flags
from .transformseq import Transforms
import builtins, numpy, re, types as builtin_types, itertools, functools, operator, abc, numbers

Expand All @@ -46,24 +46,23 @@ def lower(self, *, transform_chains: Tuple[evaluable.TransformChain] = (), coord
coordinates : sequence of :class:`nutils.evaluable.Array` objects
'''

if __debug__:
_ArrayMeta = type(Lowerable)

if debug_flags.lower:
def _lower(self, **kwargs):
result = self._ArrayMeta__lower(**kwargs)
assert isinstance(result, evaluable.Array)
offset = kwargs['coordinates'][0].ndim-1 if kwargs.get('coordinates', ()) else 0
assert result.ndim == self.ndim + offset
for n, m in zip(result.shape[offset:], self.shape):
if isinstance(m, int):
assert n == m, 'shape mismatch'
assert all(m == n for m, n in zip(result.shape[offset:], self.shape) if isinstance(n, int)), 'shape mismatch'
return result
class _ArrayMeta(type(Lowerable)):

class _ArrayMeta(_ArrayMeta):
def __new__(mcls, name, bases, namespace):
if 'lower' in namespace:
namespace['_ArrayMeta__lower'] = namespace.pop('lower')
namespace['lower'] = _lower
return super().__new__(mcls, name, bases, namespace)
else:
_ArrayMeta = type

class Array(Lowerable, metaclass=_ArrayMeta):
'''Base class for array valued functions.
Expand Down

0 comments on commit 9139dfb

Please sign in to comment.