Commit 87e9e215 authored by Markus Scheidgen's avatar Markus Scheidgen

Merge branch 'v0.8.1' into 'master'

V0.8.1

See merge request !123
parents 6677d66e 759e1bdd
Pipeline #76964 passed with stages
in 18 minutes and 59 seconds
......@@ -5,6 +5,7 @@
**/*.pyc
**/NOMAD.egg-info
.*env/
.pyenv*/
.pytest_cache
.vscode/
.volumes/
......
.DS_Store
.*env/
.pyenv*/
.pytest/
.python-version
.ipynb_checkpoints/
.python-version
__pycache__
.mypy_cache
*.pyc
......
......@@ -96,7 +96,7 @@ tests:
install_tests:
stage: test
image: python:3.6
image: python:3.7
before_script:
- git submodule sync
- git submodule update --init --jobs=4
......@@ -107,9 +107,9 @@ install_tests:
- pip install numpy
- python setup.py compile
- python setup.py sdist
- pip install dist/nomad-0.8.0.tar.gz
- pip install dist/nomad-lab-*.tar.gz
- python -c "import nomad.datamodel, nomad.datamodel.metainfo, nomad.client"
- pip install dist/nomad-0.8.0.tar.gz[parsing]
- pip install `echo dist/nomad-lab-*.tar.gz`[parsing]
- python -m nomad.cli parse tests/data/parsers/vasp/vasp.xml
deploy:
......
......@@ -155,3 +155,42 @@
[submodule "dependencies/parsers/eels"]
path = dependencies/parsers/eels
url = https://github.com/markus1978/eels.git
[submodule "dependencies/parsers/namd"]
path = dependencies/parsers/namd
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-namd.git
[submodule "dependencies/parsers/charmm"]
path = dependencies/parsers/charmm
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-charmm.git
[submodule "dependencies/parsers/dftbplus"]
path = dependencies/parsers/dftbplus
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-dftb-plus.git
[submodule "dependencies/parsers/asap"]
path = dependencies/parsers/asap
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-asap.git
[submodule "dependencies/parsers/fplo"]
path = dependencies/parsers/fplo
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-fplo.git
[submodule "dependencies/parsers/mopac"]
path = dependencies/parsers/mopac
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-mopac.git
[submodule "dependencies/parsers/amber"]
path = dependencies/parsers/amber
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-amber.git
[submodule "dependencies/parsers/gromacs"]
path = dependencies/parsers/gromacs
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-gromacs.git
[submodule "dependencies/parsers/gromos"]
path = dependencies/parsers/gromos
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-gromos.git
[submodule "dependencies/parsers/lammps"]
path = dependencies/parsers/lammps
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-lammps.git
[submodule "dependencies/parsers/openkim"]
path = dependencies/parsers/openkim
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-openkim.git
[submodule "dependencies/parsers/tinker"]
path = dependencies/parsers/tinker
url = https://gitlab.mpcdf.mpg.de/nomad-lab/parser-tinker.git
[submodule "dependencies/nomad-dos-fingerprints"]
path = dependencies/nomad-dos-fingerprints
url = https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-dos-fingerprints.git
......@@ -20,7 +20,7 @@
# copy only necessities to a slim final image
# We use slim for the final image
FROM python:3.6-slim as final
FROM python:3.7-slim as final
# First built the GUI in a gui build image
FROM node:latest as gui_build
......@@ -35,9 +35,14 @@ RUN yarn run build
# RUN yarn run --silent react-docgen src/components --pretty > react-docgen.out
# Second, build all python stuff in a python build image
FROM python:3.6-stretch as build
FROM python:3.7-stretch as build
RUN mkdir /install
# Install linux package dependencies
RUN apt-get update
RUN apt-get install -y --no-install-recommends libgomp1
RUN apt-get install -y libmagic-dev curl vim make cmake swig libnetcdf-dev
# Install some specific dependencies necessary for the build process
RUN pip install --upgrade pip
RUN pip install fastentrypoints
......@@ -54,26 +59,33 @@ RUN pip install scikit-learn==0.20.2
RUN pip install ase==3.19.0
RUN pip install Pint
RUN pip install matid
RUN pip install mdtraj==1.9.1
RUN pip install mdanalysis==0.16.2
RUN pip install mdtraj
RUN pip install mdanalysis
# Make will be necessary to build the docs with sphynx
RUN apt-get update && apt-get install -y make
RUN apt-get update && apt-get install -y vim
# Install pymolfile (required by some parsers)
RUN git clone -b nomad-fair https://gitlab.mpcdf.mpg.de/nomad-lab/pymolfile.git
WORKDIR /pymolfile/
RUN python3 setup.py install
RUN rm -rf /pymolfile
# Copy files and install nomad@FAIRDI
WORKDIR /install
COPY . /install
RUN python setup.py compile
RUN pip install .[all]
RUN python setup.py sdist
RUN cp dist/nomad-lab-*.tar.gz dist/nomad-lab.tar.gz
WORKDIR /install/docs
# COPY --from=gui_build /app/react-docgen.out /install/docs
RUN make html
RUN \
find /usr/local/lib/python3.6/ -name 'tests' ! -path '*/networkx/*' -exec rm -r '{}' + && \
find /usr/local/lib/python3.6/ -name 'test' -exec rm -r '{}' + && \
find /usr/local/lib/python3.6/site-packages/ -name '*.so' -print -exec sh -c 'file "{}" | grep -q "not stripped" && strip -s "{}"' \;
find /usr/local/lib/python3.7/ -name 'tests' ! -path '*/networkx/*' -exec rm -r '{}' + && \
find /usr/local/lib/python3.7/ -name 'test' -exec rm -r '{}' + && \
find /usr/local/lib/python3.7/site-packages/ -name '*.so' -print -exec sh -c 'file "{}" | grep -q "not stripped" && strip -s "{}"' \;
# Third, create a slim final image
FROM final
......@@ -84,7 +96,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 && apt
COPY . /app
WORKDIR /app
# transfer installed packages from dependency stage
COPY --from=build /usr/local/lib/python3.6/site-packages /usr/local/lib/python3.6/site-packages
COPY --from=build /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages
RUN echo "copy 1"
# copy the meta-info, since it files are loaded via relative paths. TODO that should change.
COPY --from=build /install/dependencies/nomad-meta-info /app/dependencies/nomad-meta-info
......
......@@ -46,9 +46,12 @@ contributing, and API reference.
Omitted versions are plain bugfix releases with only minor changes and fixes.
### v0.8.1
- switched to support Python 3.7
### v0.8.0
- new underlying datamodel that allows to maintain multiple domains
- mulitple domains supported the GUI
- multiple domains supported the GUI
- new metainfo implementation
- API endpoint to access the metainfo
- new archive based on new metainfo
......@@ -175,4 +178,4 @@ The first production version of nomad@fairdi as the upload API and gui for NOMAD
### v0.4.2
- bugfixes regarding the migration
- better migration configurability and reproducibility
- scales to multi node kubernetes deployment
- scales to multi node kubernetes deployment
\ No newline at end of file
Subproject commit bb633623789ee9850873ba0b16a32c66c8265558
Subproject commit c424e75671e8c09c2f29c90ec63feafd0a2a706e
Subproject commit a2df84b2dfc2c96344e7261580a40d655c904047
Subproject commit b9619d6b34a8f8e66120fb02f5fd3dbc16d26517
Subproject commit 11af5d0b67b53abf2d6593b40aa9b4a4735012e2
Subproject commit 09b52a7494b9655c53bbe3dcab2719823e5f2e27
Subproject commit dd555aad1ce925b5b56be7e55b6650f959ea5261
Subproject commit dc2b8d5a08fb27e53057f27d9854b22ffee28f06
Subproject commit c447c6b07d8528210975337571c98096caf26770
Subproject commit e4bd0a1bd72092de4f41c88ebf843265c162a84c
Subproject commit 2b49f652182adb2139f9bc7503c25212c5ad35a7
Subproject commit b830cf96f325c521c232ce8ccba83073eb5f3bab
Subproject commit ae0068cd75c1b0f6bb818e8cbd5a6a72fe7722f4
Subproject commit 4a74602f7dd287da835cf6a64228b5ad53fd09be
Subproject commit 433f848030759d28bacb780d800877445490da70
Subproject commit aac03d990b7823776c51a1976b2d5a304e4a1cce
Subproject commit 3d225e6858fc449e12c5ca45d9597562011f6589
Subproject commit e38d2615a243c775a378e47a461c731babebf3e6
Subproject commit af2bcff3956b83698e3c3fa733df7b5a54264ee1
Subproject commit 5023497ce1651f41de44cb35e953432d450b29f5
Subproject commit 2e385c1dbf934157d0e533ee709595fd0ccfb742
......@@ -7,4 +7,4 @@ Of course, you can access the NOMAD Archive directly via the NOMAD API (see the
and `API reference <api.html>`_). But, it is more effective and convenient to use NOMAD's Python client
library.
.. automodule:: nomad.client
\ No newline at end of file
.. automodule:: nomad.client
......@@ -2,11 +2,18 @@ Install the NOMAD client library
================================
We release the NOMAD client library as a Python `distutils <https://docs.python.org/3/library/distutils.html>`_ source distribution.
You can install it the usual way using *pip* (or *conda*).
You can download and install it the usual way using *pip* (or *conda*).
Install from pypi
.. parsed-literal::
pip install nomad --extra-index-url |pypi_url|
pip install nomad-lab
Download and install latest release from nomad
.. parsed-literal::
curl https://repository.nomad-coe.eu/v0.8/dist/nomad-lab.tar.gz -o nomad-lab.tar.gz
pip install ./nomad-lab.tar.gz
There are different layers of dependencies that you have to install, in order to use
certain functions of NOMAD. The base install above, will only install the
......@@ -19,9 +26,9 @@ requirements:
.. parsed-literal::
pip install nomad[parsing] --extra-index-url |pypi_url|
pip install nomad[infrastructure] --extra-index-url |pypi_url|
pip install nomad[dev] --extra-index-url |pypi_url|
pip install nomad-lab[parsing]
pip install nomad-lab[infrastructure]
pip install nomad-lab[dev]
The various *extras* have the following meaning:
......
......@@ -29,10 +29,6 @@ project = 'nomad-FAIRDI'
copyright = '2018, FAIRDI e.V.'
author = 'FAIRDI e.V.'
rst_epilog = '''
.. |pypi_url| replace:: https://repository.nomad-coe.eu/v0.8/dist/
'''
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
......
......@@ -38,7 +38,7 @@ cd nomad-FAIR
### C libs
Even though the NOMAD infrastructure is written in python, there is a C library
required by one of our pyhton dependencies.
required by one of our python dependencies.
#### libmagic
......@@ -52,11 +52,9 @@ brew install libmagic
### Virtual environment
#### pyenv
The nomad code currently targets python 3.6. If you host machine has 3.7 or later installed,
you can use [pyenv](https://github.com/pyenv/pyenv) to use python 3.6 in parallel.
To use 3.7 there is a slight issue about the `enum34` which fails the compilation of the
`mdtraj` and `mdanalysis` packages. A possible work arround is to uninstall and tham re-install
`enum34` once the other packages are installed.
The nomad code currently targets python 3.7. If you host machine has an older version installed,
you can use [pyenv](https://github.com/pyenv/pyenv) to use python 3.7 in parallel to your
system's python.
#### virtualenv
We strongly recommend to use *virtualenv* to create a virtual environment. It will allow you
......@@ -73,7 +71,7 @@ source .pyenv/bin/activate
If you are a conda user, there is an equivalent, but you have to install pip and the
right python version while creating the environment.
```
conda create --name nomad_env pip python=3.6
conda create --name nomad_env pip python=3.7
conda activate nomad_env
```
......
module.exports = {
"extends": ["standard", "plugin:react/recommended"],
"extends": [
"standard",
"plugin:react/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
......
{
"name": "nomad-fair-gui",
"version": "0.8.0",
"version": "0.8.1",
"commit": "e98694e",
"private": true,
"dependencies": {
......
......@@ -3,5 +3,8 @@ window.nomadEnv = {
'keycloakRealm': 'fairdi_nomad_test',
'keycloakClientId': 'nomad_gui_dev',
'appBase': 'http://localhost:8000/fairdi/nomad/latest',
'debug': false
'debug': false,
'matomoEnabled': true,
'matomoUrl': 'https://repository.nomad-coe.eu/fairdi/stat',
'matomoSiteId': '2'
}
......@@ -102,7 +102,7 @@ export default function About() {
makeClickable('search', () => {
history.push('/search')
})
}, [svg])
}, [svg, makeClickable, setText, history])
useEffect(() => {
const statistics = (info && info.statistics) || {}
......@@ -130,7 +130,7 @@ export default function About() {
value('n_calculations', 'results'),
value('n_quantities', 'quantities')
])
}, [svg, info])
}, [svg, info, setText])
return <div className={classes.root}>
<Grid className={classes.container} container spacing={2}>
......@@ -214,7 +214,7 @@ export default function About() {
There is a [tutorial on how to use the API with plain Python](${appBase}/docs/api_tutorial.html).
Another [tutorial covers how to install and use NOMAD's Python client library](${appBase}/docs/archive_tutorial.html).
The [NOMAD Analytics Toolkit](https://analytic-toolkit.nomad-coe.eu) allows to use
The [NOMAD Analytics Toolkit](https://analytics-toolkit.nomad-coe.eu) allows to use
this without installation and directly on NOMAD servers.
`}</Markdown></InfoCard>
<Grid item xs={12}>
......@@ -272,7 +272,7 @@ export default function About() {
- domains: ${info ? Object.keys(info.domains).map(domain => info.domains[domain].name).join(', ') : 'loading'}
- git: \`${info ? info.git.ref : 'loading'}; ${info ? info.git.version : 'loading'}\`
- last commit message: *${info ? info.git.log : 'loading'}*
- supported codes: ${info ? info.codes.join(', ') : 'loading'}
- supported codes: ${info ? info.codes.map(code => code.code_name).join(', ') : 'loading'}
- parsers: ${info ? info.parsers.join(', ') : 'loading'}
- normalizers: ${info ? info.normalizers.join(', ') : 'loading'}
`}</Markdown>
......
// trigger rebuild
import React, { useEffect, useState, useContext, useCallback, useRef } from 'react'
import PropTypes, { instanceOf } from 'prop-types'
import PropTypes from 'prop-types'
import { compose } from 'recompose'
import classNames from 'classnames'
import { MuiThemeProvider, withStyles, makeStyles } from '@material-ui/core/styles'
import { LinearProgress, MenuList, Typography,
AppBar, Toolbar, Button, DialogContent, DialogTitle, DialogActions, Dialog, Tooltip,
Snackbar, SnackbarContent } from '@material-ui/core'
Snackbar, SnackbarContent, FormGroup, FormControlLabel, Switch } from '@material-ui/core'
import { Route, Link, withRouter, useLocation } from 'react-router-dom'
import BackupIcon from '@material-ui/icons/Backup'
import SearchIcon from '@material-ui/icons/Search'
......@@ -17,6 +17,7 @@ import FAQIcon from '@material-ui/icons/QuestionAnswer'
import MetainfoIcon from '@material-ui/icons/Info'
import DocIcon from '@material-ui/icons/Help'
import CodeIcon from '@material-ui/icons/Code'
import TermsIcon from '@material-ui/icons/Assignment'
import {help as searchHelp, default as SearchPage} from './search/SearchPage'
import HelpDialog from './Help'
import { ApiProvider, withApi, apiContext } from './api'
......@@ -27,8 +28,6 @@ import LoginLogout from './LoginLogout'
import { guiBase, consent, nomadTheme, appBase } from '../config'
import {help as metainfoHelp, default as MetaInfoBrowser} from './metaInfoBrowser/MetaInfoBrowser'
import packageJson from '../../package.json'
import { Cookies, withCookies } from 'react-cookie'
import Markdown from './Markdown'
import {help as uploadHelp, default as UploadPage} from './uploads/UploadPage'
import ResolvePID from './entry/ResolvePID'
import DatasetPage from './DatasetPage'
......@@ -37,6 +36,9 @@ import {help as userdataHelp, default as UserdataPage} from './UserdataPage'
import ResolveDOI from './dataset/ResolveDOI'
import FAQ from './FAQ'
import EntryQuery from './entry/EntryQuery'
import {matomo} from '../index'
import { useCookies } from 'react-cookie'
import Markdown from './Markdown'
export const ScrollContext = React.createContext({scrollParentRef: null})
......@@ -80,7 +82,7 @@ const useMainMenuItemStyles = makeStyles(theme => ({
}
}))
function MainMenuItem({tooltip, title, path, href, icon}) {
function MainMenuItem({tooltip, title, path, href, onClick, icon}) {
const {pathname} = useLocation()
const classes = useMainMenuItemStyles()
const selected = path === pathname || (path !== '/' && pathname.startsWith(path))
......@@ -91,6 +93,7 @@ function MainMenuItem({tooltip, title, path, href, icon}) {
color={selected ? 'primary' : 'default'}
size="small"
startIcon={icon}
onClick={onClick}
{...rest}
>
{title}
......@@ -102,9 +105,73 @@ MainMenuItem.propTypes = {
'title': PropTypes.string.isRequired,
'path': PropTypes.string,
'href': PropTypes.string,
'onClick': PropTypes.func,
'icon': PropTypes.element.isRequired
}
function Consent() {
const [cookies, setCookie] = useCookies()
const [accepted, setAccepted] = useState(cookies['terms-accepted'])
const [optOut, setOptOut] = useState(cookies['tracking-enabled'] === 'false')
useEffect(() => {
if (!optOut) {
matomo.push(['setConsentGiven'])
} else {
matomo.push(['requireConsent'])
}
})
const handleClosed = accepted => {
if (accepted) {
setCookie('terms-accepted', true)
setCookie('tracking-enabled', !optOut)
setAccepted(true)
}
}
const handleOpen = () => {
setCookie('terms-accepted', false)
setAccepted(false)
}
return (
<React.Fragment>
<MainMenuItem
title="Terms"
onClick={handleOpen}
tooltip="NOMAD's terms"
icon={<TermsIcon/>}
/>
<Dialog
disableBackdropClick disableEscapeKeyDown
open={!accepted}
>
<DialogTitle>Terms of Use</DialogTitle>
<DialogContent>
<Markdown>{consent}</Markdown>
<FormGroup>
<FormControlLabel
control={<Switch
checked={optOut}
onChange={(e) => {
setOptOut(!optOut)
}}
color="primary"
/>}
label="Do not provide information about your use of NOMAD (opt-out)."
/>
</FormGroup>
</DialogContent>
<DialogActions>
<Button onClick={() => handleClosed(true)} color="primary">
Accept
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
)
}
const useMainMenuStyles = makeStyles(theme => ({
root: {
display: 'inline-flex',
......@@ -186,6 +253,7 @@ function MainMenu() {
tooltip="NOMAD's Gitlab project"
icon={<CodeIcon/>}
/>
<Consent />
</MenuList>
}
......@@ -378,62 +446,6 @@ class NavigationUnstyled extends React.Component {
const Navigation = compose(withRouter, withErrors, withApi(false), withStyles(NavigationUnstyled.styles))(NavigationUnstyled)
class LicenseAgreementUnstyled extends React.Component {
static propTypes = {
classes: PropTypes.object.isRequired,
cookies: instanceOf(Cookies).isRequired
}
static styles = theme => ({
content: {
backgroundColor: theme.palette.primary.main
},
button: {
color: 'white'
}
})
constructor(props) {
super(props)
this.handleClosed = this.handleClosed.bind(this)
}
state = {
accepted: this.props.cookies.get('terms-accepted')
}
handleClosed(accepted) {
if (accepted) {
this.props.cookies.set('terms-accepted', true)
this.setState({accepted: true})
}
}
render() {
return (
<div>
<Dialog
disableBackdropClick disableEscapeKeyDown
open={!this.state.accepted}
>
<DialogTitle>Terms of Use</DialogTitle>
<DialogContent>
<Markdown>{consent}</Markdown>
</DialogContent>
<DialogActions>
<Button onClick={() => this.handleClosed(true)} color="primary">
Accept
</Button>
</DialogActions>
</Dialog>
</div>
)
}
}
const LicenseAgreement = compose(withCookies, withStyles(LicenseAgreementUnstyled.styles))(LicenseAgreementUnstyled)
const routes = {
'about': {
exact: true,
......@@ -506,6 +518,8 @@ class App extends React.PureComponent {
if (props.match || route.exists) {
route.exists = true
return <route.component visible={props.match && true} {...props} />
} else {
return ''
}
} else {
return props.match && <route.component {...props} />
......@@ -516,7 +530,6 @@ class App extends React.PureComponent {
</Navigation>
</ApiProvider>
</ErrorSnacks>
<LicenseAgreement />
</MuiThemeProvider>
)
}
......
......@@ -53,7 +53,7 @@ export default function DatasetPage() {
setDataset({})
raiseError(error)
})
}, [location.pathname, api])
}, [datasetId, location.pathname, api, raiseError])
if (!dataset) {
return <div>loading...</div>
......
......@@ -706,14 +706,14 @@ export function DisableOnLoading({children}) {
const enable = loading ? 'none' : ''
containerRef.current.style.pointerEvents = enable
containerRef.current.style.userSelects = enable
}, [api])
}, [])
useEffect(() => {
api.onLoading(handleLoading)
return () => {
api.removeOnLoading(handleLoading)
}
}, [])
}, [api, handleLoading])
return <div ref={containerRef}>{children}</div>
}
......
......@@ -9,6 +9,7 @@ export function DFTMethodVisualizations(props) {
const {response: {statistics, metric}, setStatistics} = useContext(searchContext)
useEffect(() => {
setStatistics(['dft.code_name', 'dft.basis_set', 'dft.xc_functional'])
// eslint-disable-next-line
}, [])
if (statistics.code_name && info) {
......@@ -47,6 +48,7 @@ export function DFTSystemVisualizations(props) {
const {response: {statistics, metric}, setStatistics} = useContext(searchContext)
useEffect(() => {
setStatistics(['dft.labels_springer_compound_class', 'dft.system', 'dft.crystal_system', 'dft.compound_type'])
// eslint-disable-next-line
}, [])
if (statistics.code_name && info) {
......@@ -156,6 +158,7 @@ export function DFTPropertyVisualizations(props) {
'dft.searchable_quantities',
'dft.labels_springer_classification'
])
// eslint-disable-next-line
}, [])
if (statistics.code_name && info) {
......
......@@ -7,7 +7,9 @@ export default function EMSVisualizations(props) {
const {setStatistics} = useContext(searchContext)
useEffect(() => {
setStatistics(['ems.method', 'ems.probing_method', 'ems.sample_microstructure', 'ems.sample_constituents'])
// eslint-disable-next-line
}, [])
return (
<Grid container spacing={2}>
<Grid item xs={6}>
......
......@@ -91,7 +91,7 @@ export default function MetaInfoBrowser({visible}) {
api.getInfo().then(info => {
setPackages(info.metainfo_packages)
}).catch(raiseError)
}, [api])
}, [api, raiseError])