Python Simple Range and Bearing Calculator using Complex Numbers
Keyword-only parameters
You are not using **kwargs correctly.  **kwargs should be used when you can accept any number of keywords, but you don't know what the keywords will be, such as dictionary creation.  If you only accept 2 keyword parameters, you should list those keyword parameters explicitly:
    def __init__(self, *, a_e=None, a_n=None):
        &quot;&quot;&quot;
        :param a_e: initial easting
        :param a_n: initial northing
        &quot;&quot;&quot;

        self.a_e = a_e
        self.a_n = a_n

That * marks the end of positional parameters.  a_e and a_n can be specified by keyword only.  Since both default to None, both are optional.  Any other keywords is reject with an error message, instead of silently being ignored.
Operator Precedence
        if self.a_e and self.a_n is not False:

This statement does not do what you think it does.  is not is higher precedence than and, so it reads:
        if self.a_e and (self.a_n is not False):

thus, if a_n is never given as False, the result of is not will be True, and the and will always result in the truthiness of a_e only.
You probably intended the evaluation to be:
        if (self.a_e and self.a_n) is not False:

which tests the truthiness of both a_e and a_n.  Sort of.  There are very few ways of getting something for which is not False is not true out of that expression.  The only way to get to the else expression is if a_e == False, or if a_e held a truthy value and a_n == False.  Again, since if the values are not given, they are defaulted to None, and since None and None evaluates to None, and None is not False is a true statement, the if clause would be executed.
So you probably wanted to write:
        if self.a_e is not None and self.a_n is not None:

Why not Zero?
If you used 0 as the default for a_n and a_e, then
            new_easting = self.a_e + delta_easting
            new_northing = self.a_n + delta_northing

new_easting would simply become delta_easting and new_northing would become delta_northing, and you could always do the addition and return `new_easting, new_northing.
    def __init__(self, *, a_e=0, a_n=0):
        &quot;&quot;&quot;
        :param a_e: initial easting
        :param a_n: initial northing
        &quot;&quot;&quot;

        self.a_e = a_e
        self.a_n = a_n

    def complex_randb(self, r, b):
        &quot;&quot;&quot;
        An equation that using imaginary numbers to calculate the coordinates of a new
        point from a range and bearing of an old point
        :param r: range from original coordinate to new coordinate
        :param b: bearing from original coordinate to new coordinate
        &quot;&quot;&quot;

        # -b is required as geodetic bearings are opposite to mathematical bearings
        t = complex(cos(radians(-b)), sin(radians(-b))) * complex(0, r)
        delta_easting = t.real
        delta_northing = t.imag

        new_easting = self.a_e + delta_easting
        new_northing = self.a_n + delta_northing

        return new_easting, new_northing

Naming
Your parameter names a_e, a_n, r, and b are too short and cryptic.  You should used easting northing, range, and bearing.
complex_randb is also confusing.  The input is real, the output is real.  The fact that complex numbers are internally used is an internal detail irrelevant to the caller.  What is randb, some kind of random b?  Oh, range_and_bearing!  But it is not a range and bearing function, it is a new coordinate function:
    def new_coordinate(self, range, bearing):
        &quot;&quot;&quot;Doc-string without the complex number internal detail mentioned&quot;&quot;&quot;
        ...

The class name CmO is also quite cryptic.  Is that &quot;C minus O&quot; because it runs &quot;C-O&quot; calculations?  You need a better class name.