A "symbolic" solution always exists: I just invented a new function intcos(x) , which by definition is the antiderivative of 1/cos(x**2) . Now this integral has a symbolic solution!

For the question to be rigorously answerable, one has to restrict the class of functions allowed in the answer. Typically one considers elementary functions. As SymPy integral reference explains, the Risch algorithm it employs can prove that some functions do not have elementary antiderivatives. Use the option risch=True and check whether the return value is an instance of sympy.integrals.risch.NonElementaryIntegral

from sympy.integrals.risch import NonElementaryIntegral isinstance(integrate(1/exp(x**2), x, risch=True), NonElementaryIntegral) # True

However, since Risch algorithm implementation is incomplete, in many cases like 1/cos(x**2) it returns an ordinary Integral object. This means it was not able to either find an elementary antiderivative or prove that one does not exist.

For this example, it helps to rewrite the trigonometric function in terms of exponential, with rewrite(cos, exp) :

isinstance(integrate((1/cos(x**2)).rewrite(cos, exp), x, risch=True), NonElementaryIntegral)

returns True, so we know the integral is nonelementary.

Non-elementary antiderivatives

But often we don't really need an elementary function; something like Gamma or erf or Bessel functions may be okay; as long as it's some "known" function (which of course is a fuzzy term). The question becomes: how to tell if SymPy was able to integrate a specific expression or not? Use .has(Integral) check for that:

integrate(2/cos(x**2), x).has(Integral) # True