Skip to content

Commit

Permalink
Merge branch 'cleanup'
Browse files Browse the repository at this point in the history
  • Loading branch information
gertjanvanzwieten committed Aug 8, 2023
2 parents e198132 + e306c2e commit d351dc4
Show file tree
Hide file tree
Showing 28 changed files with 301 additions and 1,897 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ jobs:
- {name: "baseline", os: ubuntu-latest, python-version: "3.10", matrix-backend: numpy, nprocs: 1}
- {name: "windows", os: windows-latest, python-version: "3.10", matrix-backend: numpy, nprocs: 1}
- {name: "macos", os: macos-latest, python-version: "3.10", matrix-backend: numpy, nprocs: 1}
- {name: "python 3.7", os: ubuntu-latest, python-version: "3.7", matrix-backend: numpy, nprocs: 1}
- {name: "python 3.8", os: ubuntu-latest, python-version: "3.8", matrix-backend: numpy, nprocs: 1}
- {name: "python 3.9", os: ubuntu-latest, python-version: "3.9", matrix-backend: numpy, nprocs: 1}
- {name: "scipy matrix", os: ubuntu-latest, python-version: "3.10", matrix-backend: scipy, nprocs: 1}
Expand All @@ -54,7 +53,7 @@ jobs:
- {name: "mkl windows", os: windows-latest, python-version: "3.10", matrix-backend: mkl, nprocs: 1}
- {name: "mkl macos", os: macos-latest, python-version: "3.10", matrix-backend: mkl, nprocs: 1}
- {name: "parallel", os: ubuntu-latest, python-version: "3.10", matrix-backend: numpy, nprocs: 2}
- {name: "numpy 1.17", os: ubuntu-latest, python-version: "3.7", matrix-backend: numpy, nprocs: 1, numpy-version: ==1.17}
- {name: "numpy 1.17", os: ubuntu-latest, python-version: "3.8", matrix-backend: numpy, nprocs: 1, numpy-version: ==1.17.3}
- {name: "tensorial", os: ubuntu-latest, python-version: "3.10", matrix-backend: numpy, nprocs: 1, tensorial: test}
fail-fast: false
env:
Expand Down
13 changes: 5 additions & 8 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import sys
import os
import re

try:
from sphinx import version_info as _sphinx_version_info
Expand Down Expand Up @@ -64,13 +63,11 @@

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
from nutils import version as nutils_version
# The short X.Y version.
version = re.search('^[0-9]+\\.[0-9]+', nutils_version).group(0)
# The full version, including alpha/beta/rc tags.
release = nutils_version
# built documents: 'version' refers to the short X.Y version, whereas 'release'
# refers to the full version, including alpha/beta/rc tags. For Nutils we set
# both to the same value.
from nutils import version
release = version

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
1 change: 1 addition & 0 deletions nutils/SI.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
prefixes. Dimensional values are generated primarily by instantiating the
Quantity type with a string value.
>>> from nutils import SI
>>> v = SI.parse('7μN*5h/6g')
The Quantity constructor recognizes the multiplication (\*) and division (/)
Expand Down
42 changes: 2 additions & 40 deletions nutils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,4 @@
'Numerical Utilities for Finite Element Analysis'

import sys
import numpy
from distutils.version import LooseVersion

assert sys.version_info >= (3, 5)
assert LooseVersion(numpy.version.version) >= LooseVersion('1.16'), 'nutils requires numpy 1.16 or higher, got {}'.format(numpy.version.version)

__version__ = version = '9a0'
version_name = 'idiyappam'
long_version = ('{} "{}"' if version_name else '{}').format(version, version_name)

__all__ = [
'cache',
'cli',
'element',
'elementseq',
'evaluable',
'export',
'expression_v1',
'expression_v2',
'function',
'matrix',
'mesh',
'numeric',
'parallel',
'points',
'pointsseq',
'sample',
'solver',
'sparse',
'testing',
'topology',
'transform',
'transformseq',
'types',
'unit',
'warnings',
]

# vim:sw=2:sts=2:et
__version__ = version = '9a1'
version_name = 'jook-sing'
83 changes: 51 additions & 32 deletions nutils/_backports.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,66 @@
drop-on replacements.
"""

# Introduced in Python 3.8

try:
from functools import cached_property
except ImportError:
if False: # awaiting introduction

# Fallback implementation. Notable difference: no lock is used to prevent
# race conditions in multi-threaded contexts.
from doctest import DocTestFinder

class cached_property:
else:

def __init__(self, func):
self.func = func
# This is a modified version of doctest.DocTestFinder to fix issue
# https://github.com/python/cpython/issues/107715, which prevents doctest
# operation for the SI module. The modification assumes that `find` relies
# on the internal `_find_lineno` method.

def __set_name__(self, owner, name):
self.attrname = name
import doctest, inspect, re

def __get__(self, instance, owner=None):
if instance is None:
return self
try:
val = instance.__dict__[self.attrname]
except KeyError:
val = instance.__dict__[self.attrname] = self.func(instance)
return val
class DocTestFinder(doctest.DocTestFinder):

def _find_lineno(self, obj, source_lines):
"""
Return a line number of the given object's docstring. Note:
this method assumes that the object has a docstring.
"""
lineno = None

try:
from math import comb
except ImportError:
# Find the line number for modules.
if inspect.ismodule(obj):
lineno = 0

# Fallback implementation. Notable difference: if k > n, this
# implementation raises a ValueError rather than returning 0.
# Find the line number for classes.
# Note: this could be fooled if a class is defined multiple
# times in a single file.
if inspect.isclass(obj):
if source_lines is None:
return None
pat = re.compile(r'^\s*class\s*%s\b' %
re.escape(getattr(obj, '__name__', '-')))
for i, line in enumerate(source_lines):
if pat.match(line):
lineno = i
break

import math, functools, operator
# Find the line number for functions & methods.
if inspect.ismethod(obj): obj = obj.__func__
if inspect.isfunction(obj): obj = obj.__code__
if inspect.istraceback(obj): obj = obj.tb_frame
if inspect.isframe(obj): obj = obj.f_code
if inspect.iscode(obj):
lineno = getattr(obj, 'co_firstlineno', None)-1

def comb(n, k):
a, b = sorted([k, n-k])
numer = functools.reduce(operator.mul, range(1+b, 1+n), 1)
denom = math.factorial(a)
return numer // denom
# Find the line number where the docstring starts. Assume
# that it's the first line that begins with a quote mark.
# Note: this could be fooled by a multiline function
# signature, where a continuation line begins with a quote
# mark.
if lineno is not None:
if source_lines is None:
return lineno+1
pat = re.compile(r'(^|.*:)\s*\w*("|\')')
for lineno in range(lineno, len(source_lines)):
if pat.match(source_lines[lineno]):
return lineno


# vim:sw=4:sts=4:et
# We couldn't find the line number.
return None
64 changes: 0 additions & 64 deletions nutils/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,70 +173,6 @@ def __call__(self, *args, **kwargs):
return retvals


class positional_only:
'''Change all positional-or-keyword arguments to positional-only.
Python introduces syntax to define positional-only parameters in version 3.8,
but the same effect can be achieved in older versions by using a wrapper with
a var-positional argument. The :func:`positional_only` decorator uses this
technique to treat all positional-or-keyword arguments as positional-only. In
order to avoid name clashes between the positional-only arguments and
variable keyword arguments, the wrapper additionally introduces the
convention that the last argument receives the variable keyword argument
dictionary in case is has a default value of ... (ellipsis).
Example:
>>> @positional_only
... def f(x, *, y):
... pass
>>> inspect.signature(f)
<Signature (x, /, *, y)>
>>> @positional_only
... def f(x, *args, y, kwargs=...):
... pass
>>> inspect.signature(f)
<Signature (x, /, *args, y, **kwargs)>
Args
----
f : :any:`callable`
Function to be wrapped.
'''

def __init__(self, f):
signature = inspect.signature(f)
parameters = list(signature.parameters.values())
keywords = []
varkw = None
for i, param in enumerate(parameters):
if param.kind is param.VAR_KEYWORD:
raise Exception('positional_only decorated function must use ellipses to mark a variable keyword argument')
if i == len(parameters)-1 and param.default is ...:
parameters[i] = param.replace(kind=inspect.Parameter.VAR_KEYWORD, default=inspect.Parameter.empty)
varkw = param.name
elif param.kind is param.POSITIONAL_OR_KEYWORD:
parameters[i] = param.replace(kind=param.POSITIONAL_ONLY)
elif param.kind is param.KEYWORD_ONLY:
keywords.append(param.name)
self.__keywords = tuple(keywords)
self.__varkw = varkw
self.__signature__ = signature.replace(parameters=parameters)
functools.update_wrapper(self, f)

def __get__(self, instance, owner):
return positional_only(self.__wrapped__.__get__(instance, owner))

def __call__(self, *args, **kwargs):
wrappedkwargs = {name: kwargs.pop(name) for name in self.__keywords if name in kwargs}
if self.__varkw:
wrappedkwargs[self.__varkw] = kwargs
elif kwargs:
raise TypeError('{}() got an unexpected keyword argument {!r}'.format(self.__wrapped__.__name__, *kwargs))
return self.__wrapped__(*args, **wrappedkwargs)


def loadlib(**libname):
'''
Find and load a dynamic library using :any:`ctypes.CDLL`. For each
Expand Down
2 changes: 1 addition & 1 deletion nutils/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""

from . import _util as util, numeric, cache, transform, warnings, types, points
from ._backports import cached_property
from functools import cached_property
from typing import Tuple
from numbers import Integral
import nutils_poly as poly
Expand Down
2 changes: 1 addition & 1 deletion nutils/elementseq.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from . import types, numeric, _util as util
from .element import Reference
from .pointsseq import PointsSequence
from ._backports import cached_property
from functools import cached_property
from typing import Tuple, Sequence, Iterable, Iterator, Optional, Union, overload
import abc
import itertools
Expand Down
2 changes: 1 addition & 1 deletion nutils/evaluable.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
Protocol = object

from . import debug_flags, _util as util, types, numeric, cache, warnings, parallel, sparse
from ._backports import cached_property
from functools import cached_property
from ._graph import Node, RegularNode, DuplicatedLeafNode, InvisibleNode, Subgraph
import nutils_poly as poly
import numpy
Expand Down
6 changes: 2 additions & 4 deletions nutils/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@


@contextlib.contextmanager
@util.positional_only
def mplfigure(name, kwargs=...):
def mplfigure(name, /, **kwargs):
'''Matplotlib figure context, convenience function.
Returns a :class:`matplotlib.figure.Figure` object suitable for
Expand Down Expand Up @@ -197,8 +196,7 @@ def triplot(name, points, values=None, *, tri=None, hull=None, cmap=None, clim=N
fig.colorbar(im, label=vlabel, **cbarargs)


@util.positional_only
def vtk(name, cells, points, kwargs=...):
def vtk(name, cells, points, /, **kwargs):
'''Export data to a VTK file.
This method provides a simple interface to the `VTK file format`_ with a
Expand Down
4 changes: 1 addition & 3 deletions nutils/expression_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -1311,7 +1311,7 @@ def _replace_lengths(ast, lengths):
return ast


def parse(expression, variables, indices, arg_shapes={}, default_geometry_name='x', fixed_lengths=None, fallback_length=None, functions=None):
def parse(expression, variables, indices, arg_shapes={}, default_geometry_name='x', fixed_lengths=None, fallback_length=None):
'''Parse ``expression`` and return AST.
This function parses a tensor expression according to the syntax described in
Expand Down Expand Up @@ -1385,8 +1385,6 @@ def parse(expression, variables, indices, arg_shapes={}, default_geometry_name='
``expression``.
'''

if functions is not None:
warnings.deprecation('argument `functions` is deprecated; the existence and number of arguments is not checked during parsing')
parser = _ExpressionParser(expression, variables, arg_shapes, default_geometry_name, fixed_lengths or {})
parser.tokenize()
if indices is None:
Expand Down
Loading

0 comments on commit d351dc4

Please sign in to comment.