This is a surprisingly messy question.
1) Inside a test, look at the environment variable $TEST_SRCDIR. This will get you the runfiles directory or possibly a sandboxed analogue.
2) For "bazel run my-python-target" or "bazel-bin/my-python-target", there is no useful environment variable, so do as you describe. Import your project's top-level package (if it has one) and look at it's __file__ attribute. You may have to implement some kind of heuristic search based directory names (*.runfiles/) and/or well-known file names (./WORKSPACE or some_dir/some_package/__init__.py). This will be complicated if your program is built as a zip/.par/.pex/.egg file.
Internally, we have a complicated and fragile set of helper functions to encapsulate this, based on assumptions about directory structure and project organization. There doesn't seem to be a better solution without changing Python itself.
As you mentioned, pkgutil.get_data its own limitations. It also doesn't work with Python3 "namespace packages".