Repository: Qiskit/qiskit

Issue:
pulse jobs fail schema validation
Every pulse job is failing schema validation. This happened in https://github.com/Qiskit/qiskit-terra/pull/4539.

```py
from qiskit import *

IBMQ.load_account()
p = IBMQ.get_provider(project='......')
backend = p.get_backend('ibmq_armonk')

c = QuantumCircuit(1, 1)
c.measure(0, 0)
c = transpile(c, backend)
s = schedule(c, backend)
qobj = assemble(s, backend=backend, shots=100)
job = backend.run(qobj)
```


Discussion:
To make #4539  work with our broken system around schemas (because of the lack of versioning and the backwards relationship between iqx and terra) it needs to be reverted on the qobj and assembly side except for the qobj schema changes. Then after the schema changes get included in the next release we can look at adding back the pieces that use the changes. (Note this only works because the change is an addition only and a backwards compatible type change)

Right now the schemas used by iqx rely on the released version of terra as the source of truth for the schema files and are not using versioning. So until we release terra with the updated schema IQX doesn't know about any changes made in the terra and will be using the schema from the last release.
It seems like it may be failing because `rep_time` may be empty? We could provide a dummy value if not supplied to make this pass validation temporarily? @zachschoenfeld33 

Resolving patch:
diff --git a/qiskit/compiler/assemble.py b/qiskit/compiler/assemble.py
--- a/qiskit/compiler/assemble.py
+++ b/qiskit/compiler/assemble.py
@@ -58,7 +58,7 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,
              meas_return: Union[str, MeasReturnType] = MeasReturnType.AVERAGE,
              meas_map: Optional[List[List[Qubit]]] = None,
              memory_slot_size: int = 100,
-             rep_time: Optional[float] = None,
+             rep_time: Optional[int] = None,
              rep_delay: Optional[float] = None,
              parameter_binds: Optional[List[Dict[Parameter, float]]] = None,
              parametric_pulses: Optional[List[str]] = None,
@@ -293,7 +293,7 @@ def _parse_pulse_args(backend, qubit_lo_freq, meas_lo_freq, qubit_lo_range,
                           "used instead, if specified.", RuntimeWarning)
         if isinstance(rep_time, list):
             rep_time = rep_time[0]
-        rep_time = rep_time * 1e6  # convert sec to μs
+        rep_time = int(rep_time * 1e6)  # convert sec to μs
 
     rep_delay = rep_delay or getattr(backend_config, 'rep_delays', None)
     if rep_delay:
diff --git a/qiskit/execute.py b/qiskit/execute.py
--- a/qiskit/execute.py
+++ b/qiskit/execute.py
@@ -172,10 +172,10 @@ def execute(experiments, backend,
 
         memory_slot_size (int): Size of each memory slot if the output is Level 0.
 
-        rep_time (list[float]): Time per program execution in sec. Must be from the list provided
+        rep_time (int): Time per program execution in sec. Must be from the list provided
             by the backend (``backend.configuration().rep_times``).
 
-        rep_delay (list[float]): Delay between programs in sec. Only supported on certain
+        rep_delay (float): Delay between programs in sec. Only supported on certain
             backends (``backend.configuration().dynamic_reprate_enabled`` ).
             If supported, ``rep_delay`` will be used instead of ``rep_time``. Must be from the list
             provided by the backend (``backend.configuration().rep_delays``).
diff --git a/qiskit/qobj/pulse_qobj.py b/qiskit/qobj/pulse_qobj.py
--- a/qiskit/qobj/pulse_qobj.py
+++ b/qiskit/qobj/pulse_qobj.py
@@ -249,7 +249,7 @@ def __init__(self, meas_level, meas_return, pulse_library,
                 measurement driver LO's in GHz.
             memory_slot_size (int): Size of each memory slot if the output is
                 Level 0.
-            rep_time (float): Time per program execution in sec. Must be from the list provided
+            rep_time (int): Time per program execution in sec. Must be from the list provided
                 by the backend (``backend.configuration().rep_times``).
             rep_delay (float): Delay between programs in sec. Only supported on certain
                 backends (``backend.configuration().dynamic_reprate_enabled``).


Test patch:
diff --git a/test/python/compiler/test_assembler.py b/test/python/compiler/test_assembler.py
--- a/test/python/compiler/test_assembler.py
+++ b/test/python/compiler/test_assembler.py
@@ -726,14 +726,14 @@ def test_assemble_backend_rep_times_delays(self):
         # RuntimeWarning bc using ``rep_delay`` when dynamic rep rates not enabled
         with self.assertWarns(RuntimeWarning):
             qobj = assemble(self.schedule, self.backend)
-        self.assertEqual(round(qobj.config.rep_time, 3), rep_times[0]*1e6)
+        self.assertEqual(qobj.config.rep_time, int(rep_times[0]*1e6))
         self.assertEqual(qobj.config.rep_delay, rep_delays[0]*1e6)
 
         # remove rep_delays from backend config and make sure things work
         # now no warning
         del self.backend_config.rep_delays
         qobj = assemble(self.schedule, self.backend)
-        self.assertEqual(round(qobj.config.rep_time, 3), rep_times[0]*1e6)
+        self.assertEqual(qobj.config.rep_time, int(rep_times[0]*1e6))
         self.assertEqual(hasattr(qobj.config, 'rep_delay'), False)
 
     def test_assemble_user_rep_time_delay(self):
@@ -746,7 +746,7 @@ def test_assemble_user_rep_time_delay(self):
         # RuntimeWarning bc using ``rep_delay`` when dynamic rep rates not enabled
         with self.assertWarns(RuntimeWarning):
             qobj = assemble(self.schedule, self.backend, **self.config)
-        self.assertEqual(qobj.config.rep_time, rep_time*1e6)
+        self.assertEqual(qobj.config.rep_time, int(rep_time*1e6))
         self.assertEqual(qobj.config.rep_delay, rep_delay*1e6)
 
         # now remove rep_delay and set enable dynamic rep rates
@@ -755,7 +755,7 @@ def test_assemble_user_rep_time_delay(self):
         self.backend_config.dynamic_reprate_enabled = True
         with self.assertWarns(RuntimeWarning):
             qobj = assemble(self.schedule, self.backend, **self.config)
-        self.assertEqual(qobj.config.rep_time, rep_time*1e6)
+        self.assertEqual(qobj.config.rep_time, int(rep_time*1e6))
         self.assertEqual(hasattr(qobj.config, 'rep_delay'), False)
 
         # finally, only use rep_delay and verify that everything runs w/ no warning
@@ -765,7 +765,7 @@ def test_assemble_user_rep_time_delay(self):
         del self.config['rep_time']
         self.config['rep_delay'] = rep_delay
         qobj = assemble(self.schedule, self.backend, **self.config)
-        self.assertEqual(qobj.config.rep_time, rep_times[0]*1e6)
+        self.assertEqual(qobj.config.rep_time, int(rep_times[0]*1e6))
         self.assertEqual(qobj.config.rep_delay, rep_delay*1e6)