diff --git a/NEWS.rst b/NEWS.rst
index 0f5e3fc61a0a3b09110a1fb7f232020fa1614b94_TkVXUy5yc3Q=..bb4d9359842a1e629ded55108a23f5c86e7a974e_TkVXUy5yc3Q= 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -2,6 +2,11 @@
 History
 =======
 
+7.0.0
+-----
+
+Rewrote expanding to allow blacklisting. It should be simpler to add new options.
+
 6.0.0
 -----
 
@@ -10,6 +15,7 @@
 Add .expand to several options so that a super project can reuse other super projects.
 
 Fix --odoo-help in docker_dev_start to avoid requiring a database.
+
 5.0.0
 -----
 
diff --git a/README.rst b/README.rst
index 0f5e3fc61a0a3b09110a1fb7f232020fa1614b94_UkVBRE1FLnJzdA==..bb4d9359842a1e629ded55108a23f5c86e7a974e_UkVBRE1FLnJzdA== 100644
--- a/README.rst
+++ b/README.rst
@@ -225,6 +225,24 @@
 postgresql_version
     version of postgresql to use. defaults to 9.6.
 
+It is possible to reuse another directory containing `setup.cfg`_. These type of keys can be used:
+
+.. code-block:: INI
+
+    # this key allows to define the path to the file to reuse (to expand on)
+    # name can be different from the directory name
+    # this key is mandatory
+    expand.name.path = path/to/directory
+    # this key indicates what keys to reuse from the subdirectories
+    # this is not required, but will default to all if not provided
+    # comma separated list of values.
+    expand.base.read = modules,module_list
+    # this key is to allow blacklisting some subdirectories
+    # the name is the same as the previous key
+    # if there is no blacklisting, no need to include it
+    # the value is a python regexp
+    expand.name.blacklist = regexp
+
 Completion files for zsh
 ========================
 
diff --git a/odoo_scripts/config.py b/odoo_scripts/config.py
index 0f5e3fc61a0a3b09110a1fb7f232020fa1614b94_b2Rvb19zY3JpcHRzL2NvbmZpZy5weQ==..bb4d9359842a1e629ded55108a23f5c86e7a974e_b2Rvb19zY3JpcHRzL2NvbmZpZy5weQ== 100644
--- a/odoo_scripts/config.py
+++ b/odoo_scripts/config.py
@@ -3,4 +3,5 @@
 import configparser
 import logging
 import os
+import re
 import sys
@@ -6,4 +7,5 @@
 import sys
+from collections import defaultdict
 from glob import glob
 from typing import List, Optional
 
@@ -7,6 +9,8 @@
 from glob import glob
 from typing import List, Optional
 
+SECTION = "odoo_scripts"
+
 _logger = logging.getLogger(__name__)
 
 
@@ -27,6 +31,8 @@
     At the moment, only read from `setup.cfg`.
     """
 
-    def __init__(self, base_path: str = None):
+    def __init__(
+        self, path: str = None, blacklist: str = None, read: str = None
+    ):
         self._expanded_configuration = dict()
         setup_path = "setup.cfg"
@@ -31,10 +37,9 @@
         self._expanded_configuration = dict()
         setup_path = "setup.cfg"
-        if base_path:
-            setup_path = os.path.join(base_path, setup_path)
-        section = "odoo_scripts"
+        if path:
+            setup_path = os.path.join(path, setup_path)
         config_parser = configparser.ConfigParser()
         if not os.path.exists(setup_path):
             _logger.warning("Missing %s", setup_path)
         else:
             config_parser.read(setup_path)
@@ -36,8 +41,36 @@
         config_parser = configparser.ConfigParser()
         if not os.path.exists(setup_path):
             _logger.warning("Missing %s", setup_path)
         else:
             config_parser.read(setup_path)
+        section = (
+            config_parser[SECTION] if SECTION in config_parser else dict()
+        )
+
+        # read expanded configurations information
+        expanded_info = defaultdict(dict)
+        for key in section:
+            if key.startswith("expand."):
+                remaining_key = key.split(".")[1:]
+                expanded_info[remaining_key[0]][
+                    remaining_key[1]
+                ] = section.get(key)
+
+        for name, value in expanded_info.items():
+            if "path" not in value:
+                _logger.error("Expansion without path for %s", name)
+                raise Exception("Expansion without path for %s" % name)
+            else:
+                if blacklist and re.match(blacklist, value["path"]):
+                    _logger.info(
+                        "Ignoring directory '%s' due to blacklisting",
+                        value["path"],
+                    )
+                else:
+                    if path:
+                        value["path"] = os.path.join(path, value["path"])
+                    # read expanded configurations
+                    self._expanded_configuration[name] = Configuration(**value)
 
         def set_from_glob_values(
             base: Optional[str], glob_values: List[str]
@@ -51,10 +84,9 @@
                         result_set.add(file)
             return result_set
 
-        def get_expanded_configuration(path_name: str):
-            if path_name not in self._expanded_configuration:
-                self._expanded_configuration[path_name] = Configuration(
-                    path_name
-                )
-            return self._expanded_configuration[path_name]
+        def toread(key: str) -> bool:
+            """Return true if value of key is to be read from the file"""
+            if read:
+                return key in read.split(",")
+            return True
 
@@ -60,2 +92,3 @@
 
+        # those keys are path to files (glob compatible)
         for key in ("modules", "dependencies", "other_sources"):
@@ -61,19 +94,16 @@
         for key in ("modules", "dependencies", "other_sources"):
-            # get the values from this configuration
-            values = config_parser.get(section, key, fallback="").split()
-            set_values = set_from_glob_values(base_path, values)
-            # handle expand, getting value from another configuration
-            expand_value = config_parser.get(
-                section, key + ".expand", fallback=None
-            )
-            if expand_value:
-                for element in expand_value.split():
-                    set_values.update(
-                        getattr(get_expanded_configuration(element), key)
-                    )
+            set_values = set()
+            if toread(key):
+                # add any expanded values
+                for config in self._expanded_configuration.values():
+                    set_values.update(getattr(config, key))
+                # get the values from this configuration
+                values = section.get(key, "").split()
+                # XXX eventually add option to not include path
+                set_values.update(set_from_glob_values(path, values))
             setattr(self, key, list(set_values))
 
         def key_format(a_key: str) -> str:
             """Replace invalid characters in an attribute"""
             return a_key.replace("-", "_").replace(".", "_")
 
@@ -74,9 +104,10 @@
             setattr(self, key, list(set_values))
 
         def key_format(a_key: str) -> str:
             """Replace invalid characters in an attribute"""
             return a_key.replace("-", "_").replace(".", "_")
 
+        # those keys are list of values
         for key in ("module_list", "module_list_tests", "pg.extensions"):
             value = list()
             formatted_key = key_format(key)
@@ -80,18 +111,11 @@
         for key in ("module_list", "module_list_tests", "pg.extensions"):
             value = list()
             formatted_key = key_format(key)
-            # add any expanded value
-            expand_value = config_parser.get(
-                section, key + ".expand", fallback=None
-            )
-            if expand_value:
-                for element in expand_value.split():
-                    value.extend(
-                        getattr(
-                            get_expanded_configuration(element), formatted_key
-                        )
-                    )
-            # add local values
-            value += config_parser.get(section, key, fallback="").split()
+            if toread(key):
+                # add any expanded values
+                for config in self._expanded_configuration.values():
+                    value.extend(getattr(config, formatted_key))
+                # add local values
+                value.extend(section.get(key, "").split())
             # then set it
             setattr(self, formatted_key, value)
@@ -96,9 +120,5 @@
             # then set it
             setattr(self, formatted_key, value)
-        for key in ("db_user", "db_password", "load-language"):
-            setattr(
-                self,
-                key_format(key),
-                config_parser.get(section, key, fallback=None),
-            )
+
+        # those keys are single string values, no expand
 
@@ -104,5 +124,6 @@
 
-        self.registry = config_parser.get(
-            section, "registry", fallback="registry.xcg.io"
-        )
+        for key in ("db_user", "db_password", "load-language"):
+            setattr(self, key_format(key), section.get(key, None))
+
+        self.registry = section.get("registry", "registry.xcg.io")
         project_path = os.path.realpath(".")
@@ -108,10 +129,6 @@
         project_path = os.path.realpath(".")
-        self.image = config_parser.get(
-            section, "image", fallback=os.path.basename(project_path)
-        )
-        self.odoo_type = config_parser.get(
-            section, "odoo_type", fallback="odoo7"
-        )
+        self.image = section.get("image", os.path.basename(project_path))
+        self.odoo_type = section.get("odoo_type", "odoo7")
         if self.odoo_type not in (
             "odoo7",
             "odoo8",
@@ -120,12 +137,8 @@
             "odoo13",
         ):
             _logger.warning("Unexpected odoo_type: %s", self.odoo_type)
-        self.postgresql_version = config_parser.get(
-            section, "postgresql_version", fallback="9.6"
-        )
-        self.start_py3o = config_parser.get(
-            section, "start_py3o", fallback="no"
-        ) in ("yes", "true")
+        self.postgresql_version = section.get("postgresql_version", "9.6")
+        self.start_py3o = section.get("start_py3o", "no") in ("yes", "true")
 
 
 def main(argv=None):