# Buggy code
def _random(self, n, p, size=None):
    original_dtype = p.dtype
    # Set float type to float64 for numpy. This change is related to numpy issue #8317 (https://github.com/numpy/numpy/issues/8317)
    p = p.astype("float64")
    # Now, re-normalize all of the values in float64 precision. This is done inside the conditionals
    if size == p.shape:
        size = None
    elif size[-len(p.shape) :] == p.shape:
        size = size[: len(size) - len(p.shape)]

    n_dim = n.squeeze().ndim

    if (n_dim == 0) and (p.ndim == 1):
        p = p / p.sum()
        randnum = np.random.multinomial(n, p.squeeze(), size=size)
    elif (n_dim == 0) and (p.ndim > 1):
        p = p / p.sum(axis=1, keepdims=True)
        randnum = np.asarray(
            [np.random.multinomial(n.squeeze(), pp, size=size) for pp in p]
        )
        randnum = np.moveaxis(randnum, 1, 0)
    elif (n_dim > 0) and (p.ndim == 1):
        p = p / p.sum()
        randnum = np.asarray(
            [np.random.multinomial(nn, p.squeeze(), size=size) for nn in n]
        )
        randnum = np.moveaxis(randnum, 1, 0)
    else:
        p = p / p.sum(axis=1, keepdims=True)
        randnum = np.asarray(
            [np.random.multinomial(nn, pp, size=size) for (nn, pp) in zip(n, p)]
        )
        randnum = np.moveaxis(randnum, 1, 0)
    return randnum.astype(original_dtype)


# Traceback (TypeError)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-06599b7f288c> in <module>()
----> 1 sim_priors = pm.sample_prior_predictive(samples=1000, model=dm_model, random_seed=RANDOM_SEED)

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/sampling.py in sample_prior_predictive(samples, model, vars, random_seed)
1314     names = get_default_varnames(model.named_vars, include_transformed=False)
1315     # draw_values fails with auto-transformed variables. transform them later!
-> 1316     values = draw_values([model[name] for name in names], size=samples)
1317
1318     data = {k: v for k, v in zip(names, values)}

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/distributions/distribution.py in draw_values(params, point, size)
319             else:
320                 try:  # might evaluate in a bad order,
--> 321                     evaluated[param_idx] = _draw_value(param, point=point, givens=givens.values(), size=size)
322                     if isinstance(param, collections.Hashable) and named_nodes_parents.get(param):
323                         givens[param.name] = (param, evaluated[param_idx])

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/distributions/distribution.py in _draw_value(param, point, givens, size)
403                     val = dist_tmp.random(point=point, size=None)
404                     dist_tmp.shape = val.shape
--> 405                 return dist_tmp.random(point=point, size=size)
406             else:
407                 return param.distribution.random(point=point, size=size)

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/distributions/multivariate.py in random(self, point, size)
571         samples = generate_samples(self._random, n, p,
572                                    dist_shape=self.shape,
--> 573                                    size=size)
574         return samples
575

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/distributions/distribution.py in generate_samples(generator, *args, **kwargs)
512     elif broadcast_shape[:len(size_tup)] == size_tup:
513         suffix = broadcast_shape[len(size_tup):] + dist_shape
--> 514         samples = [generator(*args, **kwargs).reshape(size_tup + (1,)) for _ in range(np.prod(suffix, dtype=int))]
515         samples = np.hstack(samples).reshape(size_tup + suffix)
516     else:

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/distributions/distribution.py in <listcomp>(.0)
512     elif broadcast_shape[:len(size_tup)] == size_tup:
513         suffix = broadcast_shape[len(size_tup):] + dist_shape
--> 514         samples = [generator(*args, **kwargs).reshape(size_tup + (1,)) for _ in range(np.prod(suffix, dtype=int))]
515         samples = np.hstack(samples).reshape(size_tup + suffix)
516     else:

/anaconda/envs/cdf/lib/python3.6/site-packages/pymc3/distributions/multivariate.py in _random(self, n, p, size)
536         if size == p.shape:
537             size = None
--> 538         elif size[-len(p.shape):] == p.shape:
539             size = size[:len(size) - len(p.shape)]
540

TypeError: 'NoneType' object is not subscriptable

# Fixed code
def _random(self, n, p, size=None):
    original_dtype = p.dtype
    # Set float type to float64 for numpy. This change is related to numpy issue #8317 (https://github.com/numpy/numpy/issues/8317)
    p = p.astype("float64")
    # Now, re-normalize all of the values in float64 precision. This is done inside the conditionals

    # np.random.multinomial needs `n` to be a scalar int and `p` a
    # sequence
    if p.ndim == 1 and (n.ndim == 0 or (n.ndim == 1 and n.shape[0] == 1)):
        # If `n` is already a scalar and `p` is a sequence, then just
        # return np.multinomial with some size handling
        p = p / p.sum()
        if size is not None:
            if size == p.shape:
                size = None
            elif size[-len(p.shape) :] == p.shape:
                size = size[: len(size) - len(p.shape)]
        randnum = np.random.multinomial(n, p, size=size)
        return randnum.astype(original_dtype)
    # The shapes of `p` and `n` must be broadcasted by hand depending on
    # their ndim. We will assume that the last axis of the `p` array will
    # be the sequence to feed into np.random.multinomial. The other axis
    # will only have to be iterated over.
    if n.ndim == p.ndim:
        # p and n have the same ndim, so n.shape[-1] must be 1
        if n.shape[-1] != 1:
            raise ValueError(
                "If n and p have the same number of "
                "dimensions, the last axis of n must be "
                "have len 1. Got {} instead.\n"
                "n.shape = {}\n"
                "p.shape = {}.".format(n.shape[-1], n.shape, p.shape)
            )
        n_p_shape = np.broadcast(np.empty(p.shape[:-1]), np.empty(n.shape[:-1])).shape
        p = np.broadcast_to(p, n_p_shape + (p.shape[-1],))
        n = np.broadcast_to(n, n_p_shape + (1,))
    elif n.ndim == p.ndim - 1:
        # n has the number of dimensions of p for the iteration, these must
        # broadcast together
        n_p_shape = np.broadcast(np.empty(p.shape[:-1]), n).shape
        p = np.broadcast_to(p, n_p_shape + (p.shape[-1],))
        n = np.broadcast_to(n, n_p_shape + (1,))
    elif p.ndim == 1:
        # p only has the sequence array. We extend it with the dimensions
        # of n
        n_p_shape = n.shape
        p = np.broadcast_to(p, n_p_shape + (p.shape[-1],))
        n = np.broadcast_to(n, n_p_shape + (1,))
    elif n.ndim == 0 or (n.dim == 1 and n.shape[0] == 1):
        # n is a scalar. We extend it with the dimensions of p
        n_p_shape = p.shape[:-1]
        n = np.broadcast_to(n, n_p_shape + (1,))
    else:
        # There is no clear rule to broadcast p and n so we raise an error
        raise ValueError(
            "Incompatible shapes of n and p.\nn.shape = {}\np.shape = {}".format(
                n.shape, p.shape
            )
        )

    # Check what happens with size
    if size is not None:
        if size == p.shape:
            size = None
            _size = 1
        elif size[-len(p.shape) :] == p.shape:
            size = size[: len(size) - len(p.shape)]
            _size = np.prod(size)
        else:
            _size = np.prod(size)
    else:
        _size = 1

    # We now flatten p and n up to the last dimension
    p_shape = p.shape
    p = np.reshape(p, (np.prod(n_p_shape), -1))
    n = np.reshape(n, (np.prod(n_p_shape), -1))
    # We renormalize p
    p = p / p.sum(axis=1, keepdims=True)
    # We iterate calls to np.random.multinomial
    randnum = np.asarray(
        [np.random.multinomial(nn, pp, size=_size) for (nn, pp) in zip(n, p)]
    )
    # We swap the iteration axis with the _size axis
    randnum = np.moveaxis(randnum, 1, 0)
    # We reshape the random numbers to the corresponding size + p_shape
    if size is None:
        randnum = np.reshape(randnum, p_shape)
    else:
        randnum = np.reshape(randnum, size + p_shape)
    # We cast back to the original dtype
    return randnum.astype(original_dtype)