diff --git a/.vscode/settings.json b/.vscode/settings.json
index 14a1a78..1ac2548 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -9,10 +9,13 @@
         "Jupyter",
         "LINQ",
         "ROOTT",
+        "Topo",
         "asts",
         "astunparse",
         "asyncio",
         "codecov",
+        "databanks",
+        "dataframes",
         "elts",
         "gwatts",
         "iscoroutine",
@@ -21,6 +24,8 @@
         "noqa",
         "numpy",
         "pytest",
+        "rucio",
+        "servicex",
         "url's",
         "xaod",
         "xrootd"
@@ -41,8 +46,5 @@
     "python.analysis.openFilesOnly": false,
     "python.pythonPath": ".venv\\Scripts\\python.exe",
     "python.venvPath": ".venv",
-    "python.analysis.typeCheckingMode": "basic",
-    "python.testing.pytestArgs": [
-        "--no-cov"
-    ]
+    "python.analysis.typeCheckingMode": "basic"
 }
\ No newline at end of file
diff --git a/README.md b/README.md
index d579bd6..962cd06 100644
--- a/README.md
+++ b/README.md
@@ -16,3 +16,5 @@ one of the following packages:
 
 - func_adl.xAOD: for running on an ATLAS experiment xAOD file hosted in ServiceX
 - func_adl.xAOD.backend: for running on a local file using docker
+
+See the documentation for more information.
diff --git a/documentation.md b/documentation.md
index f555583..ad47ae0 100644
--- a/documentation.md
+++ b/documentation.md
@@ -1,10 +1,10 @@
 # Documentation for func_adl
 
-func_adl is an SQL-like language used to construct hierarchical data queries for `servicex` (https://pypi.org/project/servicex/). func_adl is written to work with both `servicex` service modes, and requires either `func_adl_xAOD` (https://pypi.org/project/func-adl-xAOD/) or `func_adl_uproot` (https://pypi.org/project/func-adl-uproot/) for full functionality.
+func_adl is an SQL-like language used to construct hierarchical data queries for [`servicex`](https://pypi.org/project/servicex/). func_adl is written to work with both `servicex` service modes, and requires either [`func_adl_xAOD`](https://pypi.org/project/func-adl-xAOD/) or [`func_adl_uproot`](https://pypi.org/project/func-adl-uproot/) for full functionality.
 
-### Example of a func_adl_xAOD query
+## Example of a func_adl_xAOD query
 
-```
+```python
 data = ServiceXDatasetSource(dataset) \
     .Select('lambda e: (e.Electrons("Electrons"), e.Muons("Muons"))') \
     .Select('lambda ls: (ls[0].Select(lambda e: e.pt()), ls[0].Select(lambda e: e.eta()), \
@@ -23,7 +23,7 @@ The following lines are each func_adl transformations on the dataset. func_adl f
 
 It should be noted that all commands except for `.value()` are used only to construct the query, and do not send any information or request anything from `ServiceX`. The entire query is sent using the `.value()` command, and there is no data exchange until that command is sent.
 
-### Commands in a func_adl_xAOD query:
+## Commands in a func_adl_xAOD query
 
 There are a variety of useful operators that can be submitted in a func_adl query. Here, they are listed and explained:
 
@@ -41,7 +41,10 @@ This command replaces the list with its length, counting the number of elements.
 
 `.AsAwkwardArray(...)`
 `.AsPandasDF(...)`
+`.AsROOTTTree(...)`
+`.AsParquetFile(...)`
 These commands specifies how the query should return the selection. Currently, the xAOD backend can return selections as either awkward arrays or pandas dataframes.
 
 `.value()`
-This command actually executes the query built by the other commands, sending it to `ServiceX` and then returning the data. 
\ No newline at end of file
+`.value_async()`
+This command actually executes the query built by the other commands, sending it to `ServiceX` and then returning the data.
diff --git a/func_adl/__init__.py b/func_adl/__init__.py
index 4392042..859e66e 100644
--- a/func_adl/__init__.py
+++ b/func_adl/__init__.py
@@ -6,7 +6,7 @@
 # just turn off checking here.
 
 # Main streaming object
-from .object_stream import ObjectStream, ObjectStreamException  # NOQA
+from .object_stream import ObjectStream  # NOQA
 
 # Dataset accessors
 from .event_dataset import EventDataset, find_EventDataset  # NOQA
diff --git a/func_adl/object_stream.py b/func_adl/object_stream.py
index ef44ece..a1ae73e 100644
--- a/func_adl/object_stream.py
+++ b/func_adl/object_stream.py
@@ -1,16 +1,16 @@
 # An Object stream represents a stream of objects, floats, integers, etc.
 import ast
-from typing import Any, Callable, Union, cast, Awaitable
+from typing import Any, Awaitable, Callable, List, Union, cast
 
 from make_it_sync import make_sync
 
 from .util_ast import as_ast, function_call, parse_as_ast
 
 
-class ObjectStreamException(Exception):
-    'Exception thrown by the ObjectStream object.'
-    def __init__(self, msg):
-        Exception.__init__(self, msg)
+# class ObjectStreamException(Exception):
+#     'Exception thrown by the ObjectStream object.'
+#     def __init__(self, msg):
+#         Exception.__init__(self, msg)
 
 
 class ObjectStream:
@@ -117,10 +117,35 @@ class ObjectStream:
 
             A new ObjectStream with type [(filename, treename)]. This is because multiple tree's
             may be written by the back end, and need to be concatenated together to get the full
+            dataset.  The order of the files back is consistent for different queries on the same
             dataset.
         """
         return ObjectStream(function_call("ResultTTree", [self._ast, as_ast(columns), as_ast(treename), as_ast(filename)]))
 
+    def AsParquetFiles(self, filename: str, columns: Union[str, List[str]] = []) -> 'ObjectStream':
+        '''Returns the sequence of items as a `parquet` file. Each item in the ObjectStream gets a separate
+        entry in the file. The times must be of types that the infrastructure can work with:
+
+            Float               A tree with a single float in each entry will be written.
+            vector<float>       A tree with a list of floats in each entry will be written.
+            (<tuple>)           A tree with multiple items (leaves) will be written. Each leaf
+                                must have one of the above types. Nested tuples are not supported.
+            {k:v, }             A dictionary with named columns. v is either a float or a vector of floats.
+
+        Arguments:
+
+            filename            Name of a file in which the data will be written. Depending on where the data comes
+                                from this may not be used - consider it a suggestion.
+            columns             If the data does not arrive by dictionary, then these are the column names.
+
+        Returns:
+
+            A new `ObjectStream` with type `[filename]`. This is because multiple files may be written by
+            the backend - the data should be concatinated together to get a final result. The order of the files back
+            is consistent for different queries on the same dataset.
+        '''
+        return ObjectStream(function_call("ResultParquet", [self._ast, as_ast(columns), as_ast(filename)]))
+
     def AsAwkwardArray(self, columns=[]) -> 'ObjectStream':
         r'''
         Return a pandas stream that contains one item, an `awkward` array, or dictionary of `awkward` arrays.

Add AsParqetFiles
Make sure there is an end-point in `ObjectStream` that will render parquet files


<!-- Edit the body of your new issue then click the ✓ "Create Issue" button in the top right of the editor. The first line will be the issue title. Assignees and Labels follow after a blank line. Leave an empty line before beginning the body of the issue. -->
diff --git a/tests/test_object_stream.py b/tests/test_object_stream.py
index 2a76e78..9831fec 100644
--- a/tests/test_object_stream.py
+++ b/tests/test_object_stream.py
@@ -1,5 +1,6 @@
 # Test the object stream
 import sys
+from typing import Any, Optional
 sys.path += ['.']
 from func_adl import EventDataset
 import ast
@@ -29,6 +30,16 @@ def test_simple_query():
         .value()
     assert isinstance(r, ast.AST)
 
+
+def test_simple_query_parquet():
+    r = my_event() \
+        .SelectMany("lambda e: e.jets()") \
+        .Select("lambda j: j.pT()") \
+        .AsParquetFiles("junk.root", 'jetPT') \
+        .value()
+    assert isinstance(r, ast.AST)
+
+
 def test_simple_query_panda():
     r = my_event() \
         .SelectMany("lambda e: e.jets()") \
@@ -88,3 +99,22 @@ async def test_2await_exe_from_coroutine():
     rpair = await asyncio.gather(r1, r2)
     assert isinstance(rpair[0], ast.AST)
     assert isinstance(rpair[1], ast.AST)
+
+
+@pytest.mark.asyncio
+async def test_passed_in_executor():
+    logged_ast: Optional[ast.AST] = None
+    
+    async def my_exe(a: ast.AST) -> Any:
+        nonlocal logged_ast
+        logged_ast = a
+        return 1
+        
+    r = my_event() \
+        .SelectMany("lambda e: e.jets()") \
+        .Select("lambda j: j.pT()") \
+        .AsROOTTTree("junk.root", "analysis", "jetPT") \
+        .value_async(executor=my_exe)
+
+    assert (await r) == 1
+    assert logged_ast is not None

pip install -e .[complete]
parse_log_pytest
pytest
pytest
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
astunparse==1.6.3
attrs @ file:///croot/attrs_1668696182826/work
bleach==6.0.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
coverage==7.2.7
cryptography==44.0.2
docutils==0.20.1
flake8==5.0.4
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
-e git+https://github.com/iris-hep/func_adl.git@98aecdd3c10ef7a37b4fafe021afea756eee243b#egg=func_adl_test
idna==3.10
importlib-metadata==4.2.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
jaraco.classes==3.2.3
jeepney==0.9.0
keyring==23.9.3
make-it-sync==2.0.0
markdown-it-py==2.2.0
mccabe==0.7.0
mdurl==0.1.2
more-itertools==9.1.0
packaging @ file:///croot/packaging_1671697413597/work
pkginfo==1.10.0
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.17.2
pytest==7.1.2
pytest-asyncio==0.21.2
pytest-cov==4.1.0
readme-renderer==37.3
requests==2.31.0
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==13.8.1
SecretStorage==3.3.3
six==1.17.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
twine==4.0.2
typing_extensions @ file:///croot/typing_extensions_1669924550328/work
urllib3==2.0.7
webencodings==0.5.1
zipp @ file:///croot/zipp_1672387121353/work

name: func_adl
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
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_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
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=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
  - tomli=2.0.1=py37h06a4308_0
  - typing_extensions=4.4.0=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - astunparse==1.6.3
      - bleach==6.0.0
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - coverage==7.2.7
      - cryptography==44.0.2
      - docutils==0.20.1
      - flake8==5.0.4
      - idna==3.10
      - importlib-metadata==4.2.0
      - jaraco-classes==3.2.3
      - jeepney==0.9.0
      - keyring==23.9.3
      - make-it-sync==2.0.0
      - markdown-it-py==2.2.0
      - mccabe==0.7.0
      - mdurl==0.1.2
      - more-itertools==9.1.0
      - pkginfo==1.10.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pytest-asyncio==0.21.2
      - pytest-cov==4.1.0
      - readme-renderer==37.3
      - requests==2.31.0
      - requests-toolbelt==1.0.0
      - rfc3986==2.0.0
      - rich==13.8.1
      - secretstorage==3.3.3
      - six==1.17.0
      - twine==4.0.2
      - urllib3==2.0.7
      - webencodings==0.5.1
prefix: /opt/conda/envs/func_adl

tests/test_object_stream.py::test_simple_query_parquet
tests/test_object_stream.py::test_simple_query tests/test_object_stream.py::test_simple_query_panda tests/test_object_stream.py::test_simple_query_awkward tests/test_object_stream.py::test_nested_query_rendered_correctly tests/test_object_stream.py::test_await_exe_from_coroutine_with_throw tests/test_object_stream.py::test_await_exe_from_normal_function tests/test_object_stream.py::test_2await_exe_from_coroutine tests/test_object_stream.py::test_passed_in_executor
documentation.md func_adl/object_stream.py .vscode/settings.json README.md func_adl/__init__.py
documentation.md func_adl/object_stream.py .vscode/settings.json README.md func_adl/__init__.py