We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
BIDS Validator data not installed
When installing pybids through pip using an archive (e.g. tarball, zip, instead of from github with `-e`), the data for the `BIDSValidator` is not installed, causing `BIDSLayout` to fail initating
```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/dist-packages/bids/layout/layout.py", line 143, in __init__
    **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/grabbit/core.py", line 419, in __init__
    self.index()
  File "/usr/local/lib/python3.6/dist-packages/grabbit/core.py", line 610, in index
    _index_dir(path, list(domains))
  File "/usr/local/lib/python3.6/dist-packages/grabbit/core.py", line 603, in _index_dir
    elif self._validate_file(full_path):
  File "/usr/local/lib/python3.6/dist-packages/bids/layout/layout.py", line 204, in _validate_file
    return self.validator.is_bids(to_check)
  File "/usr/local/lib/python3.6/dist-packages/bids/layout/validation.py", line 64, in is_bids
    conditions.append(self.is_top_level(path))
  File "/usr/local/lib/python3.6/dist-packages/bids/layout/validation.py", line 75, in is_top_level
    with open(join(self.rule_dir, 'fixed_top_level_names.json'), 'r') as f:
FileNotFoundError: [Errno 2] No such file or directory: '/usr/local/lib/python3.6/dist-packages/bids/layout/config/validator/fixed_top_level_names.json'
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bids/version.py`
Content:
```
1 from __future__ import absolute_import, division, print_function
2 import os
3 
4 CLASSIFIERS = ["Development Status :: 3 - Alpha",
5                "Environment :: Console",
6                "Intended Audience :: Science/Research",
7                "License :: OSI Approved :: MIT License",
8                "Operating System :: OS Independent",
9                "Programming Language :: Python",
10                "Topic :: Scientific/Engineering"]
11 
12 # Description should be a one-liner:
13 description = "bids: interface with datasets conforming BIDS"
14 # Long description will go up on the pypi page
15 long_description = """
16 
17 PyBIDS
18 ======
19 PyBIDS is a Python module to interface with datasets conforming BIDS.
20 See BIDS paper_ and http://bids.neuroimaging.io website for more information.
21 
22 .. paper_: http://www.nature.com/articles/sdata201644
23 
24 License
25 =======
26 ``pybids`` is licensed under the terms of the MIT license. See the file
27 "LICENSE" for information on the history of this software, terms & conditions
28 for usage, and a DISCLAIMER OF ALL WARRANTIES.
29 
30 All trademarks referenced herein are property of their respective holders.
31 
32 Copyright (c) 2016--, PyBIDS developers, Planet Earth
33 
34 """
35 
36 NAME = "pybids"
37 MAINTAINER = "PyBIDS Developers"
38 MAINTAINER_EMAIL = "bids-discussion@googlegroups.com"
39 DESCRIPTION = description
40 LONG_DESCRIPTION = long_description
41 URL = "http://github.com/bids-standard/pybids"
42 DOWNLOAD_URL = ""
43 LICENSE = "MIT"
44 AUTHOR = "PyBIDS developers"
45 AUTHOR_EMAIL = "bids-discussion@googlegroups.com"
46 PLATFORMS = "OS Independent"
47 # No data for now
48 REQUIRES = ["grabbit==0.2.4", "six", "num2words", "numpy", "scipy", "pandas",
49             "nibabel", "patsy"]
50 EXTRAS_REQUIRE = {
51    # Just to not break compatibility with externals requiring
52    # now deprecated installation schemes
53    'analysis': []
54 }
55 TESTS_REQUIRE = ["pytest>=3.3.0"]
56 
57 
58 def package_files(directory):
59     # from https://stackoverflow.com/questions/27664504/how-to-add-package-data-recursively-in-python-setup-py
60     paths = []
61     for (path, directories, filenames) in os.walk(directory):
62         for filename in filenames:
63             paths.append(os.path.join('..', path, filename))
64     return paths
65 
66 extra_files = package_files('path_to/extra_files_dir')
67 PACKAGE_DATA = {
68     'bids.layout': ['config/*.json'],
69     'bids.reports': ['config/*.json'],
70     'bids': package_files('bids/tests/data')
71 }
72
```

Path: `bids/layout/validation.py`
Content:
```
1 """Tools for validating BIDS projects."""
2 
3 import re
4 import json
5 from os.path import join, abspath, dirname
6 
7 __all__ = ['BIDSValidator']
8 
9 
10 class BIDSValidator():
11     """An object for BIDS (Brain Imaging Data Structure) verification in a data.
12 
13     The main method of this class is `is_bids()`. You should use it for
14     checking whether a file path compatible with BIDS.
15 
16     Parameters
17     ----------
18     index_associated : bool, default: True
19         Specifies if an associated data should be checked. If it is true then
20         any file paths in directories `code/`, `derivatives/`, `sourcedata/`
21         and `stimuli/` will pass the validation, else they won't.
22 
23     Examples
24     --------
25     >>> from bids.grabbids import BIDSValidator
26     >>> validator = BIDSValidator()
27     >>> filepaths = ["/sub-01/anat/sub-01_rec-CSD_T1w.nii.gz",
28     >>> "/sub-01/anat/sub-01_acq-23_rec-CSD_T1w.exe", #wrong extension
29     >>> "/participants.tsv"]
30     >>> for filepath in filepaths:
31     >>>     print( validator.is_bids(filepath) )
32     True
33     False
34     True
35     """
36 
37     def __init__(self, index_associated=True):
38         self.rule_dir = join(dirname(abspath(__file__)), 'config',
39                               'validator')
40         self.index_associated = index_associated
41 
42     def is_bids(self, path):
43         """Check if a file path appropriate for BIDS.
44 
45         Main method of the validator. uses other class methods for checking
46         different aspects of the file path.
47 
48         Parameters
49         ----------
50             path: string
51                 A path of a file you want to check.
52 
53         Examples
54         --------
55         >>> from bids.grabbids import BIDSValidator
56         >>> validator = BIDSValidator()
57         >>> validator.is_bids("/sub-01/ses-test/anat/sub-01_ses-test_rec-CSD_run-23_T1w.nii.gz")
58         True
59         >>> validator.is_bids("/sub-01/ses-test/sub-01_run-01_dwi.bvec") # missed session in the filename
60         False
61         """
62         conditions = []
63 
64         conditions.append(self.is_top_level(path))
65         conditions.append(self.is_associated_data(path))
66         conditions.append(self.is_session_level(path))
67         conditions.append(self.is_subject_level(path))
68         conditions.append(self.is_phenotypic(path))
69         conditions.append(self.is_file(path))
70 
71         return (any(conditions))
72 
73     def is_top_level(self, path):
74         """Check if the file has appropriate name for a top-level file."""
75         with open(join(self.rule_dir, 'fixed_top_level_names.json'), 'r') as f:
76             fixed_top_level_json = json.load(f)
77             fixed_top_level_names = fixed_top_level_json['fixed_top_level_names']
78 
79         regexps = self.get_regular_expressions('top_level_rules.json')
80 
81         conditions = [False if re.compile(x).search(path) is None else True
82                       for x in regexps]
83 
84         conditions.append(path in fixed_top_level_names)
85 
86         return (any(conditions))
87 
88     def is_associated_data(self, path):
89         """Check if file is appropriate associated data."""
90         if not self.index_associated:
91             return False
92 
93         regexps = self.get_regular_expressions('associated_data_rules.json')
94 
95         conditions = [(re.compile(x).search(path) is not None)
96                       for x in regexps]
97 
98         return any(conditions)
99 
100     def is_session_level(self, path):
101         """Check if the file has appropriate name for a session level."""
102         regexps = self.get_regular_expressions('session_level_rules.json')
103 
104         conditions = [self.conditional_match(x, path) for x in regexps]
105 
106         return (any(conditions))
107 
108     def is_subject_level(self, path):
109         """Check if the file has appropriate name for a subject level."""
110         regexps = self.get_regular_expressions('subject_level_rules.json')
111 
112         conditions = [(re.compile(x).search(path) is not None)
113                       for x in regexps]
114 
115         return (any(conditions))
116 
117     def is_phenotypic(self, path):
118         """Check if file is phenotypic data."""
119         regexps = self.get_regular_expressions('phenotypic_rules.json')
120 
121         conditions = [(re.compile(x).search(path) is not None)
122                       for x in regexps]
123 
124         return (any(conditions))
125 
126     def is_file(self, path):
127         """Check if file is phenotypic data."""
128         regexps = self.get_regular_expressions('file_level_rules.json')
129 
130         conditions = [(re.compile(x).search(path) is not None)
131                       for x in regexps]
132 
133         return (any(conditions))
134 
135     def get_regular_expressions(self, filename):
136         """Get regular expressions from file."""
137         regexps = []
138 
139         filename = join(self.rule_dir, filename)
140 
141         with open(filename, 'r') as f:
142             rules = json.load(f)
143 
144         for key in list(rules.keys()):
145             rule = rules[key]
146 
147             regexp = rule["regexp"]
148 
149             if "tokens" in rule:
150                 tokens = rule["tokens"]
151 
152                 for token in list(tokens):
153                     regexp = regexp.replace(token, "|".join(tokens[token]))
154 
155             regexps.append(regexp)
156 
157         return regexps
158 
159     def get_path_values(self, path):
160         """Takes a file path and returns values found for the following path
161         keys:
162             sub-
163             ses-
164         """
165         values = {}
166 
167         regexps = self.get_regular_expressions('path.json')
168 
169         # capture subject
170         for paths in ['sub', 'ses']:
171             match = re.compile(regexps[paths]).findall(path)
172             values[paths] = match[1] if match & match[1] else None
173 
174         return values
175 
176     def conditional_match(self, expression, path):
177         match = re.compile(expression).findall(path)
178         match = match[0] if len(match) >= 1 else False
179         # adapted from JS code and JS does not support conditional groups
180         if (match):
181             return ((match[1] == match[2][1:]) | (not match[1]))
182         else:
183             return False
184
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bids/layout/validation.py b/bids/layout/validation.py
--- a/bids/layout/validation.py
+++ b/bids/layout/validation.py
@@ -35,8 +35,7 @@
     """
 
     def __init__(self, index_associated=True):
-        self.rule_dir = join(dirname(abspath(__file__)), 'config',
-                              'validator')
+        self.rule_dir = join(dirname(abspath(__file__)),'config', 'validator')
         self.index_associated = index_associated
 
     def is_bids(self, path):
diff --git a/bids/version.py b/bids/version.py
--- a/bids/version.py
+++ b/bids/version.py
@@ -65,7 +65,7 @@
 
 extra_files = package_files('path_to/extra_files_dir')
 PACKAGE_DATA = {
-    'bids.layout': ['config/*.json'],
+    'bids.layout': ['config/*.json', 'config/validator/*.json'],
     'bids.reports': ['config/*.json'],
     'bids': package_files('bids/tests/data')
 }

{"golden_diff": "diff --git a/bids/layout/validation.py b/bids/layout/validation.py\n--- a/bids/layout/validation.py\n+++ b/bids/layout/validation.py\n@@ -35,8 +35,7 @@\n     \"\"\"\n \n     def __init__(self, index_associated=True):\n-        self.rule_dir = join(dirname(abspath(__file__)), 'config',\n-                              'validator')\n+        self.rule_dir = join(dirname(abspath(__file__)),'config', 'validator')\n         self.index_associated = index_associated\n \n     def is_bids(self, path):\ndiff --git a/bids/version.py b/bids/version.py\n--- a/bids/version.py\n+++ b/bids/version.py\n@@ -65,7 +65,7 @@\n \n extra_files = package_files('path_to/extra_files_dir')\n PACKAGE_DATA = {\n-    'bids.layout': ['config/*.json'],\n+    'bids.layout': ['config/*.json', 'config/validator/*.json'],\n     'bids.reports': ['config/*.json'],\n     'bids': package_files('bids/tests/data')\n }\n", "issue": "BIDS Validator data not installed\nWhen installing pybids through pip using an archive (e.g. tarball, zip, instead of from github with `-e`), the data for the `BIDSValidator` is not installed, causing `BIDSLayout` to fail initating\r\n```\r\nTraceback (most recent call last):\r\n  File \"<stdin>\", line 1, in <module>\r\n  File \"/usr/local/lib/python3.6/dist-packages/bids/layout/layout.py\", line 143, in __init__\r\n    **kwargs)\r\n  File \"/usr/local/lib/python3.6/dist-packages/grabbit/core.py\", line 419, in __init__\r\n    self.index()\r\n  File \"/usr/local/lib/python3.6/dist-packages/grabbit/core.py\", line 610, in index\r\n    _index_dir(path, list(domains))\r\n  File \"/usr/local/lib/python3.6/dist-packages/grabbit/core.py\", line 603, in _index_dir\r\n    elif self._validate_file(full_path):\r\n  File \"/usr/local/lib/python3.6/dist-packages/bids/layout/layout.py\", line 204, in _validate_file\r\n    return self.validator.is_bids(to_check)\r\n  File \"/usr/local/lib/python3.6/dist-packages/bids/layout/validation.py\", line 64, in is_bids\r\n    conditions.append(self.is_top_level(path))\r\n  File \"/usr/local/lib/python3.6/dist-packages/bids/layout/validation.py\", line 75, in is_top_level\r\n    with open(join(self.rule_dir, 'fixed_top_level_names.json'), 'r') as f:\r\nFileNotFoundError: [Errno 2] No such file or directory: '/usr/local/lib/python3.6/dist-packages/bids/layout/config/validator/fixed_top_level_names.json'\r\n```\n", "before_files": [{"content": "from __future__ import absolute_import, division, print_function\nimport os\n\nCLASSIFIERS = [\"Development Status :: 3 - Alpha\",\n               \"Environment :: Console\",\n               \"Intended Audience :: Science/Research\",\n               \"License :: OSI Approved :: MIT License\",\n               \"Operating System :: OS Independent\",\n               \"Programming Language :: Python\",\n               \"Topic :: Scientific/Engineering\"]\n\n# Description should be a one-liner:\ndescription = \"bids: interface with datasets conforming BIDS\"\n# Long description will go up on the pypi page\nlong_description = \"\"\"\n\nPyBIDS\n======\nPyBIDS is a Python module to interface with datasets conforming BIDS.\nSee BIDS paper_ and http://bids.neuroimaging.io website for more information.\n\n.. paper_: http://www.nature.com/articles/sdata201644\n\nLicense\n=======\n``pybids`` is licensed under the terms of the MIT license. See the file\n\"LICENSE\" for information on the history of this software, terms & conditions\nfor usage, and a DISCLAIMER OF ALL WARRANTIES.\n\nAll trademarks referenced herein are property of their respective holders.\n\nCopyright (c) 2016--, PyBIDS developers, Planet Earth\n\n\"\"\"\n\nNAME = \"pybids\"\nMAINTAINER = \"PyBIDS Developers\"\nMAINTAINER_EMAIL = \"bids-discussion@googlegroups.com\"\nDESCRIPTION = description\nLONG_DESCRIPTION = long_description\nURL = \"http://github.com/bids-standard/pybids\"\nDOWNLOAD_URL = \"\"\nLICENSE = \"MIT\"\nAUTHOR = \"PyBIDS developers\"\nAUTHOR_EMAIL = \"bids-discussion@googlegroups.com\"\nPLATFORMS = \"OS Independent\"\n# No data for now\nREQUIRES = [\"grabbit==0.2.4\", \"six\", \"num2words\", \"numpy\", \"scipy\", \"pandas\",\n            \"nibabel\", \"patsy\"]\nEXTRAS_REQUIRE = {\n   # Just to not break compatibility with externals requiring\n   # now deprecated installation schemes\n   'analysis': []\n}\nTESTS_REQUIRE = [\"pytest>=3.3.0\"]\n\n\ndef package_files(directory):\n    # from https://stackoverflow.com/questions/27664504/how-to-add-package-data-recursively-in-python-setup-py\n    paths = []\n    for (path, directories, filenames) in os.walk(directory):\n        for filename in filenames:\n            paths.append(os.path.join('..', path, filename))\n    return paths\n\nextra_files = package_files('path_to/extra_files_dir')\nPACKAGE_DATA = {\n    'bids.layout': ['config/*.json'],\n    'bids.reports': ['config/*.json'],\n    'bids': package_files('bids/tests/data')\n}\n", "path": "bids/version.py"}, {"content": "\"\"\"Tools for validating BIDS projects.\"\"\"\n\nimport re\nimport json\nfrom os.path import join, abspath, dirname\n\n__all__ = ['BIDSValidator']\n\n\nclass BIDSValidator():\n    \"\"\"An object for BIDS (Brain Imaging Data Structure) verification in a data.\n\n    The main method of this class is `is_bids()`. You should use it for\n    checking whether a file path compatible with BIDS.\n\n    Parameters\n    ----------\n    index_associated : bool, default: True\n        Specifies if an associated data should be checked. If it is true then\n        any file paths in directories `code/`, `derivatives/`, `sourcedata/`\n        and `stimuli/` will pass the validation, else they won't.\n\n    Examples\n    --------\n    >>> from bids.grabbids import BIDSValidator\n    >>> validator = BIDSValidator()\n    >>> filepaths = [\"/sub-01/anat/sub-01_rec-CSD_T1w.nii.gz\",\n    >>> \"/sub-01/anat/sub-01_acq-23_rec-CSD_T1w.exe\", #wrong extension\n    >>> \"/participants.tsv\"]\n    >>> for filepath in filepaths:\n    >>>     print( validator.is_bids(filepath) )\n    True\n    False\n    True\n    \"\"\"\n\n    def __init__(self, index_associated=True):\n        self.rule_dir = join(dirname(abspath(__file__)), 'config',\n                              'validator')\n        self.index_associated = index_associated\n\n    def is_bids(self, path):\n        \"\"\"Check if a file path appropriate for BIDS.\n\n        Main method of the validator. uses other class methods for checking\n        different aspects of the file path.\n\n        Parameters\n        ----------\n            path: string\n                A path of a file you want to check.\n\n        Examples\n        --------\n        >>> from bids.grabbids import BIDSValidator\n        >>> validator = BIDSValidator()\n        >>> validator.is_bids(\"/sub-01/ses-test/anat/sub-01_ses-test_rec-CSD_run-23_T1w.nii.gz\")\n        True\n        >>> validator.is_bids(\"/sub-01/ses-test/sub-01_run-01_dwi.bvec\") # missed session in the filename\n        False\n        \"\"\"\n        conditions = []\n\n        conditions.append(self.is_top_level(path))\n        conditions.append(self.is_associated_data(path))\n        conditions.append(self.is_session_level(path))\n        conditions.append(self.is_subject_level(path))\n        conditions.append(self.is_phenotypic(path))\n        conditions.append(self.is_file(path))\n\n        return (any(conditions))\n\n    def is_top_level(self, path):\n        \"\"\"Check if the file has appropriate name for a top-level file.\"\"\"\n        with open(join(self.rule_dir, 'fixed_top_level_names.json'), 'r') as f:\n            fixed_top_level_json = json.load(f)\n            fixed_top_level_names = fixed_top_level_json['fixed_top_level_names']\n\n        regexps = self.get_regular_expressions('top_level_rules.json')\n\n        conditions = [False if re.compile(x).search(path) is None else True\n                      for x in regexps]\n\n        conditions.append(path in fixed_top_level_names)\n\n        return (any(conditions))\n\n    def is_associated_data(self, path):\n        \"\"\"Check if file is appropriate associated data.\"\"\"\n        if not self.index_associated:\n            return False\n\n        regexps = self.get_regular_expressions('associated_data_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return any(conditions)\n\n    def is_session_level(self, path):\n        \"\"\"Check if the file has appropriate name for a session level.\"\"\"\n        regexps = self.get_regular_expressions('session_level_rules.json')\n\n        conditions = [self.conditional_match(x, path) for x in regexps]\n\n        return (any(conditions))\n\n    def is_subject_level(self, path):\n        \"\"\"Check if the file has appropriate name for a subject level.\"\"\"\n        regexps = self.get_regular_expressions('subject_level_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return (any(conditions))\n\n    def is_phenotypic(self, path):\n        \"\"\"Check if file is phenotypic data.\"\"\"\n        regexps = self.get_regular_expressions('phenotypic_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return (any(conditions))\n\n    def is_file(self, path):\n        \"\"\"Check if file is phenotypic data.\"\"\"\n        regexps = self.get_regular_expressions('file_level_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return (any(conditions))\n\n    def get_regular_expressions(self, filename):\n        \"\"\"Get regular expressions from file.\"\"\"\n        regexps = []\n\n        filename = join(self.rule_dir, filename)\n\n        with open(filename, 'r') as f:\n            rules = json.load(f)\n\n        for key in list(rules.keys()):\n            rule = rules[key]\n\n            regexp = rule[\"regexp\"]\n\n            if \"tokens\" in rule:\n                tokens = rule[\"tokens\"]\n\n                for token in list(tokens):\n                    regexp = regexp.replace(token, \"|\".join(tokens[token]))\n\n            regexps.append(regexp)\n\n        return regexps\n\n    def get_path_values(self, path):\n        \"\"\"Takes a file path and returns values found for the following path\n        keys:\n            sub-\n            ses-\n        \"\"\"\n        values = {}\n\n        regexps = self.get_regular_expressions('path.json')\n\n        # capture subject\n        for paths in ['sub', 'ses']:\n            match = re.compile(regexps[paths]).findall(path)\n            values[paths] = match[1] if match & match[1] else None\n\n        return values\n\n    def conditional_match(self, expression, path):\n        match = re.compile(expression).findall(path)\n        match = match[0] if len(match) >= 1 else False\n        # adapted from JS code and JS does not support conditional groups\n        if (match):\n            return ((match[1] == match[2][1:]) | (not match[1]))\n        else:\n            return False\n", "path": "bids/layout/validation.py"}], "after_files": [{"content": "from __future__ import absolute_import, division, print_function\nimport os\n\nCLASSIFIERS = [\"Development Status :: 3 - Alpha\",\n               \"Environment :: Console\",\n               \"Intended Audience :: Science/Research\",\n               \"License :: OSI Approved :: MIT License\",\n               \"Operating System :: OS Independent\",\n               \"Programming Language :: Python\",\n               \"Topic :: Scientific/Engineering\"]\n\n# Description should be a one-liner:\ndescription = \"bids: interface with datasets conforming BIDS\"\n# Long description will go up on the pypi page\nlong_description = \"\"\"\n\nPyBIDS\n======\nPyBIDS is a Python module to interface with datasets conforming BIDS.\nSee BIDS paper_ and http://bids.neuroimaging.io website for more information.\n\n.. paper_: http://www.nature.com/articles/sdata201644\n\nLicense\n=======\n``pybids`` is licensed under the terms of the MIT license. See the file\n\"LICENSE\" for information on the history of this software, terms & conditions\nfor usage, and a DISCLAIMER OF ALL WARRANTIES.\n\nAll trademarks referenced herein are property of their respective holders.\n\nCopyright (c) 2016--, PyBIDS developers, Planet Earth\n\n\"\"\"\n\nNAME = \"pybids\"\nMAINTAINER = \"PyBIDS Developers\"\nMAINTAINER_EMAIL = \"bids-discussion@googlegroups.com\"\nDESCRIPTION = description\nLONG_DESCRIPTION = long_description\nURL = \"http://github.com/bids-standard/pybids\"\nDOWNLOAD_URL = \"\"\nLICENSE = \"MIT\"\nAUTHOR = \"PyBIDS developers\"\nAUTHOR_EMAIL = \"bids-discussion@googlegroups.com\"\nPLATFORMS = \"OS Independent\"\n# No data for now\nREQUIRES = [\"grabbit==0.2.4\", \"six\", \"num2words\", \"numpy\", \"scipy\", \"pandas\",\n            \"nibabel\", \"patsy\"]\nEXTRAS_REQUIRE = {\n   # Just to not break compatibility with externals requiring\n   # now deprecated installation schemes\n   'analysis': []\n}\nTESTS_REQUIRE = [\"pytest>=3.3.0\"]\n\n\ndef package_files(directory):\n    # from https://stackoverflow.com/questions/27664504/how-to-add-package-data-recursively-in-python-setup-py\n    paths = []\n    for (path, directories, filenames) in os.walk(directory):\n        for filename in filenames:\n            paths.append(os.path.join('..', path, filename))\n    return paths\n\nextra_files = package_files('path_to/extra_files_dir')\nPACKAGE_DATA = {\n    'bids.layout': ['config/*.json', 'config/validator/*.json'],\n    'bids.reports': ['config/*.json'],\n    'bids': package_files('bids/tests/data')\n}\n", "path": "bids/version.py"}, {"content": "\"\"\"Tools for validating BIDS projects.\"\"\"\n\nimport re\nimport json\nfrom os.path import join, abspath, dirname\n\n__all__ = ['BIDSValidator']\n\n\nclass BIDSValidator():\n    \"\"\"An object for BIDS (Brain Imaging Data Structure) verification in a data.\n\n    The main method of this class is `is_bids()`. You should use it for\n    checking whether a file path compatible with BIDS.\n\n    Parameters\n    ----------\n    index_associated : bool, default: True\n        Specifies if an associated data should be checked. If it is true then\n        any file paths in directories `code/`, `derivatives/`, `sourcedata/`\n        and `stimuli/` will pass the validation, else they won't.\n\n    Examples\n    --------\n    >>> from bids.grabbids import BIDSValidator\n    >>> validator = BIDSValidator()\n    >>> filepaths = [\"/sub-01/anat/sub-01_rec-CSD_T1w.nii.gz\",\n    >>> \"/sub-01/anat/sub-01_acq-23_rec-CSD_T1w.exe\", #wrong extension\n    >>> \"/participants.tsv\"]\n    >>> for filepath in filepaths:\n    >>>     print( validator.is_bids(filepath) )\n    True\n    False\n    True\n    \"\"\"\n\n    def __init__(self, index_associated=True):\n        self.rule_dir = join(dirname(abspath(__file__)),'config', 'validator')\n        self.index_associated = index_associated\n\n    def is_bids(self, path):\n        \"\"\"Check if a file path appropriate for BIDS.\n\n        Main method of the validator. uses other class methods for checking\n        different aspects of the file path.\n\n        Parameters\n        ----------\n            path: string\n                A path of a file you want to check.\n\n        Examples\n        --------\n        >>> from bids.grabbids import BIDSValidator\n        >>> validator = BIDSValidator()\n        >>> validator.is_bids(\"/sub-01/ses-test/anat/sub-01_ses-test_rec-CSD_run-23_T1w.nii.gz\")\n        True\n        >>> validator.is_bids(\"/sub-01/ses-test/sub-01_run-01_dwi.bvec\") # missed session in the filename\n        False\n        \"\"\"\n        conditions = []\n\n        conditions.append(self.is_top_level(path))\n        conditions.append(self.is_associated_data(path))\n        conditions.append(self.is_session_level(path))\n        conditions.append(self.is_subject_level(path))\n        conditions.append(self.is_phenotypic(path))\n        conditions.append(self.is_file(path))\n\n        return (any(conditions))\n\n    def is_top_level(self, path):\n        \"\"\"Check if the file has appropriate name for a top-level file.\"\"\"\n        with open(join(self.rule_dir, 'fixed_top_level_names.json'), 'r') as f:\n            fixed_top_level_json = json.load(f)\n            fixed_top_level_names = fixed_top_level_json['fixed_top_level_names']\n\n        regexps = self.get_regular_expressions('top_level_rules.json')\n\n        conditions = [False if re.compile(x).search(path) is None else True\n                      for x in regexps]\n\n        conditions.append(path in fixed_top_level_names)\n\n        return (any(conditions))\n\n    def is_associated_data(self, path):\n        \"\"\"Check if file is appropriate associated data.\"\"\"\n        if not self.index_associated:\n            return False\n\n        regexps = self.get_regular_expressions('associated_data_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return any(conditions)\n\n    def is_session_level(self, path):\n        \"\"\"Check if the file has appropriate name for a session level.\"\"\"\n        regexps = self.get_regular_expressions('session_level_rules.json')\n\n        conditions = [self.conditional_match(x, path) for x in regexps]\n\n        return (any(conditions))\n\n    def is_subject_level(self, path):\n        \"\"\"Check if the file has appropriate name for a subject level.\"\"\"\n        regexps = self.get_regular_expressions('subject_level_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return (any(conditions))\n\n    def is_phenotypic(self, path):\n        \"\"\"Check if file is phenotypic data.\"\"\"\n        regexps = self.get_regular_expressions('phenotypic_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return (any(conditions))\n\n    def is_file(self, path):\n        \"\"\"Check if file is phenotypic data.\"\"\"\n        regexps = self.get_regular_expressions('file_level_rules.json')\n\n        conditions = [(re.compile(x).search(path) is not None)\n                      for x in regexps]\n\n        return (any(conditions))\n\n    def get_regular_expressions(self, filename):\n        \"\"\"Get regular expressions from file.\"\"\"\n        regexps = []\n\n        filename = join(self.rule_dir, filename)\n\n        with open(filename, 'r') as f:\n            rules = json.load(f)\n\n        for key in list(rules.keys()):\n            rule = rules[key]\n\n            regexp = rule[\"regexp\"]\n\n            if \"tokens\" in rule:\n                tokens = rule[\"tokens\"]\n\n                for token in list(tokens):\n                    regexp = regexp.replace(token, \"|\".join(tokens[token]))\n\n            regexps.append(regexp)\n\n        return regexps\n\n    def get_path_values(self, path):\n        \"\"\"Takes a file path and returns values found for the following path\n        keys:\n            sub-\n            ses-\n        \"\"\"\n        values = {}\n\n        regexps = self.get_regular_expressions('path.json')\n\n        # capture subject\n        for paths in ['sub', 'ses']:\n            match = re.compile(regexps[paths]).findall(path)\n            values[paths] = match[1] if match & match[1] else None\n\n        return values\n\n    def conditional_match(self, expression, path):\n        match = re.compile(expression).findall(path)\n        match = match[0] if len(match) >= 1 else False\n        # adapted from JS code and JS does not support conditional groups\n        if (match):\n            return ((match[1] == match[2][1:]) | (not match[1]))\n        else:\n            return False\n", "path": "bids/layout/validation.py"}]}