def abs_target(target, default_module=None):
    """Determines the canonical representation of a target, while
    allowing syntactic sugar for the user.

    Params:
      target: e.g. "src=com/yext/subscriptions:app", src/com/yext/subscriptions:app"
      default_module: optional module that can be used to resolve a module-less path.

    Returns:
      The fully qualified target name.

    Raises:
      Error if no module can be found and none is provided.
    """
    # If the target is fully-specified, just return it.
    if "=" in target:
        return target

    # If the target doesn't have a : in it, assume that the "file" in
    # the directory is actually the target name.
    if ":" not in target and "/" in target:
        d, t = target.rsplit("/", 1)
        target = "%s:%s" % (d, t)

    # If the target ends with .java, then likely the user just
    # autocompleted and wants the target without .java, so strip it
    # out.
    if target.endswith(".java"):
        target = target[:-5]

    # Try splitting on 'src' directory
    if "src/" in target:
        module, rt = target.split("src/")
        return "%ssrc=%s" % (module, rt)

    # The test directory doesn't have a src dir, so add a special
    # case syntactic sugar to add "=" after test.
    elif target.startswith("test/"):
        return "test=%s" % (target[5:])

    # Ran out of guesses, use default module
    elif default_module is not None:
        return "%s=%s" % (default_module, target)

    else:
        raise Exception("No module could be determined for target: " + target)