We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow excluding file patterns when generating component definitions 
Thanks a lot for making Dash -- we have found it very useful for building dashboards.

We ran into an issue migrating to the new `dash-generate-components` utility.

In [dash-bootstrap-components](https://github.com/ASIDataScience/dash-bootstrap-components), we keep the components in `src/components`. Besides components files, this also includes a few unit test files called, e.g. `src/components/__tests__/DropdownMenu.test.js`. When we run `dash-generate-components ./src/components <output>`, these test files also get picked up. This leads to a traceback in the build logs: 

```
Error with path src/components/__tests__/DropdownMenu.test.jsError: No suitable component definition found.
Error: No suitable component definition found.
at parse (/project/pascal/dash-bootstrap-components/node_modules/react-docgen/dist/parse.js:84:9)
at Object.defaultParse [as parse] (/project/pascal/dash-bootstrap-components/node_modules/react-docgen/dist/main.js:66:30)
at parseFile (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:64:51)
at dirs.forEach.filename (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:84:17)
at Array.forEach (<anonymous>)
at collectMetadataRecursively (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:79:14)
at dirs.forEach.filename (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:82:17)
at Array.forEach (<anonymous>)
at collectMetadataRecursively (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:79:14)
at componentPaths.forEach.componentPath (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:15:5)
```

While the error is, of course, legitimate, it would be nice to be able to suppress these tracebacks. I can see three routes:
- do nothing -- after all, this doesn't stop us from building `metadata.json`, it just makes it slightly more confusing.
- in `dash/extract-meta.js`, we could explicitly blacklist `__tests__` directories in the same way that files that don't end in `jsx?` are black-listed. AFAICT, the `__tests__` directory structure is the default with [jest](https://jestjs.io/docs/en/configuration.html#testmatch-array-string). [react-docgen](https://github.com/reactjs/react-docgen#cli) ignores `node_modules`, `__tests__` and `__mocks__` by default, so there is definitely a precedent.
- add a `--ignore` argument to `dash-generate-components` that allows passing file globs to be excluded. 

Very happy to submit a PR if you decide on what the best course of action is.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dash/development/component_generator.py`
Content:
```
1 from __future__ import print_function
2 
3 import json
4 import sys
5 import subprocess
6 import shlex
7 import os
8 import argparse
9 import shutil
10 
11 import pkg_resources
12 
13 from ._py_components_generation import generate_class_file
14 from ._py_components_generation import generate_imports
15 from ._py_components_generation import generate_classes_files
16 
17 
18 class _CombinedFormatter(argparse.ArgumentDefaultsHelpFormatter,
19                          argparse.RawDescriptionHelpFormatter):
20     pass
21 
22 
23 # pylint: disable=too-many-locals
24 def generate_components(components_source, project_shortname,
25                         package_info_filename='package.json'):
26     is_windows = sys.platform == 'win32'
27 
28     extract_path = pkg_resources.resource_filename('dash', 'extract-meta.js')
29 
30     os.environ['NODE_PATH'] = 'node_modules'
31     cmd = shlex.split('node {} {}'.format(extract_path, components_source),
32                       posix=not is_windows)
33 
34     shutil.copyfile('package.json',
35                     os.path.join(project_shortname, package_info_filename))
36 
37     proc = subprocess.Popen(cmd,
38                             stdout=subprocess.PIPE,
39                             stderr=subprocess.PIPE,
40                             shell=is_windows)
41     out, err = proc.communicate()
42     status = proc.poll()
43 
44     if err:
45         print(err.decode(), file=sys.stderr)
46 
47     if not out:
48         print(
49             'Error generating metadata in {} (status={})'.format(
50                 project_shortname, status),
51             file=sys.stderr)
52         sys.exit(1)
53 
54     metadata = json.loads(out.decode())
55 
56     components = generate_classes_files(
57         project_shortname,
58         metadata,
59         generate_class_file
60     )
61 
62     with open(os.path.join(project_shortname, 'metadata.json'), 'w') as f:
63         json.dump(metadata, f)
64 
65     generate_imports(project_shortname, components)
66 
67 
68 def cli():
69     parser = argparse.ArgumentParser(
70         prog='dash-generate-components',
71         formatter_class=_CombinedFormatter,
72         description='Generate dash components by extracting the metadata '
73         'using react-docgen. Then map the metadata to python classes.'
74     )
75     parser.add_argument('components_source',
76                         help='React components source directory.')
77     parser.add_argument(
78         'project_shortname',
79         help='Name of the project to export the classes files.'
80     )
81     parser.add_argument(
82         '-p', '--package-info-filename',
83         default='package.json',
84         help='The filename of the copied `package.json` to `project_shortname`'
85     )
86 
87     args = parser.parse_args()
88     generate_components(args.components_source, args.project_shortname,
89                         package_info_filename=args.package_info_filename)
90 
91 
92 if __name__ == '__main__':
93     cli()
94
```

Path: `dash/version.py`
Content:
```
1 __version__ = '0.33.0'
2
```
--- 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/dash/development/component_generator.py b/dash/development/component_generator.py
--- a/dash/development/component_generator.py
+++ b/dash/development/component_generator.py
@@ -22,14 +22,17 @@
 
 # pylint: disable=too-many-locals
 def generate_components(components_source, project_shortname,
-                        package_info_filename='package.json'):
+                        package_info_filename='package.json',
+                        ignore='^_'):
     is_windows = sys.platform == 'win32'
 
     extract_path = pkg_resources.resource_filename('dash', 'extract-meta.js')
 
     os.environ['NODE_PATH'] = 'node_modules'
-    cmd = shlex.split('node {} {}'.format(extract_path, components_source),
-                      posix=not is_windows)
+    cmd = shlex.split(
+        'node {} {} {}'.format(extract_path, ignore, components_source),
+        posix=not is_windows
+    )
 
     shutil.copyfile('package.json',
                     os.path.join(project_shortname, package_info_filename))
@@ -83,10 +86,18 @@
         default='package.json',
         help='The filename of the copied `package.json` to `project_shortname`'
     )
+    parser.add_argument(
+        '-i', '--ignore',
+        default='^_',
+        help='Files/directories matching the pattern will be ignored'
+    )
 
     args = parser.parse_args()
-    generate_components(args.components_source, args.project_shortname,
-                        package_info_filename=args.package_info_filename)
+    generate_components(
+        args.components_source, args.project_shortname,
+        package_info_filename=args.package_info_filename,
+        ignore=args.ignore
+    )
 
 
 if __name__ == '__main__':
diff --git a/dash/version.py b/dash/version.py
--- a/dash/version.py
+++ b/dash/version.py
@@ -1 +1 @@
-__version__ = '0.33.0'
+__version__ = '0.34.0'

{"golden_diff": "diff --git a/dash/development/component_generator.py b/dash/development/component_generator.py\n--- a/dash/development/component_generator.py\n+++ b/dash/development/component_generator.py\n@@ -22,14 +22,17 @@\n \n # pylint: disable=too-many-locals\n def generate_components(components_source, project_shortname,\n-                        package_info_filename='package.json'):\n+                        package_info_filename='package.json',\n+                        ignore='^_'):\n     is_windows = sys.platform == 'win32'\n \n     extract_path = pkg_resources.resource_filename('dash', 'extract-meta.js')\n \n     os.environ['NODE_PATH'] = 'node_modules'\n-    cmd = shlex.split('node {} {}'.format(extract_path, components_source),\n-                      posix=not is_windows)\n+    cmd = shlex.split(\n+        'node {} {} {}'.format(extract_path, ignore, components_source),\n+        posix=not is_windows\n+    )\n \n     shutil.copyfile('package.json',\n                     os.path.join(project_shortname, package_info_filename))\n@@ -83,10 +86,18 @@\n         default='package.json',\n         help='The filename of the copied `package.json` to `project_shortname`'\n     )\n+    parser.add_argument(\n+        '-i', '--ignore',\n+        default='^_',\n+        help='Files/directories matching the pattern will be ignored'\n+    )\n \n     args = parser.parse_args()\n-    generate_components(args.components_source, args.project_shortname,\n-                        package_info_filename=args.package_info_filename)\n+    generate_components(\n+        args.components_source, args.project_shortname,\n+        package_info_filename=args.package_info_filename,\n+        ignore=args.ignore\n+    )\n \n \n if __name__ == '__main__':\ndiff --git a/dash/version.py b/dash/version.py\n--- a/dash/version.py\n+++ b/dash/version.py\n@@ -1 +1 @@\n-__version__ = '0.33.0'\n+__version__ = '0.34.0'\n", "issue": "Allow excluding file patterns when generating component definitions \nThanks a lot for making Dash -- we have found it very useful for building dashboards.\r\n\r\nWe ran into an issue migrating to the new `dash-generate-components` utility.\r\n\r\nIn [dash-bootstrap-components](https://github.com/ASIDataScience/dash-bootstrap-components), we keep the components in `src/components`. Besides components files, this also includes a few unit test files called, e.g. `src/components/__tests__/DropdownMenu.test.js`. When we run `dash-generate-components ./src/components <output>`, these test files also get picked up. This leads to a traceback in the build logs: \r\n\r\n```\r\nError with path src/components/__tests__/DropdownMenu.test.jsError: No suitable component definition found.\r\nError: No suitable component definition found.\r\nat parse (/project/pascal/dash-bootstrap-components/node_modules/react-docgen/dist/parse.js:84:9)\r\nat Object.defaultParse [as parse] (/project/pascal/dash-bootstrap-components/node_modules/react-docgen/dist/main.js:66:30)\r\nat parseFile (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:64:51)\r\nat dirs.forEach.filename (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:84:17)\r\nat Array.forEach (<anonymous>)\r\nat collectMetadataRecursively (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:79:14)\r\nat dirs.forEach.filename (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:82:17)\r\nat Array.forEach (<anonymous>)\r\nat collectMetadataRecursively (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:79:14)\r\nat componentPaths.forEach.componentPath (/opt/anaconda/envs/Python3/lib/python3.6/site-packages/dash/extract-meta.js:15:5)\r\n```\r\n\r\nWhile the error is, of course, legitimate, it would be nice to be able to suppress these tracebacks. I can see three routes:\r\n- do nothing -- after all, this doesn't stop us from building `metadata.json`, it just makes it slightly more confusing.\r\n- in `dash/extract-meta.js`, we could explicitly blacklist `__tests__` directories in the same way that files that don't end in `jsx?` are black-listed. AFAICT, the `__tests__` directory structure is the default with [jest](https://jestjs.io/docs/en/configuration.html#testmatch-array-string). [react-docgen](https://github.com/reactjs/react-docgen#cli) ignores `node_modules`, `__tests__` and `__mocks__` by default, so there is definitely a precedent.\r\n- add a `--ignore` argument to `dash-generate-components` that allows passing file globs to be excluded. \r\n\r\nVery happy to submit a PR if you decide on what the best course of action is.\n", "before_files": [{"content": "from __future__ import print_function\n\nimport json\nimport sys\nimport subprocess\nimport shlex\nimport os\nimport argparse\nimport shutil\n\nimport pkg_resources\n\nfrom ._py_components_generation import generate_class_file\nfrom ._py_components_generation import generate_imports\nfrom ._py_components_generation import generate_classes_files\n\n\nclass _CombinedFormatter(argparse.ArgumentDefaultsHelpFormatter,\n                         argparse.RawDescriptionHelpFormatter):\n    pass\n\n\n# pylint: disable=too-many-locals\ndef generate_components(components_source, project_shortname,\n                        package_info_filename='package.json'):\n    is_windows = sys.platform == 'win32'\n\n    extract_path = pkg_resources.resource_filename('dash', 'extract-meta.js')\n\n    os.environ['NODE_PATH'] = 'node_modules'\n    cmd = shlex.split('node {} {}'.format(extract_path, components_source),\n                      posix=not is_windows)\n\n    shutil.copyfile('package.json',\n                    os.path.join(project_shortname, package_info_filename))\n\n    proc = subprocess.Popen(cmd,\n                            stdout=subprocess.PIPE,\n                            stderr=subprocess.PIPE,\n                            shell=is_windows)\n    out, err = proc.communicate()\n    status = proc.poll()\n\n    if err:\n        print(err.decode(), file=sys.stderr)\n\n    if not out:\n        print(\n            'Error generating metadata in {} (status={})'.format(\n                project_shortname, status),\n            file=sys.stderr)\n        sys.exit(1)\n\n    metadata = json.loads(out.decode())\n\n    components = generate_classes_files(\n        project_shortname,\n        metadata,\n        generate_class_file\n    )\n\n    with open(os.path.join(project_shortname, 'metadata.json'), 'w') as f:\n        json.dump(metadata, f)\n\n    generate_imports(project_shortname, components)\n\n\ndef cli():\n    parser = argparse.ArgumentParser(\n        prog='dash-generate-components',\n        formatter_class=_CombinedFormatter,\n        description='Generate dash components by extracting the metadata '\n        'using react-docgen. Then map the metadata to python classes.'\n    )\n    parser.add_argument('components_source',\n                        help='React components source directory.')\n    parser.add_argument(\n        'project_shortname',\n        help='Name of the project to export the classes files.'\n    )\n    parser.add_argument(\n        '-p', '--package-info-filename',\n        default='package.json',\n        help='The filename of the copied `package.json` to `project_shortname`'\n    )\n\n    args = parser.parse_args()\n    generate_components(args.components_source, args.project_shortname,\n                        package_info_filename=args.package_info_filename)\n\n\nif __name__ == '__main__':\n    cli()\n", "path": "dash/development/component_generator.py"}, {"content": "__version__ = '0.33.0'\n", "path": "dash/version.py"}], "after_files": [{"content": "from __future__ import print_function\n\nimport json\nimport sys\nimport subprocess\nimport shlex\nimport os\nimport argparse\nimport shutil\n\nimport pkg_resources\n\nfrom ._py_components_generation import generate_class_file\nfrom ._py_components_generation import generate_imports\nfrom ._py_components_generation import generate_classes_files\n\n\nclass _CombinedFormatter(argparse.ArgumentDefaultsHelpFormatter,\n                         argparse.RawDescriptionHelpFormatter):\n    pass\n\n\n# pylint: disable=too-many-locals\ndef generate_components(components_source, project_shortname,\n                        package_info_filename='package.json',\n                        ignore='^_'):\n    is_windows = sys.platform == 'win32'\n\n    extract_path = pkg_resources.resource_filename('dash', 'extract-meta.js')\n\n    os.environ['NODE_PATH'] = 'node_modules'\n    cmd = shlex.split(\n        'node {} {} {}'.format(extract_path, ignore, components_source),\n        posix=not is_windows\n    )\n\n    shutil.copyfile('package.json',\n                    os.path.join(project_shortname, package_info_filename))\n\n    proc = subprocess.Popen(cmd,\n                            stdout=subprocess.PIPE,\n                            stderr=subprocess.PIPE,\n                            shell=is_windows)\n    out, err = proc.communicate()\n    status = proc.poll()\n\n    if err:\n        print(err.decode(), file=sys.stderr)\n\n    if not out:\n        print(\n            'Error generating metadata in {} (status={})'.format(\n                project_shortname, status),\n            file=sys.stderr)\n        sys.exit(1)\n\n    metadata = json.loads(out.decode())\n\n    components = generate_classes_files(\n        project_shortname,\n        metadata,\n        generate_class_file\n    )\n\n    with open(os.path.join(project_shortname, 'metadata.json'), 'w') as f:\n        json.dump(metadata, f)\n\n    generate_imports(project_shortname, components)\n\n\ndef cli():\n    parser = argparse.ArgumentParser(\n        prog='dash-generate-components',\n        formatter_class=_CombinedFormatter,\n        description='Generate dash components by extracting the metadata '\n        'using react-docgen. Then map the metadata to python classes.'\n    )\n    parser.add_argument('components_source',\n                        help='React components source directory.')\n    parser.add_argument(\n        'project_shortname',\n        help='Name of the project to export the classes files.'\n    )\n    parser.add_argument(\n        '-p', '--package-info-filename',\n        default='package.json',\n        help='The filename of the copied `package.json` to `project_shortname`'\n    )\n    parser.add_argument(\n        '-i', '--ignore',\n        default='^_',\n        help='Files/directories matching the pattern will be ignored'\n    )\n\n    args = parser.parse_args()\n    generate_components(\n        args.components_source, args.project_shortname,\n        package_info_filename=args.package_info_filename,\n        ignore=args.ignore\n    )\n\n\nif __name__ == '__main__':\n    cli()\n", "path": "dash/development/component_generator.py"}, {"content": "__version__ = '0.34.0'\n", "path": "dash/version.py"}]}