Skip to content

Commit

Permalink
Bump versions (#38)
Browse files Browse the repository at this point in the history
* Bump versions

* Update run_tests.yml

* Update light_python_wrapper

- Fix DuplicateSuperClass error
- Fix helpwin.xsl path change
- Add check for empty module in install_python_mod to return early

* Fix euphonic doc test for R2022b and newer

* Pin Brille to 0.7.0 as wheels for 0.8.0 crash on Windows

* Update readthedocs configurations

* Remove 1.3.1 version pin, revert to just latest Matlab in CI

* Update light_python_wrapper to latest main sha

* Switch to conda on Windows. Remove brille-0.7.0 pin

* Revert brille-0.7.0 pin as still segfaults on CI

---------

Co-authored-by: Duc Le <[email protected]>
  • Loading branch information
oerc0122 and mducle authored Aug 29, 2024
1 parent 30bcce9 commit 79dcf97
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 87 deletions.
3 changes: 3 additions & 0 deletions +euphonic/install_python_modules.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ function install_python_modules()
% >> euphonic.install_python_modules

req_mods = required_modules;
if isempty(req_mods)
return
end

pipe = py.subprocess.PIPE;
kwargs = pyargs('stdout', pipe, 'stderr', pipe);
Expand Down
55 changes: 24 additions & 31 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,69 +14,62 @@ jobs:
matrix:
os: [windows-latest, ubuntu-latest]
matlab_version: [latest]
python_version: [3.9]
python_version: [3.11]
euphonic_version: ['']
# Test lowest supported Python/Euphonic versions, and lowest available Matlab
include:
- os: ubuntu-latest
matlab_version: R2020a
python_version: 3.7
euphonic_version: '--version 1.2.0'
matlab_version: R2021b
python_version: 3.9
fail-fast: false
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash -l {0} # Needed to use conda environments
steps:
- name: Check out Horace-Euphonic-Interface
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: true
- name: Set up MATLAB
uses: matlab-actions/setup-matlab@v1 # v1.1.0 required for Windows/MacOS support
uses: matlab-actions/setup-matlab@v2 # v1.1.0 required for Windows/MacOS support
with:
release: ${{ matrix.matlab_version }}
- name: Set up Python
uses: conda-incubator/setup-miniconda@v2
uses: conda-incubator/setup-miniconda@v3
with:
python-version: ${{ matrix.python_version }}
- name: Set Python environment variable for access by Matlab
if: ${{ matrix.os != 'windows-latest' }}
run: echo "PYTHON_EX_PATH=`which python`" >> $GITHUB_ENV
- name: Set Python environment variable for access by Matlab (Windows)
auto-update-conda: true
conda-solver: libmamba
channels: conda-forge
- name: Set up Python environment (Windows)
if: ${{ matrix.os == 'windows-latest' }}
shell: powershell
run: |
python -m pip install requests psutil numpy==1.26.4 brille==0.7.0 euphonic[phonopy_reader]
$pypath = (Get-Command python).Path
echo "PYTHON_EX_PATH=$pypath" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
- name: Update pip and create Matlab toolbox
- name: Set up Python environment (Linux)
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
python -m pip install --upgrade pip &&
python -m pip install requests &&
python create_mltbx.py
- name: Install base Euphonic
run: |
python -m pip install numpy &&
python euphonic_sqw_models/apply_requirements.py ${{ matrix.euphonic_version }}
python create_mltbx.py
python -m pip install requests psutil numpy==1.26.4 euphonic[phonopy_reader,brille]
echo "PYTHON_EX_PATH=`which python`" >> $GITHUB_ENV
- name: Create Matlab toolbox
run: python create_mltbx.py
- name: create_toolbox
uses: matlab-actions/run-command@v2
with:
command: cd('mltbx'); create_mltbx()
- name: Run tests with base Euphonic
uses: matlab-actions/run-command@v1
uses: matlab-actions/run-command@v2
with:
command: cd('test'); set_up_dependencies; run_tests('not', 'phonopy_reader', 'not', 'brille')
- name: Install Euphonic phonopy_reader
if: always()
run: python euphonic_sqw_models/apply_requirements.py ${{ matrix.euphonic_version}} --extras phonopy_reader
- name: Run tests with Euphonic and phonopy_reader
if: always()
uses: matlab-actions/run-command@v1
uses: matlab-actions/run-command@v2
with:
command: cd('test'); set_up_dependencies; run_tests('phonopy_reader')
- name: Install brille
if: always()
run: python euphonic_sqw_models/apply_requirements.py ${{ matrix.euphonic_version}} --extras brille
- name: Run tests with Euphonic and Brille
if: always()
uses: matlab-actions/run-command@v1
uses: matlab-actions/run-command@v2
with:
command: cd('test'); set_up_dependencies; run_tests('brille')
- uses: codecov/codecov-action@v3
Expand Down
35 changes: 35 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.12"
# You can also specify other tool versions:
# nodejs: "20"
# rust: "1.70"
# golang: "1.20"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: doc/source/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
# fail_on_warning: true

# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub

# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: doc/requirements.txt
109 changes: 65 additions & 44 deletions create_mltbx.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,79 @@
import os
import fileinput
import re
import subprocess
import shutil
import glob
import subprocess
from pathlib import Path

import versioneer
import update_module_versions
import versioneer

__version__ = versioneer.get_version()

HELPDOCSTR = '\n' \
' % Overloaded help command to display Python help in Matlab\n' \
' % To use it, please type\n' \
' %\n' \
' % >> import euphonic.help\n' \
' % >> help <topic>\n' \
' %\n' \
' % where <topic> is a Python class or method which has been wrapped for use in Matlab.\n' \
' % If the topic is not wrapped, the normal Matlab help is displayed.\n' \

def replace_matlab_docstring(filename, replacement_str):
with open(filename) as f:
txt = f.read()
cm = [m.start() for m in re.finditer(r'\n\s*%', txt)]
nl = [m.start() for m in re.finditer(r'\n', txt)]
idx = [cm[idx] for idx in range(len(cm)) if cm[idx] == nl[idx]]
HELPDOCSTR = """
% Overloaded help command to display Python help in Matlab
% To use it, please type
%
% >> import euphonic.help
% >> help <topic>
%
% where <topic> is a Python class or method which has been wrapped for use in Matlab.
% If the topic is not wrapped, the normal Matlab help is displayed.
"""


def replace_matlab_docstring(filename: Path, replacement_str: str):
txt = filename.read_text(encoding="utf-8")
comment = [m.start() for m in re.finditer(r'\n\s*%', txt)]
newline = [m.start() for m in re.finditer(r'\n', txt)]
idx = [cm for cm, nl in zip(comment, newline) if cm == nl]
newtxt = txt[:idx[0]] + replacement_str + txt[idx[-1]:]
with open(filename, 'w') as f:
f.write(newtxt)

def create_mltbx():
import fileinput
# replace version string
version = __version__.split('+')[0] if '+' in __version__ else __version__ # Matlab only accepts numbers
with fileinput.FileInput('mltbx/horace_euphonic_interface.prj', inplace=True) as prj:
filename.write_text(newtxt, encoding="utf-8")


def create_mltbx(base_path: Path):
"""
Create toolbox assuming files relative to `base_path`
"""

# replace version string as MATLAB only accepts numbers
version = __version__.split('+')[0] if '+' in __version__ else __version__
base_path = base_path.absolute()

lpw_src = base_path / "light_python_wrapper"
eup_src = base_path / "+euphonic"
mdl_src = base_path / "euphonic_sqw_models" / "euphonic_sqw_models"
mltbx_path = base_path / 'mltbx'
lpw_dest = mltbx_path / "+light_python_wrapper"
eup_dest = mltbx_path / "+euphonic"
mdl_dest = mltbx_path / "euphonic_sqw_models" / "euphonic_sqw_models"

with fileinput.FileInput(mltbx_path / 'horace_euphonic_interface.prj', inplace=True) as prj:
for line in prj:
# FileInput redirect stdout to the file, for inplace replacement; end='' means don't add extra newlines
print(line.replace('<param.version>1.0</param.version>', f'<param.version>{version}</param.version>'), end='')
# FileInput redirects stdout to the file, for inplace replacement
print(line.replace('<param.version>1.0</param.version>',
f'<param.version>{version}</param.version>'), end='')

update_module_versions.update_module_versions()
# shutil.copytree expects destination to not exist
for dest_folder in ['+light_python_wrapper', 'euphonic_sqw_models', '+euphonic']:
if os.path.isdir('mltbx/' + dest_folder): shutil.rmtree('mltbx/' + dest_folder)
shutil.copyfile('LICENSE', 'mltbx/LICENSE')
shutil.copyfile('CITATION.cff', 'mltbx/CITATION.cff')
shutil.copytree('light_python_wrapper/+light_python_wrapper', 'mltbx/+light_python_wrapper')
shutil.copytree('euphonic_sqw_models/euphonic_sqw_models', 'mltbx/euphonic_sqw_models/euphonic_sqw_models')
shutil.copytree('+euphonic', 'mltbx/+euphonic')
for fil in glob.glob('light_python_wrapper/helputils/*.m'): shutil.copy(fil, 'mltbx/+euphonic')
for fil in glob.glob('light_python_wrapper/helputils/private/*.m'): shutil.copy(fil, 'mltbx/+euphonic/private')
replace_matlab_docstring('mltbx/+euphonic/help.m', HELPDOCSTR)
replace_matlab_docstring('mltbx/+euphonic/doc.m', HELPDOCSTR.replace('help', 'doc'))
subprocess.run(['matlab', '-batch', 'create_mltbx'], cwd='mltbx')
print('.mltbx created')
if (dest := mltbx_path / dest_folder).is_dir():
shutil.rmtree(dest)

if __name__ == '__main__':
create_mltbx()
for file in ('LICENSE', 'CITATION.cff'):
shutil.copy(file, mltbx_path)

shutil.copytree(lpw_src / "+light_python_wrapper", lpw_dest)
shutil.copytree(mdl_src, mdl_dest)
shutil.copytree(eup_src, eup_dest)
for fil in (lpw_src / "helputils").glob("*.m"):
shutil.copy(fil, eup_dest)
for fil in (lpw_src / "helputils/private").glob("*.m"):
shutil.copy(fil, eup_dest / "private")

replace_matlab_docstring(eup_dest / "help.m", HELPDOCSTR)
replace_matlab_docstring(eup_dest / "doc.m", HELPDOCSTR.replace('help', 'doc'))


if __name__ == '__main__':
curr_path = Path(__file__).parent
create_mltbx(curr_path)
2 changes: 2 additions & 0 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sphinx==7.4.7
sphinx_rtd_theme==2.0.0
13 changes: 13 additions & 0 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@
# import sys
# sys.path.insert(0, os.path.abspath('.'))

# -- RTD setup ---------------------------------------------------------------
# See: https://about.readthedocs.com/blog/2024/07/addons-by-default/
import os

# Define the canonical URL if you are using a custom domain on Read the Docs
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")

# Tell Jinja2 templates the build is running on Read the Docs
if os.environ.get("READTHEDOCS", "") == "True":
if "html_context" not in globals():
html_context = {}
html_context["READTHEDOCS"] = True


# -- Project information -----------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion light_python_wrapper
16 changes: 11 additions & 5 deletions test/EuphonicHelpTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,17 @@ function run_euphonic_doc_tests(testCase)
import matlab.unittest.constraints.IsFalse
txt_fc_noimport = eval_doc('doc euphonic.ForceConstants');
txt_fc_import = eval_doc_import('doc euphonic.ForceConstants');
% Checks both cases called "web" with the "-helpbrowser" argument
testCase.verifySubstring(txt_fc_noimport{2}, 'helpbrowser');
testCase.verifySubstring(txt_fc_import{2}, 'helpbrowser');
% Checks the two text are different
testCase.verifyThat(strcmp(txt_fc_noimport{1}, txt_fc_import{1}), IsFalse);
if verLessThan('matlab', '9.13')
% Checks both cases called "web" with the "-helpbrowser" argument
testCase.verifySubstring(txt_fc_noimport{2}, 'helpbrowser');
testCase.verifySubstring(txt_fc_import{2}, 'helpbrowser');
% Checks the two text are different
testCase.verifyThat(strcmp(txt_fc_noimport{1}, txt_fc_import{1}), IsFalse);
else
% Doc system changed in R2020b does not use the "web" command any more.
testCase.verifySubstring(txt_fc_noimport{1}.Topic, 'ForceConstants');
testCase.verifySubstring(txt_fc_import{2}, 'helpbrowser');
end
% Checks we still have hyperlinks in the imported version
testCase.verifyThat(contains(txt_fc_import{1}, 'href'), IsTrue);
% Checks that __init__ method is included
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function [docPage, displayText, primitive] = getReferencePage(varargin)
% Function to overload built-in "getReferencePage" function
global web_called_with;
web_called_with = varargin;
displayText = string.empty;
primitive = true;
docPage = [];
end

2 changes: 1 addition & 1 deletion test/set_up_dependencies.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@
% Set flags on Linux to avoid segfault with libraries
if ~ispc
py.sys.setdlopenflags(int32(10))
end
end
11 changes: 6 additions & 5 deletions update_module_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
def get_module_versions():
# gets the required module versions from `min_requirements.txt` file
curdir = os.path.dirname(os.path.abspath(__file__))
req_file = os.path.join(
curdir, 'euphonic_sqw_models', 'min_requirements.txt')
if not os.path.isfile(req_file):
from update_dependencies import update_submodules
update_submodules('euphonic_sqw_models')
for submodule in [['light_python_wrapper', '+light_python_wrapper'],
['euphonic_sqw_models', 'min_requirements.txt']]:
if not os.path.isfile(os.path.join(curdir, *submodule)):
from update_dependencies import update_submodules
update_submodules(submodule[0])
req_file = os.path.join(curdir, 'euphonic_sqw_models', 'min_requirements.txt')
with open(req_file, 'r') as minreq:
reqstrs = minreq.read().splitlines()
reqmods = []
Expand Down

0 comments on commit 79dcf97

Please sign in to comment.