From 3ad541d6a225c096f6053d189b35c29f696bc7de Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Wed, 29 Jan 2020 18:05:02 +0100 Subject: [PATCH 01/11] Update pre-commit tools and fix issues. --- .gitignore | 3 +++ .pre-commit-config.yaml | 2 +- phasemap/_box.py | 2 +- phasemap/_result.py | 2 +- phasemap/io/_encoding.py | 5 ++--- phasemap/plot.py | 2 +- setup.py | 3 ++- tests/conftest.py | 19 +++++++++---------- tests/plottest_helpers.py | 11 +++++------ tests/test_doc.py | 2 +- tests/test_run.py | 6 +++--- 11 files changed, 29 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index c6bd338..5726a76 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ htmlcov # profiling files *.lprof + +# VSCode +.vscode diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 738ebe5..429e68d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: git://github.com/pre-commit/mirrors-yapf - rev: v0.24.0 + rev: v0.29.0 hooks: - id: yapf language: system diff --git a/phasemap/_box.py b/phasemap/_box.py index 2aa108a..5c0572b 100644 --- a/phasemap/_box.py +++ b/phasemap/_box.py @@ -15,7 +15,7 @@ def __new__(cls, value): if value in cls.__INSTANCES: return cls.__INSTANCES[value] self = super().__new__(cls) - self._value = value # pylint: disable=protected-access + self._value = value cls.__INSTANCES[value] = self return self diff --git a/phasemap/_result.py b/phasemap/_result.py index 2c1d052..8f1e28b 100644 --- a/phasemap/_result.py +++ b/phasemap/_result.py @@ -15,5 +15,5 @@ def __init__(self, *, points, boxes, limits): # pylint: disable=useless-super-d super().__init__( points=points, boxes=set(boxes), - limits=[(low, high) for low, high in limits] + limits=[(low, high) for low, high in limits] # pylint: disable=unnecessary-comprehension ) diff --git a/phasemap/io/_encoding.py b/phasemap/io/_encoding.py index 4c37351..4ba30ca 100644 --- a/phasemap/io/_encoding.py +++ b/phasemap/io/_encoding.py @@ -90,7 +90,7 @@ def _(obj): @singledispatch def decode(obj): """ - Decodes JSON / msgpack objects into the corresponding Z2Pack types. + Decodes JSON / msgpack objects into the corresponding PhaseMap types. """ return obj @@ -101,8 +101,7 @@ def decode_complex(obj): def decode_result(obj): return Result( - points={k: v - for k, v in obj['points']}, + points=dict(obj['points']), boxes=obj['boxes'], limits=obj['limits'], ) diff --git a/phasemap/plot.py b/phasemap/plot.py index 83af395..516d18a 100644 --- a/phasemap/plot.py +++ b/phasemap/plot.py @@ -170,6 +170,6 @@ def points(result, *, ax=None, scale_val=None, cmap=None, **kwargs): point_colors[cmap(norm(phase))].append(coord) for color, coordinates in point_colors.items(): - ax.scatter(*np.array(coordinates).T, color=color, **kwargs) + ax.scatter(*np.array(coordinates).T, color=color, **kwargs) # pylint: disable=not-an-iterable return ax, cmap, norm, all_vals diff --git a/setup.py b/setup.py index fa138eb..901c998 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ EXTRAS_REQUIRE = dict( dev=[ - 'yapf==0.24', 'pre-commit==1.8.2', 'pylint==2.1.1', 'prospector==1.1.2' + 'yapf==0.29', 'pre-commit==2.0.0', 'pylint==2.4.4', 'prospector==1.2.0' ], test=['msgpack', 'pytest', 'pytest-cov'], doc=['sphinx', 'sphinx-rtd-theme', 'ipython'] @@ -46,6 +46,7 @@ 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Intended Audience :: Science/Research', 'Topic :: Scientific/Engineering :: Physics', 'Development Status :: 5 - Production/Stable' diff --git a/tests/conftest.py b/tests/conftest.py index af86e8d..0ba631e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -56,18 +56,17 @@ def inner(compare_fct, data, tag=None): ) ) raise ValueError('Reference data does not exist.') - else: - val = json.loads( - json.dumps(val, default=phasemap.io._encoding.encode), + val = json.loads( + json.dumps(val, default=phasemap.io._encoding.encode), + object_hook=phasemap.io._encoding.decode + ) + assert compare_fct( + val, + json.loads( + json.dumps(data, default=phasemap.io._encoding.encode), object_hook=phasemap.io._encoding.decode ) - assert compare_fct( - val, - json.loads( - json.dumps(data, default=phasemap.io._encoding.encode), - object_hook=phasemap.io._encoding.decode - ) - ) # get rid of json-specific quirks + ) # get rid of json-specific quirks return inner diff --git a/tests/plottest_helpers.py b/tests/plottest_helpers.py index 85f8034..b490a87 100644 --- a/tests/plottest_helpers.py +++ b/tests/plottest_helpers.py @@ -43,11 +43,10 @@ def inner(tol=1e-6): os.makedirs(os.path.dirname(path), exist_ok=True) plt.savefig(path) raise ValueError('Reference plot did not exist.') - else: - with tempfile.NamedTemporaryFile(suffix='.png') as temp_file: - plt.savefig(temp_file.name) - assert compare_images( - path, temp_file.name, tol=tol, in_decorator=True - ) is None + with tempfile.NamedTemporaryFile(suffix='.png') as temp_file: + plt.savefig(temp_file.name) + assert compare_images( + path, temp_file.name, tol=tol, in_decorator=True + ) is None return inner diff --git a/tests/test_doc.py b/tests/test_doc.py index d9b1f69..496a3d3 100644 --- a/tests/test_doc.py +++ b/tests/test_doc.py @@ -21,7 +21,7 @@ def test_all_doc(): del sys.modules[key] fsc.export.test_doc() try: - import phasemap # pylint: disable=unused-variable + import phasemap # pylint: disable=import-outside-toplevel,unused-import finally: # reset to the previous phasemap -- just doing import breaks pickle for key in list(sys.modules.keys()): diff --git a/tests/test_run.py b/tests/test_run.py index e7c159b..b17b894 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -38,7 +38,7 @@ def test_save_file(results_equal): def test_init_result(results_equal): - def error(x): # pylint: disable=unused-argument + def error(x): raise ValueError res1 = pm.run(phase1, limits=[(-1, 1)] * 2, num_steps=2) @@ -47,7 +47,7 @@ def error(x): # pylint: disable=unused-argument def test_load(results_equal): - def error(x): # pylint: disable=unused-argument + def error(x): raise ValueError with tempfile.NamedTemporaryFile() as tmpf: @@ -199,7 +199,7 @@ async def inner(inp): def test_raises(): - def func(val): # pylint: disable=unused-argument + def func(val): raise ValueError('test succeeded.') with pytest.raises(ValueError): From e4dba7f6b20faf461d7686cdbe5c7478e9b153df Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Wed, 29 Jan 2020 18:10:25 +0100 Subject: [PATCH 02/11] Remove Python 3.5 support. --- .travis.yml | 11 ++++------- phasemap/_box.py | 1 - phasemap/_cache.py | 1 - phasemap/_coordinate.py | 1 - phasemap/_result.py | 1 - setup.py | 2 +- tests/conftest.py | 1 - tests/plottest_helpers.py | 2 -- 8 files changed, 5 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3e7d1e4..a13cc17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,18 @@ language: python cache: pip python: - - "3.5" - "3.6" - + - "3.7" + - "3.8" env: - TEST_TYPE="test" - -matrix: +jobs: include: - - python: 3.6 + - python: 3.7 env: TEST_TYPE="compliance" - install: - pip install -U pytest - pip install .[dev] - script: - if [ "$TEST_TYPE" == "compliance" ] ; then pre-commit run --all-files ; fi - if [ "$TEST_TYPE" == "test" ] ; then cd tests; pytest --no-plot-tests ; fi diff --git a/phasemap/_box.py b/phasemap/_box.py index 5c0572b..9ad2480 100644 --- a/phasemap/_box.py +++ b/phasemap/_box.py @@ -39,7 +39,6 @@ class Box: phase: The phase of the box, determined by the evaluated points it contains: If all points have the same phase, the box will have that phase. Otherwise, the phase of the box is undefined. """ - def __init__(self, *, corner, size): self.corner = Coordinate(corner) self.phase = None diff --git a/phasemap/_cache.py b/phasemap/_cache.py index a0805c3..908a223 100644 --- a/phasemap/_cache.py +++ b/phasemap/_cache.py @@ -13,7 +13,6 @@ class FuncCache: """ Caches calls to a function or coroutine. """ - def __init__(self, func, data=None): self.func = _wrap_to_coroutine(func) self.data = data if data is not None else dict() diff --git a/phasemap/_coordinate.py b/phasemap/_coordinate.py index 97f0a31..05e3acd 100644 --- a/phasemap/_coordinate.py +++ b/phasemap/_coordinate.py @@ -12,7 +12,6 @@ class Coordinate(np.ndarray): """ Array class describing the relative position within the calculation window. """ - def __new__(cls, coord): coord_list = [Fraction(x) for x in coord] self = super().__new__(cls, shape=(len(coord_list), ), dtype=object) diff --git a/phasemap/_result.py b/phasemap/_result.py index 8f1e28b..7e4f4d8 100644 --- a/phasemap/_result.py +++ b/phasemap/_result.py @@ -10,7 +10,6 @@ class Result(types.SimpleNamespace): """ Container class for the result of a :func:`.run` calculation. Contains the boxes, points and limits of the calculation. """ - def __init__(self, *, points, boxes, limits): # pylint: disable=useless-super-delegation super().__init__( points=points, diff --git a/setup.py b/setup.py index 901c998..7075e2d 100644 --- a/setup.py +++ b/setup.py @@ -37,13 +37,13 @@ 'numpy', 'matplotlib', 'decorator', 'fsc.export', 'fsc.iohelper>=1.0.2', 'fsc.async-tools' ], + python_requires='>=3.6', extras_require=EXTRAS_REQUIRE, long_description=README, classifiers=[ 'License :: OSI Approved :: Apache Software License', 'Natural Language :: English', 'Operating System :: Unix', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', diff --git a/tests/conftest.py b/tests/conftest.py index 0ba631e..10a83e9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -44,7 +44,6 @@ def test_name(request): @pytest.fixture def compare_data(request, test_name, scope="session"): """Returns a function which either saves some data to a file or (if that file exists already) compares it to pre-existing data using a given comparison function.""" - def inner(compare_fct, data, tag=None): full_name = test_name + (tag or '') val = request.config.cache.get(full_name, None) diff --git a/tests/plottest_helpers.py b/tests/plottest_helpers.py index b490a87..480fd87 100644 --- a/tests/plottest_helpers.py +++ b/tests/plottest_helpers.py @@ -22,7 +22,6 @@ def disable_diff_save(monkeypatch): """ Do not save the diff of images if the test fails. """ - def do_nothing(*args, **kwargs): pass @@ -36,7 +35,6 @@ def assert_image_equal(disable_diff_save, pytestconfig, test_name): """ Save the current figure to a temporary file and check that it's the same as the reference image of the given name. """ - def inner(tol=1e-6): path = './reference_plots/' + test_name + '.png' if not os.path.exists(path): From c8e2de88640b6f06b37039390f82cd17313c5184 Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Wed, 29 Jan 2020 20:41:39 +0100 Subject: [PATCH 03/11] Use install script / test script on Travis. --- .travis-data/install_script.sh | 21 +++++++++++++++++++++ .travis-data/test_script.sh | 16 ++++++++++++++++ .travis.yml | 15 +++++++++------ 3 files changed, 46 insertions(+), 6 deletions(-) create mode 100755 .travis-data/install_script.sh create mode 100755 .travis-data/test_script.sh diff --git a/.travis-data/install_script.sh b/.travis-data/install_script.sh new file mode 100755 index 0000000..4a58ed9 --- /dev/null +++ b/.travis-data/install_script.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Author: Dominik Gresch + +# Be verbose, and stop with error as soon there's one +set -ev + +cd ${TRAVIS_BUILD_DIR} + +case "$INSTALL_TYPE" in + dev) + pip install .[dev] + ;; + test) + pip install .[test] + ;; + test_sdist) + python setup.py sdist + ls -1 dist/ | xargs -I % pip install dist/%[test] + ;; +esac diff --git a/.travis-data/test_script.sh b/.travis-data/test_script.sh new file mode 100755 index 0000000..195fbc5 --- /dev/null +++ b/.travis-data/test_script.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# © 2017-2019, ETH Zurich, Institut für Theoretische Physik +# Author: Dominik Gresch + +# Be verbose, and stop with error as soon there's one +set -ev + +case "$TEST_TYPE" in + test) + cd ${TRAVIS_BUILD_DIR}/tests; pytest + ;; + precommit) + pre-commit run --all-files + ;; +esac diff --git a/.travis.yml b/.travis.yml index a13cc17..f9c14c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,13 +6,16 @@ python: - "3.8" env: - TEST_TYPE="test" + INSTALL_TYPE="test" + - TEST_TYPE="test" + INSTALL_TYPE="test_sdist" jobs: include: - - python: 3.7 - env: TEST_TYPE="compliance" + - python: "3.7" + env: + - TEST_TYPE="precommit" + INSTALL_TYPE="dev" install: - - pip install -U pytest - - pip install .[dev] + - ./.travis-data/install_script.sh script: - - if [ "$TEST_TYPE" == "compliance" ] ; then pre-commit run --all-files ; fi - - if [ "$TEST_TYPE" == "test" ] ; then cd tests; pytest --no-plot-tests ; fi + - ./.travis-data/test_script.sh From 6c40e52e363e209a776d61d8d08979b0ac4056d5 Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Wed, 29 Jan 2020 20:58:45 +0100 Subject: [PATCH 04/11] Update build status badge Use default branch instead of hardcoded master in build status. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56f5c4d..c6e2f72 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ PhaseMap is a tool for mapping phase diagrams. The purpose of the tool is to con Documentation: http://z2pack.ethz.ch/phasemap -[![Build Status](https://travis-ci.org/greschd/PhaseMap.svg?branch=master)](https://travis-ci.org/greschd/PhaseMap) +[![Build Status](https://travis-ci.org/greschd/PhaseMap.svg)](https://travis-ci.org/greschd/PhaseMap) From 190459b4b7d864084e13f1d0534e52f3f0fd2af1 Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Mon, 17 Feb 2020 10:41:40 +0100 Subject: [PATCH 05/11] Add readthedocs config file. --- .readthedocs.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..d2f8caa --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,22 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the doc/ directory with Sphinx +sphinx: + configuration: doc/source/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +formats: [] + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - method: pip + path: . + extra_requirements: + - doc From b87bd609afd1e48eb79bd44658b673c3a1f06b6d Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Mon, 17 Feb 2020 11:22:55 +0100 Subject: [PATCH 06/11] Change documentation URL to phasemap.greschd.ch --- README.md | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c6e2f72..e1cd18b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,6 @@ PhaseMap is a tool for mapping phase diagrams. The purpose of the tool is to concentrate the evaluations on the space around the phase boundaries, thus requiring less evaluations. -Documentation: http://z2pack.ethz.ch/phasemap +Documentation: http://phasemap.greschd.ch [![Build Status](https://travis-ci.org/greschd/PhaseMap.svg)](https://travis-ci.org/greschd/PhaseMap) diff --git a/setup.py b/setup.py index 7075e2d..fa58c95 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ setup( name='phasemap', version=VERSION, - url='http://z2pack.ethz.ch/phasemap', + url='http://phasemap.greschd.ch', author='Dominik Gresch', author_email='greschd@gmx.ch', description='Algorithm for calculating phase diagrams', From 6b7b09e533961ea70313f0b5f2f599b2da741def Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Mon, 17 Feb 2020 11:29:58 +0100 Subject: [PATCH 07/11] Add documentation status badge. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e1cd18b..7468af2 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,5 @@ PhaseMap is a tool for mapping phase diagrams. The purpose of the tool is to con Documentation: http://phasemap.greschd.ch +[![Documentation Status](https://readthedocs.org/projects/phasemap/badge/?version=latest)](https://phasemap.greschd.ch/en/latest/?badge=latest) [![Build Status](https://travis-ci.org/greschd/PhaseMap.svg)](https://travis-ci.org/greschd/PhaseMap) From 013011773c224015e39c3219087bb09d41c41bda Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Fri, 2 Oct 2020 12:57:16 +0200 Subject: [PATCH 08/11] Update tooling and some dependencies. (#5) --- .pre-commit-config.yaml | 26 +- .prospector.yaml | 13 - .pylintrc | 425 ----------------------------- .style.yapf | 4 - .travis-data/install_script.sh | 6 +- README.md | 6 +- doc/source/conf.py | 121 ++++---- examples/hypersphere/run.py | 12 +- examples/pathological_phase/run.py | 19 +- examples/toy_phase/create_video.py | 28 +- examples/toy_phase/run.py | 28 +- logo/test.py | 44 ++- mypy.ini | 32 +++ phasemap/__init__.py | 6 +- phasemap/_box.py | 35 +-- phasemap/_cache.py | 3 +- phasemap/_coordinate.py | 5 +- phasemap/_logging_setup.py | 6 +- phasemap/_result.py | 9 +- phasemap/_run.py | 59 ++-- phasemap/io/__init__.py | 2 - phasemap/io/_encoding.py | 50 ++-- phasemap/io/_save_load.py | 4 +- phasemap/plot.py | 22 +- phasemap/py.typed | 0 playground/plot.py | 15 +- playground/test.py | 122 ++++----- playground/test2.py | 1 - pyproject.toml | 53 ++++ setup.cfg | 54 ++++ setup.py | 59 +--- tests/conftest.py | 27 +- tests/phases.py | 8 +- tests/plottest_helpers.py | 23 +- tests/test_doc.py | 6 +- tests/test_func_cache.py | 4 +- tests/test_plot.py | 11 +- tests/test_run.py | 46 ++-- tests/test_save_load.py | 13 +- 39 files changed, 507 insertions(+), 900 deletions(-) delete mode 100644 .prospector.yaml delete mode 100644 .pylintrc delete mode 100644 .style.yapf create mode 100644 mypy.ini create mode 100644 phasemap/py.typed create mode 100644 pyproject.toml create mode 100644 setup.cfg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 429e68d..f2cd02b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,23 @@ repos: -- repo: git://github.com/pre-commit/mirrors-yapf - rev: v0.29.0 +- repo: https://github.com/asottile/pyupgrade + rev: v2.7.2 hooks: - - id: yapf - language: system - -- repo: git://github.com/guykisel/prospector-mirror - rev: 7ff847e779347033ebbd9e3b88279e7f3a998b45 + - id: pyupgrade + args: [--py36-plus] +- repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.782 + hooks: + - id: mypy + exclude: '^(doc/)|(examples/)|(logo/)|(playground/)' +- repo: local hooks: - - id: prospector + - id: pylint + name: pylint + entry: pylint language: system + types: [python] exclude: '^(doc/)|(examples/)|(logo/)|(playground/)' diff --git a/.prospector.yaml b/.prospector.yaml deleted file mode 100644 index 68d3dd1..0000000 --- a/.prospector.yaml +++ /dev/null @@ -1,13 +0,0 @@ -ignore-paths: - - doc - - examples - - futures - -pep8: - disable: - - E501 - - E116 - - E402 - -pyflakes: - run: false diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index e6c1847..0000000 --- a/.pylintrc +++ /dev/null @@ -1,425 +0,0 @@ -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS,test,examples,setup.py - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=too-few-public-methods,too-many-public-methods,bad-continuation,wrong-import-position,line-too-long,locally-disabled,wildcard-import,locally-enabled,too-many-instance-attributes,fixme,logging-format-interpolation,missing-docstring,no-else-return,len-as-condition - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[BASIC] - -# Naming hint for argument names -argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Naming hint for attribute names -attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=5 - -# Naming hint for function names -function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_, _INPUT_FILE_NAME, _OUTPUT_FILE_NAME,t,x,y,z,f,kx,ky,kz,k1,k2,s,c,n,p,ax - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for method names -method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*)|(setUp)|(tearDown))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_,setUp,tearDown - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Naming hint for variable names -variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=140 - -# Maximum number of lines in a module -max-module-lines=1000 - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=8 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=20 - -# Maximum number of parents for a class (see R0901). -max-parents=20 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=1 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make,_get_linkname_retrieved - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index 816b2cc..0000000 --- a/.style.yapf +++ /dev/null @@ -1,4 +0,0 @@ -[style] -based_on_style = pep8 -coalesce_brackets = true -dedent_closing_brackets = true diff --git a/.travis-data/install_script.sh b/.travis-data/install_script.sh index 4a58ed9..8634cff 100755 --- a/.travis-data/install_script.sh +++ b/.travis-data/install_script.sh @@ -7,15 +7,17 @@ set -ev cd ${TRAVIS_BUILD_DIR} + case "$INSTALL_TYPE" in dev) pip install .[dev] ;; test) - pip install .[test] + pip install .[dev] ;; test_sdist) + pip install -U setuptools python setup.py sdist - ls -1 dist/ | xargs -I % pip install dist/%[test] + ls -1 dist/ | xargs -I % pip install dist/%[dev] ;; esac diff --git a/README.md b/README.md index 7468af2..0ecf61e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ ## PhaseMap -PhaseMap is a tool for mapping phase diagrams. The purpose of the tool is to concentrate the evaluations on the space around the phase boundaries, thus requiring less evaluations. +PhaseMap is a tool for mapping phase diagrams. The purpose of the tool is to concentrate the evaluations on the space around the phase boundaries, to require fewer evaluations. + +The PhaseMap algorithm is ideally suited for cases where: +- phases can be determined as a discrete number or label +- evaluating the phase at a single point is relatively expensive Documentation: http://phasemap.greschd.ch diff --git a/doc/source/conf.py b/doc/source/conf.py index fcb47f8..7f3c1da 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -11,53 +9,56 @@ # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', 'sphinx.ext.mathjax', 'sphinx.ext.intersphinx', - 'sphinx.ext.napoleon', 'sphinx.ext.viewcode', - 'IPython.sphinxext.ipython_directive' + "sphinx.ext.autodoc", + "sphinx.ext.mathjax", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "IPython.sphinxext.ipython_directive", ] intersphinx_mapping = { - 'python': ('https://docs.python.org/3', None), - 'msgpack': ('https://msgpack-python.readthedocs.io/en/latest', None), - 'z2pack': ('http://z2pack.ethz.ch/doc', None), - 'matplotlib': ('https://matplotlib.org', None) + "python": ("https://docs.python.org/3", None), + "msgpack": ("https://msgpack-python.readthedocs.io/en/latest", None), + "z2pack": ("http://z2pack.ethz.ch/doc", None), + "matplotlib": ("https://matplotlib.org", None), } -nitpick_ignore = [('py:obj', 'module'), ('py:class', 'module')] +nitpick_ignore = [("py:obj", "module"), ("py:class", "module")] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -#~ master_doc = 'index' -master_doc = 'index' +# ~ master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'PhaseMap' +project = "PhaseMap" year = time.localtime().tm_year if year == 2016: - copyright = u'2016, Dominik Gresch' + copyright = "2016, Dominik Gresch" else: - copyright = u'2016-{}, Dominik Gresch'.format(year) + copyright = f"2016-{year}, Dominik Gresch" # 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. # # The short X.Y version. -version = '.'.join(phasemap.__version__.split('.')[:2]) +version = ".".join(phasemap.__version__.split(".")[:2]) # The full version, including alpha/beta/rc tags. release = phasemap.__version__ @@ -70,65 +71,65 @@ # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['doc.rst'] -#~ exclude_patterns = ['index.rst'] +exclude_patterns = ["doc.rst"] +# ~ exclude_patterns = ['index.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. show_authors = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -#~ html_theme = 'basicstrap' -html_theme = 'sphinx_rtd_theme' +# ~ html_theme = 'basicstrap' +html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#~ html_theme_options = { -#~ 'inner_theme': True, -#~ 'inner_theme_name': 'bootswatch-darkly', -#~ 'nav_fixed_top': False -#~ } +# ~ html_theme_options = { +# ~ 'inner_theme': True, +# ~ 'inner_theme_name': 'bootswatch-darkly', +# ~ 'nav_fixed_top': False +# ~ } # Add any paths that contain custom themes here, relative to this directory. -#~ html_theme_path = ["."] +# ~ html_theme_path = ["."] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -142,78 +143,76 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -#html_extra_path = [] +# html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#~ html_show_copyright = False +# ~ html_show_copyright = False # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -html_use_opensearch = 'http://z2pack.ethz.ch/phasemap' +html_use_opensearch = "http://z2pack.ethz.ch/phasemap" # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' -html_search_language = 'en' +html_search_language = "en" # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value -#html_search_options = {'type': 'default'} +# html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' +# html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'PhaseMapdoc' +htmlhelp_basename = "PhaseMapdoc" # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'phasemap', u'PhaseMap Documentation', [u'Dominik Gresch'], 1) -] +man_pages = [("index", "phasemap", "PhaseMap Documentation", ["Dominik Gresch"], 1)] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False diff --git a/examples/hypersphere/run.py b/examples/hypersphere/run.py index d65ae5e..1dee9d6 100644 --- a/examples/hypersphere/run.py +++ b/examples/hypersphere/run.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -10,7 +8,7 @@ def phase(pos): """ Defines an n-dimensional hypersphere. """ - return int(sum(x**2 for x in pos) <= 1) + return int(sum(x ** 2 for x in pos) <= 1) def run_calc(dim, num_steps, all_corners=False): @@ -19,15 +17,13 @@ def run_calc(dim, num_steps, all_corners=False): limits=[(-1.1, 1.1)] * dim, num_steps=num_steps, mesh=3, - all_corners=all_corners + all_corners=all_corners, ) return res -if __name__ == '__main__': +if __name__ == "__main__": for i in [1, 2, 3]: for n in range(1, 5): for all_corners in [False, True]: - print( - i, n, all_corners, len(run_calc(i, n, all_corners).points) - ) + print(i, n, all_corners, len(run_calc(i, n, all_corners).points)) diff --git a/examples/pathological_phase/run.py b/examples/pathological_phase/run.py index 4fdce87..014b72c 100644 --- a/examples/pathological_phase/run.py +++ b/examples/pathological_phase/run.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -35,29 +34,29 @@ def run(num_steps, mesh=2): [(0, 1), (0, 1)], num_steps=num_steps, mesh=mesh, - save_interval=0., + save_interval=0.0, ) def plot_boxes(res): pm.plot.boxes(res) - plt.savefig('boxes.pdf', bbox_inches='tight') + plt.savefig("boxes.pdf", bbox_inches="tight") def plot_points(res): - pm.plot.points(res, s=POINT_SIZE, lw=0.) - plt.savefig('points.pdf', bbox_inches='tight') + pm.plot.points(res, s=POINT_SIZE, lw=0.0) + plt.savefig("points.pdf", bbox_inches="tight") def plot_combined(res): fig, ax = plt.subplots(figsize=[4.2, 4]) - ax.set_aspect(1.) - pm.plot.boxes(res, ax=ax, zorder=0, add_cbar=False, lw=0.1, edgecolor='k') - pm.plot.points(res, ax=ax, edgecolors='k', lw=0.1, s=POINT_SIZE) - plt.savefig('combined.pdf', bbox_inches='tight') + ax.set_aspect(1.0) + pm.plot.boxes(res, ax=ax, zorder=0, add_cbar=False, lw=0.1, edgecolor="k") + pm.plot.points(res, ax=ax, edgecolors="k", lw=0.1, s=POINT_SIZE) + plt.savefig("combined.pdf", bbox_inches="tight") -if __name__ == '__main__': +if __name__ == "__main__": res = run(5, mesh=2) # res = run(5, mesh=3) # res = run(5, mesh=4) diff --git a/examples/toy_phase/create_video.py b/examples/toy_phase/create_video.py index 9f30b94..758354c 100644 --- a/examples/toy_phase/create_video.py +++ b/examples/toy_phase/create_video.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -15,14 +13,14 @@ from matplotlib.colorbar import ColorbarBase from matplotlib.colors import Normalize -RESULTS_DIR = 'results' -POINT_SIZE = 1. +RESULTS_DIR = "results" +POINT_SIZE = 1.0 VALS = (-2, 0, 1, 3) CUTOFF = None def get_idx(name): - return int(name.split('.')[0].split('_')[1]) + return int(name.split(".")[0].split("_")[1]) def get_filenames(): @@ -38,7 +36,7 @@ def init(): fig, (ax, cbar_ax) = plt.subplots( ncols=2, gridspec_kw=dict(width_ratios=(0.95, 0.05)) ) - ax.set_aspect(1.) + ax.set_aspect(1.0) fig.subplots_adjust(right=0.9) norm = Normalize() @@ -50,7 +48,7 @@ def init(): cmap=plt.get_cmap(), norm=norm, boundaries=range(5), - ticklocation='right', + ticklocation="right", ticks=[x + 0.5 for x in range(4)], ) c_bar.solids.set_edgecolor("k") @@ -66,26 +64,20 @@ def plot(res, ax): zorder=0, add_cbar=False, lw=0.1, - edgecolor='k', + edgecolor="k", scale_val=VALS, ) pm.plot.points( - res, - ax=ax, - edgecolors='k', - lw=0.1, - add_cbar=False, - scale_val=VALS, - s=POINT_SIZE + res, ax=ax, edgecolors="k", lw=0.1, add_cbar=False, scale_val=VALS, s=POINT_SIZE ) -if __name__ == '__main__': +if __name__ == "__main__": with contextlib.suppress(FileNotFoundError): - os.remove('video.mp4') + os.remove("video.mp4") fig, ax = init() plot_func = functools.partial(plot, ax=ax) ani = animation.FuncAnimation( fig, plot_func, get_results, interval=120, repeat=False ) - ani.save('video.mp4', dpi=300, bitrate=2000, writer='ffmpeg_file') + ani.save("video.mp4", dpi=300, bitrate=2000, writer="ffmpeg_file") diff --git a/examples/toy_phase/run.py b/examples/toy_phase/run.py index 53a995e..f4796af 100644 --- a/examples/toy_phase/run.py +++ b/examples/toy_phase/run.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -11,7 +10,8 @@ import phasemap as pm import matplotlib.pyplot as plt -plt.set_cmap('viridis') + +plt.set_cmap("viridis") POINT_SIZE = 1 @@ -33,43 +33,43 @@ def phase_fct(pos): if y >= 0 and y < 0.1: return 1 - if (x - 0.5)**2 + (y - 0.5)**2 < 0.1: + if (x - 0.5) ** 2 + (y - 0.5) ** 2 < 0.1: return 3 return 0 def run(num_steps): - os.makedirs('results', exist_ok=True) + os.makedirs("results", exist_ok=True) return pm.run( phase_fct, [(0, 1), (0, 1)], num_steps=num_steps, mesh=2, - save_file='results/res_{}.json', - save_interval=0., + save_file="results/res_{}.json", + save_interval=0.0, ) def plot_boxes(res): pm.plot.boxes(res) - plt.savefig('boxes.pdf', bbox_inches='tight') + plt.savefig("boxes.pdf", bbox_inches="tight") def plot_points(res): - pm.plot.points(res, s=POINT_SIZE, lw=0.) - plt.savefig('points.pdf', bbox_inches='tight') + pm.plot.points(res, s=POINT_SIZE, lw=0.0) + plt.savefig("points.pdf", bbox_inches="tight") def plot_combined(res): fig, ax = plt.subplots(figsize=[4.2, 4]) - ax.set_aspect(1.) - pm.plot.boxes(res, ax=ax, zorder=0, add_cbar=False, lw=0.1, edgecolor='k') - pm.plot.points(res, ax=ax, edgecolors='k', lw=0.1, s=POINT_SIZE) - plt.savefig('combined.pdf', bbox_inches='tight') + ax.set_aspect(1.0) + pm.plot.boxes(res, ax=ax, zorder=0, add_cbar=False, lw=0.1, edgecolor="k") + pm.plot.points(res, ax=ax, edgecolors="k", lw=0.1, s=POINT_SIZE) + plt.savefig("combined.pdf", bbox_inches="tight") -if __name__ == '__main__': +if __name__ == "__main__": res = run(8) plot_boxes(res) plot_points(res) diff --git a/logo/test.py b/logo/test.py index 89fbcbf..0402398 100644 --- a/logo/test.py +++ b/logo/test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -10,14 +9,14 @@ import matplotlib.pyplot as plt -#~ def circle(x, y): -#~ return 1 if x**2 + y**2 < 1 else 0 +# ~ def circle(x, y): +# ~ return 1 if x**2 + y**2 < 1 else 0 -#~ def wedge(x, y): -#~ return 1 if (y - abs(x)) > 0 and (x**2 + y**2 < 1) else 0 +# ~ def wedge(x, y): +# ~ return 1 if (y - abs(x)) > 0 and (x**2 + y**2 < 1) else 0 -#~ def phase(val): -#~ return [wedge(x, y) + circle(x, y) for x, y in val] +# ~ def phase(val): +# ~ return [wedge(x, y) + circle(x, y) for x, y in val] def rhombus(x, y): @@ -25,25 +24,23 @@ def rhombus(x, y): def circle2(x, y, r=1): - return 1 if (x**2 + y**2) < r**2 else 0 + return 1 if (x ** 2 + y ** 2) < r ** 2 else 0 -#~ def box(x, y, l=0.5): -#~ return 1 if (-l < x < l) and (-l < y < l) else 0 +# ~ def box(x, y, l=0.5): +# ~ return 1 if (-l < x < l) and (-l < y < l) else 0 def phase(val): return [rhombus(x, y) + circle2(x, y, r=np.sqrt(0.5)) for x, y in val] -#~ def phase(val): -#~ return [rhombus(x, y) for x, y in val] +# ~ def phase(val): +# ~ return [rhombus(x, y) for x, y in val] -if __name__ == '__main__': - plt.set_cmap('viridis') - res = pm.get_phase_map( - phase, [(-1.1, 1.1), (-1.1, 1.1)], num_steps=6, mesh=3 - ) +if __name__ == "__main__": + plt.set_cmap("viridis") + res = pm.get_phase_map(phase, [(-1.1, 1.1), (-1.1, 1.1)], num_steps=6, mesh=3) A = np.zeros(res.mesh, dtype=int) - 1 for k, v in res.items(): A[k] = v @@ -52,7 +49,8 @@ def phase(val): B[k] = v for i in range(B.shape[0]): iterator = range(B.shape[1]) - if i % 2 == 1: iterator = reversed(iterator) + if i % 2 == 1: + iterator = reversed(iterator) for j in iterator: if B[i, j] == -1: B[i, j] = current @@ -62,13 +60,13 @@ def phase(val): -1: [0, 0, 0], 0: [0x00, 0x00, 0x00], 1: [0, 0x33, 0x99], - 2: [0xee, 0x66, 0] + 2: [0xEE, 0x66, 0], } color_mapping_2 = { -1: [0, 0, 0], - 0: [0xff, 0xff, 0xff], - 1: [0, 0x1f, 0x5c], - 2: [0xc2, 0x3b, 5] + 0: [0xFF, 0xFF, 0xFF], + 1: [0, 0x1F, 0x5C], + 2: [0xC2, 0x3B, 5], } A = np.zeros(tuple(list(res.mesh) + [3]), dtype=int) for i, line in enumerate(B): @@ -77,4 +75,4 @@ def phase(val): for k, v in res.items(): A[k] = color_mapping_2[v] - scipy.misc.imsave('logo_out.png', A, format='png') + scipy.misc.imsave("logo_out.png", A, format="png") diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..fb1552c --- /dev/null +++ b/mypy.ini @@ -0,0 +1,32 @@ +# Global options + +[mypy] +python_version = 3.7 + +; Strictness settings +; disallow_any_unimported = True +; disallow_any_expr = True +; disallow_any_decorated = True +; disallow_any_explicit = True +disallow_any_generics = True +; disallow_subclassing_any = True + +; disallow_untyped_calls = True +; disallow_untyped_defs = True +disallow_incomplete_defs = True +; disallow_untyped_decorators = True + +no_implicit_optional = True +no_strict_optional = False + +; Enable all warnings +warn_redundant_casts = True +warn_unused_ignores = True +warn_return_any = True +warn_unreachable = True + +allow_untyped_globals = False +strict_equality = True + +[mypy-numpy.*] +ignore_missing_imports = True diff --git a/phasemap/__init__.py b/phasemap/__init__.py index b38026d..f853289 100644 --- a/phasemap/__init__.py +++ b/phasemap/__init__.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch -__version__ = '1.0.0' +__version__ = "1.0.0" from ._run import * from . import plot from . import io -__all__ = ['plot', 'io'] + _run.__all__ # pylint: disable=undefined-variable +__all__ = ["plot", "io"] + _run.__all__ # type: ignore # pylint: disable=undefined-variable diff --git a/phasemap/_box.py b/phasemap/_box.py index 9ad2480..2351deb 100644 --- a/phasemap/_box.py +++ b/phasemap/_box.py @@ -1,29 +1,29 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch +import typing as ty + import numpy as np from ._coordinate import Coordinate class Sentinel: - __INSTANCES = dict() + __INSTANCES: ty.Dict[str, "Sentinel"] = dict() - def __new__(cls, value): + def __new__(cls, value: str) -> "Sentinel": if value in cls.__INSTANCES: return cls.__INSTANCES[value] - self = super().__new__(cls) - self._value = value + self = ty.cast("Sentinel", super().__new__(cls)) + self._value = value # type: ignore cls.__INSTANCES[value] = self return self def __repr__(self): - return 'Sentinel({!r})'.format(self._value) # pylint: disable=no-member + return f"Sentinel({self._value!r})" # pylint: disable=no-member -PHASE_UNDEFINED = Sentinel('undefined phase') +PHASE_UNDEFINED = Sentinel("undefined phase") class Box: @@ -39,6 +39,7 @@ class Box: phase: The phase of the box, determined by the evaluated points it contains: If all points have the same phase, the box will have that phase. Otherwise, the phase of the box is undefined. """ + def __init__(self, *, corner, size): self.corner = Coordinate(corner) self.phase = None @@ -50,23 +51,17 @@ def __hash__(self): return hash((self.corner, self.size)) def __eq__(self, other): - return np.all(self.corner == other.corner - ) and np.all(self.size == other.size) + return np.all(self.corner == other.corner) and np.all(self.size == other.size) def __repr__(self): - return 'Box(corner={0.corner}, size={0.size}, phase={0.phase})'.format( - self - ) + return "Box(corner={0.corner}, size={0.size}, phase={0.phase})".format(self) def contains_coord(self, coord): # Faster than pure numpy operations because of the slow 'Fraction'. # In this way, the remaining operations are not performed if one # expression evaluates to False. - return ( - all(c1 <= c2 for c1, c2 in zip(self.corner, coord)) and all( - c2 <= c1 + s - for c1, c2, s in zip(self.corner, coord, self.size) - ) + return all(c1 <= c2 for c1, c2 in zip(self.corner, coord)) and all( + c2 <= c1 + s for c1, c2, s in zip(self.corner, coord, self.size) ) def add_point(self, coord, phase): @@ -81,8 +76,8 @@ def add_point(self, coord, phase): def is_neighbour(self, other): return all( - c1 + s1 >= c2 and c2 + s2 >= c1 for c1, s1, c2, s2 in - zip(self.corner, self.size, other.corner, other.size) + c1 + s1 >= c2 and c2 + s2 >= c1 + for c1, s1, c2, s2 in zip(self.corner, self.size, other.corner, other.size) ) def process_possible_neighbour(self, box): diff --git a/phasemap/_cache.py b/phasemap/_cache.py index 908a223..832c722 100644 --- a/phasemap/_cache.py +++ b/phasemap/_cache.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -13,6 +11,7 @@ class FuncCache: """ Caches calls to a function or coroutine. """ + def __init__(self, func, data=None): self.func = _wrap_to_coroutine(func) self.data = data if data is not None else dict() diff --git a/phasemap/_coordinate.py b/phasemap/_coordinate.py index 05e3acd..da1b4f7 100644 --- a/phasemap/_coordinate.py +++ b/phasemap/_coordinate.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -12,9 +10,10 @@ class Coordinate(np.ndarray): """ Array class describing the relative position within the calculation window. """ + def __new__(cls, coord): coord_list = [Fraction(x) for x in coord] - self = super().__new__(cls, shape=(len(coord_list), ), dtype=object) + self = super().__new__(cls, shape=(len(coord_list),), dtype=object) self[:] = coord_list self.flags.writeable = False return self diff --git a/phasemap/_logging_setup.py b/phasemap/_logging_setup.py index bb68137..096af2a 100644 --- a/phasemap/_logging_setup.py +++ b/phasemap/_logging_setup.py @@ -1,14 +1,12 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch import sys import logging -__all__ = ['LOGGER', 'DEFAULT_HANDLER'] +__all__ = ["LOGGER", "DEFAULT_HANDLER"] -LOGGER = logging.getLogger('phasemap') +LOGGER = logging.getLogger("phasemap") LOGGER.setLevel(logging.INFO) DEFAULT_HANDLER = logging.StreamHandler(sys.stdout) diff --git a/phasemap/_result.py b/phasemap/_result.py index 7e4f4d8..20d45f0 100644 --- a/phasemap/_result.py +++ b/phasemap/_result.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -10,9 +8,12 @@ class Result(types.SimpleNamespace): """ Container class for the result of a :func:`.run` calculation. Contains the boxes, points and limits of the calculation. """ - def __init__(self, *, points, boxes, limits): # pylint: disable=useless-super-delegation + + def __init__( + self, *, points, boxes, limits + ): # pylint: disable=useless-super-delegation super().__init__( points=points, boxes=set(boxes), - limits=[(low, high) for low, high in limits] # pylint: disable=unnecessary-comprehension + limits=[tuple(low_high) for low_high in limits], ) diff --git a/phasemap/_run.py b/phasemap/_run.py index 406e645..d36c621 100644 --- a/phasemap/_run.py +++ b/phasemap/_run.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -33,8 +31,8 @@ def run( # pylint: disable=too-many-arguments save_file=None, load=False, load_quiet=True, - serializer='auto', - save_interval=5., + serializer="auto", + save_interval=5.0, ): """Run the PhaseMap algorithm. @@ -77,15 +75,16 @@ def run( # pylint: disable=too-many-arguments ) try: init_result = _io.load(save_file, serializer=serializer) - except IOError as err: + except OSError as err: if not load_quiet: raise err if init_result is not None: if not np.allclose(limits, init_result.limits): raise ValueError( - "Limits {} of the 'init_result' do not match the given limits {}" - .format(init_result.limits, limits) + "Limits {} of the 'init_result' do not match the given limits {}".format( + init_result.limits, limits + ) ) init_points = init_result.points else: @@ -114,8 +113,8 @@ def __init__( # pylint: disable=too-many-arguments all_corners=False, init_points=None, save_file=None, - serializer='auto', - save_interval=5., + serializer="auto", + save_interval=5.0, ): self._save_file = save_file self._serializer = serializer @@ -127,14 +126,14 @@ def __init__( # pylint: disable=too-many-arguments self._func = FuncCache( lambda coord: fct(self._coordinate_to_position(coord)), - data=copy.deepcopy(init_points) + data=copy.deepcopy(init_points), ) self.result = Result( boxes=set(self._get_initial_boxes()), # Note: 'points' needs to be the same object, not a copy. Otherwise # it will not update when the '_func' is called. points=self._func.data, - limits=limits + limits=limits, ) self._loop = asyncio.get_event_loop() @@ -162,12 +161,14 @@ def execute(self): async def _run(self): async with PeriodicTask(self._save, delay=self._save_interval): while not self._check_done(): - await asyncio.sleep(0.) + await asyncio.sleep(0.0) def _check_done(self): - done_tasks = [(box, fut) - for (box, fut) in self._split_futures_pending.items() - if fut.done()] + done_tasks = [ + (box, fut) + for (box, fut) in self._split_futures_pending.items() + if fut.done() + ] # Retrieve all exceptions to avoid asyncio 'exception never retrieved' # warning, but can only raise one. @@ -189,7 +190,7 @@ def _init_dimensions(self, limits, mesh, num_steps): self._validate_mesh(mesh) self._max_size = Coordinate([Fraction(1, m - 1) for m in self._mesh]) - self._min_size = self._max_size / 2**num_steps + self._min_size = self._max_size / 2 ** num_steps def _validate_mesh(self, mesh): if isinstance(mesh, numbers.Integral): @@ -197,11 +198,12 @@ def _validate_mesh(self, mesh): else: if len(mesh) != self._dim: raise ValueError( - "Length of 'mesh' {} does not match the dimension {} of the 'limits'." - .format(len(mesh), self._dim) + "Length of 'mesh' {} does not match the dimension {} of the 'limits'.".format( + len(mesh), self._dim + ) ) if any(m < 2 for m in mesh): - raise ValueError('Mesh must be >= 2 for each dimension.') + raise ValueError("Mesh must be >= 2 for each dimension.") self._mesh = mesh # pylint: disable=attribute-defined-outside-init def _coordinate_to_position(self, coord): @@ -209,12 +211,11 @@ def _coordinate_to_position(self, coord): def _get_initial_boxes(self): corners = itertools.product( - *[[i * s for i in range(m - 1)] - for s, m in zip(self._max_size, self._mesh)] + *[[i * s for i in range(m - 1)] for s, m in zip(self._max_size, self._mesh)] ) boxes = [Box(corner=c, size=self._max_size) for c in corners] for i, sq1 in enumerate(boxes): - for sq2 in boxes[i + 1:]: + for sq2 in boxes[i + 1 :]: sq1.process_possible_neighbour(sq2) return boxes @@ -227,17 +228,15 @@ def _schedule_split_box(self, box): self._split_futures[box] = fut async def _split_box(self, box): - LOGGER.debug('Splitting {}.'.format(box)) + LOGGER.debug(f"Splitting {box}.") if self._all_corners: coordinate_stencil = np.array( - list( - itertools.product([0, Fraction(1, 2), 1], repeat=self._dim) - ) + list(itertools.product([0, Fraction(1, 2), 1], repeat=self._dim)) ) else: coordinate_stencil = np.array( - [[Fraction(1, 2)] * self._dim] + - list(itertools.product([0, 1], repeat=self._dim)) + [[Fraction(1, 2)] * self._dim] + + list(itertools.product([0, 1], repeat=self._dim)) ) coords = box.corner + coordinate_stencil * box.size phases = await asyncio.gather(*[self._func(c) for c in coords]) @@ -265,7 +264,7 @@ async def _split_box(self, box): for old_nb in old_neighbours: new_sq.process_possible_neighbour(old_nb) for i, new_sq1 in enumerate(new_boxes): - for new_sq2 in new_boxes[i + 1:]: + for new_sq2 in new_boxes[i + 1 :]: new_sq1.process_certain_neighbour(new_sq2) # remove old box @@ -280,7 +279,7 @@ def _save(self): _io.save( self.result, self._save_file.format(self._save_count), - serializer=self._serializer + serializer=self._serializer, ) self._save_count += 1 self.needs_saving = False diff --git a/phasemap/io/__init__.py b/phasemap/io/__init__.py index e6afda1..82b8a24 100644 --- a/phasemap/io/__init__.py +++ b/phasemap/io/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch """This module contains functions for saving and loading PhaseMap objects.""" diff --git a/phasemap/io/_encoding.py b/phasemap/io/_encoding.py index 4ba30ca..5041e10 100644 --- a/phasemap/io/_encoding.py +++ b/phasemap/io/_encoding.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -25,36 +23,36 @@ def encode(obj): """ Encodes PhaseMap types into JSON / msgpack - compatible types. """ - raise TypeError('cannot JSONify {} object {}'.format(type(obj), obj)) + raise TypeError("cannot JSONify {} object {}".format(type(obj), obj)) @encode.register(np.bool_) -def _(obj): +def _encode_bool(obj): return bool(obj) @encode.register(Fraction) -def _(obj): +def _encode_fraction(obj): return dict(__fraction__=True, n=obj.numerator, d=obj.denominator) @encode.register(numbers.Real) -def _(obj): +def _encode_real(obj): return float(obj) @encode.register(numbers.Complex) -def _(obj): +def _encode_complex(obj): return dict(__complex__=True, real=encode(obj.real), imag=encode(obj.imag)) @encode.register(Iterable) -def _(obj): +def _encode_iterable(obj): return list(obj) @encode.register(Result) -def _(obj): +def _encode_result(obj): return dict( __result__=True, points=obj.points.items(), @@ -64,12 +62,12 @@ def _(obj): @encode.register(Coordinate) -def _(obj): +def _encode_coordinate(obj): return dict(__coord__=True, c=list(obj)) @encode.register(Box) -def _(obj): +def _encode_box(obj): return dict( __box__=True, corner=obj.corner, @@ -79,11 +77,11 @@ def _(obj): @encode.register(Sentinel) -def _(obj): +def _encode_sentinel(obj): return dict(__sentinel__=True, value=obj._value) -#-----------------------------------------------------------------------# +# -----------------------------------------------------------------------# @export @@ -96,42 +94,42 @@ def decode(obj): def decode_complex(obj): - return complex(obj['real'], obj['imag']) + return complex(obj["real"], obj["imag"]) def decode_result(obj): return Result( - points=dict(obj['points']), - boxes=obj['boxes'], - limits=obj['limits'], + points=dict(obj["points"]), + boxes=obj["boxes"], + limits=obj["limits"], ) def decode_box(obj): - res = Box(corner=obj['corner'], size=obj['size']) - res.phase = obj['phase'] + res = Box(corner=obj["corner"], size=obj["size"]) + res.phase = obj["phase"] return res def decode_coord(obj): - return Coordinate(obj['c']) + return Coordinate(obj["c"]) def decode_fraction(obj): - return Fraction(obj['n'], obj['d']) + return Fraction(obj["n"], obj["d"]) def decode_sentinel(obj): - return Sentinel(obj['value']) + return Sentinel(obj["value"]) @decode.register(dict) def _(obj): with contextlib.suppress(AttributeError): - obj = {k.decode('utf-8'): v for k, v in obj.items()} - special_markers = [key for key in obj.keys() if key.startswith('__')] + obj = {k.decode("utf-8"): v for k, v in obj.items()} + special_markers = [key for key in obj.keys() if key.startswith("__")] if len(special_markers) == 1: - name = special_markers[0].strip('__') - return globals()['decode_' + name](obj) + name = special_markers[0].strip("__") + return globals()["decode_" + name](obj) else: return obj diff --git a/phasemap/io/_save_load.py b/phasemap/io/_save_load.py index b0c6413..7061c9e 100644 --- a/phasemap/io/_save_load.py +++ b/phasemap/io/_save_load.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -9,7 +7,7 @@ from . import _encoding -__all__ = ['save', 'load'] +__all__ = ["save", "load"] IO_HANDLER = SerializerDispatch(_encoding, exclude=[pickle]) diff --git a/phasemap/plot.py b/phasemap/plot.py index 516d18a..b1ef097 100644 --- a/phasemap/plot.py +++ b/phasemap/plot.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch """ @@ -62,13 +60,7 @@ def _plot(func, result, *, ax=None, add_cbar=True, **kwargs): @export @_plot def boxes( - result, - *, - ax=None, - scale_val=None, - plot_undefined=False, - cmap=None, - **kwargs + result, *, ax=None, scale_val=None, plot_undefined=False, cmap=None, **kwargs ): """ Plots the phase diagram as a collection of boxes, which are colored according to the estimate of the phase in a given box. @@ -113,9 +105,7 @@ def boxes( xy=box.corner, width=box.size[0], height=box.size[1], - **ChainMap( - rect_properties, dict(facecolor=color, edgecolor=color) - ) + **ChainMap(rect_properties, dict(facecolor=color, edgecolor=color)) ) ) if plot_undefined: @@ -125,7 +115,7 @@ def boxes( xy=box.corner, width=box.size[0], height=box.size[1], - **ChainMap(rect_properties, dict(facecolor='white')) + **ChainMap(rect_properties, dict(facecolor="white")) ) ) return ax, cmap, norm, all_vals @@ -170,6 +160,10 @@ def points(result, *, ax=None, scale_val=None, cmap=None, **kwargs): point_colors[cmap(norm(phase))].append(coord) for color, coordinates in point_colors.items(): - ax.scatter(*np.array(coordinates).T, color=color, **kwargs) # pylint: disable=not-an-iterable + ax.scatter( + *np.array(coordinates).T, # pylint: disable=not-an-iterable + color=color, + **kwargs + ) return ax, cmap, norm, all_vals diff --git a/phasemap/py.typed b/phasemap/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/playground/plot.py b/playground/plot.py index e491357..db4044d 100644 --- a/playground/plot.py +++ b/playground/plot.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -13,12 +12,18 @@ def sqr_to_coord(sqr): edge, size = sqr.corner, sqr.size return [ - edge[0], edge[1], edge[0] + size, edge[1], edge[0] + size, - edge[1] + size, edge[0], edge[1] + size + edge[0], + edge[1], + edge[0] + size, + edge[1], + edge[0] + size, + edge[1] + size, + edge[0], + edge[1] + size, ] -def plot(sqr_list, max_size, base_mult, AP, savefile='test.svg'): +def plot(sqr_list, max_size, base_mult, AP, savefile="test.svg"): mult = base_mult max_size *= mult @@ -35,7 +40,7 @@ def plot(sqr_list, max_size, base_mult, AP, savefile='test.svg'): gp.add( util.svg.polygon( fill=col_dict[sqr.phase], - points="{},{} {},{} {},{} {},{}".format(*coord) + points="{},{} {},{} {},{} {},{}".format(*coord), ) ) diff --git a/playground/test.py b/playground/test.py index 0a875e3..97861df 100644 --- a/playground/test.py +++ b/playground/test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -12,14 +11,15 @@ import phasemap as pm import matplotlib.pyplot as plt -plt.set_cmap('viridis') + +plt.set_cmap("viridis") from matplotlib.colors import ListedColormap from plot import plot from ptools.advanced_plot import cmap_irregular from ptools.monitoring import Timer -logger = logging.getLogger('phasemap') +logger = logging.getLogger("phasemap") logger.setLevel(logging.INFO) DEFAULT_HANDLER = logging.StreamHandler(sys.stdout) logger.addHandler(DEFAULT_HANDLER) @@ -42,23 +42,23 @@ def phase_single(x, y): return 0 -#~ def phase_single(x, y): -#~ if x < 0 or x > 1 : -#~ return 2 -#~ if y < 0 or y > 1 : -#~ return 2 -#~ if y < 0.5 and x < 0.5: -#~ return 1 -#~ return 0 -#~ def phase_single(x, y): -#~ if 0.48 < y < 0.6 and x < 0.35: -#~ return 1 -#~ if 0.4 < x and y < 0.65: -#~ return 1 -#~ if 0.24 < y < 0.26 and x < 0.1: -#~ return 1 +# ~ def phase_single(x, y): +# ~ if x < 0 or x > 1 : +# ~ return 2 +# ~ if y < 0 or y > 1 : +# ~ return 2 +# ~ if y < 0.5 and x < 0.5: +# ~ return 1 +# ~ return 0 +# ~ def phase_single(x, y): +# ~ if 0.48 < y < 0.6 and x < 0.35: +# ~ return 1 +# ~ if 0.4 < x and y < 0.65: +# ~ return 1 +# ~ if 0.24 < y < 0.26 and x < 0.1: +# ~ return 1 -#~ return 0 +# ~ return 0 def phase_fct(pos): @@ -77,47 +77,47 @@ def phase_fct(pos): if pos[1] >= 0 and pos[1] < 0.1: return 1 - if (pos[0] - 0.5)**2 + (pos[1] - 0.5)**2 < 0.1: + if (pos[0] - 0.5) ** 2 + (pos[1] - 0.5) ** 2 < 0.1: return 3 return 0 -#~ def phase_fct(x, y): -#~ return x**2 + y**2 < 1 - -#~ def phase_fct(x, y): -#~ return (x**2 + y**2) < 1 -#~ def phase_fct(x, y, z=0): -#~ return x**2 + y**2 + z**2 < 1 -#~ def phase_fct(x, y, z=0): -#~ if x < 1 / np.pi and y < 1 / np.pi: -#~ return 0 -#~ elif x < 1 / np.pi: -#~ return 1 -#~ return 2 - -#~ def phase(val): -#~ return [phase_fct(v) for v in val] - -#~ def phase(val): -#~ x, y = val -#~ if 0.2 < y < 0.3 and 0.1 < x < 0.6: -#~ return 1 -#~ if y < 0.25 and x < 0.15: -#~ return 1 -#~ return 0 -#~ def phase(val): -#~ x, y = val -#~ return 1 if x**2 + y**2 < 1 else 0 -#~ print(val) -#~ if val in [[0., 0.], [0.25, 0.25], [0.5, 0.125]]: -#~ return 1 -#~ elif val in [[0.375, 0.125], [0.5, 0.125]]: -#~ return 2 -#~ return 0 - -if __name__ == '__main__': +# ~ def phase_fct(x, y): +# ~ return x**2 + y**2 < 1 + +# ~ def phase_fct(x, y): +# ~ return (x**2 + y**2) < 1 +# ~ def phase_fct(x, y, z=0): +# ~ return x**2 + y**2 + z**2 < 1 +# ~ def phase_fct(x, y, z=0): +# ~ if x < 1 / np.pi and y < 1 / np.pi: +# ~ return 0 +# ~ elif x < 1 / np.pi: +# ~ return 1 +# ~ return 2 + +# ~ def phase(val): +# ~ return [phase_fct(v) for v in val] + +# ~ def phase(val): +# ~ x, y = val +# ~ if 0.2 < y < 0.3 and 0.1 < x < 0.6: +# ~ return 1 +# ~ if y < 0.25 and x < 0.15: +# ~ return 1 +# ~ return 0 +# ~ def phase(val): +# ~ x, y = val +# ~ return 1 if x**2 + y**2 < 1 else 0 +# ~ print(val) +# ~ if val in [[0., 0.], [0.25, 0.25], [0.5, 0.125]]: +# ~ return 1 +# ~ elif val in [[0.375, 0.125], [0.5, 0.125]]: +# ~ return 2 +# ~ return 0 + +if __name__ == "__main__": NUM_STEPS = 10 res = pm.get_phase_map( @@ -127,11 +127,11 @@ def phase_fct(pos): mesh=2, ) - BORDEAUX = '#770044' - GREY = '#AAAAAA' - BLUE = '#003399' - GREEN = '#008833' - ORANGE = '#EE6600' + BORDEAUX = "#770044" + GREY = "#AAAAAA" + BLUE = "#003399" + GREEN = "#008833" + ORANGE = "#EE6600" cmap = ListedColormap([GREY, BORDEAUX, BLUE, ORANGE]) pm.plot.boxes(res, cmap=cmap) - plt.savefig('foo.pdf', bbox_inches='tight') + plt.savefig("foo.pdf", bbox_inches="tight") diff --git a/playground/test2.py b/playground/test2.py index 7646ce2..020fd84 100755 --- a/playground/test2.py +++ b/playground/test2.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1f85871 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,53 @@ +[build-system] +requires = ["setuptools >= 46.4.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.pylint.basic] +good-names = [ + "i", + "j", + "k", + "ex", + "Run", + "_", + " _INPUT_FILE_NAME", + " _OUTPUT_FILE_NAME", + "t", + "x", + "y", + "z", + "f", + "kx", + "ky", + "kz", + "k1", + "k2", + "s", + "c", + "n", + "p", + "ax" +] + +[tool.pylint.messages_control] +disable = [ + "too-few-public-methods", + "too-many-public-methods", + "bad-continuation", + "wrong-import-position", + "line-too-long", + "locally-disabled", + "wildcard-import", + "locally-enabled", + "too-many-instance-attributes", + "fixme", + "missing-docstring", + "no-else-return", + "len-as-condition", + "logging-format-interpolation", + "logging-fstring-interpolation", + "duplicate-code" +] + +[tool.pylint.design] +max-locals = 20 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..39762ae --- /dev/null +++ b/setup.cfg @@ -0,0 +1,54 @@ +[metadata] +name = phasemap +author = Dominik Gresch +author_email = greschd@gmx.ch +version = attr: phasemap.__version__ +url = https://phasemap.greschd.ch +description = An algorithm for calculating phase diagrams. +long_description = file: README.md +long_description_content_type = text/markdown +keywords = + phase + map + diagram + scaling +license = Apache 2.0 +classifiers = + License :: OSI Approved :: Apache Software License + Natural Language :: English + Operating System :: Unix + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Intended Audience :: Science/Research + Topic :: Scientific/Engineering :: Physics + Development Status :: 5 - Production/Stable + +[options] +python_requires = >=3.6 +install_requires = + numpy + matplotlib + decorator + fsc.export + fsc.iohelper>=1.0.3 + fsc.async-tools +packages = find: + +[options.extras_require] +dev = + black==20.8b1 + pre-commit==2.7.1 + pylint==2.6.0 + isort==5.5.1 + mypy==0.782 + pytest>=4.6 + pytest-cov + msgpack + sphinx + sphinx-rtd-theme + ipython>=7.10 + +[options.package_data] +phasemap = py.typed diff --git a/setup.py b/setup.py index fa58c95..bac24a4 100644 --- a/setup.py +++ b/setup.py @@ -1,57 +1,6 @@ -# -*- coding: utf-8 -*- +#!/usr/bin/env python -# © 2015-2018, ETH Zurich, Institut für Theoretische Physik -# Author: Dominik Gresch +import setuptools -import re -import sys -from setuptools import setup - -if sys.version_info < (3, 5): - raise 'Must use Python version 3.5 or higher.' - -README = r"""The PhaseMap algorithm maps a phase diagram, given a function to evaluate the phase at a given point. The number of phase evaluations needed scales with the dimension of the phase boundary, instead of the dimenstion of the phase space. Thus, this algorithm is efficient when evaluating the phase is relatively expensive. -""" - -with open('./phasemap/__init__.py', 'r') as f: - MATCH_EXPR = "__version__[^'\"]+(['\"])([^'\"]+)" - VERSION = re.search(MATCH_EXPR, f.read()).group(2).strip() - -EXTRAS_REQUIRE = dict( - dev=[ - 'yapf==0.29', 'pre-commit==2.0.0', 'pylint==2.4.4', 'prospector==1.2.0' - ], - test=['msgpack', 'pytest', 'pytest-cov'], - doc=['sphinx', 'sphinx-rtd-theme', 'ipython'] -) -EXTRAS_REQUIRE['dev'] += EXTRAS_REQUIRE['test'] + EXTRAS_REQUIRE['doc'] - -setup( - name='phasemap', - version=VERSION, - url='http://phasemap.greschd.ch', - author='Dominik Gresch', - author_email='greschd@gmx.ch', - description='Algorithm for calculating phase diagrams', - install_requires=[ - 'numpy', 'matplotlib', 'decorator', 'fsc.export', - 'fsc.iohelper>=1.0.2', 'fsc.async-tools' - ], - python_requires='>=3.6', - extras_require=EXTRAS_REQUIRE, - long_description=README, - classifiers=[ - 'License :: OSI Approved :: Apache Software License', - 'Natural Language :: English', 'Operating System :: Unix', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Intended Audience :: Science/Research', - 'Topic :: Scientific/Engineering :: Physics', - 'Development Status :: 5 - Production/Stable' - ], - license='Apache 2.0', - keywords=['phase', 'map', 'diagram', 'scaling'], - packages=['phasemap', 'phasemap.io'] -) +if __name__ == "__main__": + setuptools.setup() diff --git a/tests/conftest.py b/tests/conftest.py index 10a83e9..f3054c1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -16,7 +14,7 @@ def pytest_addoption(parser): parser.addoption( - '--no-plot-tests', action='store_true', help='disable the plot tests' + "--no-plot-tests", action="store_true", help="disable the plot tests" ) @@ -38,33 +36,34 @@ def pytest_runtest_setup(item): @pytest.fixture def test_name(request): """Returns module_name.function_name for a given test""" - return request.module.__name__ + '/' + request._parent_request._pyfuncitem.name # pylint: disable=protected-access + return ( + request.module.__name__ + "/" + request._parent_request._pyfuncitem.name + ) # pylint: disable=protected-access @pytest.fixture def compare_data(request, test_name, scope="session"): """Returns a function which either saves some data to a file or (if that file exists already) compares it to pre-existing data using a given comparison function.""" + def inner(compare_fct, data, tag=None): - full_name = test_name + (tag or '') + full_name = test_name + (tag or "") val = request.config.cache.get(full_name, None) if val is None: request.config.cache.set( full_name, - json.loads( - json.dumps(data, default=phasemap.io._encoding.encode) - ) + json.loads(json.dumps(data, default=phasemap.io._encoding.encode)), ) - raise ValueError('Reference data does not exist.') + raise ValueError("Reference data does not exist.") val = json.loads( json.dumps(val, default=phasemap.io._encoding.encode), - object_hook=phasemap.io._encoding.decode + object_hook=phasemap.io._encoding.decode, ) assert compare_fct( val, json.loads( json.dumps(data, default=phasemap.io._encoding.encode), - object_hook=phasemap.io._encoding.decode - ) + object_hook=phasemap.io._encoding.decode, + ), ) # get rid of json-specific quirks return inner @@ -107,9 +106,7 @@ def inner(boxes1, boxes2): def sample(): def inner(name): return os.path.join( - os.path.join( - os.path.dirname(os.path.abspath(__file__)), 'samples' - ), name + os.path.join(os.path.dirname(os.path.abspath(__file__)), "samples"), name ) return inner diff --git a/tests/phases.py b/tests/phases.py index 104b37e..4b799cc 100644 --- a/tests/phases.py +++ b/tests/phases.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch def circle(x, y): - return 2 if x**2 + y**2 < 1 else 0 + return 2 if x ** 2 + y ** 2 < 1 else 0 def line(x, y): @@ -34,7 +32,7 @@ def phase2(coord): if 0 <= y < 0.1: return 1 - if (x - 0.5)**2 + (y - 0.5)**2 < 0.1: + if (x - 0.5) ** 2 + (y - 0.5) ** 2 < 0.1: return 3 return 0 @@ -57,7 +55,7 @@ def phase3(coord): if 0 <= y < 0.1: return 1 - if (x - 0.5)**2 + (y - 0.5)**2 < 0.1: + if (x - 0.5) ** 2 + (y - 0.5) ** 2 < 0.1: return 3 return 0 diff --git a/tests/plottest_helpers.py b/tests/plottest_helpers.py index 480fd87..a6640fc 100644 --- a/tests/plottest_helpers.py +++ b/tests/plottest_helpers.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch """ @@ -11,7 +9,8 @@ import os import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.testing.compare import compare_images import pytest @@ -22,12 +21,11 @@ def disable_diff_save(monkeypatch): """ Do not save the diff of images if the test fails. """ + def do_nothing(*args, **kwargs): pass - monkeypatch.setattr( - matplotlib.testing.compare, 'save_diff_image', do_nothing - ) + monkeypatch.setattr(matplotlib.testing.compare, "save_diff_image", do_nothing) @pytest.fixture @@ -35,16 +33,17 @@ def assert_image_equal(disable_diff_save, pytestconfig, test_name): """ Save the current figure to a temporary file and check that it's the same as the reference image of the given name. """ + def inner(tol=1e-6): - path = './reference_plots/' + test_name + '.png' + path = "./reference_plots/" + test_name + ".png" if not os.path.exists(path): os.makedirs(os.path.dirname(path), exist_ok=True) plt.savefig(path) - raise ValueError('Reference plot did not exist.') - with tempfile.NamedTemporaryFile(suffix='.png') as temp_file: + raise ValueError("Reference plot did not exist.") + with tempfile.NamedTemporaryFile(suffix=".png") as temp_file: plt.savefig(temp_file.name) - assert compare_images( - path, temp_file.name, tol=tol, in_decorator=True - ) is None + assert ( + compare_images(path, temp_file.name, tol=tol, in_decorator=True) is None + ) return inner diff --git a/tests/test_doc.py b/tests/test_doc.py index 496a3d3..98661bc 100644 --- a/tests/test_doc.py +++ b/tests/test_doc.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -11,8 +9,8 @@ # This should never appear in any serious code ;) # To out-manoeuver pickle's caching, and force re-loading phasemap def test_all_doc(): - old_name = 'phasemap' - new_name = 'hoopy_phasemap' + old_name = "phasemap" + new_name = "hoopy_phasemap" for key in list(sys.modules.keys()): # move previous phasemap to hoopy_phasemap if key.startswith(old_name): diff --git a/tests/test_func_cache.py b/tests/test_func_cache.py index 207a488..74b73ea 100644 --- a/tests/test_func_cache.py +++ b/tests/test_func_cache.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -22,7 +20,7 @@ def error(x): raise ValueError(x) -@pytest.mark.parametrize('func', [echo, echo_async]) +@pytest.mark.parametrize("func", [echo, echo_async]) def test_func_cache(func): async def run(): func_cache = FuncCache(func) diff --git a/tests/test_plot.py b/tests/test_plot.py index 0557052..de20750 100644 --- a/tests/test_plot.py +++ b/tests/test_plot.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch """Tests for the plot functions.""" @@ -7,17 +5,18 @@ import pytest import matplotlib -matplotlib.use('Agg') -import phasemap as pm +matplotlib.use("Agg") from phases import phase3 from plottest_helpers import * +import phasemap as pm + @pytest.mark.plot -@pytest.mark.parametrize('scale_val', [None, (-3, 3)]) -@pytest.mark.parametrize('plot_fct', [pm.plot.boxes, pm.plot.points]) +@pytest.mark.parametrize("scale_val", [None, (-3, 3)]) +@pytest.mark.parametrize("plot_fct", [pm.plot.boxes, pm.plot.points]) def test_plots(assert_image_equal, plot_fct, scale_val): res = pm.run( phase3, diff --git a/tests/test_run.py b/tests/test_run.py index b17b894..fd58053 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -9,14 +7,14 @@ from collections import Counter import pytest -import phasemap as pm - from phases import phase1, phase2, phase3 +import phasemap as pm + -@pytest.mark.parametrize('num_steps', [0, 1, 3]) +@pytest.mark.parametrize("num_steps", [0, 1, 3]) @pytest.mark.parametrize( - 'phase, limits', [(phase1, [(-1, 1), (-1, 1)]), (phase2, [(0, 1), (0, 1)])] + "phase, limits", [(phase1, [(-1, 1), (-1, 1)]), (phase2, [(0, 1), (0, 1)])] ) def test_phase(compare_result_equal, num_steps, phase, limits): res = pm.run( @@ -31,9 +29,7 @@ def test_phase(compare_result_equal, num_steps, phase, limits): def test_save_file(results_equal): with tempfile.NamedTemporaryFile() as tmpf: - res = pm.run( - phase1, limits=[(-1, 1)] * 2, num_steps=2, save_file=tmpf.name - ) + res = pm.run(phase1, limits=[(-1, 1)] * 2, num_steps=2, save_file=tmpf.name) assert results_equal(res, pm.io.load(tmpf.name, serializer=json)) @@ -51,16 +47,14 @@ def error(x): raise ValueError with tempfile.NamedTemporaryFile() as tmpf: - res1 = pm.run( - phase1, limits=[(-1, 1)] * 2, num_steps=2, save_file=tmpf.name - ) + res1 = pm.run(phase1, limits=[(-1, 1)] * 2, num_steps=2, save_file=tmpf.name) res2 = pm.run( error, limits=[(-1, 1)] * 2, num_steps=2, save_file=tmpf.name, load=True, - serializer=json + serializer=json, ) results_equal(res1, res2) @@ -71,10 +65,10 @@ def test_load_invalid(): phase1, limits=[(-1, 1)] * 2, num_steps=2, - save_file='inexistent_file', + save_file="inexistent_file", load=True, load_quiet=False, - serializer=json + serializer=json, ) @@ -88,7 +82,7 @@ def test_load_init_result_conflict(): num_steps=2, save_file=tmpf.name, load=True, - init_result=res1 + init_result=res1, ) @@ -103,9 +97,7 @@ def test_complex_phase(compare_result_equal): compare_result_equal(res) -@pytest.mark.parametrize( - 'phase, limits', [(phase1, [(-1, 1), (-1, 1), (-1, 1)])] -) +@pytest.mark.parametrize("phase, limits", [(phase1, [(-1, 1), (-1, 1), (-1, 1)])]) def test_3d(compare_result_equal, phase, limits): res = pm.run( phase, @@ -116,10 +108,10 @@ def test_3d(compare_result_equal, phase, limits): compare_result_equal(res) -@pytest.mark.parametrize('mesh', [2, 4]) -@pytest.mark.parametrize('num_steps_1', [0, 2]) -@pytest.mark.parametrize('num_steps_2', [0, 1]) -@pytest.mark.parametrize('save', [True, False]) +@pytest.mark.parametrize("mesh", [2, 4]) +@pytest.mark.parametrize("num_steps_1", [0, 2]) +@pytest.mark.parametrize("num_steps_2", [0, 1]) +@pytest.mark.parametrize("save", [True, False]) def test_restart(results_equal, mesh, num_steps_1, num_steps_2, save): num_steps_total = num_steps_1 + num_steps_2 res = pm.run( @@ -149,7 +141,7 @@ def test_restart(results_equal, mesh, num_steps_1, num_steps_2, save): results_equal(res, res3) -@pytest.mark.parametrize('num_steps', range(3)) +@pytest.mark.parametrize("num_steps", range(3)) def test_restart_nocalc(results_equal, num_steps): def error(x): raise ValueError(x) @@ -171,7 +163,7 @@ def error(x): results_equal(res, res_restart) -@pytest.mark.parametrize('mesh', [1, (2, 2), (3, 2, 1)]) +@pytest.mark.parametrize("mesh", [1, (2, 2), (3, 2, 1)]) def test_invalid_mesh(mesh): with pytest.raises(ValueError): pm.run(phase1, limits=[(0, 1), (0, 1), (0, 1)], mesh=mesh) @@ -183,7 +175,7 @@ def _call_count(func): async def inner(inp): count.update([inp]) - await asyncio.sleep(0.) + await asyncio.sleep(0.0) return func(inp) return inner, count @@ -200,7 +192,7 @@ async def inner(inp): def test_raises(): def func(val): - raise ValueError('test succeeded.') + raise ValueError("test succeeded.") with pytest.raises(ValueError): pm.run(func, limits=[(0, 1)]) diff --git a/tests/test_save_load.py b/tests/test_save_load.py index 6d2222a..85bad5b 100644 --- a/tests/test_save_load.py +++ b/tests/test_save_load.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # © 2015-2018, ETH Zurich, Institut für Theoretische Physik # Author: Dominik Gresch @@ -10,13 +9,13 @@ import pytest import msgpack -import phasemap as pm - from phases import phase1, phase3 +import phasemap as pm + -@pytest.mark.parametrize('num_steps', range(2, 5)) -@pytest.mark.parametrize('serializer', [json, msgpack]) +@pytest.mark.parametrize("num_steps", range(2, 5)) +@pytest.mark.parametrize("serializer", [json, msgpack]) def test_consistency(results_equal, num_steps, serializer): res = pm.run( phase1, @@ -24,13 +23,13 @@ def test_consistency(results_equal, num_steps, serializer): num_steps=num_steps, mesh=3, ) - with tempfile.NamedTemporaryFile('w+') as f: + with tempfile.NamedTemporaryFile("w+") as f: pm.io.save(res, f.name, serializer=serializer) res2 = pm.io.load(f.name, serializer=serializer) results_equal(res, res2) def test_load(results_equal, sample): - res_loaded = pm.io.load(sample('res.json')) + res_loaded = pm.io.load(sample("res.json")) res_new = pm.run(phase3, [(0, 1), (0, 1)], num_steps=5, mesh=2) results_equal(res_loaded, res_new) From 02d031a4f6c4c1fa9b0c6521311efc2a4c3f80e0 Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Tue, 6 Oct 2020 09:47:03 +0200 Subject: [PATCH 09/11] Change extra requirement on RTD to 'dev'. (#6) --- .readthedocs.yml | 2 +- pyproject.toml | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index d2f8caa..0c20293 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -19,4 +19,4 @@ python: - method: pip path: . extra_requirements: - - doc + - dev diff --git a/pyproject.toml b/pyproject.toml index 1f85871..6d2447a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,21 +7,12 @@ good-names = [ "i", "j", "k", - "ex", - "Run", "_", - " _INPUT_FILE_NAME", - " _OUTPUT_FILE_NAME", "t", "x", "y", "z", "f", - "kx", - "ky", - "kz", - "k1", - "k2", "s", "c", "n", From d934a8c735c7b1f1a27f72bcc276f7663d27242c Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Tue, 6 Oct 2020 10:30:11 +0200 Subject: [PATCH 10/11] Suppress output in tutorial. --- doc/source/tutorial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst index 58031b3..15f6cff 100644 --- a/doc/source/tutorial.rst +++ b/doc/source/tutorial.rst @@ -108,7 +108,7 @@ For long-running calculations, we would like to store intermediate results durin ...: limits=[(-1, 1), (-1, 1)], ...: mesh=3, ...: save_file=FILE_PATH - ...: ) + ...: ); In [0]: res_loaded = pm.io.load(FILE_PATH) This is especially useful if the calculation might time out. The result can be used as input to a new calculation either by setting ``load=True`` to load the result from the ``save_file``, or by explicitly passing it as ``init_result``. Since all phase evaluations were done previously, the phase function is not actually called here. We show this by passing a broken phase function: From d70586cdfd13956ff4c0073a1c26b214295dc7fc Mon Sep 17 00:00:00 2001 From: Dominik Gresch Date: Tue, 6 Oct 2020 10:39:08 +0200 Subject: [PATCH 11/11] Add missing newline in tutorial. --- doc/source/tutorial.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst index 15f6cff..595f846 100644 --- a/doc/source/tutorial.rst +++ b/doc/source/tutorial.rst @@ -109,6 +109,7 @@ For long-running calculations, we would like to store intermediate results durin ...: mesh=3, ...: save_file=FILE_PATH ...: ); + In [0]: res_loaded = pm.io.load(FILE_PATH) This is especially useful if the calculation might time out. The result can be used as input to a new calculation either by setting ``load=True`` to load the result from the ``save_file``, or by explicitly passing it as ``init_result``. Since all phase evaluations were done previously, the phase function is not actually called here. We show this by passing a broken phase function: