Repository: glotzerlab/signac
Pull request #192 (2019-05-19 19:08:59)

Fix/issue 191
Fixes issue #191.


Patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 149402e2..c1e918b0 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,7 +1,7 @@
 [bumpversion]
 current_version = 1.0.0
 commit = True
-tag = True
+tag = False
 message = Bump up to version {new_version}.
 
 [bumpversion:file:setup.py]
@@ -10,3 +10,6 @@ message = Bump up to version {new_version}.
 
 [bumpversion:file:doc/conf.py]
 
+[bumpversion:file:CITATION.cff]
+
+[bumpversion:file:.zenodo.json]
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 336fdaea..4c584fb7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -93,10 +93,6 @@ jobs:
     <<: *test-template
     docker:
       - image: circleci/python:3.5
-  test-3.4:
-    <<: *test-template
-    docker:
-      - image: circleci/python:3.4
   test-2.7:
     <<: *test-template
     docker:
@@ -159,9 +155,6 @@ workflows:
       - test-2.7:
           requires:
             - style-check
-      - test-3.4:
-          requires:
-            - style-check
       - test-3.5:
           requires:
             - style-check
@@ -187,7 +180,6 @@ workflows:
               only: /release\/.*/
           requires:
             - test-2.7
-            - test-3.4
             - test-3.5
             - test-3.6
             - test-3.7
diff --git a/.sync-zenodo-metadata.py b/.sync-zenodo-metadata.py
new file mode 100755
index 00000000..a870eecb
--- /dev/null
+++ b/.sync-zenodo-metadata.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+"""Synchronize authors and contributor metadata.
+
+This script synchronizes the metadata provided in the CITATION.cff and
+the contributors.yaml file with the metadata stored in the .zenodo.json
+file.
+
+All authors should be listed in the CITATION.cff file, while contributors
+should be listed in the contributors.yaml file.
+Both files use the [citation file-format][1] for [person objects][2].
+
+[1] https://citation-file-format.github.io/
+[2] https://citation-file-format.github.io/1.0.3/specifications/#/person-objects
+"""
+from dataclasses import dataclass
+
+import click
+import json
+from ruamel.yaml import load, Loader
+
+
+@dataclass
+class Contributor:
+    last_names: str
+    first_names: str
+    affiliation: str
+    orcid: str = None
+
+    @classmethod
+    def from_citation_author(cls, **citation):
+        return cls(
+            last_names=citation.pop('family-names'),
+            first_names=citation.pop('given-names'),
+            **citation)
+
+    def as_zenodo_creator(self):
+        ret = dict(
+            name='{} {}'.format(self.first_names, self.last_names),
+            affiliation=self.affiliation)
+        if self.orcid:
+            ret['orcid'] = self.orcid.lstrip('https://orcid.org/')
+        return ret
+
+
+@click.command()
+@click.pass_context
+@click.option('--check', default=False, is_flag=True,
+              help="Return with non-zero exit code if metadata needs to be updated.")
+@click.option('-i', '--in-place', type=bool, is_flag=True,
+              help="Modify metadata in place.")
+def sync(ctx, in_place=False, check=True):
+
+    with open('CITATION.cff', 'rb') as file:
+        citation = load(file.read(), Loader=Loader)
+        authors = [
+            Contributor.from_citation_author(**author)
+            for author in citation['authors']]
+
+    with open('contributors.yaml', 'rb') as file:
+        contributors = load(file.read(), Loader=Loader)['contributors']
+        contributors = [Contributor.from_citation_author(
+            **contributor) for contributor in contributors]
+
+    with open('.zenodo.json', 'rb') as file:
+        zenodo = json.loads(file.read())
+        zenodo_updated = zenodo.copy()
+        zenodo_updated['creators'] = [a.as_zenodo_creator() for a in authors]
+        zenodo_updated['contributors'] = [c.as_zenodo_creator()
+                                          for c in contributors if c not in authors]
+        for key in ('version', 'keywords'):
+            zenodo_updated[key] = citation[key]
+
+    modified = json.dumps(zenodo, sort_keys=True) != json.dumps(zenodo_updated, sort_keys=True)
+    if modified:
+        if in_place:
+            with open('.zenodo.json', 'wb') as file:
+                file.write(json.dumps(zenodo_updated, indent=4, sort_keys=True).encode('utf-8'))
+        else:
+            click.echo(json.dumps(zenodo_updated, indent=4, sort_keys=True))
+        if check:
+            ctx.exit(1)
+    else:
+        click.echo("No changes.", err=True)
+
+
+if __name__ == '__main__':
+    sync()
diff --git a/.zenodo.json b/.zenodo.json
index d8bb1460..b6a46f0d 100644
--- a/.zenodo.json
+++ b/.zenodo.json
@@ -1,44 +1,78 @@
 {
-    "description": "<p>The signac framework aids in the management of large and heterogeneous data spaces. It provides a simple and robust data model to create a well-defined indexable storage layout for data and metadata. This makes it easier to operate on large data spaces, streamlines post-processing and analysis and makes data collectively accessible.</p>",
-    "license": "BSD-3-Clause",
-    "upload_type": "software",
-    "creators": [
+    "contributors": [
         {
             "affiliation": "University of Michigan",
-            "name": "Carl S. Adorf"
+            "name": "Benjamin Swerdlow",
+            "orcid": "0000-0001-6240-1430"
         },
         {
             "affiliation": "University of Michigan",
-            "name": "Paul M. Dodd"
+            "name": "Jens Glaser",
+            "orcid": "0000-0003-1852-3849"
         },
         {
             "affiliation": "University of Michigan",
-            "name": "Vyas Ramasubramani"
+            "name": "Timothy Moore",
+            "orcid": "0000-0002-5709-7259"
         },
         {
             "affiliation": "University of Michigan",
-            "name": "Benjamin Swerdlow"
+            "name": "Yuan Zhou"
         },
         {
-            "affiliation": "University of Michigan",
-            "name": "Jens Glaser"
+            "affiliation": "Air Force Science and Technology Fellowship Program",
+            "name": "Eric Harper",
+            "orcid": "0000-0002-7058-1686"
         },
         {
             "affiliation": "University of Michigan",
-            "name": "Bradley Dice"
+            "name": "Kelly Wang"
         }
     ],
-    "access_right": "open",
-    "related_identifiers": [
+    "creators": [
+        {
+            "affiliation": "University of Michigan",
+            "name": "Carl Simon Adorf",
+            "orcid": "0000-0003-4962-2495"
+        },
+        {
+            "affiliation": "University of Michigan",
+            "name": "Vyas Ramasubramani",
+            "orcid": "0000-0001-5181-9532"
+        },
         {
-            "scheme": "url",
-            "identifier": "https://dx.doi.org/10.1016/j.commatsci.2018.01.035",
-            "relation": "isSupplementedBy"
+            "affiliation": "University of Michigan",
+            "name": "Bradley D. Dice",
+            "orcid": "0000-0002-9983-0770"
+        },
+        {
+            "affiliation": "Boise State University",
+            "name": "Mike Henry",
+            "orcid": "0000-0002-3870-9993"
+        },
+        {
+            "affiliation": "University of Michigan",
+            "name": "Paul M. Dodd"
         },
         {
-            "scheme": "url",
-            "identifier": "arXiv://1611.03543 [cs.DB]",
-            "relation": "isSupplementedBy"
+            "affiliation": "University of Michigan",
+            "name": "Sharon C. Glotzer",
+            "orcid": "0000-0002-7197-0085"
         }
-    ]
-}
+    ],
+    "description": "The signac framework helps users manage and scale file-based workflows, facilitating data reuse, sharing, and reproducibility.\n\nIt provides a simple and robust data model to create a well-defined indexable storage layout for data and metadata. This makes it easier to operate on large data spaces, streamlines post-processing and analysis and makes data collectively accessible.",
+    "doi": "10.5281/zenodo.2581327",
+    "keywords": [
+        "python",
+        "data management",
+        "reproducibility",
+        "sharability",
+        "workflow",
+        "scientific computing"
+    ],
+    "license": {
+        "id": "http://www.opensource.org/licenses/BSD-3-Clause"
+    },
+    "title": "signac",
+    "version": "1.0.0"
+}
\ No newline at end of file
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 00000000..31c4018d
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,87 @@
+# YAML 1.2
+---
+cff-version: "1.0.3"
+title: signac
+version: 1.0.0
+abstract: |
+    The signac framework helps users manage and scale file-based workflows, facilitating data
+    reuse, sharing, and reproducibility. It provides a simple and robust data model to create
+    a well-defined indexable storage layout for data and metadata. This makes it easier to
+    operate on large data spaces, streamlines post-processing and analysis and makes data
+    collectively accessible.
+doi: 10.5281/zenodo.2581327
+authors:
+  -
+    family-names: Adorf
+    given-names: "Carl Simon"
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0003-4962-2495"
+  -
+    family-names: Ramasubramani
+    given-names: Vyas
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0001-5181-9532"
+  -
+    family-names: Dice
+    given-names: "Bradley D."
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0002-9983-0770"
+  -
+    family-names: Henry
+    given-names: Mike
+    affiliation: "Boise State University"
+    orcid: "https://orcid.org/0000-0002-3870-9993"
+  -
+    family-names: Dodd
+    given-names: "Paul M."
+    affiliation: "University of Michigan"
+  -
+    family-names: Glotzer
+    given-names: "Sharon C."
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0002-7197-0085"
+keywords:
+  - python
+  - "data management"
+  - reproducibility
+  - sharability
+  - workflow
+  - "scientific computing"
+license: "http://www.opensource.org/licenses/BSD-3-Clause"
+message: >
+  Development and deployment supported by MICCoM, as part of the Computational
+  Materials Sciences Program funded by the U.S. Department of Energy, Office of
+  Science, Basic Energy Sciences, Materials Sciences and Engineering Division,
+  under Subcontract No. 6F-30844. Project conceptualization and implementation
+  supported by the National Science Foundation, Award # DMR 1409620.
+repository-code: https://github.com/glotzerlab/signac
+references:
+  - type: article
+  - authors:
+    -
+      family-names: Adorf
+      given-names: "Carl Simon"
+      affiliation: "University of Michigan"
+      orcid: "https://orcid.org/0000-0003-4962-2495"
+    -
+      family-names: Dodd
+      given-names: "Paul M."
+      affiliation: "University of Michigan"
+    -
+      family-names: Ramasubramani
+      given-names: Vyas
+      affiliation: "University of Michigan"
+      orcid: "https://orcid.org/0000-0001-5181-9532"
+    -
+      family-names: Glotzer
+      given-names: "Sharon C."
+      affiliation: "University of Michigan"
+      orcid: "https://orcid.org/0000-0002-7197-0085"
+  - title: "Simple data and workflow management with the signac framework"
+  - journal: "Comput. Mater. Sci."
+  - volume: 146
+  - number: C
+  - year: 2018
+  - pages: 9
+  - doi: "10.1016/j.commatsci.2018.01.035"
+...
diff --git a/changelog.txt b/changelog.txt
index 5f2ca6a4..954a8483 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -32,6 +32,7 @@ Fixed
  - Fix: Passing an instance of dict to `H5Store.setdefault()` will return an instance of `H5Group` instead of a dict (#180).
  - Fix error with storing numpy arrays and scalars in a synced dictionary (e.g. `job.statepoint`, `job.document`) (#184).
  - Fix issue with ``ResourceWarning`` originating from unclosed instance of ``Collection`` (#186).
+ - Fix issue with using the ``get_project()`` function with a relative path and ``search=False``.
 
 
 [1.0.0] -- 2019-02-28
diff --git a/contributors.txt b/contributors.txt
deleted file mode 100644
index 921ee79e..00000000
--- a/contributors.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Carl Simon Adorf
-Paul Dodd
-Vyas Ramasubramani
-Benjamin Swerdlow
-Jens Glaser
-Bradley Dice
-Tim Moore
-Pengji Zhou
-Eric Harper
-Mike Henry
-Kelly Wang
diff --git a/contributors.yaml b/contributors.yaml
new file mode 100644
index 00000000..985e092f
--- /dev/null
+++ b/contributors.yaml
@@ -0,0 +1,51 @@
+# YAML 1.2
+---
+contributors:
+  -
+    family-names: Adorf
+    given-names: "Carl Simon"
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0003-4962-2495"
+  -
+    family-names: Dodd
+    given-names: "Paul M."
+    affiliation: "University of Michigan"
+  -
+    family-names: Ramasubramani
+    given-names: Vyas
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0001-5181-9532"
+  -
+    family-names: Swerdlow
+    given-names: Benjamin
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0001-6240-1430"
+  -
+    family-names: Glaser
+    given-names: Jens
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0003-1852-3849"
+  -
+    family-names: Dice
+    given-names: "Bradley D."
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0002-9983-0770"
+  -
+    family-names: Moore
+    given-names: Timothy
+    affiliation: "University of Michigan"
+    orcid: "https://orcid.org/0000-0002-5709-7259"
+  -
+    family-names: Zhou
+    given-names: Yuan
+    affiliation: "University of Michigan"
+  -
+    family-names: Harper
+    given-names: Eric
+    affiliation: "Air Force Science and Technology Fellowship Program"
+    orcid: "https://orcid.org/0000-0002-7058-1686"
+  -
+    family-names: Wang
+    given-names: Kelly
+    affiliation: "University of Michigan"
+...
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 16091bde..6c1c4157 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -6,3 +6,5 @@ pandas==0.23; python_version>'3.4' and implementation_name=='cpython'
 h5py==2.9; implementation_name!='cpython' --no-binary h5py
 h5py==2.9; implementation_name=='cpython'
 tables==3.4.4
+click>=7.0
+ruamel.yaml>=0.15.89
diff --git a/setup.py b/setup.py
index c1862c5a..7fb30dd2 100644
--- a/setup.py
+++ b/setup.py
@@ -32,7 +32,6 @@ setup(
         "Topic :: Database",
         "Topic :: Scientific/Engineering :: Physics",
         "Programming Language :: Python :: 2.7",
-        "Programming Language :: Python :: 3.4",
         "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
diff --git a/signac/contrib/project.py b/signac/contrib/project.py
index d554d36c..987e6cc9 100644
--- a/signac/contrib/project.py
+++ b/signac/contrib/project.py
@@ -1495,7 +1495,8 @@ class Project(object):
         if root is None:
             root = os.getcwd()
         config = load_config(root=root, local=False)
-        if 'project' not in config or (not search and config['project_dir'] != root):
+        if 'project' not in config or \
+                (not search and os.path.realpath(config['project_dir']) != os.path.realpath(root)):
             raise LookupError(
                 "Unable to determine project id for path '{}'.".format(os.path.abspath(root)))
         return cls(config=config)


Test patch:
diff --git a/tests/test_project.py b/tests/test_project.py
index 5a93c22e..ec422ef9 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -1798,6 +1798,10 @@ class ProjectInitTest(unittest.TestCase):
         project = signac.init_project(root=root, name='testproject')
         self.assertEqual(project, project.get_project(root=root))
         self.assertEqual(project, signac.get_project(root=root))
+        self.assertEqual(project, project.get_project(root=root, search=False))
+        self.assertEqual(project, signac.get_project(root=root, search=False))
+        self.assertEqual(project, project.get_project(root=os.path.relpath(root), search=False))
+        self.assertEqual(project, signac.get_project(root=os.path.relpath(root), search=False))
         with self.assertRaises(LookupError):
             self.assertEqual(project, project.get_project(root=subdir, search=False))
         with self.assertRaises(LookupError):