prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Build filename parser utility function
  It would be useful to have a function in the `utils.py` module that returned the individual elements of a given filename, for example:
  
  ```python
  from jwql.utils.utils import parse_filename
  filename_dict = parse_filename('jw94015001001_02102_00001_nrcb1_uncal.fits')
  ```
  
  where `filename_dict` is:
  
  ```
  {
      'program_id' : '94015',
      'observation' : '001',
      'visit' : '001',
      'visit_group' : '02',
      'parallel_seq_id' : '1',
      'activity' : '02',
      'exposure_id' : '00001',
      'detector' : 'nrcb1',
      'suffix' : 'uncal'
  }
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `jwql/utils/utils.py`
  Content:
  ```
  1 """Various utility functions for the jwql project.
  2 
  3 Authors
  4 -------
  5 
  6     Matthew Bourque
  7 
  8 Use
  9 ---
  10 
  11     This module can be imported as such:
  12 
  13     >>> import utils
  14     settings = get_config()
  15 """
  16 
  17 import json
  18 
  19 
  20 def get_config():
  21     """Return a dictionary that holds the contents of the jwql config
  22     file.
  23 
  24     Returns
  25     -------
  26     settings : dict
  27         A dictionary that holds the contents of the config file.
  28     """
  29 
  30     with open('config.json', 'r') as config_file:
  31         settings = json.load(config_file)
  32 
  33     return settings
  34
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/jwql/utils/utils.py b/jwql/utils/utils.py
  --- a/jwql/utils/utils.py
  +++ b/jwql/utils/utils.py
  @@ -3,7 +3,8 @@
   Authors
   -------
   
  -    Matthew Bourque
  +    - Matthew Bourque
  +    - Lauren Chambers
   
   Use
   ---
  @@ -12,9 +13,19 @@
   
       >>> import utils
       settings = get_config()
  +
  +References
  +----------
  +
  +    Filename parser modifed from Joe Hunkeler:
  +    https://gist.github.com/jhunkeler/f08783ca2da7bfd1f8e9ee1d207da5ff
   """
   
   import json
  +import os
  +import re
  +
  +__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
   
   
   def get_config():
  @@ -27,7 +38,50 @@
           A dictionary that holds the contents of the config file.
       """
   
  -    with open('config.json', 'r') as config_file:
  +    with open(os.path.join(__location__, 'config.json'), 'r') as config_file:
           settings = json.load(config_file)
   
       return settings
  +
  +
  +def filename_parser(filename):
  +    """Return a dictionary that contains the properties of a given
  +    JWST file (e.g. program ID, visit number, detector, etc.)
  +
  +    Parameters
  +    ----------
  +    filename : str
  +        Path or name of JWST file to parse
  +
  +    Returns
  +    -------
  +    filename_dict : dict
  +        Collection of file properties
  +
  +    Raises
  +    ------
  +    ValueError
  +        When the provided file does not follow naming conventions
  +    """
  +    filename = os.path.basename(filename)
  +
  +    elements = \
  +        re.compile(r"[a-z]+"
  +                   "(?P<program_id>\d{5})"
  +                   "(?P<observation>\d{3})"
  +                   "(?P<visit>\d{3})"
  +                   "_(?P<visit_group>\d{2})"
  +                   "(?P<parallel_seq_id>\d{1})"
  +                   "(?P<activity>\d{2})"
  +                   "_(?P<exposure_id>\d+)"
  +                   "_(?P<detector>\w+)"
  +                   "_(?P<suffix>\w+).*")
  +
  +    jwst_file = elements.match(filename)
  +
  +    if jwst_file is not None:
  +        filename_dict = jwst_file.groupdict()
  +    else:
  +        raise ValueError('Provided file {} does not follow JWST naming conventions (jw<PPPPP><OOO><VVV>_<GGSAA>_<EEEEE>_<detector>_<suffix>.fits)'.format(filename))
  +
  +    return filename_dict
  
verification_info: {"golden_diff": "diff --git a/jwql/utils/utils.py b/jwql/utils/utils.py\n--- a/jwql/utils/utils.py\n+++ b/jwql/utils/utils.py\n@@ -3,7 +3,8 @@\n Authors\n -------\n \n-    Matthew Bourque\n+    - Matthew Bourque\n+    - Lauren Chambers\n \n Use\n ---\n@@ -12,9 +13,19 @@\n \n     >>> import utils\n     settings = get_config()\n+\n+References\n+----------\n+\n+    Filename parser modifed from Joe Hunkeler:\n+    https://gist.github.com/jhunkeler/f08783ca2da7bfd1f8e9ee1d207da5ff\n \"\"\"\n \n import json\n+import os\n+import re\n+\n+__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))\n \n \n def get_config():\n@@ -27,7 +38,50 @@\n         A dictionary that holds the contents of the config file.\n     \"\"\"\n \n-    with open('config.json', 'r') as config_file:\n+    with open(os.path.join(__location__, 'config.json'), 'r') as config_file:\n         settings = json.load(config_file)\n \n     return settings\n+\n+\n+def filename_parser(filename):\n+    \"\"\"Return a dictionary that contains the properties of a given\n+    JWST file (e.g. program ID, visit number, detector, etc.)\n+\n+    Parameters\n+    ----------\n+    filename : str\n+        Path or name of JWST file to parse\n+\n+    Returns\n+    -------\n+    filename_dict : dict\n+        Collection of file properties\n+\n+    Raises\n+    ------\n+    ValueError\n+        When the provided file does not follow naming conventions\n+    \"\"\"\n+    filename = os.path.basename(filename)\n+\n+    elements = \\\n+        re.compile(r\"[a-z]+\"\n+                   \"(?P<program_id>\\d{5})\"\n+                   \"(?P<observation>\\d{3})\"\n+                   \"(?P<visit>\\d{3})\"\n+                   \"_(?P<visit_group>\\d{2})\"\n+                   \"(?P<parallel_seq_id>\\d{1})\"\n+                   \"(?P<activity>\\d{2})\"\n+                   \"_(?P<exposure_id>\\d+)\"\n+                   \"_(?P<detector>\\w+)\"\n+                   \"_(?P<suffix>\\w+).*\")\n+\n+    jwst_file = elements.match(filename)\n+\n+    if jwst_file is not None:\n+        filename_dict = jwst_file.groupdict()\n+    else:\n+        raise ValueError('Provided file {} does not follow JWST naming conventions (jw<PPPPP><OOO><VVV>_<GGSAA>_<EEEEE>_<detector>_<suffix>.fits)'.format(filename))\n+\n+    return filename_dict\n", "issue": "Build filename parser utility function\nIt would be useful to have a function in the `utils.py` module that returned the individual elements of a given filename, for example:\r\n\r\n```python\r\nfrom jwql.utils.utils import parse_filename\r\nfilename_dict = parse_filename('jw94015001001_02102_00001_nrcb1_uncal.fits')\r\n```\r\n\r\nwhere `filename_dict` is:\r\n\r\n```\r\n{\r\n    'program_id' : '94015',\r\n    'observation' : '001',\r\n    'visit' : '001',\r\n    'visit_group' : '02',\r\n    'parallel_seq_id' : '1',\r\n    'activity' : '02',\r\n    'exposure_id' : '00001',\r\n    'detector' : 'nrcb1',\r\n    'suffix' : 'uncal'\r\n}\r\n```\n", "before_files": [{"content": "\"\"\"Various utility functions for the jwql project.\n\nAuthors\n-------\n\n    Matthew Bourque\n\nUse\n---\n\n    This module can be imported as such:\n\n    >>> import utils\n    settings = get_config()\n\"\"\"\n\nimport json\n\n\ndef get_config():\n    \"\"\"Return a dictionary that holds the contents of the jwql config\n    file.\n\n    Returns\n    -------\n    settings : dict\n        A dictionary that holds the contents of the config file.\n    \"\"\"\n\n    with open('config.json', 'r') as config_file:\n        settings = json.load(config_file)\n\n    return settings\n", "path": "jwql/utils/utils.py"}], "after_files": [{"content": "\"\"\"Various utility functions for the jwql project.\n\nAuthors\n-------\n\n    - Matthew Bourque\n    - Lauren Chambers\n\nUse\n---\n\n    This module can be imported as such:\n\n    >>> import utils\n    settings = get_config()\n\nReferences\n----------\n\n    Filename parser modifed from Joe Hunkeler:\n    https://gist.github.com/jhunkeler/f08783ca2da7bfd1f8e9ee1d207da5ff\n\"\"\"\n\nimport json\nimport os\nimport re\n\n__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))\n\n\ndef get_config():\n    \"\"\"Return a dictionary that holds the contents of the jwql config\n    file.\n\n    Returns\n    -------\n    settings : dict\n        A dictionary that holds the contents of the config file.\n    \"\"\"\n\n    with open(os.path.join(__location__, 'config.json'), 'r') as config_file:\n        settings = json.load(config_file)\n\n    return settings\n\n\ndef filename_parser(filename):\n    \"\"\"Return a dictionary that contains the properties of a given\n    JWST file (e.g. program ID, visit number, detector, etc.)\n\n    Parameters\n    ----------\n    filename : str\n        Path or name of JWST file to parse\n\n    Returns\n    -------\n    filename_dict : dict\n        Collection of file properties\n\n    Raises\n    ------\n    ValueError\n        When the provided file does not follow naming conventions\n    \"\"\"\n    filename = os.path.basename(filename)\n\n    elements = \\\n        re.compile(r\"[a-z]+\"\n                   \"(?P<program_id>\\d{5})\"\n                   \"(?P<observation>\\d{3})\"\n                   \"(?P<visit>\\d{3})\"\n                   \"_(?P<visit_group>\\d{2})\"\n                   \"(?P<parallel_seq_id>\\d{1})\"\n                   \"(?P<activity>\\d{2})\"\n                   \"_(?P<exposure_id>\\d+)\"\n                   \"_(?P<detector>\\w+)\"\n                   \"_(?P<suffix>\\w+).*\")\n\n    jwst_file = elements.match(filename)\n\n    if jwst_file is not None:\n        filename_dict = jwst_file.groupdict()\n    else:\n        raise ValueError('Provided file {} does not follow JWST naming conventions (jw<PPPPP><OOO><VVV>_<GGSAA>_<EEEEE>_<detector>_<suffix>.fits)'.format(filename))\n\n    return filename_dict\n", "path": "jwql/utils/utils.py"}]}