I'm going to answer my question although thank you to everyone who commented: Andrew's answer is very informative and while it doesn't quite answer the question it certainly does lead to answers. I do think Potemkin will do this but I went ahead and wrote my own solution based on this thread. I will say I don't feel this approach is generally idiomatic, based on some responses here and further discussion in IRC, however it may make sense for limited use cases, such as mine.
But to answer the question, this function should do what I had originally intended:
(defn immigrate
[from-ns]
(require from-ns)
(doseq [[sym v] (ns-publics (find-ns from-ns))]
(let [target (if (bound? v)
(intern *ns* sym (var-get v))
(intern *ns* sym))]
(->>
(select-keys (meta target) [:name :ns])
(merge (meta v))
(with-meta '~target)))))
Then you could invoke it something like this, let's say we put this in foo.clj (if you see the gist I added in the edit):
(ns testing.foo)
(immigrate `testing.baz)
Now if we require testing.foo in the REPL:
=> (require '[testing.foo :as foo])
=> (foo/qux "hi!")
;; "hi!"
After speaking with Stuart Sierra on IRC and reading the email thread Andrew linked, I came to the conclusion that this is not necessarily the intended way to use namespaces.
Instead a better way to implement my library might look like this:
=> (require '[accord.oauth2 :as oauth2])
=> (def my-serv (oauth2/service 123 456 ...))
=> (require '[accord.http :as http])
=> (http/get my-serv "http://example.com/endpoint")
However given that I want to present the end-user with the cleanest API as possible, I may go ahead and use the immigrate
function in this very limited scope of "importing" the HTTP method functions.
Edit:
After further discussion, I think the above solution should not generally be used, as I said already. And for my use-case I'll probably go with my last solution, i.e. using two separate namespaces.