Repository: facelessuser/wcmatch

Issue:
Simplify WcMatch argument handling (__init__ and on_init)
WcMatch, when instantiating, can take both `args` and `kwargs`. Because of this, the `on_init` function also takes the same. This makes things unnecessarily complicated.

Moving forward, WcMatch should only accept the base directory as an arg, but we can default it to `.`. All other parameters should be `kwargs`. That will also force `on_init` to only take `kwargs`. This will simplify our `__init__` argument handling and provide a more sane method for inputs.

I think this originated from us originally providing an interface without customization, and then we tried to keep things backwards compatible when we made it more customizable. Unfortunately, this makes things complicated and probably should have just required `kwargs` right away.

Rummage, the original user of this library and the reason I originally wrote this library (though now I think others use it too and I have it in other projects as well) is already using for `on_init` so this shouldn't be a problem. We will probably have to release such a change in a major release.

Discussion:
facelessuser: @gir-bot lgtm

Patch:
diff --git a/docs/src/markdown/about/changelog.md b/docs/src/markdown/about/changelog.md
index d55c79b..1b7b352 100644
--- a/docs/src/markdown/about/changelog.md
+++ b/docs/src/markdown/about/changelog.md
@@ -1,5 +1,14 @@
 # Changelog
 
+## 8.0
+
+- **NEW**: `WcMatch`'s `on_init` hook now only accepts `kwargs` and not `args`.
+- **NEW**: Cosmetic change of referring to the first `__init__` parameter as `root_dir` instead of `base`. This is to
+  make it more clear when we are talking about the overall root directory that all paths are relative to vs the base
+  base path of a file which is relative to the root directory and the actual file name.
+- **NEW**: Internal attribute of `WcMatch` changed from `base` to `_root_dir`. This attribute is not really meant to be
+  referenced by users and as been marked as private.
+
 ## 7.2
 
 - **NEW**: Drop Python 3.5 support.
diff --git a/docs/src/markdown/fnmatch.md b/docs/src/markdown/fnmatch.md
index d0408e2..0e6e5da 100644
--- a/docs/src/markdown/fnmatch.md
+++ b/docs/src/markdown/fnmatch.md
@@ -159,10 +159,6 @@ we wrap the entire group to be captured: `#!py3 '+(a)'` --> `#!py3 r'((a)+)'`.
 ('file', '33', '.test.txt')
 ```
 
-!!! new "Changes 4.0"
-    Translate now outputs exclusion patterns so that if they match, the file is excluded. This is opposite logic to how
-    it used to be, but is more efficient.
-
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
@@ -175,9 +171,6 @@ we wrap the entire group to be captured: `#!py3 '+(a)'` --> `#!py3 r'((a)+)'`.
 
 `CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#ignorecase).
 
-!!! new "New 4.3"
-    `CASE` is new in 4.3.0.
-
 #### `fnmatch.IGNORECASE, fnmatch.I` {: #ignorecase}
 
 `IGNORECASE` forces case insensitivity. [`CASE`](#case) has higher priority than `IGNORECASE`.
@@ -197,11 +190,6 @@ Assuming the `SPLIT` flag, this means using it in a pattern such as `inclusion|!
 If it is desired, you can force exclusion patterns, when no inclusion pattern is provided, to assume all files match
 unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#negateall) flag.
 
-!!! warning "Changes 4.0"
-    In 4.0, `NEGATE` now requires a non-exclusion pattern to be paired with it or it will match nothing. If you really
-    need something similar to the old behavior, that would assume a default inclusion pattern, you can use the
-    [`NEGATEALL`](#negateall).
-
 #### `fnmatch.NEGATEALL, fnmatch.A` {: #negateall}
 
 `NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the
@@ -286,9 +274,6 @@ normalized. This is great if you need to match Windows specific names on a Linux
 
 If `FORCEWIN` is used along side [`FORCEUNIX`](#forceunix), both will be ignored.
 
-!!! new "New 4.2"
-    `FORCEWIN` is new in 4.2.0.
-
 #### `fnmatch.FORCEUNIX, fnmatch.U` {: #forceunix}
 
 `FORCEUNIX` will force Linux/Unix name and case logic to be used on Windows systems. This is great if you need to match
@@ -299,9 +284,6 @@ to use case insensitivity.
 
 If `FORCEUNIX` is used along side [`FORCEWIN`](#forcewin), both will be ignored.
 
-!!! new "New 4.2"
-    `FORCEUNIX` is new in 4.2.0.
-
 --8<--
 refs.txt
 --8<--
diff --git a/docs/src/markdown/glob.md b/docs/src/markdown/glob.md
index 428bef6..ed8ab56 100644
--- a/docs/src/markdown/glob.md
+++ b/docs/src/markdown/glob.md
@@ -479,10 +479,6 @@ we wrap the entire group to be captured: `#!py3 '+(a)'` --> `#!py3 r'((a)+)'`.
 ('file', '33', '.test.txt')
 ```
 
-!!! new "Changes 4.0"
-    Translate now outputs exclusion patterns so that if they match, the file is excluded. This is opposite logic to how
-    it used to be, but is more efficient.
-
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
@@ -629,9 +625,6 @@ escaping will be used.
 On Windows, drive letters (`C:`) and UNC host/share (`//host/share`) portions of a path will still be treated case
 insensitively, but the rest of the path will have case sensitive logic applied.
 
-!!! new "New 4.3"
-    `CASE` is new in 4.3.0.
-
 #### `glob.IGNORECASE, glob.I` {: #ignorecase}
 
 `IGNORECASE` forces case insensitivity. [`CASE`](#case) has higher priority than `IGNORECASE`.
@@ -654,11 +647,6 @@ unless the file matches the excluded pattern. This is done with the [`NEGATEALL`
 `NEGATE` enables [`DOTGLOB`](#dotglob) in all exclude patterns, this cannot be disabled. This will not affect the
 inclusion patterns.
 
-!!! new "Changes 4.0"
-    In 4.0, `NEGATE` now requires a non-exclusion pattern to be paired with it or it will match nothing. If you really
-    need something similar to the old behavior, that would assume a default inclusion pattern, you can use the
-    [`NEGATEALL`](#negateall).
-
 #### `glob.NEGATEALL, glob.A` {: #negateall}
 
 `NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the
@@ -678,17 +666,10 @@ When `MINUSNEGATE` is used with [`NEGATE`](#negate), exclusion patterns are reco
 
 `GLOBSTAR` enables the feature where `**` matches zero or more directories.
 
-!!! new "New 3.0"
-    `GLOBSTAR` will no longer match or traverse symlink directories. This models the recent behavior in Bash 5.0. To
-    crawl symlink directories, the new [`FOLLOW`](#follow) flag must be enabled.
-
 #### `glob.FOLLOW, glob.L` {: #follow}
 
 `FOLLOW` will cause [`GLOBSTAR`](#globstar) patterns (`**`) to match and traverse symlink directories.
 
-!!! new "New 3.0"
-    `FOLLOW` was added in 3.0.
-
 #### `glob.REALPATH, glob.P` {: #realpath}
 
 In the past, only [`glob`](#glob) and [`iglob`](#iglob) operated on the filesystem, but with `REALPATH`, other
@@ -714,9 +695,6 @@ logic so that the path must meet the following in order to match:
 Since `REALPATH` causes the file system to be referenced when matching a path, flags such as
 [`FORCEUNIX`](#forceunix) and [`FORCEWIN`](#forcewin) are not allowed with this flag and will be ignored.
 
-!!! new "New 3.0"
-    `REALPATH` was added in 3.0.
-
 #### `glob.DOTGLOB, glob.D` {: #dotglob}
 
 By default, [`glob`](#glob) and [`globmatch`](#globmatch) will not match file or directory names that start with
@@ -942,9 +920,6 @@ enabled, ensuring the files have trailing slashes can still save you a call to `
 ['appveyor.yml', 'base.patch', 'basematch.diff', 'docs', 'LICENSE.md', 'MANIFEST.in', 'mkdocs.yml', 'README.md', 'requirements', 'setup.cfg', 'setup.py', 'tests', 'tools', 'tox.ini', 'wcmatch']
 ```
 
-!!! new "New 4.0"
-    `MARK` added in 4.0.
-
 #### `glob.MATCHBASE, glob.X` {: #matchbase}
 
 `MATCHBASE`, when a pattern has no slashes in it, will cause [`glob`](#glob) and [`iglob`](#iglob) to seek for
@@ -959,9 +934,6 @@ start with `.` and will not match such files and directories if [`DOTGLOB`](#dot
 ['docs/src/dictionary/en-custom.txt', 'docs/src/markdown/_snippets/abbr.txt', 'docs/src/markdown/_snippets/links.txt', 'docs/src/markdown/_snippets/posix.txt', 'docs/src/markdown/_snippets/refs.txt', 'requirements/docs.txt', 'requirements/lint.txt', 'requirements/setup.txt', 'requirements/test.txt', 'requirements/tools.txt']
 ```
 
-!!! new "New 4.0"
-    `MATCHBASE` added in 4.0.
-
 #### `glob.NODIR, glob.O` {: #nodir}
 
 `NODIR` will cause [`glob`](#glob), [`iglob`](#iglob), [`globmatch`](#globmatch), and [`globfilter`](#globfilter) to return only matched files.
@@ -985,9 +957,6 @@ or [`iglob`](#iglob). It also will not work when using the [`REALPATH`](#realpat
 
 If `FORCEWIN` is used along side [`FORCEUNIX`](#forceunix), both will be ignored.
 
-!!! new "New 4.2"
-    `FORCEWIN` is new in 4.2.0.
-
 #### `glob.FORCEUNIX, glob.U` {: #forceunix}
 
 `FORCEUNIX` will force Linux/Unix path and case logic to be used on Windows systems. This is great if you need to match
@@ -1001,9 +970,6 @@ use case insensitivity.
 
 If `FORCEUNIX` is used along side [`FORCEWIN`](#forcewin), both will be ignored.
 
-!!! new "New 4.2"
-    `FORCEUNIX` is new in 4.2.0.
-
 --8<--
 refs.txt
 --8<--
diff --git a/docs/src/markdown/wcmatch.md b/docs/src/markdown/wcmatch.md
index 88cc67a..471c240 100644
--- a/docs/src/markdown/wcmatch.md
+++ b/docs/src/markdown/wcmatch.md
@@ -8,7 +8,7 @@ from wcmatch import wcmatch
 
 `wcmatch.WcMatch` was originally written to provide a simple user interface for searching specific files in
 [Rummage](https://github.com/facelessuser/Rummage). A class was needed to facilitate a user interface where a user could
-select a base path, define one or more file patterns they wanted to search for, and provide folders to exclude if
+select a root directory, define one or more file patterns they wanted to search for, and provide folders to exclude if
 needed. It needed to be aware of hidden files on different systems, not just ignoring files that start with `.`. It also
 needed to be extendable so we could further filter returned files by size, creation date, or whatever else was decided.
 While [`glob`](./glob.md) is a fantastic file and folder search tool, it just didn't make sense for such a user
@@ -16,14 +16,22 @@ interface.
 
 ## `wcmatch.WcMatch` {: #wcmatch}
 
-`WcMatch` is an extendable file search class. It allows you to specify a base path, file patterns, and optional folder
-exclude patterns. You can specify whether you want to see hidden files and whether the search should be recursive. You
-can also derive from the class and tap into specific hooks to change what is returned or done when a file is matched,
-skipped, or when there is an error. There are also hooks where you can inject additional, custom filtering.
+```py3
+class WcMatch:
+    """Finds files by wildcard."""
+
+    def __init__(self, root_dir=".", file_pattern=None, **kwargs):
+        """Initialize the directory walker object."""
+```
+
+`WcMatch` is an extendable file search class. It allows you to specify a root directory path, file patterns, and
+optional folder exclude patterns. You can specify whether you want to see hidden files and whether the search should be
+recursive. You can also derive from the class and tap into specific hooks to change what is returned or done when a file
+is matched, skipped, or when there is an error. There are also hooks where you can inject additional, custom filtering.
 
 Parameter         | Default       | Description
 ----------------- | ------------- | -----------
-`directory`       |               | The base directory to search.
+`root_dir`        |               | The root directory to search.
 `file_pattern`    | `#!py3 ''`    | One or more patterns separated by `|`. You can define exceptions by starting a pattern with `!` (or `-` if [`MINUSNEGATE`](#minusnegate) is set). The default is an empty string, but if an empty string is used, all files will be matched.
 `exclude_pattern` | `#!py3 ''`    | Zero or more folder exclude patterns separated by `|`. You can define exceptions by starting a pattern with `!` (or `-` if [`MINUSNEGATE`](#minusnegate) is set).
 `flags`           | `#!py3 0`     | Flags to alter behavior of folder and file matching. See [Flags](#flags) for more info.
@@ -34,10 +42,6 @@ Parameter         | Default       | Description
     files) are excluded from the crawling processes, so there is no risk of `*` matching a dot file as it will not show
     up in the crawl. If the `HIDDEN` flag is included, `*`, `?`, and `[.]` will then match dot files.
 
-!!! danger "Removed in 3.0"
-    `show_hidden` and `recursive` were removed to provide a more consistent interface. Hidden files and recursion can be
-    enabled via the [`HIDDEN`](#hidden) and [`RECURSIVE`](#recursive) flag respectively.
-
 !!! new "New 6.0"
     `limit` was added in 6.0.
 
@@ -72,7 +76,7 @@ Excluding directories:
 
 ```pycon3
 >>> from wcmatch import wcmatch
->>> wcmatch.WcMatch('.', '*.md|*.txt', 'docs', flags=wcmatch.RECURSIVE).match()
+>>> wcmatch.WcMatch('.', '*.md|*.txt', exclude_pattern='docs', flags=wcmatch.RECURSIVE).match()
 ['./LICENSE.md', './README.md', './requirements/docs.txt', './requirements/lint.txt', './requirements/setup.txt', './requirements/test.txt']
 ```
 
@@ -80,7 +84,7 @@ Using file negation patterns:
 
 ```pycon3
 >>> from wcmatch import wcmatch
->>> wcmatch.WcMatch('.', '*.md|*.txt|!README*', 'docs', flags=wcmatch.RECURSIVE).match()
+>>> wcmatch.WcMatch('.', '*.md|*.txt|!README*', exclude_pattern='docs', flags=wcmatch.RECURSIVE).match()
 ['./LICENSE.md', './requirements/docs.txt', './requirements/lint.txt', './requirements/setup.txt', './requirements/test.txt']
 ```
 
@@ -89,7 +93,7 @@ You can also use negation patterns in directory exclude. Here we avoid all folde
 
 ```pycon3
 >>> from wcmatch import wcmatch
->>> wcmatch.WcMatch('.', '*.md|*.txt', '*|!requirements', flags=wcmatch.RECURSIVE).match()
+>>> wcmatch.WcMatch('.', '*.md|*.txt', exclude_pattern='*|!requirements', flags=wcmatch.RECURSIVE).match()
 ['./LICENSE.md', './README.md', './requirements/docs.txt', './requirements/lint.txt', './requirements/setup.txt', './requirements/test.txt']
 ```
 
@@ -97,7 +101,7 @@ Negative patterns can be given by themselves.
 
 ```pycon3
 >>> from wcmatch import wcmatch
->>> wcmatch.WcMatch('.', '*.md|*.txt', '!requirements', flags=wcmatch.RECURSIVE).match()
+>>> wcmatch.WcMatch('.', '*.md|*.txt', exclude_pattern='!requirements', flags=wcmatch.RECURSIVE).match()
 ['./LICENSE.md', './README.md', './requirements/docs.txt', './requirements/lint.txt', './requirements/setup.txt', './requirements/test.txt']
 ```
 
@@ -186,9 +190,6 @@ Checks if an abort has been issued.
 True
 ```
 
-!!! new "New 4.1"
-    `is_aborted` was added in 4.1.0.
-
 #### `WcMatch.get_skipped` {: #get_skipped}
 
 Returns the number of skipped files. Files in skipped folders are not included in the count.
@@ -207,13 +208,17 @@ Returns the number of skipped files. Files in skipped folders are not included i
 #### `WcMatch.on_init` {: #on_init}
 
 ```py3
-   def on_init(self, *args, **kwargs):
+   def on_init(self, **kwargs):
         """Handle custom init."""
 ```
 
-Any arguments or keyword arguments not processed by the main initializer are sent to `on_init`. This allows you to
+Any keyword arguments not processed by the main initializer are sent to `on_init`. This allows you to
 specify additional arguments when deriving from `WcMatch`.
 
+!!! new "Changed 8.0"
+    Starting in 8.0, `on_init` only accepts keyword arguments as now `WcMatch` requires all parameters (except
+    `root_dir` and `file_pattern`) to be keyword parameters and must explicitly be specified in the form `key=value`.
+
 #### `WcMatch.on_validate_directory` {: #on_validate_directory}
 
 ```py3
@@ -290,41 +295,26 @@ file meta data. `on_match` must return something, and all results will be return
 `on_reset` is a hook to provide a way to reset any custom logic in classes that have derived from `WcMatch`. `on_reset`
 is called on every new [`match`](#match) call.
 
-!!! new "New 4.0"
-    `on_reset` was added in 4.0.
-
 ## Flags
 
 #### `wcmatch.RECURSIVE, wcmatch.RV` {: #recursive}
 
 `RECURSIVE` forces a recursive search that will crawl all subdirectories.
 
-!!! new "New 3.0"
-    Added in 3.0 and must be used instead of the old `recursive` parameter which has also been removed as of 3.0.
-
 #### `wcmatch.HIDDEN, wcmatch.HD` {: #hidden}
 
 `HIDDEN` enables the crawling of hidden directories and will return hidden files if the wildcard pattern matches. This
 enables not just dot files, but system hidden files as well.
 
-!!! new "New 3.0"
-    Added in 3.0 and must be used instead of the old `show_hidden` parameter which has also been removed as of 3.0.
-
 #### `wcmatch.SYMLINK, wcmatch.SL` {: #symlink}
 
 `SYMLINK` enables the crawling of symlink directories. By default, symlink directories are ignored during the file
 crawl.
 
-!!! new "New 3.0"
-    Added in 3.0. Additionally, symlinks are now ignored by default moving forward if `SYMLINK` is not enabled.
-
 #### `wcmatch.CASE, wcmatch.C` {: #case}
 
 `CASE` forces case sensitivity. `CASE` has higher priority than [`IGNORECASE`](#ignorecase).
 
-!!! new "New 4.3"
-    `CASE` is new in 4.3.0.
-
 #### `wcmatch.IGNORECASE, wcmatch.I` {: #ignorecase}
 
 `IGNORECASE` forces case insensitive searches. [`CASE`](#case) has higher priority than `IGNORECASE`.
@@ -384,8 +374,9 @@ pattern which will perform much better: `@(ab|ac|ad)`.
 
 `DIRPATHNAME` will enable path name searching for excluded folder patterns, but it will not apply to file patterns. This
 is mainly provided for cases where you may have multiple folders with the same name, but you want to target a specific
-folder to exclude. The path name compared will be the entire path relative to the base path.  So if the provided base
-folder was `.`, and the folder under evaluation is `./some/folder`, `some/folder` will be matched against the pattern.
+folder to exclude. The path name compared will be the entire path relative to the root directory.  So if the provided
+root directory folder was `.`, and the folder under evaluation is `./some/folder`, `some/folder` will be matched against
+the pattern.
 
 ```pycon3
 >>> from wcmatch import wcmatch
@@ -396,8 +387,9 @@ folder was `.`, and the folder under evaluation is `./some/folder`, `some/folder
 #### `wcmatch.FILEPATHNAME, wcmatch.FP` {: #filepathname}
 
 `FILEPATHNAME` will enable path name searching for the file patterns, but it will not apply to directory exclude
-patterns. The path name compared will be the entire path relative to the base path.  So if the provided base folder was
-`.`, and the file under evaluation is `./some/file.txt`, `some/file.txt` will be matched against the pattern.
+patterns. The path name compared will be the entire path relative to the root directory path.  So if the provided root
+directory was `.`, and the file under evaluation is `./some/file.txt`, `some/file.txt` will be matched against the
+pattern.
 
 ```pycon3
 >>> from wcmatch import wcmatch
diff --git a/wcmatch/wcmatch.py b/wcmatch/wcmatch.py
index 1163a37..9b6a1c1 100644
--- a/wcmatch/wcmatch.py
+++ b/wcmatch/wcmatch.py
@@ -78,16 +78,15 @@ FLAG_MASK = (
 )
 
 
-class WcMatch(object):
+class WcMatch:
     """Finds files by wildcard."""
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, root_dir, file_pattern=None, exclude_pattern=None, flags=0, limit=_wcparse.PATHNAME, **kwargs):
         """Initialize the directory walker object."""
 
         self._abort = False
-        args = list(args)
         self._skipped = 0
-        self._directory = _wcparse.norm_slash(args.pop(0), 0)
+        self._directory = _wcparse.norm_slash(root_dir, 0)
         self.is_bytes = isinstance(self._directory, bytes)
         if not self._directory:
             if self.is_bytes:
@@ -97,16 +96,16 @@ class WcMatch(object):
         else:
             curdir = self._directory
         self.sep = os.fsencode(os.sep) if self.is_bytes else os.sep
-        self.base = curdir if curdir.endswith(self.sep) else curdir + self.sep
-        self.file_pattern = args.pop(0) if args else kwargs.pop('file_pattern', b'' if self.is_bytes else '')
+        self._root_dir = curdir if curdir.endswith(self.sep) else curdir + self.sep
+        self.file_pattern = file_pattern
         if not self.file_pattern:
             self.file_pattern = _wcparse.WcRegexp(
                 (re.compile(br'^.*$', re.DOTALL),) if self.is_bytes else (re.compile(r'^.*$', re.DOTALL),)
             )
-        self.exclude_pattern = args.pop(0) if args else kwargs.pop('exclude_pattern', b'' if self.is_bytes else '')
-        self._parse_flags(args.pop(0) if args else kwargs.pop('flags', 0))
-        self.limit = kwargs.pop('limit', _wcparse.PATTERN_LIMIT)
-        self.on_init(*args, **kwargs)
+        self.exclude_pattern = exclude_pattern if exclude_pattern is not None else (b'' if self.is_bytes else '')
+        self._parse_flags(flags)
+        self.limit = limit
+        self.on_init(**kwargs)
         self.file_check, self.folder_exclude_check = self._compile(self.file_pattern, self.exclude_pattern)
 
     def _parse_flags(self, flags):
@@ -189,7 +188,7 @@ class WcMatch(object):
 
         return not self.folder_exclude_check.match(directory + self.sep if self.dir_pathname else directory)
 
-    def on_init(self, *args, **kwargs):
+    def on_init(self, **kwargs):
         """Handle custom initialization."""
 
     def on_validate_directory(self, base, name):
@@ -238,9 +237,9 @@ class WcMatch(object):
     def _walk(self):
         """Start search for valid files."""
 
-        self._base_len = len(self.base)
+        self._base_len = len(self._root_dir)
 
-        for base, dirs, files in os.walk(self.base, followlinks=self.follow_links):
+        for base, dirs, files in os.walk(self._root_dir, followlinks=self.follow_links):
             if self.is_aborted():
                 break
 


Test patch:
diff --git a/tests/test_wcmatch.py b/tests/test_wcmatch.py
index e07147b..ffd1588 100644
--- a/tests/test_wcmatch.py
+++ b/tests/test_wcmatch.py
@@ -147,8 +147,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', '**/.hidden',
-            self.default_flags | wcmatch.DIRPATHNAME | wcmatch.GLOBSTAR | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt', exclude_pattern='**/.hidden',
+            flags=self.default_flags | wcmatch.DIRPATHNAME | wcmatch.GLOBSTAR | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)
@@ -160,8 +160,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '**/*.txt|-**/.hidden/*', None,
-            self.default_flags | wcmatch.FILEPATHNAME | wcmatch.GLOBSTAR | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '**/*.txt|-**/.hidden/*',
+            flags=self.default_flags | wcmatch.FILEPATHNAME | wcmatch.GLOBSTAR | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)
@@ -173,8 +173,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags
+            '*.txt',
+            flags=self.default_flags
         )
 
         self.crawl_files(walker)
@@ -186,8 +186,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.*|-*.file', None,
-            self.default_flags
+            '*.*|-*.file',
+            flags=self.default_flags
         )
 
         self.crawl_files(walker)
@@ -199,8 +199,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE
         )
 
         self.crawl_files(walker)
@@ -212,8 +212,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             os.fsencode(self.tempdir),
-            b'*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE
+            b'*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE
         )
 
         self.crawl_files(walker)
@@ -225,8 +225,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)
@@ -238,8 +238,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             os.fsencode(self.tempdir),
-            b'*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            b'*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)
@@ -251,8 +251,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', '.hidden',
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt', exclude_pattern='.hidden',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)
@@ -264,8 +264,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', '*|-.hidden',
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt', exclude_pattern='*|-.hidden',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)
@@ -277,8 +277,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         records = 0
@@ -302,8 +302,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt*', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt*',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         walker.kill()
@@ -319,25 +319,25 @@ class TestWcmatch(_TestWcmatch):
         target = '.' + os.sep
         walker = wcmatch.WcMatch(
             '',
-            '*.txt*', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt*',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
-        self.assertEqual(walker.base, target)
+        self.assertEqual(walker._root_dir, target)
 
         walker = wcmatch.WcMatch(
             b'',
-            b'*.txt*', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            b'*.txt*',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
-        self.assertEqual(walker.base, os.fsencode(target))
+        self.assertEqual(walker._root_dir, os.fsencode(target))
 
     def test_empty_string_file(self):
         """Test when file pattern is an empty string."""
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -352,8 +352,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         walker.on_skip = lambda base, name: '<SKIPPED>'
@@ -366,8 +366,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         walker.on_validate_file = lambda base, name: self.force_err()
@@ -381,8 +381,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         walker.on_validate_directory = lambda base, name: self.force_err()
@@ -395,8 +395,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         walker.on_validate_file = lambda base, name: self.force_err()
@@ -410,8 +410,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.FILEPATHNAME | wcmatch.MATCHBASE
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.FILEPATHNAME | wcmatch.MATCHBASE
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -426,8 +426,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '.hidden/*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.FILEPATHNAME | wcmatch.MATCHBASE
+            '.hidden/*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.FILEPATHNAME | wcmatch.MATCHBASE
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -442,8 +442,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '/*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.FILEPATHNAME | wcmatch.MATCHBASE
+            '/*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.FILEPATHNAME | wcmatch.MATCHBASE
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -458,8 +458,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            'A.TXT', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.FILEPATHNAME | wcmatch.IGNORECASE
+            'A.TXT',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.FILEPATHNAME | wcmatch.IGNORECASE
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -474,8 +474,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            'A.TXT', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.FILEPATHNAME | wcmatch.CASE
+            'A.TXT',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.FILEPATHNAME | wcmatch.CASE
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -490,8 +490,8 @@ class TestWcmatch(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            'a.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.FILEPATHNAME | wcmatch.CASE
+            'a.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.FILEPATHNAME | wcmatch.CASE
         )
         self.crawl_files(walker)
         self.assertEqual(
@@ -539,8 +539,8 @@ class TestWcmatchSymlink(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.SYMLINKS
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN | wcmatch.SYMLINKS
         )
 
         self.crawl_files(walker)
@@ -556,8 +556,8 @@ class TestWcmatchSymlink(_TestWcmatch):
 
         walker = wcmatch.WcMatch(
             self.tempdir,
-            '*.txt', None,
-            self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
+            '*.txt',
+            flags=self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN
         )
 
         self.crawl_files(walker)