coveralls: 
[![Coverage Status](https://coveralls.io/builds/29204828/badge)](https://coveralls.io/builds/29204828)

Coverage remained the same at 100.0% when pulling **fa7c364092c92ea4dcce2b4a5bf7933078498fde on igore** into **19f91d9ca806018dd83de419c12377f3ca0add3f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/29204828/badge)](https://coveralls.io/builds/29204828)

Coverage remained the same at 100.0% when pulling **fa7c364092c92ea4dcce2b4a5bf7933078498fde on igore** into **19f91d9ca806018dd83de419c12377f3ca0add3f on master**.

diff --git a/TexSoup/__init__.py b/TexSoup/__init__.py
index cd8782a..9e622c0 100644
--- a/TexSoup/__init__.py
+++ b/TexSoup/__init__.py
@@ -9,7 +9,7 @@ from TexSoup.tex import *
 
 
 # noinspection PyPep8Naming
-def TexSoup(tex_code):
+def TexSoup(tex_code, skip_envs=()):
     r"""
     At a high-level, parses provided Tex into a navigable, searchable structure.
     This is accomplished in two steps:
@@ -18,6 +18,7 @@ def TexSoup(tex_code):
     2. Structure fed to TexNodes for a searchable, coder-friendly interface.
 
     :param Union[str,iterable] tex_code: the Tex source
+    :param Union[str] skip_envs: names of environments to skip parsing
     :return: :class:`TexSoup.data.TexNode` object representing tex document
 
     >>> from TexSoup import TexSoup
@@ -80,5 +81,5 @@ def TexSoup(tex_code):
     >>> soup
     SOUP
     """
-    parsed, src = read(tex_code)
+    parsed, src = read(tex_code, skip_envs=skip_envs)
     return TexNode(parsed, src=src)
diff --git a/TexSoup/reader.py b/TexSoup/reader.py
index 6dc4a99..0b9c182 100644
--- a/TexSoup/reader.py
+++ b/TexSoup/reader.py
@@ -224,7 +224,7 @@ def tokenize_string(text, delimiters=None):
 ##########
 
 
-def read_tex(src):
+def read_tex(src, skip_envs=()):
     r"""Read next expression from buffer
 
     :param Buffer src: a buffer of tokens
@@ -262,7 +262,7 @@ def read_tex(src):
         expr.args = read_args(src, expr.args)
 
         if mode == 'begin':
-            read_env(src, expr)
+            read_env(src, expr, skip_envs=skip_envs)
         return expr
     if c in ARG_START_TOKENS:
         return read_arg(src, c)
@@ -340,7 +340,7 @@ def read_math_env(src, expr):
     return expr
 
 
-def read_env(src, expr):
+def read_env(src, expr, skip_envs=()):
     r"""Read the environment from buffer.
 
     Advances the buffer until right after the end of the environment. Adds
@@ -351,7 +351,7 @@ def read_env(src, expr):
     :rtype: TexExpr
     """
     contents = []
-    if expr.name in SKIP_ENVS:
+    if expr.name in SKIP_ENVS + skip_envs:
         contents = [src.forward_until(lambda s: s == '\\end')]
     while src.hasNext() and not src.startswith('\\end{%s}' % expr.name):
         contents.append(read_tex(src))
diff --git a/TexSoup/tex.py b/TexSoup/tex.py
index ad8ce44..1b2ec63 100644
--- a/TexSoup/tex.py
+++ b/TexSoup/tex.py
@@ -4,7 +4,7 @@ from TexSoup.utils import *
 import itertools
 
 
-def read(tex):
+def read(tex, skip_envs=()):
     """Read and parse all LaTeX source
 
     :param Union[str,iterable] tex: LaTeX source
@@ -16,7 +16,7 @@ def read(tex):
         tex = ''.join(itertools.chain(*tex))
     buf, children = Buffer(tokenize(tex)), []
     while buf.hasNext():
-        content = read_tex(buf)
+        content = read_tex(buf, skip_envs=skip_envs)
         if content is not None:
             children.append(content)
     return TexEnv('[tex]', children), tex

Ignoring Latex in certain cases
In the LaTex files I try to parse are some blocks that TexSoup shouldn't try to parse as LaTex.  They are, in fact, similar to a `\begin{code}
...\end{code}` block, what is between the begin and end should not be read as LaTex.  In fact, doing so would lead to a lot of errors in a book about programming.  I have some special code block here (not using `\begin{code}`, but `\begin{console}` or `\begin{special}`.  I could replace these in the original LaTex before using TexSoup, but that sounds like an unnecessary step.  Although I'm not that familiar with laTex, I expect these blocks are described as 'escaped' (perhaps as 'math' blocks) in the `tty` file.  But that's just a guess.  At any rate, when TexSoup tries to parse such files, it fails (with a `EOFError` or `TypeError`, indicating mismatching punctuation, which is kind of normal).

A fix in the API might not be that easy.  A keyword argument in the converter might not be ideal but it would be the easiest fix I guess.  An alternative would be another function (or a method on the parser itself) to ignore such codes.  Perhaps this method already exists, I couldn't find a way to do it in the documentation.

Thank you again for this tool.  I'm using it to try to convert these LaTex books to easy Markdown and that will involve a lot of content and a lot of adjustments, but I think with such a parser it shouldn't be too hard.  So I hope, anyway!
diff --git a/tests/test_api.py b/tests/test_api.py
index a3bd66b..b2a3825 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -1,6 +1,7 @@
 from TexSoup import TexSoup
 from TexSoup.utils import TokenWithPosition
 from tests.config import chikin
+import pytest
 import re
 
 ##############
@@ -169,3 +170,20 @@ def test_search_regex_precompiled_pattern(chikin):
     assert len(matches) == 1
     assert matches[0] == "unless ordered to squat"
     assert matches[0].position == 341
+
+
+###########
+# TEXSOUP #
+###########
+
+
+def test_skip_envs():
+    """Test envs with invalid latex are not parsed."""
+    with pytest.raises(TypeError):
+        soup = TexSoup(r"""will raise error \textbf{aaaaa""")
+
+    # no error, ignores verbatim
+    TexSoup(r"""\begin{verbatim} \textbf{aaaaa \end{verbatim}""")
+
+    # no error, customized to ignore foobar
+    TexSoup(r"""\begin{foobar} \textbf{aaaaa \end{foobar}""", skip_envs=('foobar',))

pip install -e .
parse_log_pytest
pytest
pytest pytest-cov coverage coveralls
apt-get update apt-get install -y gcc
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
charset-normalizer==2.0.12
coverage==6.2
coveralls==3.3.1
docopt==0.6.2
idna==3.10
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
pytest-cov==4.0.0
requests==2.27.1
-e git+https://github.com/alvinwan/TexSoup.git@19f91d9ca806018dd83de419c12377f3ca0add3f#egg=TexSoup
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tomli==1.2.3
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
urllib3==1.26.20
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: TexSoup
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=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - charset-normalizer==2.0.12
      - coverage==6.2
      - coveralls==3.3.1
      - docopt==0.6.2
      - idna==3.10
      - pytest-cov==4.0.0
      - requests==2.27.1
      - tomli==1.2.3
      - urllib3==1.26.20
prefix: /opt/conda/envs/TexSoup

tests/test_api.py::test_skip_envs
tests/test_api.py::test_navigation_attributes tests/test_api.py::test_navigation_parent tests/test_api.py::test_navigation_children tests/test_api.py::test_navigation_descendants tests/test_api.py::test_navigation_positions tests/test_api.py::test_find_basic tests/test_api.py::test_find_by_command tests/test_api.py::test_find_env tests/test_api.py::test_delete tests/test_api.py::test_delete_arg tests/test_api.py::test_delete_token tests/test_api.py::test_replace_single tests/test_api.py::test_replace_multiple tests/test_api.py::test_append tests/test_api.py::test_insert tests/test_api.py::test_text tests/test_api.py::test_search_regex tests/test_api.py::test_search_regex_precompiled_pattern tests/test_parser.py::test_commands_only tests/test_parser.py::test_commands_envs_only tests/test_parser.py::test_commands_envs_text tests/test_parser.py::test_text_preserved tests/test_parser.py::test_command_name_parse tests/test_parser.py::test_commands_without_arguments tests/test_parser.py::test_unlabeled_environment tests/test_parser.py::test_ignore_environment tests/test_parser.py::test_inline_math tests/test_parser.py::test_escaped_characters tests/test_parser.py::test_math_environment_weirdness tests/test_parser.py::test_item_parsing tests/test_parser.py::test_item_argument_parsing tests/test_parser.py::test_comment_escaping tests/test_parser.py::test_comment_unparsed tests/test_parser.py::test_items_with_labels tests/test_parser.py::test_multiline_args tests/test_parser.py::test_nested_commands tests/test_parser.py::test_basic_whitespace tests/test_parser.py::test_whitespace_in_command tests/test_parser.py::test_math_environment_whitespace tests/test_parser.py::test_math_environment_escape tests/test_parser.py::test_punctuation_command_structure tests/test_parser.py::test_non_punctuation_command_structure tests/test_parser.py::test_buffer tests/test_parser.py::test_to_buffer tests/test_parser.py::test_unclosed_commands tests/test_parser.py::test_unclosed_environments tests/test_parser.py::test_unclosed_math_environments tests/test_parser.py::test_arg_parse tests/test_search.py::test_commands_without_any_sort_arguments tests/test_search.py::test_commands_with_one_or_more_arguments tests/test_search.py::test_list_search TexSoup/__init__.py::TexSoup.TexSoup TexSoup/data.py::TexSoup.data.Arg TexSoup/data.py::TexSoup.data.Arg.delims TexSoup/data.py::TexSoup.data.Arg.parse TexSoup/data.py::TexSoup.data.Arg.value TexSoup/data.py::TexSoup.data.TexArgs TexSoup/data.py::TexSoup.data.TexArgs.__contains__ TexSoup/data.py::TexSoup.data.TexArgs.__getitem__ TexSoup/data.py::TexSoup.data.TexArgs.__repr__ TexSoup/data.py::TexSoup.data.TexArgs.__str__ TexSoup/data.py::TexSoup.data.TexArgs.append TexSoup/data.py::TexSoup.data.TexArgs.clear TexSoup/data.py::TexSoup.data.TexArgs.extend TexSoup/data.py::TexSoup.data.TexArgs.insert TexSoup/data.py::TexSoup.data.TexArgs.pop TexSoup/data.py::TexSoup.data.TexArgs.remove TexSoup/data.py::TexSoup.data.TexArgs.reverse TexSoup/data.py::TexSoup.data.TexArgs.sort TexSoup/data.py::TexSoup.data.TexCmd TexSoup/data.py::TexSoup.data.TexEnv TexSoup/data.py::TexSoup.data.TexExpr.all TexSoup/data.py::TexSoup.data.TexExpr.append TexSoup/data.py::TexSoup.data.TexExpr.contents TexSoup/data.py::TexSoup.data.TexExpr.insert TexSoup/data.py::TexSoup.data.TexExpr.remove TexSoup/data.py::TexSoup.data.TexNode.__iter__ TexSoup/data.py::TexSoup.data.TexNode.__match__ TexSoup/data.py::TexSoup.data.TexNode.all TexSoup/data.py::TexSoup.data.TexNode.append TexSoup/data.py::TexSoup.data.TexNode.args TexSoup/data.py::TexSoup.data.TexNode.char_pos_to_line TexSoup/data.py::TexSoup.data.TexNode.children TexSoup/data.py::TexSoup.data.TexNode.contents TexSoup/data.py::TexSoup.data.TexNode.copy TexSoup/data.py::TexSoup.data.TexNode.count TexSoup/data.py::TexSoup.data.TexNode.delete TexSoup/data.py::TexSoup.data.TexNode.descendants TexSoup/data.py::TexSoup.data.TexNode.find TexSoup/data.py::TexSoup.data.TexNode.find_all TexSoup/data.py::TexSoup.data.TexNode.insert TexSoup/data.py::TexSoup.data.TexNode.name TexSoup/data.py::TexSoup.data.TexNode.remove TexSoup/data.py::TexSoup.data.TexNode.replace TexSoup/data.py::TexSoup.data.TexNode.replace_with TexSoup/data.py::TexSoup.data.TexNode.string TexSoup/data.py::TexSoup.data.TexNode.text TexSoup/data.py::TexSoup.data.TexText TexSoup/data.py::TexSoup.data.TexText.__contains__ TexSoup/data.py::TexSoup.data.TexText.__eq__ TexSoup/data.py::TexSoup.data.TexText.__repr__ TexSoup/data.py::TexSoup.data.TexText.__str__ TexSoup/reader.py::TexSoup.reader.next_token TexSoup/reader.py::TexSoup.reader.tokenize TexSoup/reader.py::TexSoup.reader.tokenize_line_comment TexSoup/reader.py::TexSoup.reader.tokenize_math TexSoup/reader.py::TexSoup.reader.tokenize_string TexSoup/utils.py::TexSoup.utils.Buffer TexSoup/utils.py::TexSoup.utils.Buffer.__getitem__ TexSoup/utils.py::TexSoup.utils.Buffer.backward TexSoup/utils.py::TexSoup.utils.Buffer.forward TexSoup/utils.py::TexSoup.utils.CharToLineOffset TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__add__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__contains__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__eq__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__getitem__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__iadd__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__iter__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.__radd__ TexSoup/utils.py::TexSoup.utils.TokenWithPosition.lstrip TexSoup/utils.py::TexSoup.utils.TokenWithPosition.rstrip
TexSoup/reader.py TexSoup/__init__.py TexSoup/tex.py
TexSoup/reader.py TexSoup/__init__.py TexSoup/tex.py