human
Complete this python program:
def factor_terms(expr, radical=False, clear=False, fraction=False, sign=True):
assistant
#Here is the Python program you requested.

    """Remove common factors from terms in all arguments without
    changing the underlying structure of the expr. No expansion or
    simplification (and no processing of non-commutatives) is performed.
    If radical=True then a radical common to all terms will be factored
    out of any Add sub-expressions of the expr.
    If clear=False (default) then coefficients will not be separated
    from a single Add if they can be distributed to leave one or more
    terms with integer coefficients.
    If fraction=True (default is False) then a common denominator will be
    constructed for the expression.
    If sign=True (default) then even if the only factor in common is a -1,
    it will be factored out of the expression.
    Examples
    >>> from sympy import factor_terms, Symbol
    >>> from sympy.abc import x, y
    >>> factor_terms(x + x*(2 + 4*y)**3)
    x*(8*(2*y + 1)**3 + 1)
    >>> A = Symbol(\A\, commutative=False)
    >>> factor_terms(x*A + x*A + x*y*A)
    x*(y*A + 2*A)
    When ``clear`` is False, a rational will only be factored out of an
    Add expression if all terms of the Add have coefficients that are
    fractions:
    >>> factor_terms(x/2 + 1, clear=False)
    x/2 + 1
    >>> factor_terms(x/2 + 1, clear=True)
    (x + 2)/2
    If a -1 is all that can be factored out, to *not* factor it out, the
    flag ``sign`` must be False:
    >>> factor_terms(-x - y)
    -(x + y)
    >>> factor_terms(-x - y, sign=False)
    -x - y
    >>> factor_terms(-2*x - 2*y, sign=False)
    -2*(x + y)
    See Also
    gcd_terms, sympy.polys.polytools.terms_gcd
    """
    def do(expr):
        from sympy.concrete.summations import Sum
        from sympy.simplify.simplify import factor_sum
        is_iterable = iterable(expr)
        if ((not isinstance(expr, Basic)) or expr.is_Atom):
            if is_iterable:
                return type(expr)([do(i) for i in expr])
            return expr
        if (expr.is_Pow or expr.is_Function or is_iterable or (not hasattr(expr, 'args_cnc'))):
            args = expr.args
            newargs = tuple([do(i) for i in args])
            if (newargs == args):
                return expr
            return expr.func(*newargs)
        if isinstance(expr, Sum):
            return factor_sum(expr, radical=radical, clear=clear, fraction=fraction, sign=sign)
        (cont, p) = expr.as_content_primitive(radical=radical, clear=clear)
        if p.is_Add:
            list_args = [do(a) for a in Add.make_args(p)]
            if all(((a.as_coeff_Mul()[0] < 0) for a in list_args)):
                cont = (- cont)
                list_args = [(- a) for a in list_args]
            special = {}
            for (i, a) in enumerate(list_args):
                (b, e) = a.as_base_exp()
                if (e.is_Mul and (e != Mul(*e.args))):
                    list_args[i] = Dummy()
                    special[list_args[i]] = a
            p = Add._from_args(list_args)
            p = gcd_terms(p, isprimitive=True, clear=clear, fraction=fraction).xreplace(special)
        elif p.args:
            p = p.func(*[do(a) for a in p.args])
        rv = _keep_coeff(cont, p, clear=clear, sign=sign)
        return rv
    expr = sympify(expr)
    return do(expr)