diff --git a/.github/actions/.gitinclude b/.github/actions/.gitinclude new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml new file mode 100644 index 0000000..92782ad --- /dev/null +++ b/.github/workflows/lint-and-test.yml @@ -0,0 +1,43 @@ +--- +name: CI/CD +on: + push: + branches: + - main + - develop + - feature/** + pull_request: + branches: + - main + - develop +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: psf/black@stable + with: + options: "--check --verbose" + src: "./accelerator_core" + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ "3.10" ] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Test with pytest + run: | + coverage run -m pytest -v -s + - name: Generate Coverage Report + run: | + coverage report -m diff --git a/.gitignore b/.gitignore index 15201ac..924b9fb 100644 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,6 @@ cython_debug/ # PyPI configuration file .pypirc + +.idea +.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4d82889 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files +- repo: https://github.com/psf/black + rev: 25.1.0 + hooks: + - id: black + language_version: python3.11 diff --git a/README.md b/README.md index 30a59c7..168069e 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,10 @@ Core libraries and classes for accelerator metadata backbone ## Description -This project is the base python package and libraries for the core of the Accellerator Project +This project is the base python package and libraries for the core of the Accelerator Project +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![CI/CD](https://github.com/NIEHS/accelerator-core/actions/workflows/lint-and-test.yml/badge.svg)](https://github.com/NIEHS/accelerator-core/actions/workflows/lint-and-test.yml) ![System Whiteboard](https://github.com/user-attachments/assets/2a2b07fa-bbed-454c-9050-73eccb7cbf6c) @@ -12,4 +14,16 @@ The project implements all of the core components (accession, dissemination) and Each source and disseination target should be developed in a separate accelerator-source-xxx or accelerator-dissemination-xxx repository - + +## Developer Notes + +This project uses pre-commit hooks to validate code, run tests, and accomplish other tasks. + +Loading the requirements.txt into your dev environment will install pre-commit, then you can set up the pre-commit +hooks by running: + +``` +pre-commit install +``` + +This should be the first thing you do when cloning this project. More docs on pre-commit are available [here](https://pre-commit.com/) diff --git a/accelerator_core/__init__.py b/accelerator_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accelerator_core/accession.py b/accelerator_core/accession.py new file mode 100644 index 0000000..0b57ceb --- /dev/null +++ b/accelerator_core/accession.py @@ -0,0 +1,29 @@ +from accelerator_core.crosswalk import Crosswalk + + +class Accession: + """Handles validation and CRUD operations for metadata records.""" + + def __init__(self, data: dict): + """Initialize Accession with validated data.""" + self.data = data + + def validate(self) -> bool: + """Validate JSON output from Crosswalk.""" + pass + + def create(self) -> str: + """Create a new record in the database.""" + pass + + def read(self, record_id: str) -> dict: + """Retrieve a record from the database.""" + pass + + def update(self, record_id: str, new_data: dict) -> bool: + """Update an existing record.""" + pass + + def delete(self, record_id: str) -> bool: + """Delete a record from the database.""" + pass diff --git a/accelerator_core/crosswalk.py b/accelerator_core/crosswalk.py new file mode 100644 index 0000000..7688e56 --- /dev/null +++ b/accelerator_core/crosswalk.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod + + +class Crosswalk(ABC): + """Abstract superclass for mapping raw data to a structured JSON format.""" + + @abstractmethod + def transform(self, raw_data: dict) -> dict: + """Convert raw data into a standardized format.""" + pass diff --git a/accelerator_core/db/__init__.py b/accelerator_core/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accelerator_core/db/connector.py b/accelerator_core/db/connector.py new file mode 100644 index 0000000..e69de29 diff --git a/accelerator_core/db/models.py b/accelerator_core/db/models.py new file mode 100644 index 0000000..e69de29 diff --git a/accelerator_core/dissemination.py b/accelerator_core/dissemination.py new file mode 100644 index 0000000..44fc891 --- /dev/null +++ b/accelerator_core/dissemination.py @@ -0,0 +1,18 @@ +class Dissemination: + """Retrieves data from the database and transforms it into a JSON document for endpoint systems.""" + + def __init__(self, record_id: str): + """Initialize Dissemination with a record ID.""" + self.record_id = record_id + + def fetch_data(self) -> dict: + """Retrieve data from the database.""" + pass + + def format_for_endpoint(self, system: str) -> dict: + """Convert data into a format required by a specific endpoint (CHORDS, Navigator, CEDAR).""" + pass + + def export(self, system: str) -> bool: + """Send the formatted data to the respective system.""" + pass diff --git a/accelerator_core/schema/README.md b/accelerator_core/schema/README.md new file mode 100644 index 0000000..cbf299d --- /dev/null +++ b/accelerator_core/schema/README.md @@ -0,0 +1,12 @@ +# Accelerator Data Model +## Version: 0.0.1-alpha + +## Description + +This accel.json file, and the accompanying JSON schema, represent the core data model for Accelerator. + + +## Development process + +The initial accel.json file is derived from the Excel model of the 1.5 CHORDS model +found here: https://nih.sharepoint.com/:f:/r/sites/NIH-DataAcceleratorProgram/Shared%20Documents/General/Design/term%20mappings?csf=1&web=1&e=1JTZT1 diff --git a/accelerator_core/schema/__init__.py b/accelerator_core/schema/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accelerator_core/schema/accel-schema-v1.0.0.json b/accelerator_core/schema/accel-schema-v1.0.0.json new file mode 100644 index 0000000..93abfca --- /dev/null +++ b/accelerator_core/schema/accel-schema-v1.0.0.json @@ -0,0 +1,473 @@ +{ + "$schema": "http://json-schema.org/2020-12/schema#", + "$id": "http://www.niehs.nih.gov/schemas/accelerator.json", + "$ref": "#/definitions/Accelerator", + "description": "Data model for accelerator metadata", + "definitions": { + "Accelerator": { + "type": "object", + "additionalProperties": false, + "properties": { + "submission": { + "$ref": "#/definitions/Submission" + }, + "data": { + "$ref": "#/definitions/Data" + }, + "technical_metadata": { + "$ref": "#/definitions/TechnicalMetadata" + } + }, + "required": [ + "data", + "submission" + ], + "title": "Accelerator" + }, + "Data": { + "type": "object", + "additionalProperties": false, + "properties": { + "program": { + "$ref": "#/definitions/Program" + }, + "project": { + "$ref": "#/definitions/Project" + }, + "resource": { + "$ref": "#/definitions/Resource" + }, + "data_resource": { + "$ref": "#/definitions/DataResource" + }, + "temporal_data": { + "$ref": "#/definitions/TemporalData" + }, + "population_data": { + "$ref": "#/definitions/PopulationData" + }, + "geospatial_data": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "array", + "items": {} + }, + { + "type": "null" + } + ] + } + } + }, + "required": [ + "data_resource", + "geospatial_data", + "population_data", + "program", + "project", + "resource", + "temporal_data" + ], + "title": "Data" + }, + "DataResource": { + "type": "object", + "additionalProperties": false, + "properties": { + "exposure_media": { + "type": "array", + "items": {} + }, + "measures": { + "type": "array", + "items": {} + }, + "measures_other": { + "type": "array", + "items": {} + }, + "measurement_method": { + "type": "null" + }, + "measurement_method_other": { + "type": "null" + }, + "time_extent_start": { + "type": "null" + }, + "time_extent_end": { + "type": "null" + }, + "time_available_comment": { + "type": "null" + }, + "data_formats": { + "type": "array", + "items": {} + }, + "data_location": { + "type": "array", + "items": { + "$ref": "#/definitions/DataLocation" + } + } + }, + "required": [ + "data_formats", + "data_location", + "exposure_media", + "measurement_method", + "measurement_method_other", + "measures", + "measures_other", + "time_available_comment", + "time_extent_end", + "time_extent_start" + ], + "title": "DataResource" + }, + "DataLocation": { + "type": "object", + "additionalProperties": false, + "properties": { + "data_location_text": { + "type": "null" + }, + "data_location_link": { + "type": "null" + } + }, + "required": [ + "data_location_link", + "data_location_text" + ], + "title": "DataLocation" + }, + "PopulationData": { + "type": "object", + "additionalProperties": false, + "properties": { + "individual_level": { + "type": "boolean" + }, + "population_studies": { + "type": "array", + "items": {} + }, + "population_studies_other": { + "type": "array", + "items": {} + }, + "linkable_encounters": { + "type": "boolean" + }, + "biospecimens_from_humans": { + "type": "boolean" + }, + "biospecimens_type": { + "type": "array", + "items": {} + } + }, + "required": [ + "biospecimens_from_humans", + "biospecimens_type", + "individual_level", + "linkable_encounters", + "population_studies", + "population_studies_other" + ], + "title": "PopulationData" + }, + "Program": { + "type": "object", + "additionalProperties": false, + "properties": { + "program_name": { + "type": "null" + }, + "preferred_label": { + "type": "null" + } + }, + "required": [ + "preferred_label", + "program_name" + ], + "title": "Program" + }, + "Project": { + "type": "object", + "additionalProperties": false, + "properties": { + "project_code": { + "type": "null" + }, + "project_name": { + "type": "null" + }, + "project_short_name": { + "type": "null" + }, + "project_sponsor": { + "type": "array", + "items": {} + }, + "project_sponsor_other": { + "type": "array", + "items": {} + }, + "project_sponsor_type": { + "type": "array", + "items": {} + }, + "project_sponsor_type_other": { + "type": "array", + "items": {} + } + }, + "required": [ + "project_code", + "project_name", + "project_short_name", + "project_sponsor", + "project_sponsor_other", + "project_sponsor_type", + "project_sponsor_type_other" + ], + "title": "Project" + }, + "Resource": { + "type": "object", + "additionalProperties": false, + "properties": { + "resource_name": { + "type": "null" + }, + "resource_version": { + "type": "null" + }, + "resource_short_name": { + "type": "null" + }, + "resource_type": { + "type": "null" + }, + "resource_url": { + "type": "null" + }, + "resource_description": { + "type": "null" + }, + "resource_domain": { + "type": "array", + "items": {} + }, + "resource_domain_other": { + "type": "array", + "items": {} + }, + "resource_keywords": { + "type": "array", + "items": {} + }, + "resource_access_type": { + "type": "null" + }, + "resource_reference": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceReference" + } + }, + "resource_use_agreement": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceUseAgreement" + } + }, + "publication": { + "type": "array", + "items": { + "$ref": "#/definitions/Publication" + } + }, + "is_static": { + "type": "boolean" + }, + "comments": { + "type": "null" + } + }, + "required": [ + "comments", + "is_static", + "publication", + "resource_access_type", + "resource_description", + "resource_domain", + "resource_domain_other", + "resource_keywords", + "resource_name", + "resource_reference", + "resource_short_name", + "resource_type", + "resource_url", + "resource_use_agreement", + "resource_version" + ], + "title": "Resource" + }, + "Publication": { + "type": "object", + "additionalProperties": false, + "properties": { + "citation": { + "type": "null" + }, + "citation_link": { + "type": "null" + } + }, + "required": [ + "citation", + "citation_link" + ], + "title": "Publication" + }, + "ResourceReference": { + "type": "object", + "additionalProperties": false, + "properties": { + "resource_reference_text": { + "type": "null" + }, + "resource_reference_link": { + "type": "null" + } + }, + "required": [ + "resource_reference_link", + "resource_reference_text" + ], + "title": "ResourceReference" + }, + "ResourceUseAgreement": { + "type": "object", + "additionalProperties": false, + "properties": { + "resource_use_agreement_text": { + "type": "null" + }, + "resource_use_agreement_link": { + "type": "null" + } + }, + "required": [ + "resource_use_agreement_link", + "resource_use_agreement_text" + ], + "title": "ResourceUseAgreement" + }, + "TemporalData": { + "type": "object", + "additionalProperties": false, + "properties": { + "temporal_resolution": { + "type": "array", + "items": {} + }, + "temporal_resolution_other": { + "type": "array", + "items": {} + }, + "temporal_resolution_all_available": { + "type": "array", + "items": {} + }, + "temporal_resolution_comment": { + "type": "null" + } + }, + "required": [ + "temporal_resolution", + "temporal_resolution_all_available", + "temporal_resolution_comment", + "temporal_resolution_other" + ], + "title": "TemporalData" + }, + "Submission": { + "type": "object", + "additionalProperties": false, + "properties": { + "submitter_name": { + "type": "null" + }, + "submitter_email": { + "type": "null" + }, + "submitter_comment": { + "type": "null" + } + }, + "required": [ + "submitter_comment", + "submitter_email", + "submitter_name" + ], + "title": "Submission" + }, + "TechnicalMetadata": { + "type": "object", + "additionalProperties": false, + "properties": { + "created": { + "type": "null" + }, + "modified": { + "type": "null" + }, + "original_source": { + "type": "null" + }, + "original_source_link": { + "type": "null" + }, + "history": { + "type": "array", + "items": { + "$ref": "#/definitions/History" + } + } + }, + "required": [ + "created", + "history", + "modified", + "original_source", + "original_source_link" + ], + "title": "TechnicalMetadata" + }, + "History": { + "type": "object", + "additionalProperties": false, + "properties": { + "timestamp": { + "type": "null" + }, + "msg": { + "type": "null" + } + }, + "required": [ + "msg", + "timestamp" + ], + "title": "History" + } + } +} diff --git a/accelerator_core/schema/accel.json b/accelerator_core/schema/accel.json new file mode 100644 index 0000000..3fdcb33 --- /dev/null +++ b/accelerator_core/schema/accel.json @@ -0,0 +1,114 @@ +{ + "submission": { + "submitter_name": null, + "submitter_email": null, + "submitter_comment": null + }, + "data": { + "program": { + "program_name": null, + "preferred_label": null + }, + "project": { + "project_code": null, + "project_name": null, + "project_short_name": null, + "project_sponsor": [], + "project_sponsor_other": [], + "project_sponsor_type": [], + "project_sponsor_type_other": [] + }, + "resource": { + "resource_name": null, + "resource_version": null, + "resource_short_name": null, + "resource_type": null, + "resource_url": null, + "resource_description": null, + "resource_domain": [], + "resource_domain_other": [], + "resource_keywords": [], + "resource_access_type": null, + "resource_reference": [ + { + "resource_reference_text": null, + "resource_reference_link": null + } + ], + "resource_use_agreement": [ + { + "resource_use_agreement_text": null, + "resource_use_agreement_link": null + } + ], + "publication": [ + { + "citation": null, + "citation_link": null + } + ], + "is_static": false, + "comments": null + }, + "data_resource": { + "exposure_media": [], + "measures": [], + "measures_other": [], + "measurement_method": null, + "measurement_method_other": null, + "time_extent_start": null, + "time_extent_end": null, + "time_available_comment": null, + "data_formats": [], + "data_location": [ + { + "data_location_text": null, + "data_location_link": null + } + ] + }, + "temporal_data": { + "temporal_resolution": [], + "temporal_resolution_other": [], + "temporal_resolution_all_available": [], + "temporal_resolution_comment": null + }, + "population_data": { + "individual_level": false, + "population_studies": [], + "population_studies_other": [], + "linkable_encounters": false, + "biospecimens_from_humans": false, + "biospecimens_type": [] + }, + "geospatial_data": { + "spatial_resolution": [], + "spatial_resolution_other": [], + "spatial_resolution_all_available": [], + "spatial_resolution_comment": null, + "spatial_coverage": [], + "spatial_coverage_other": [], + "spatial_bounding_box": [], + "geometry_type": [], + "geometry_source": [], + "geometry_source_other": [], + "model_methods": [], + "model_methods_other": [], + "exposure_media": [], + "geographic_feature": [], + "geographic_feature_other": [] + } + }, + "technical_metadata": { + "created": null, + "modified": null, + "original_source": null, + "original_source_link": null, + "history": [ + { + "timestamp": null, + "msg": null + } + ] + } +} diff --git a/accelerator_core/utils/config.py b/accelerator_core/utils/config.py new file mode 100644 index 0000000..4a1ac2f --- /dev/null +++ b/accelerator_core/utils/config.py @@ -0,0 +1,23 @@ +""" +Utilities related to configuration, resources and environment variables. +""" + +import importlib.resources +from pathlib import Path +from accelerator_core.utils.logger import setup_logger +import json + +logger = setup_logger("accelerator") + + +def determine_resource_path(resource_package, resource_name) -> Path: + """ + Given a package and resource name, get the given program resource + :param resource_package: package where resources are located + :param resource_name: name of the resource in the package + :return: Path object to the resource + """ + + with importlib.resources.path(resource_package, resource_name) as fspath: + logger.debug(f"resource path:{fspath}") + return fspath diff --git a/accelerator_core/utils/logger.py b/accelerator_core/utils/logger.py new file mode 100644 index 0000000..fd387e9 --- /dev/null +++ b/accelerator_core/utils/logger.py @@ -0,0 +1,11 @@ +import logging + + +def setup_logger(name: str): + """Setup and return a logger instance.""" + logger = logging.getLogger(name) + logger.setLevel(logging.INFO) + ch = logging.StreamHandler() + ch.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) + logger.addHandler(ch) + return logger diff --git a/accelerator_core/utils/schema_tools.py b/accelerator_core/utils/schema_tools.py new file mode 100644 index 0000000..b96d987 --- /dev/null +++ b/accelerator_core/utils/schema_tools.py @@ -0,0 +1,48 @@ +import importlib.resources + +from accelerator_core.utils.logger import setup_logger +import accelerator_core.schema +from accelerator_core.utils.config import determine_resource_path +import json +import jsonschema + +logger = setup_logger("accelerator") + +CURRENT_ACCEL_SCHEMA_VERSION = "1.0.0" +CURRENT_JSON_SCHEMA_VERSION = "2020-12" + + +def read_current_schema(schema_version: str = CURRENT_ACCEL_SCHEMA_VERSION): + """ + Read the current JSON schema + :param schema_version: n.n.n schema version (defaults to most current) + :return: json object representing schema + """ + + schema_name = f"accel-schema-v{schema_version}.json" + + with determine_resource_path(accelerator_core.schema, schema_name) as fspath: + logger.debug(f"resource path:{fspath}") + with open(fspath) as json_data: + d = json.load(json_data) + return d + + +def validate_json_against_schema( + json_doc, schema_version: str = CURRENT_ACCEL_SCHEMA_VERSION +) -> bool: + """ + validate the given json (as a json dict) + :param json_doc: dict with json to validate + :param schema_version: version of accel schema to validate against, as a version string: 1.0.0 + :return: bool is True if valid + """ + + json_schema_doc = read_current_schema(schema_version) + try: + jsonschema.validate(json_doc, json_schema_doc) + except jsonschema.exceptions.ValidationError as e: + logger.error(f"invalid json document {e}") + return False + + return True diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..474ab51 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,48 @@ +# Main documentation file + + + +## Project structure overview +``` +accelerator-core/ +│── accelerator_core/ # Main package directory +│ ├── __init__.py # Makes this a Python package +│ ├── accession.py # Accession class (CRUD operations, validation) +│ ├── dissemination.py # Dissemination class (data retrieval, JSON transformation) +│ ├── crosswalk.py # Superclass for data mapping +│ ├── db/ # Database interaction module +│ │ ├── __init__.py +│ │ ├── models.py # Database models +│ │ ├── connector.py # Database connection logic +│ ├── utils/ # Utility functions (common helpers) +│ │ ├── __init__.py +│ │ ├── logger.py # Logging setup +│ │ ├── config.py # Configuration management +│ +├── tests/ # Unit tests directory +│ ├── __init__.py +│ ├── test_accession.py # Unit tests for accession module +│ ├── test_dissemination.py # Unit tests for dissemination module +│ ├── test_crosswalk.py # Unit tests for crosswalk superclass +│ ├── test_db.py # Tests for database interaction +│ +├── docs/ # Documentation +│ ├── index.md # Main documentation file +│ ├── api_reference.md # API reference +│ ├── usage_guide.md # Usage guide +│ +├── .gitignore # Git ignore file +├── pyproject.toml # Build system configuration (PEP 517) +├── setup.py # Legacy setup script for packaging +├── setup.cfg # Configuration for setuptools +├── README.md # Project overview and usage +├── LICENSE # License file +``` + +### Key Features: +* accelerator_core/ contains the core modules: accession.py, dissemination.py, and crosswalk.py. +* db/ handles database interactions. +* utils/ holds helper functions like logging and config management. +* tests/ includes unit tests to validate functionality. +* docs/ provides API reference and usage documentation. +* pyproject.toml, setup.py, and setup.cfg enable packaging and distribution via pip. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2ba7adc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,32 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "accelerator-core" +version = "0.1.0" +description = "Core libraries for the accelerator metadata backbone" +readme = "README.md" +authors = [{ name = "Your Name", email = "your.email@example.com" }] +license = { file = "LICENSE" } +keywords = ["metadata", "data-processing", "accelerator"] +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", +] +requires-python = ">=3.8" +dependencies = [ + +] + +[project.urls] +Homepage = "https://github.com/yourusername/accelerator-core" +Documentation = "https://github.com/yourusername/accelerator-core/wiki" +Repository = "https://github.com/yourusername/accelerator-core" + +[tool.setuptools.packages.find] +where = ["accelerator_core"] + +[black] +include = "accelerator_core" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..40b2975 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +setuptools~=65.6.3 +jsonschema~=4.23.0 +pre-commit~=4.1.0 +black~=25.1.0 +pytest~=8.3.5 +coverage~=7.6.12 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fa33a7a --- /dev/null +++ b/setup.py @@ -0,0 +1,20 @@ +from setuptools import setup, find_packages + +setup( + name="accelerator-core", + version="0.1.0", + description="Core libraries for the accelerator metadata backbone", + author="Your Name", + author_email="your.email@example.com", + url="https://github.com/yourusername/accelerator-core", + packages=find_packages(), + install_requires=[ + ], + license="BSD 3-Clause", + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + ], + python_requires=">=3.9", +) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/context.py b/tests/context.py new file mode 100644 index 0000000..1406b77 --- /dev/null +++ b/tests/context.py @@ -0,0 +1,4 @@ +import os +import sys + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) diff --git a/tests/test_accession.py b/tests/test_accession.py new file mode 100644 index 0000000..6fa47bb --- /dev/null +++ b/tests/test_accession.py @@ -0,0 +1,10 @@ +import unittest + + +class MyTestCase(unittest.TestCase): + def test_something(self): + self.assertEqual(True, True) # add assertion here + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_crosswalk.py b/tests/test_crosswalk.py new file mode 100644 index 0000000..6fa47bb --- /dev/null +++ b/tests/test_crosswalk.py @@ -0,0 +1,10 @@ +import unittest + + +class MyTestCase(unittest.TestCase): + def test_something(self): + self.assertEqual(True, True) # add assertion here + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_db.py b/tests/test_db.py new file mode 100644 index 0000000..6fa47bb --- /dev/null +++ b/tests/test_db.py @@ -0,0 +1,10 @@ +import unittest + + +class MyTestCase(unittest.TestCase): + def test_something(self): + self.assertEqual(True, True) # add assertion here + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_dissemination.py b/tests/test_dissemination.py new file mode 100644 index 0000000..6fa47bb --- /dev/null +++ b/tests/test_dissemination.py @@ -0,0 +1,10 @@ +import unittest + + +class MyTestCase(unittest.TestCase): + def test_something(self): + self.assertEqual(True, True) # add assertion here + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_schema_tools.py b/tests/test_schema_tools.py new file mode 100644 index 0000000..72c597d --- /dev/null +++ b/tests/test_schema_tools.py @@ -0,0 +1,25 @@ +import json +import unittest + +import accelerator_core +from accelerator_core.utils.config import determine_resource_path +from accelerator_core.utils.schema_tools import read_current_schema, validate_json_against_schema + + +class TestSchemaTools(unittest.TestCase): + def test_read_current_schema(self): + schema_json = read_current_schema() + self.assertIsNotNone(schema_json, "did not schema ") + self.assertIsInstance(schema_json, dict) + + + def test_validate_schema(self): + json_path = determine_resource_path(accelerator_core.schema, "accel.json") + with open(json_path) as json_data: + d = json.load(json_data) + + actual = validate_json_against_schema(d) + self.assertTrue(actual, 'Did not validate json against schema') + +if __name__ == '__main__': + unittest.main()