diff --git a/altair/vegalite/v3/api.py b/altair/vegalite/v3/api.py
index 16796458..a57e009c 100644
--- a/altair/vegalite/v3/api.py
+++ b/altair/vegalite/v3/api.py
@@ -487,7 +487,7 @@ class TopLevelMixin(mixins.ConfigMethodMixin):
     def __or__(self, other):
         return HConcatChart(hconcat=[self, other])
 
-    def repeat(self, row=Undefined, column=Undefined, **kwargs):
+    def repeat(self, repeat=Undefined, row=Undefined, column=Undefined, columns=Undefined, **kwargs):
         """Return a RepeatChart built from the chart
 
         Fields within the chart can be set to correspond to the row or
@@ -495,19 +495,36 @@ class TopLevelMixin(mixins.ConfigMethodMixin):
 
         Parameters
         ----------
+        repeat : list
+            a list of data column names to be repeated. This cannot be
+            used along with the ``row`` or ``column`` argument.
         row : list
             a list of data column names to be mapped to the row facet
         column : list
             a list of data column names to be mapped to the column facet
+        columns : int
+            the maximum number of columns before wrapping. Only referenced
+            if ``repeat`` is specified.
+        **kwargs :
+            additional keywords passed to RepeatChart.
 
         Returns
         -------
         chart : RepeatChart
             a repeated chart.
-
         """
-        repeat = core.RepeatMapping(row=row, column=column)
-        return RepeatChart(spec=self, repeat=repeat, **kwargs)
+        repeat_specified = (repeat is not Undefined)
+        rowcol_specified = (row is not Undefined or column is not Undefined)
+
+        if repeat_specified and rowcol_specified:
+            raise ValueError("repeat argument cannot be combined with row/column argument.")
+
+        if repeat_specified:
+            repeat = repeat
+        else:
+            repeat = core.RepeatMapping(row=row, column=column)
+
+        return RepeatChart(spec=self, repeat=repeat, columns=columns, **kwargs)
 
     def properties(self, **kwargs):
         """Set top-level properties of the Chart.
@@ -1378,7 +1395,7 @@ class EncodingMixin(object):
                                      "".format(encoding))
                 kwargs[encoding] = arg
 
-        def _wrap_in_channel_class(obj, prop):  
+        def _wrap_in_channel_class(obj, prop):
             clsname = prop.title()
 
             if isinstance(obj, core.SchemaBase):
@@ -1662,7 +1679,7 @@ class RepeatChart(TopLevelMixin, core.TopLevelRepeatSpec):
         return copy
 
 
-def repeat(repeater):
+def repeat(repeater='repeat'):
     """Tie a channel to the row or column within a repeated chart
 
     The output of this should be passed to the ``field`` attribute of
@@ -1671,13 +1688,14 @@ def repeat(repeater):
     Parameters
     ----------
     repeater : {'row'|'column'|'repeat'}
-        The repeater to tie the field to.
+        The repeater to tie the field to. Default is 'repeat'.
 
     Returns
     -------
     repeat : RepeatRef object
     """
-    assert repeater in ['row', 'column', 'repeat']
+    if repeater not in ['row', 'column', 'repeat']:
+        raise ValueError("repeater must be one of ['row', 'column', 'repeat']")
     return core.RepeatRef(repeat=repeater)
 
 

repeat() function is borked in Altair 3
Need to make certain ``alt.repeat()`` and ``alt.Chart.repeat()`` work correctly together and support wrapped repeats.
diff --git a/altair/vegalite/v3/tests/test_api.py b/altair/vegalite/v3/tests/test_api.py
index e9f9143d..119ed6eb 100644
--- a/altair/vegalite/v3/tests/test_api.py
+++ b/altair/vegalite/v3/tests/test_api.py
@@ -493,9 +493,10 @@ def test_chart_from_dict():
               base & base,
               base.facet(row='c:N'),
               (base + base).facet(row='c:N', data='data.csv'),
-              base.repeat(row=['c:N', 'd:N'])]
+              base.repeat(['c:N', 'd:N'])]
 
     for chart in charts:
+        print(chart)
         chart_out = alt.Chart.from_dict(chart.to_dict())
         assert type(chart_out) is type(chart)
 
@@ -571,4 +572,37 @@ def test_deprecated_encodings():
     assert 'alt.StrokeOpacity' in record[0].message.args[0]
     chart2 = base.encode(strokeOpacity=alt.StrokeOpacity('x:Q')).to_dict()
 
-    assert chart1 == chart2
\ No newline at end of file
+    assert chart1 == chart2
+
+
+def test_repeat():
+    # wrapped repeat
+    chart1 = alt.Chart('data.csv').mark_point().encode(
+        x=alt.X(alt.repeat(), type='quantitative'),
+        y='y:Q',
+    ).repeat(
+        ['A', 'B', 'C', 'D'],
+        columns=2
+    )
+
+    dct1 = chart1.to_dict()
+
+    assert dct1['repeat'] == ['A', 'B', 'C', 'D']
+    assert dct1['columns'] == 2
+    assert dct1['spec']['encoding']['x']['field'] == {'repeat': 'repeat'}
+
+    # explicit row/col repeat
+    chart2 = alt.Chart('data.csv').mark_point().encode(
+        x=alt.X(alt.repeat('row'), type='quantitative'),
+        y=alt.Y(alt.repeat('column'), type='quantitative')
+    ).repeat(
+        row=['A', 'B', 'C'],
+        column=['C', 'B', 'A']
+    )
+
+    dct2 = chart2.to_dict()
+
+    assert dct2['repeat'] == {'row': ['A', 'B', 'C'], 'column': ['C', 'B', 'A']}
+    assert 'columns' not in dct2
+    assert dct2['spec']['encoding']['x']['field'] == {'repeat': 'row'}
+    assert dct2['spec']['encoding']['y']['field'] == {'repeat': 'column'}

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc pip install -U pytest
3.7
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
-e git+https://github.com/altair-viz/altair.git@5894423b359fcd911defab1495dd7e7b89f65bfe#egg=altair
attrs==24.2.0
Babel==2.14.0
backcall==0.2.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
charset-normalizer==3.4.1
commonmark==0.9.1
decorator==5.1.1
docutils==0.17.1
entrypoints==0.4
exceptiongroup==1.2.2
flake8==5.0.4
idna==3.10
imagesize==1.4.1
importlib-metadata==4.2.0
importlib-resources==5.12.0
iniconfig==2.0.0
ipython==7.34.0
jedi==0.19.2
Jinja2==3.1.6
jsonschema==4.17.3
m2r==0.3.1
MarkupSafe==2.1.5
matplotlib-inline==0.1.6
mccabe==0.7.0
mistune==0.8.4
numpy==1.21.6
packaging==24.0
pandas==1.3.5
parso==0.8.4
pexpect==4.9.0
pickleshare==0.7.5
pkgutil_resolve_name==1.3.10
pluggy==1.2.0
prompt_toolkit==3.0.48
ptyprocess==0.7.0
pycodestyle==2.9.1
pyflakes==2.5.0
Pygments==2.17.2
pyrsistent==0.19.3
pytest==7.4.4
python-dateutil==2.9.0.post0
pytz==2025.2
recommonmark==0.7.1
requests==2.31.0
six==1.17.0
snowballstemmer==2.2.0
Sphinx==4.3.2
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
tomli==2.0.1
toolz==0.12.1
traitlets==5.9.0
typing_extensions==4.7.1
urllib3==2.0.7
vega-datasets==0.9.0
wcwidth==0.2.13
zipp==3.15.0

name: altair
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - attrs==24.2.0
      - babel==2.14.0
      - backcall==0.2.0
      - charset-normalizer==3.4.1
      - commonmark==0.9.1
      - decorator==5.1.1
      - docutils==0.17.1
      - entrypoints==0.4
      - exceptiongroup==1.2.2
      - flake8==5.0.4
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==4.2.0
      - importlib-resources==5.12.0
      - iniconfig==2.0.0
      - ipython==7.34.0
      - jedi==0.19.2
      - jinja2==3.1.6
      - jsonschema==4.17.3
      - m2r==0.3.1
      - markupsafe==2.1.5
      - matplotlib-inline==0.1.6
      - mccabe==0.7.0
      - mistune==0.8.4
      - numpy==1.21.6
      - packaging==24.0
      - pandas==1.3.5
      - parso==0.8.4
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pkgutil-resolve-name==1.3.10
      - pluggy==1.2.0
      - prompt-toolkit==3.0.48
      - ptyprocess==0.7.0
      - pycodestyle==2.9.1
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pyrsistent==0.19.3
      - pytest==7.4.4
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - recommonmark==0.7.1
      - requests==2.31.0
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==4.3.2
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - tomli==2.0.1
      - toolz==0.12.1
      - traitlets==5.9.0
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - vega-datasets==0.9.0
      - wcwidth==0.2.13
      - zipp==3.15.0
prefix: /opt/conda/envs/altair

altair/vegalite/v3/tests/test_api.py::test_repeat
altair/vegalite/v3/tests/test_api.py::test_transforms
altair/vegalite/v3/tests/test_api.py::test_chart_data_types altair/vegalite/v3/tests/test_api.py::test_chart_infer_types altair/vegalite/v3/tests/test_api.py::test_multiple_encodings altair/vegalite/v3/tests/test_api.py::test_chart_operations altair/vegalite/v3/tests/test_api.py::test_selection_to_dict altair/vegalite/v3/tests/test_api.py::test_facet_parse altair/vegalite/v3/tests/test_api.py::test_facet_parse_data altair/vegalite/v3/tests/test_api.py::test_selection altair/vegalite/v3/tests/test_api.py::test_filter_transform_selection_predicates altair/vegalite/v3/tests/test_api.py::test_resolve_methods altair/vegalite/v3/tests/test_api.py::test_layer_marks altair/vegalite/v3/tests/test_api.py::test_layer_encodings altair/vegalite/v3/tests/test_api.py::test_add_selection altair/vegalite/v3/tests/test_api.py::test_selection_property altair/vegalite/v3/tests/test_api.py::test_LookupData altair/vegalite/v3/tests/test_api.py::test_themes altair/vegalite/v3/tests/test_api.py::test_chart_from_dict altair/vegalite/v3/tests/test_api.py::test_consolidate_datasets altair/vegalite/v3/tests/test_api.py::test_consolidate_InlineData altair/vegalite/v3/tests/test_api.py::test_deprecated_encodings
altair/vegalite/v3/api.py
altair/vegalite/v3/api.py