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

A few fixes related to usage as a library #119

Merged
merged 7 commits into from
Jan 9, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deps_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -U setuptools
pip install .[dev]
pip install -e .[dev]

- name: Run pre-commit
run: |
Expand Down
4 changes: 3 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
recursive-include *.txt *.g *.py *.ini
recursive-include optimade/server/ *.ini *.cfg *.json
recursive-include optimade/server/data *
recursive-include optimade/grammar *.g
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Latest release | Build status | Activity |
|:--------------:|:------------:|:--------:|
| [![PyPI Version](https://img.shields.io/pypi/v/optimade?logo=pypi)](https://pypi.org/project/optimade/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/optimade?logo=python)](https://pypi.org/project/optimade/) [![OPTiMaDe](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Materials-Consortia/optimade-python-tools/master/.ci/optimade-version.json&logo=json)](https://github.com/Materials-Consortia/OPTiMaDe/) | [![Build Status](https://img.shields.io/github/workflow/status/Materials-Consortia/optimade-python-tools/Dependency,%20linting,%20and%20OpenAPI%20validation/gh_action_linter?logo=github)](https://github.com/Materials-Consortia/optimade-python-tools/actions?query=branch%3Amaster+) [![codecov](https://codecov.io/gh/Materials-Consortia/optimade-python-tools/branch/master/graph/badge.svg)](https://codecov.io/gh/Materials-Consortia/optimade-python-tools)[![Heroku](https://heroku-badge.herokuapp.com/?app=optimade&root=optimade/info)](https://optimade.herokuapp.com/optimade/info) | [![Commit Activity](https://img.shields.io/github/commit-activity/m/Materials-Consortia/optimade-python-tools?logo=github)](https://github.com/Materials-Consortia/optimade-python-tools/pulse) |
| [![PyPI Version](https://img.shields.io/pypi/v/optimade?logo=pypi)](https://pypi.org/project/optimade/)<br>[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/optimade?logo=python)](https://pypi.org/project/optimade/)<br>[![OPTiMaDe](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Materials-Consortia/optimade-python-tools/master/.ci/optimade-version.json&logo=json)](https://github.com/Materials-Consortia/OPTiMaDe/) | [![Build Status](https://img.shields.io/github/workflow/status/Materials-Consortia/optimade-python-tools/Dependency,%20linting,%20and%20OpenAPI%20validation/gh_action_linter?logo=github)](https://github.com/Materials-Consortia/optimade-python-tools/actions?query=branch%3Amaster+)<br>[![codecov](https://codecov.io/gh/Materials-Consortia/optimade-python-tools/branch/master/graph/badge.svg)](https://codecov.io/gh/Materials-Consortia/optimade-python-tools)<br>[![Heroku](https://heroku-badge.herokuapp.com/?app=optimade&root=optimade/info)](https://optimade.herokuapp.com/optimade/info) | [![Commit Activity](https://img.shields.io/github/commit-activity/m/Materials-Consortia/optimade-python-tools?logo=github)](https://github.com/Materials-Consortia/optimade-python-tools/pulse) |

The aim of OPTiMaDe is to develop a common API, compliant with the [JSON API 1.0](http://jsonapi.org/format/1.0/) specification.
This is to enable interoperability among databases that contain calculated properties of existing and hypothetical materials.
Expand All @@ -16,14 +16,25 @@ Both the OPTiMaDe specification and this repository are **under development**.
## Installation (Index Meta-Database)

This package may be used to setup and run an [OPTiMaDe index meta-database](https://github.com/Materials-Consortia/OPTiMaDe/blob/develop/optimade.rst#index-meta-database).
Install the package via `pip install optimade[server]` and change the file `server.cfg` found in the root of the package.
Install the package via `pip install optimade[server]` and change the file [`server.cfg`](server.cfg) found in the root of the package.

The `server.cfg` file serves paths to a server runtime configuration file (either an `ini` or `json` file, see the [`config.ini` file](optimade/server/config.ini) for an example) and an index `/links`-endpoint data file.
The paths must be relative from your current working directory, where your `server.cfg` is located, or they must be absolute paths.

The `server.cfg` file serves paths to a server config file (either an `ini` or `json` file, see the `./optimade/server/config.ini` for an example) and an index `/links`-endpoint data file.
The index meta-database is set up to populate a `mongomock` in-memory database with resources from a static `json` file containing the `child` resources you, as a database provider, want to serve under this index meta-database.

Running the index meta-database is then as simple as writing `./run.sh index` in a terminal from the root of this package.
You can find it at the base URL: [`http://localhost:5001/index/optimade/`](http://localhost:5001/index/optimade/).

_Note_: `server.cfg` is loaded from the current working directory, from where you run `run.sh`.
E.g., if you have installed `optimade` on a Linux machine at `/home/USERNAME/optimade/optimade-python-tools` and you run the following:

```shell
:~$ ./optimade/optimade-python-tools/run.sh index
```

Then you need `server.cfg` to be located in your home folder containing either relative paths from its current location or absolute paths.

## Development installation & Contributing

Full installation instructions and contribution guidelines can be found in [CONTRIBUTING](CONTRIBUTING.md).
Expand Down
12 changes: 6 additions & 6 deletions optimade/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ class NoFallback(Exception):
class Config:
"""Base class for loading config files and its parameters"""

index_links_path: Path = Path("./optimade/server/index_links.json")
_path: Path = Path("./optimade/server/config.ini")
index_links_path: Path = Path(__file__).parent.joinpath("index_links.json")
_path: Path = Path(__file__).parent.joinpath("config.ini")

def __init__(self, server_cfg: Path = None):
self._server = (
Path(__file__).resolve().parent.parent.parent.joinpath("server.cfg")
Path().resolve().joinpath("server.cfg")
CasperWA marked this conversation as resolved.
Show resolved Hide resolved
if server_cfg is None
else server_cfg
)
Expand All @@ -38,9 +38,9 @@ def __getattr__(self, name: str) -> Any:

def _create_server_config(self):
"""Create 'server.cfg' in top-package dir from 'server_template.cfg' if it does not exist"""
import shutil
import shutil # pylint: disable=import-outside-toplevel

server_cfg_template = self._server.parent.joinpath("server_template.cfg")
server_cfg_template = Path(__file__).parent.joinpath("server_template.cfg")
shutil.copyfile(server_cfg_template, self._server)

def _load_server_config(self):
Expand All @@ -66,7 +66,7 @@ def _load_server_config(self):
)

if not self.index_links_path.exists():
from warnings import warn
from warnings import warn # pylint: disable=import-outside-toplevel

warn(
f'Cannot resolve {self.index_links_path}. Check the index_links.json file exists. Note, "~" is not allowed.'
Expand Down
8 changes: 4 additions & 4 deletions optimade/server/entry_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,20 @@ def find(
for doc in self.collection.find(**criteria):
results.append(self.resource_cls(**self.resource_mapper.map_back(doc)))

nresults_now = len(results)
if isinstance(params, EntryListingQueryParams):
nresults_now = len(results)
criteria_nolimit = criteria.copy()
criteria_nolimit.pop("limit", None)
data_returned = self.count(**criteria_nolimit)
more_data_available = nresults_now < data_returned
else:
# SingleEntryQueryParams, e.g., /structures/{entry_id}
data_returned = 1
data_returned = nresults_now
more_data_available = False
if len(results) > 1:
if nresults_now > 1:
raise HTTPException(
status_code=404,
detail=f"Instead of a single entry, {len(results)} entries were found",
detail=f"Instead of a single entry, {nresults_now} entries were found",
)
results = results[0] if results else None

Expand Down
9 changes: 7 additions & 2 deletions optimade/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"references": Path(__file__).resolve().parent.joinpath("data/test_references.json"),
"links": Path(__file__).resolve().parent.joinpath("data/test_links.json"),
}
if not CONFIG.use_real_mongo and (path.exists() for path in test_paths.values()):
if not CONFIG.use_real_mongo and all(path.exists() for path in test_paths.values()):
import bson.json_util
from .routers import ENTRY_COLLECTIONS

Expand Down Expand Up @@ -89,7 +89,12 @@ def load_entries(endpoint_name: str, endpoint_collection: MongoCollection):

def update_schema(app):
"""Update OpenAPI schema in file 'local_openapi.json'"""
with open("openapi/local_openapi.json", "w") as f:
local_openapi = (
Path(__file__)
.resolve()
.parent.parent.parent.joinpath("openapi/local_openapi.json")
)
with open(local_openapi, "w") as f:
json.dump(app.openapi(), f, indent=2)


Expand Down
8 changes: 7 additions & 1 deletion optimade/server/main_index.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from pathlib import Path

from pydantic import ValidationError
from fastapi import FastAPI
Expand Down Expand Up @@ -69,7 +70,12 @@

def update_schema(app):
"""Update OpenAPI schema in file 'local_index_openapi.json'"""
with open("openapi/local_index_openapi.json", "w") as f:
local_openapi = (
Path(__file__)
.resolve()
.parent.parent.parent.joinpath("openapi/local_index_openapi.json")
)
with open(local_openapi, "w") as f:
json.dump(app.openapi(), f, indent=2)


Expand Down
File renamed without changes.
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
keywords="optimade jsonapi materials",
include_package_data=True,
packages=find_packages(),
package_data={"": ["*.lark"]},
classifiers=[
"Development Status :: 3 - Alpha",
"Programming Language :: Python :: 3",
Expand Down
14 changes: 14 additions & 0 deletions tests/server/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ def test_structures_endpoint_data(self):
)


class MissingSingleStructureEndpointTests(EndpointTests, unittest.TestCase):

test_id = "mpf_random_string_that_is_not_in_test_data"
request_str = f"/structures/{test_id}"
response_cls = StructureResponseOne

def test_structures_endpoint_data(self):
self.assertTrue("data" in self.json_response)
self.assertTrue("meta" in self.json_response)
self.assertEqual(self.json_response["data"], None)
self.assertEqual(self.json_response["meta"]["data_returned"], 0)
self.assertEqual(self.json_response["meta"]["more_data_available"], False)


class SingleStructureWithRelationshipsTests(EndpointTests, unittest.TestCase):

test_id = "mpf_1"
Expand Down