diff --git a/kgb/spies.py b/kgb/spies.py
index 4e818d0717e5e01e12b615333b7f90c3d2e8a37f..3abc2de68beae5191003c444f966d8d28a553df1 100644
--- a/kgb/spies.py
+++ b/kgb/spies.py
@@ -521,6 +521,9 @@ class FunctionSpy(object):
         code_args = [temp_code.co_argcount]
 
         if pyver[0] >= 3:
+            if pyver[1] >= 8:
+                code_args.append(temp_code.co_posonlyargcount)
+
             code_args.append(temp_code.co_kwonlyargcount)
 
         code_args += [
@@ -1058,38 +1061,84 @@ class FunctionSpy(object):
             argspec = inspect.getargspec(func)
 
             result = {
+                'args_name': argspec.varargs,
                 'kwargs_name': argspec.keywords,
             }
-        else:
-            argspec = inspect.getfullargspec(func)
 
-            result = {
-                'kwargs_name': argspec.varkw,
-                'kwonly_args': argspec.kwonlyargs,
-                'kwonly_defaults': argspec.kwonlydefaults,
-            }
+            all_args = argspec.args
+            defaults = argspec.defaults
 
-        all_args = argspec.args
+            result.update({
+                'all_args': all_args,
+                'args_name': argspec.varargs,
+                'defaults': defaults,
+            })
 
-        result.update({
-            'all_args': all_args,
-            'defaults': argspec.defaults,
-            'args_name': argspec.varargs,
-        })
+            keyword_args = result.get('kwonly_args', [])
 
-        keyword_args = result.get('kwonly_args', [])
+            if all_args and defaults:
+                num_defaults = len(argspec.defaults)
+                keyword_args = all_args[-num_defaults:]
+                pos_args = all_args[:-num_defaults]
+            else:
+                pos_args = all_args
 
-        if all_args and argspec.defaults:
-            num_defaults = len(argspec.defaults)
-            keyword_args = all_args[-num_defaults:]
-            pos_args = all_args[:-num_defaults]
+            result.update({
+                'args': pos_args,
+                'kwargs': keyword_args,
+            })
         else:
-            pos_args = all_args
-
-        result.update({
-            'args': pos_args,
-            'kwargs': keyword_args,
-        })
+            assert hasattr(inspect, '_signature_from_callable'), (
+                'Python %s.%s does not have inspect._signature_from_callable, '
+                'which is needed in order to generate a Signature from a '
+                'function.'
+                % pyver)
+
+            sig = inspect._signature_from_callable(
+                func,
+                follow_wrapper_chains=False,
+                skip_bound_arg=False,
+                sigcls=inspect.Signature)
+
+            all_args = []
+            args = []
+            args_name = None
+            kwargs = []
+            kwargs_name = None
+
+            for param in sig.parameters.values():
+                kind = param.kind
+                name = param.name
+
+                if kind is param.POSITIONAL_OR_KEYWORD:
+                    # Standard arguments -- either positional or keyword.
+                    all_args.append(name)
+
+                    if param.default is param.empty:
+                        args.append(name)
+                    else:
+                        kwargs.append(name)
+                elif kind is param.POSITIONAL_ONLY:
+                    # Positional-only arguments (Python 3.8+).
+                    all_args.append(name)
+                    args.append(name)
+                elif kind is param.KEYWORD_ONLY:
+                    # Keyword-only arguments (Python 3+).
+                    kwargs.append(name)
+                elif kind is param.VAR_POSITIONAL:
+                    # *args
+                    args_name = name
+                elif kind is param.VAR_KEYWORD:
+                    kwargs_name = name
+
+            return {
+                'all_args': all_args,
+                'args': args,
+                'args_name': args_name,
+                'kwargs': kwargs,
+                'kwargs_name': kwargs_name,
+                'sig': sig,
+            }
 
         return result
 
@@ -1109,47 +1158,26 @@ class FunctionSpy(object):
             unicode:
             A string representing an argument list for a function definition.
         """
-        if hasattr(inspect, 'Signature'):
-            Parameter = inspect.Parameter
-
-            args = argspec['all_args']
-            defaults = argspec['defaults'] or ()
-            kwonly_args = argspec['kwonly_args']
-            kwonly_defaults = argspec['kwonly_defaults']
-            args_name = argspec['args_name']
-            kwargs_name = argspec['kwargs_name']
-
+        if 'sig' in argspec:
             parameters = []
-            first_default = len(args) - len(defaults)
 
-            for i, arg in enumerate(args):
-                if defaults and i >= first_default:
+            # Make a copy of the Signature and its parameters, but leave out
+            # all type annotations.
+            for orig_param in argspec['sig'].parameters.values():
+                default = orig_param.default
+
+                if (orig_param.kind is orig_param.POSITIONAL_OR_KEYWORD and
+                    default is not orig_param.empty):
                     default = _UNSET_ARG
-                else:
-                    default = Parameter.empty
 
-                parameters.append(Parameter(
-                    name=arg,
-                    kind=Parameter.POSITIONAL_OR_KEYWORD,
+                parameters.append(inspect.Parameter(
+                    name=orig_param.name,
+                    kind=orig_param.kind,
                     default=default))
 
-            if args_name:
-                parameters.append(Parameter(
-                    name=args_name,
-                    kind=Parameter.VAR_POSITIONAL))
+            sig = inspect.Signature(parameters=parameters)
 
-            for arg in kwonly_args:
-                parameters.append(Parameter(
-                    name=arg,
-                    kind=Parameter.KEYWORD_ONLY,
-                    default=kwonly_defaults.get(arg, Parameter.empty)))
-
-            if kwargs_name:
-                parameters.append(Parameter(
-                    name=kwargs_name,
-                    kind=Parameter.VAR_KEYWORD))
-
-            return str(inspect.Signature(parameters=parameters))[1:-1]
+            return str(sig)[1:-1]
         else:
             kwargs = {
                 'args': argspec['all_args'],
@@ -1159,12 +1187,6 @@ class FunctionSpy(object):
                 'formatvalue': lambda value: '=_UNSET_ARG',
             }
 
-            if pyver[0] >= 3:
-                kwargs.update({
-                    'kwonlyargs': argspec['kwonly_args'],
-                    'kwonlydefaults': argspec['kwonly_defaults'],
-                })
-
             return inspect.formatargspec(**kwargs)[1:-1]
 
     def _are_argspecs_compatible(self, master_argspec, compat_argspec):
diff --git a/kgb/tests/base.py b/kgb/tests/base.py
index 5341b84d44704ddfb31ca2a77050cb7cbbb676ff..d4c284c39cf95d7480da27790bb30f5670c4817e 100644
--- a/kgb/tests/base.py
+++ b/kgb/tests/base.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 import re
 import sys
+import textwrap
 
 if sys.version_info[:2] >= (2, 7):
     import unittest
@@ -72,3 +73,30 @@ class TestCase(unittest.TestCase):
             doc = self.ws_re.sub(' ', doc).strip()
 
         return doc
+
+    def make_func(self, code_str, func_name='func'):
+        """Return a new function, created by the supplied Python code.
+
+        This is used to create functions with signatures that depend on a
+        specific version of Python, and would generate syntax errors on
+        earlier versions.
+
+        Args:
+            code_str (unicode):
+                The Python code used to create the function.
+
+            func_name (unicode, optional):
+                The expected name of the function.
+
+        Returns:
+            callable:
+            The resulting function.
+
+        Raises:
+            Exception:
+                There was an error with the supplied code.
+        """
+        scope = {}
+        exec(textwrap.dedent(code_str), scope)
+
+        return scope[func_name]
diff --git a/kgb/tests/py3/test_function_spy.py b/kgb/tests/py3/test_function_spy.py
index e60f5c61379d93a34004d33940a2e5f18fe71c29..5c8b0e2ee6d7495ebcfa2b5605064f37ec6f7c35 100644
--- a/kgb/tests/py3/test_function_spy.py
+++ b/kgb/tests/py3/test_function_spy.py
@@ -1,3 +1,6 @@
+import sys
+from unittest import SkipTest
+
 from kgb.tests.base import TestCase
 
 
@@ -78,6 +81,46 @@ class FunctionSpyTests(TestCase):
                 'return': bool,
             })
 
+    def test_call_with_function_and_positional_only_args(self):
+        """Testing FunctionSpy calls with function containing positional-only
+        arguments
+        """
+        if sys.version_info[:2] < (3, 8):
+            raise SkipTest('Not supported on this version of Python')
+
+        func = self.make_func("""
+            def func(a, b=1, /):
+                return a * b
+        """)
+
+        self.agency.spy_on(func)
+        result = func(2, 5)
+
+        self.assertEqual(result, 10)
+        self.assertEqual(len(func.spy.calls), 1)
+        self.assertEqual(func.spy.calls[0].args, (2, 5))
+        self.assertEqual(func.spy.calls[0].kwargs, {})
+
+    def test_call_with_function_and_positional_only_args_no_pos_passed(self):
+        """Testing FunctionSpy calls with function containing positional-only
+        arguments and no positional argument passed
+        """
+        if sys.version_info[:2] < (3, 8):
+            raise SkipTest('Not supported on this version of Python')
+
+        func = self.make_func("""
+            def func(a, b=2, /):
+                return a * b
+        """)
+
+        self.agency.spy_on(func)
+        result = func(2)
+
+        self.assertEqual(result, 4)
+        self.assertEqual(len(func.spy.calls), 1)
+        self.assertEqual(func.spy.calls[0].args, (2, 2))
+        self.assertEqual(func.spy.calls[0].kwargs, {})
+
     def test_call_with_function_and_keyword_only_args(self):
         """Testing FunctionSpy calls with function containing keyword-only
         arguments
@@ -93,7 +136,7 @@ class FunctionSpyTests(TestCase):
         self.assertEqual(func.spy.calls[0].args, (2,))
         self.assertEqual(func.spy.calls[0].kwargs, {'b': 5})
 
-    def test_call_with_function_and_keyword_only_args(self):
+    def test_call_with_function_and_keyword_only_args_no_kw_passed(self):
         """Testing FunctionSpy calls with function containing keyword-only
         arguments and no keyword passed
         """
