code: def update(self, table_name, values, constraints=None, *, returning=None):
      
      if constraints is None:
        constraints = "1=1"
      assignments, assignment_params = self.sql_writer.parse_constraints(
        values, ", ", is_assignment=True)
      where, where_params = self.sql_writer.parse_constraints(constraints, " and ")
      returns = ""
      if returning and self.core.supports_returning_syntax:
        returns = " returning {0}".format(returning)
      sql = "update {0} set {1} where {2}{3};".format(table_name, assignments, where, returns)
      params = assignment_params
  
      if constraints is None or isinstance(constraints, str):
        pass
      elif isinstance(constraints, dict):
        if isinstance(params, list):
          raise ValueError("you cannot mix enumerable and dict values and constraints")
        params = params or {}
        params.update(where_params)
      else:
        if isinstance(params, dict):
          raise ValueError("you cannot mix enumerable and dict values and constraints")
        params = params or []
        params.extend(where_params)
  
      cr = self.execute(sql, params)
      return cr
docs: Builds and executes and update statement.
  
      :param table_name: the name of the table to update
      :param values: can be either a dict or an enuerable of 2-tuples in the form (column, value).
      :param constraints: can be any construct that can be parsed by SqlWriter.parse_constraints.
                          However, you cannot mix tuples and dicts between values and constraints.
      :param returning: the columns to return after updating. Only works for cores that support the
                        returning syntax
      :return: a cursor object