Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Bump versions #38

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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'],
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Urgh, os.path...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing wrong with that... I don't like to divide my paths...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>>> Path() / 0
ZeroDivisionError: division by zero

oh no!

['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
Loading