Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3124feb
Next development iteration `v1.0.0-RC4-SNAPSHOT`.
ielis Apr 25, 2023
71c6a2e
Merge pull request #183 from ielis/develop
ielis Apr 25, 2023
03de2a9
Add molecule context to the variation descriptor during conversion fr…
ielis Apr 27, 2023
3cc54e1
Improve handling of the VcfRecord filter field.
ielis Apr 27, 2023
6cf109f
Add missing VCF info field.
ielis Apr 27, 2023
b477d3f
Fix conversion test.
ielis Apr 27, 2023
4869dc3
Merge pull request #185 from ielis/fix_variant_conversion
ielis Apr 27, 2023
f9a0219
The conversion code should not set default instances to a field in ca…
ielis Apr 28, 2023
10e6420
Fix bug in `PhenotypicFeatureConverter`.
ielis Apr 28, 2023
930c3c3
Merge pull request #187 from ielis/conversion_subtleties
ielis Apr 28, 2023
70c79bd
Add instructions for validation results serialization.
ielis May 25, 2023
eb2f991
`phenopacket-tools-validator-jsonschema` requires `phenopacket.schema…
ielis May 25, 2023
f3dbf59
Try to be portable with Windows.
ielis May 25, 2023
ac1fc24
Merge pull request #188 from ielis/add_json_annotations
ielis May 25, 2023
56f605c
Add message utils package into `phenopacket-tools-util`.
ielis Jun 2, 2023
41c3734
Merge pull request #189 from ielis/message_utils
ielis Jun 2, 2023
5516c33
Use phenol `2.0.2`. Use `MinimalOntology` and the new graph API inste…
ielis Jul 27, 2023
b770324
Run CI using `mvnw`.
ielis Jul 27, 2023
e6fb479
Merge pull request #190 from ielis/update-phenol
ielis Jul 27, 2023
7a431fc
Check that phenotypic features are present at most once.
ielis Aug 22, 2023
848e357
Remove unused `conf.py` parts.
ielis Aug 22, 2023
11a452a
Add unique validator into the standard validation pipeline.
ielis Aug 22, 2023
539ce11
Update changelog.
ielis Aug 22, 2023
3db71e5
Merge pull request #191 from ielis/check-phenotypic-features-are-unique
ielis Aug 22, 2023
53c9733
Check `Age` is a valid ISO8601 period string.
ielis Sep 3, 2023
b911773
Merge pull request #193 from ielis/validate-iso8601
ielis Sep 22, 2023
2750ce2
Merge branch 'main' into develop
ielis Feb 20, 2026
a0685fc
Use latest phenol.
ielis Jun 15, 2026
a48e5c0
Update dependencies.
ielis Jun 15, 2026
de707d0
Merge pull request #205 from phenopackets/update-dependencies
ielis Jun 15, 2026
885a88a
Setup releasing.
ielis Jun 15, 2026
6376920
Merge pull request #206 from phenopackets/setup-releasing-in-ci
ielis Jun 15, 2026
59d2e44
Make release `v1.0.0`.
ielis Jun 15, 2026
e29f4c9
Add the plugin for publishing to Maven central.
ielis Jun 15, 2026
d2c37e4
Allow deployment upon workflow dispatch.
ielis Jun 15, 2026
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
57 changes: 57 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Deploy to Sonatype Central

on:
push:
tags:
- 'v*' # Trigger the workflow when a tag starting with 'v' is pushed, like v1.0.0
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'adopt'

- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-

- name: Import GPG key
run: |
echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --import --armor --batch --no-tty

- name: Setup Maven settings
run: |
rm ${HOME}/.m2/settings.xml

cat << EOF > ${HOME}/.m2/settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>central</id>
<username>${{ secrets.SONATYPE_USERNAME }}</username>
<password>${{ secrets.SONATYPE_PASSWORD }}</password>
</server>
</servers>
</settings>
EOF

- name: Deploy to Sonatype Central
run: |
./mvnw clean deploy -Prelease \
--batch-mode \
-Dgpg.keyname=${{ secrets.GPG_KEY_ID }}
2 changes: 1 addition & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
java-version: '17'
distribution: 'adopt'
- name: Build with Maven
run: mvn --batch-mode --update-snapshots verify
run: ./mvnw --batch-mode --update-snapshots verify
2 changes: 1 addition & 1 deletion .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Changelog
* Improve user guide, tutorial, and documentation.
* Introduce *latest* and *stable* documentation branches
* Add showcase of apps that use phenopacket-tools to add more code examples
* Run `MetaDataValidator` during base validation
* Run `MetaDataValidator` and `HpoUniqueValidator` during base validation
* Finalize JSON and YAML format sniffing
* Fix example phenopackets

Expand Down
21 changes: 2 additions & 19 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,8 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

#############
# JR added:
import os
import sys

sys.path.insert(0, os.path.abspath('../../'))
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.githubpages',
'sphinx_rtd_theme',
'recommonmark'
]

html_theme = 'sphinx_rtd_theme'
##############

project = 'phenopacket-tools'
copyright = '2022, Daniel Danis, Peter Robinson'
copyright = '2026, Daniel Danis, Peter Robinson'
author = u'Daniel Danis, Peter Robinson'

# The version info for the project you're documenting, acts as replacement for
Expand All @@ -33,7 +17,7 @@
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0.0-RC3'
release = '1.0.0'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand All @@ -48,7 +32,6 @@
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'alabaster'
html_static_path = ['_static']
html_css_files = ['pxftools.css']

Expand Down
14 changes: 14 additions & 0 deletions docs/validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,20 @@ library to parse the HPO JSON file. The `OntologyLoader` is part of
`phenol-io <https://mvnrepository.com/artifact/org.monarchinitiative.phenol/phenol-io>`_ module, you may need to add
an appropriate dependency into your build file.

.. _rstuniquephenotypevalidation:

Unique phenotypic features
##########################

The `HpoUniqueValidator` checks if the HPO terms used by a phenopacket are *unique* - present at most once.
If a term is not unique, the validator points this out along with the term's occurrence count.

In code, we add the corresponding validator into the validation workflow by running:

.. code-block:: java

builder.addValidator(HpoPhenotypeValidators.Unique.phenopacketValidator(hpo));


.. _rstancestryphenotypevalidation:

Expand Down
2 changes: 1 addition & 1 deletion phenopacket-tools-builder/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.phenopackets.phenopackettools</groupId>
<artifactId>phenopacket-tools</artifactId>
<version>1.0.0-RC3</version>
<version>1.0.0</version>
</parent>

<artifactId>phenopacket-tools-builder</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ public VariationDescriptorBuilder transcript() {
return this;
}

public VariationDescriptorBuilder moleculeContext(MoleculeContext context) {
builder.setMoleculeContext(context);
return this;
}

public VariationDescriptorBuilder structuralType(OntologyClass structuralType) {
builder.setStructuralType(structuralType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import org.ga4gh.vrsatile.v1.VcfRecord;

import java.util.ArrayList;
import java.util.List;

public class VcfRecordBuilder {

private final VcfRecord.Builder builder;
private boolean passIsSet = false;
private List<String> filters = null;

private VcfRecordBuilder(String assembly, String chromosome, int position, String ref, String alt) {
builder = VcfRecord.newBuilder()
Expand Down Expand Up @@ -48,18 +53,46 @@ public VcfRecordBuilder qual(String qual) {
}

/**
* If this method is called, "PASS" is added to the FILTER column
* If this method is called, the FILTER column is set to "PASS" and any other previously added filters are cleared.
* Calling {@code pass()} is equivalent to calling <code>filter("PASS")</code>.
*/
public VcfRecordBuilder pass() {
builder.setFilter("PASS");
public synchronized VcfRecordBuilder pass() {
passIsSet = true;
if (filters != null)
filters.clear();

return this;
}

/**
* @param filter FILTER field of VCF. calling {@link #pass()} is equivant to calling filter("PASS)
* Add a VCF filter field.
* <p>
* The field can be a single value (e.g. <code>q50</code>) or several values joined by <code>;</code> (e.g. <code>q10;q50</code>).
* <p>
* Calling <code>filter("PASS")</code> is equivalent to calling {@link #pass()}. As a side effect,
* all previously added filter values are removed.
*
* @param filter add a FILTER field.
* @see #pass()
*/
public VcfRecordBuilder filter(String filter) {
builder.setFilter(filter);
public synchronized VcfRecordBuilder filter(String filter) {
passIsSet = false;
if (filters == null)
filters = new ArrayList<>();

if ("PASS".equalsIgnoreCase(filter))
return pass();
else {
if (filter.contains(";")) {
for (String field : filter.split(";")) {
String trimmed = field.trim();
if (!trimmed.isEmpty())
this.filter(field);
}
} else
filters.add(filter);
}

return this;
}

Expand All @@ -71,7 +104,13 @@ public VcfRecordBuilder info(String info) {
return this;
}

public VcfRecord build() {
public synchronized VcfRecord build() {
if (passIsSet)
builder.setFilter("PASS");

else if (filters != null && !filters.isEmpty())
builder.setFilter(String.join(";", filters));

return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.phenopackets.phenopackettools.builder.builders;

import org.ga4gh.vrsatile.v1.VcfRecord;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.junit.jupiter.api.Assertions.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;

public class VcfRecordBuilderTest {

@ParameterizedTest
@CsvSource({
"PASS, PASS",
"pass, PASS",
"q50, q50",
"q50;q10, q50;q10",
"q50;pass, PASS",
"pass;q50, q50",
})
public void addFilter(String filter, String expected) {
VcfRecord record = VcfRecordBuilder.builder("GRCh37", "chr1", 123_456, "C", "G")
.filter(filter)
.build();

assertThat(record.getFilter(), equalTo(expected));
}
}
2 changes: 1 addition & 1 deletion phenopacket-tools-cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.phenopackets.phenopackettools</groupId>
<artifactId>phenopacket-tools</artifactId>
<version>1.0.0-RC3</version>
<version>1.0.0</version>
</parent>

<artifactId>phenopacket-tools-cli</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"phenopacket-tools (pxf)",
"An application and library for building, conversion, and validation of GA4GH Phenopackets.\n"
},
version = "v1.0.0-RC3",
version = "v1.0.0",
mixinStandardHelpOptions = true,
subcommands = {
// see https://picocli.info/autocomplete.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import com.google.protobuf.MessageOrBuilder;
import org.monarchinitiative.phenol.base.PhenolRuntimeException;
import org.monarchinitiative.phenol.io.OntologyLoader;
import org.monarchinitiative.phenol.ontology.data.Ontology;
import org.monarchinitiative.phenol.io.MinimalOntologyLoader;
import org.monarchinitiative.phenol.ontology.data.MinimalOntology;
import org.monarchinitiative.phenol.ontology.data.TermId;
import org.phenopackets.phenopackettools.core.PhenopacketElement;
import org.phenopackets.phenopackettools.core.PhenopacketSchemaVersion;
Expand Down Expand Up @@ -149,10 +149,10 @@ private <T extends MessageOrBuilder> List<PhenopacketValidator<T>> configureSema
// Right now we only have one semantic validator, but we'll extend this in the future.
LOGGER.debug("Configuring semantic validators");
List<PhenopacketValidator<T>> validators = new ArrayList<>();
Ontology hpo = null;
MinimalOntology hpo = null;
if (validateSection.hpJson != null) {
LOGGER.debug("Reading HPO from {}", validateSection.hpJson.toAbsolutePath());
hpo = OntologyLoader.loadOntology(validateSection.hpJson.toFile());
hpo = MinimalOntologyLoader.loadOntology(validateSection.hpJson.toFile());

// The entire logic of this command stands and falls on correct state of `element` and the read message(s).
// This method requires an appropriate combination of `T` and `element`, as described in Javadoc.
Expand All @@ -163,18 +163,24 @@ private <T extends MessageOrBuilder> List<PhenopacketValidator<T>> configureSema
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Primary.phenopacketHpoPhenotypeValidator(hpo));
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Unique.phenopacketValidator(hpo));
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Ancestry.phenopacketHpoAncestryValidator(hpo));
}
case FAMILY -> {
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Primary.familyHpoPhenotypeValidator(hpo));
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Unique.familyValidator(hpo));
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Ancestry.familyHpoAncestryValidator(hpo));
}
case COHORT -> {
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Primary.cohortHpoPhenotypeValidator(hpo));
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Unique.cohortValidator(hpo));
//noinspection unchecked
validators.add((PhenopacketValidator<T>) HpoPhenotypeValidators.Ancestry.cohortHpoAncestryValidator(hpo));
}
}
Expand All @@ -191,7 +197,7 @@ private <T extends MessageOrBuilder> List<PhenopacketValidator<T>> configureSema
return validators;
}

private static <T extends MessageOrBuilder> PhenopacketValidator<T> prepareOrganSystemValidator(Ontology hpo,
private static <T extends MessageOrBuilder> PhenopacketValidator<T> prepareOrganSystemValidator(MinimalOntology hpo,
List<String> organSystems,
PhenopacketElement element) {
// Organ system validation can only be done when HPO is provided.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.phenopackets.phenopackettools.cli.command.validate;

import com.google.protobuf.MessageOrBuilder;
import org.monarchinitiative.phenol.io.OntologyLoader;
import org.monarchinitiative.phenol.ontology.data.Ontology;
import org.monarchinitiative.phenol.io.MinimalOntologyLoader;
import org.monarchinitiative.phenol.ontology.data.MinimalOntology;
import org.phenopackets.phenopackettools.validator.core.PhenopacketValidator;
import org.phenopackets.phenopackettools.validator.core.ValidationResult;
import org.phenopackets.phenopackettools.validator.core.ValidationResults;
Expand Down Expand Up @@ -109,14 +109,14 @@ protected List<PhenopacketValidator<T>> configureSemanticValidators() {
List<PhenopacketValidator<T>> validators = new ArrayList<>();
if (hpJson != null) {
LOGGER.debug("Reading HPO from '{}}'", hpJson.toAbsolutePath());
Ontology hpo = OntologyLoader.loadOntology(hpJson.toFile());
MinimalOntology hpo = MinimalOntologyLoader.loadOntology(hpJson.toFile());
validators.add(createHpoValidator(hpo));
}

LOGGER.debug("Configured {} semantic validator(s)", validators.size());
return validators;
}

protected abstract PhenopacketValidator<T> createHpoValidator(Ontology hpo);
protected abstract PhenopacketValidator<T> createHpoValidator(MinimalOntology hpo);

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.phenopackets.phenopackettools.cli.command.validate;

import org.monarchinitiative.phenol.ontology.data.Ontology;
import org.monarchinitiative.phenol.ontology.data.MinimalOntology;
import org.phenopackets.phenopackettools.validator.core.PhenopacketValidator;
import org.phenopackets.phenopackettools.validator.core.ValidationWorkflowRunner;
import org.phenopackets.phenopackettools.validator.core.phenotype.HpoPhenotypeValidators;
Expand Down Expand Up @@ -30,7 +30,7 @@ protected ValidationWorkflowRunner<CohortOrBuilder> prepareValidationWorkflow(Li
}

@Override
protected PhenopacketValidator<CohortOrBuilder> createHpoValidator(Ontology hpo) {
protected PhenopacketValidator<CohortOrBuilder> createHpoValidator(MinimalOntology hpo) {
return HpoPhenotypeValidators.cohortHpoPhenotypeValidator(hpo);
}

Expand Down
Loading
Loading