pax_global_header00006660000000000000000000000064134435143540014520gustar00rootroot0000000000000052 comment=0d24efd47c4f6fe829dbda870d2b53226e7afefd redbaron-0.9.2/000077500000000000000000000000001344351435400133245ustar00rootroot00000000000000redbaron-0.9.2/.gitignore000066400000000000000000000016521344351435400153200ustar00rootroot00000000000000# Created by http://www.gitignore.io ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ ### vim ### [._]*.s[a-w][a-z] [._]s[a-w][a-z] *.un~ Session.vim .netrwhist *~ ### Emacs ### # -*- mode: gitignore; -*- *~ \#*\# /.emacs.desktop /.emacs.desktop.lock *.elc auto-save-list tramp .\#* # Org-mode .org-id-locations *_archive # flymake-mode *_flymake.* # eshell files /eshell/history /eshell/lastdir # elpa packages /elpa/ # reftex files *.rel # AUCTeX auto folder /auto/ # PyCharm files .idea/*.* .idea/redbaron-0.9.2/.travis.yml000066400000000000000000000006251344351435400154400ustar00rootroot00000000000000language: python install: - pip install git+https://github.com/Psycojoker/baron.git - pip install pytest - find . -name '*.pyc' -delete - python setup.py install python: - "2.6" - "2.7" - "3.4" - "3.5" - "3.6" - "3.7-dev" script: - py.test tests - bash ./test_doc.sh - pip install pygments - py.test tests - bash ./test_doc.sh notifications: irc: "chat.freenode.net#baron" redbaron-0.9.2/CHANGELOG000066400000000000000000000172521344351435400145450ustar00rootroot00000000000000Changelog ========= 0.9.2 (2019-03-17) ------------------ - fix a situation in .help() where some code where colorized twice by Hanaasagi https://github.com/PyCQA/redbaron/pull/182 0.9.1 (2019-02-01) ------------------ - fix .names() and variations that didn't handle the case where there was "()" on FromImport nodes 0.9 (2019-02-01) ---------------- - full python 3.7 syntax support - BREAKING CHANGE: annotations are now member of {Def,List,Dict}Argument to flatten the data structure, TypedNameNode doesn't exist anymore - add support for return annotation by bram - add support for variable annotation https://github.com/PyCQA/redbaron/pull/177 by scottbelden and additional work by bram - add support for raise from by bram 0.8 (2018-10-29) ---------------- - add support to typed function arguments https://github.com/PyCQA/redbaron/pull/168 Scott Belden and additional work by bram - add support to set async attributes to with/for nodes, was missing in previous release 0.7 (2018-08-21) ---------------- - fix to_python() when strings are indented by stripping whitespace before evaluating by duncf https://github.com/PyCQA/redbaron/pull/140 Python 3 support (based on work in Baron): - support ellipsis - support matrix operator - support f-strings - support numeric literals - support nonlocal statement - support keyword only markers - support yield from statement - support async/await statements 0.6.3 (2017-01-02) ----------------- - fix help() after append - fix _synchronise() for base_nodes to avoid recursion in __repr__ function if code run not in the shell - add at method 0.6.2 (2016-10-03) ---------------- - fix some old call to log() weren't lazy, that could cause a crash in some situations by an infinite recursive call and also reduce performances - fix in _iter_in_rendering_order method to avoid bug in edge cases (issue #107) 0.6.1 (2016-03-28) ---------------- - fix setup.py, package weren't pushed on pypi since splitting of redbaron.py into multiple files. 0.6 (2016-03-28) ---------------- This release is guaranteed to have a retro-compatible public documented API from now on until maybe 2.0. There might be the only exception that if you directly call specific nodes constructors with FST that this API change, but this is not documented and simply horribly unpracticable, so I'm expecting no one to do that. From now on the focus will be on moving to a stable 1.0 meaning: bugs fixes and API additions for missing needed features and no more big modifications, this will be for other releases, the workload is already big enough. - BIG improvement on the proxy list merging algorithm, it is not perfect yet (comments aren't handled yet) but it's really a big move forward - possible retrocompatibility breaking change: from now on the node.find("name") to node.name shortcut ONLY works with possible nodes identifiers. For example node.i_dont_exist_as_an_identifier will raise AttributeError - new helper method .to_python that wrap ast.literal_eval on compatible nodes https://redbaron.readthedocs.io/en/latest/other.html#to-python - breaking: IntNode no longer return an int on .value but a .string instead, use .to_python to have an evaluated version - fix node.decrease_indentation (that was simply not working) - fix code_block_node.value was broken on node with no parent - add string representation for Path object - now redbaron Path() class can be compared directly to baron paths without using to_baron_path() helper. - fix by novocaine: 'function' was used as a function type detector instead of 'def' - add getitem() method with same api on NodeList and ProxyList - fix: inconsistencies when inserting lines around code blocks - inserting a blank lines inserts effectively a \n in a LineProxyList - new helper methods: .next_recursive and .previous_recursive https://redbaron.readthedocs.io/en/latest/other.html - fix: doc is tested in CI now, it shouldn't break anymore - more rendering test for python3, it shouldn't break anymore - pygments is now an optional dependency, "pip install redbaron" won't install it, "pip install redbaron[pygments"] will - new node.next_intuitive and node.previous_intuitive methods for situations where .next/previous doesn't behave the way the user expect it https://redbaron.readthedocs.io/en/latest/other.html#next-intuitive-previous-intuitive 0.5.1 (2015-03-11) ------------------ - fix whitespace duplication when using .insert() - DecoratorProxyList of the last method of a function wasn't handling correctly the indentation of its last endl token 0.5 (2015-01-31) ---------------- - fix index handling in get_absolute_bounding_box_of_attribute method in a LineProxyList - pretty rendering of RedBaron repr in ipython notebook using _repr_html_, see: https://cloud.githubusercontent.com/assets/41827/5731132/65ff4c92-9b80-11e4-977c-0faebbf63415.png - fix: RedBaron repr was crashing in bpython and in ipython notebook. The new behavior should be way more stable and never crash. - new helpers .names, .modules, .full_path_modules for from_import node https://redbaron.readthedocs.io/en/latest/other.html#index-on-parent-raw - add a node.index_on_parent_raw and make node.index_on_parent works has it should be intuitively according to the proxy list api https://redbaron.readthedocs.io/en/latest/other.html#index-on-parent-raw - new helper methods: .insert_before and .insert_after https://redbaron.readthedocs.io/en/latest/other.html#insert-before-insert-after - fix: some white space bugs in the merging algorithm of line proxy - fix: on_attribute and parent were correctly set on newly added elements to the root node 0.4 (2014-12-11) ---------------- - compatibility with baron upstream (removal of def_argument_node and uniformisation of def_arguments structure) - fix: long wasn't supported in redbaron (due to a bug in baron) 0.3 (2014-11-12) ---------------- - proxy lists, major improvement in the management of list of things - .append_value is no more since it is useless now due to proxy lists - .index has been renamed to .index_on_parent to be more coherent 0.2 (2014-09-23) ---------------- - for EVERY NODES in RedBaron, the automagic behavior when passing a string to modify an attribute has been done, this is HUGE improvement https://redbaron.readthedocs.io/en/latest/modifying.html#full-documentations - it's now possible to use regex, globs, list/tuple and lambda (callable) in .find and .find_all, see https://redbaron.readthedocs.io/en/latest/querying.html#advanced-querying - new method on node: .replace() to replace in place a node https://redbaron.readthedocs.io/en/latest/other.html#replace - .map .filter and .apply are now documented https://redbaron.readthedocs.io/en/latest/other.html#map-filter-apply - .edit() new helper method to launch a text editor on the selected node and replace the node with the modified code https://redbaron.readthedocs.io/en/latest/other.html#edit - .root node attribute (property) that return the root node of the tree in which the node is stored https://redbaron.readthedocs.io/en/latest/other.html#root - .index node attribute (property) that returns the index at which the node is store if it's store in a nodelist, None otherwise https://redbaron.readthedocs.io/en/latest/other.html#index - setitem (a[x] = b) on nodelist now works as expected (accepting string, fst node and redbaron node) - new method to handle indentation: .increase_indentation and .decrease_indentation https://redbaron.readthedocs.io/en/latest/other.html#increase-indentation-and-decrease-indentation - various small bugfix - we have one new contributor \o/ https://github.com/ze42 - to_node has been move to a class method of Node: Node.from_fst - pretty print of nodes when using redbaron in a script 0.1 (2014-06-13) ---------------- - First release redbaron-0.9.2/MANIFEST.in000066400000000000000000000001661344351435400150650ustar00rootroot00000000000000include README.md CHANGELOG TODO.md include requirements.txt requirements-docs.txt test_doc.sh graft tests graft docs redbaron-0.9.2/README.md000066400000000000000000000150761344351435400146140ustar00rootroot00000000000000Introduction ============ [![Build Status](https://travis-ci.org/PyCQA/redbaron.svg?branch=master)](https://travis-ci.org/PyCQA/redbaron) [![Latest Version](https://img.shields.io/pypi/v/redbaron.svg)](https://pypi.python.org/pypi/redbaron/) [![Supported Python versions](https://img.shields.io/pypi/pyversions/redbaron.svg)](https://pypi.python.org/pypi/redbaron/) [![Development Status](https://img.shields.io/pypi/status/redbaron.svg)](https://pypi.python.org/pypi/redbaron/) [![Wheel Status](https://img.shields.io/pypi/wheel/redbaron.svg)](https://pypi.python.org/pypi/redbaron/) [![Download format](https://img.shields.io/pypi/format/redbaron.svg)](https://pypi.python.org/pypi/redbaron/) [![License](https://img.shields.io/pypi/l/redbaron.svg)](https://pypi.python.org/pypi/redbaron/) [![Backers on Open Collective](https://opencollective.com/redbaron/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/redbaron/sponsors/badge.svg)](#sponsors) RedBaron is a python library and tool powerful enough to be used into IPython solely that intent to make the process of **writing code that modify source code** as easy and as simple as possible. That include writing custom refactoring, generic refactoring, tools, IDE or directly modifying you source code into IPython with a higher and more powerful abstraction than the advanced texts modification tools that you find in advanced text editors and IDE. RedBaron guaranteed you that **it will only modify your code where you ask him to**. To achieve this, it is based on [Baron](https://github.com/PyCQA/baron) a lossless [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) for Python that guarantees the operation ast_to_code(code_to_ast(source_code)) == source_code. (Baron's AST is called an FST, a Full Syntax Tree). RedBaron API and feel is heavily inspired by BeautifulSoup. It tries to be simple and intuitive and that once you've get the basics principles, you are good without reading the doc for 80% of your operations. **For now, RedBaron can be considered in alpha, the core is quite stable but it is not battle tested yet and is still a bit rough.** Feedback and contribution are very welcome. The public documented API on the other side is guaranteed to be retro-compatible and won't break until 2.0 (if breaking is needed at that point). There might be the only exception that if you directly call specific nodes constructors with FST that this API change, but this is not documented and simply horribly unpracticable, so I'm expecting no one to do that. Support ======= RedBaron is support python python 2 and up to python 3.7 grammar. Roadmap ======= Current roadmap is as boring as needed: * bug fixes * new small features (walker pattern, maybe code generation) and performance improvement. Installation ============ pip install redbaron[pygments] Or if you don't want to have syntax highlight in your shell or don't need it: pip install redbaron Running tests ============= pip install pytest py.test tests Community ========= You can reach us on [irc.freenode.net#baron](https://webchat.freenode.net/?channels=%23baron) or [irc.freenode.net##python-code-quality](https://webchat.freenode.net/?channels=%23%23python-code-quality). Financial support ================= Baron and RedBaron are a very advanced piece of engineering that requires a lot of time of concentration to work on. Until the end of 2018, the development has been a full volunteer work mostly done by [Bram](https://github.com/psycojoker), but now, to reach the next level and bring those projects to the stability and quality you expect, we need your support. You can join our contributors and sponsors on our transparent [OpenCollective](https://opencollective.com/redbaron), every contribution will count and will be mainly used to work on the projects stability and quality but also on continuing, on the side, the R&D side of those projects. ## Backers Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/redbaron#backer)] ## Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/redbaron#sponsor)] ## Contributors This project exists thanks to all the people who contribute. Code of Conduct =============== As a member of [PyCQA](https://github.com/PyCQA), RedBaron follows its [Code of Conduct](http://meta.pycqa.org/en/latest/code-of-conduct.html). Links ===== **RedBaron is fully documented, be sure to check the tutorial and documentation**. * [Tutorial](https://redbaron.readthedocs.io/en/latest/tuto.html) * [Documentation](https://redbaron.readthedocs.io/en/latest/) * [Baron](https://github.com/PyCQA/baron) * IRC chat: [irc.freenode.net#baron](https://webchat.freenode.net/?channels=%23baron) redbaron-0.9.2/TODO.md000066400000000000000000000054701344351435400144210ustar00rootroot00000000000000# Todo ### Important - .help() seems really slow on big piece of code (for example RedBaron("baron/grammator.py").read())("dict")[0].help() is suuuuuuuuuuuuuuuuper slow) - .rename() (name -> value, def/class -> name) - .replace() expect a whole valid python program. This could be fixed by look at "on_attribute" and resetting itself like that. - generate default constructors for nodes using nodes_rendering_order - if possible try to keep a coherent signature with possibles attributes, set correctly default attributes - examples: * SpaceNode(" ") * CommaNode() * CommaNode(first_formatting=[" "]) # allow to pass strings again - auto merging behavior for Atomtrailer: "a.b.c".value[0].replace("x.y.z") should not include one Atomtrailer in the current one but flatten both. Same for getitem. do a check on every setitem, some doesn't works as expected and I'm expected that none works as expected, for eg, this one fails: RedBaron("a(b, c=d, *e, **f)")[0].value[1].value[0] = "**dsq" in addition of passing empty string, allow to pass None value on setattr this needs to be done in "_convert_input_to_node_object" and it's possible now since we have string type in nodes_rendering_order - implement tree visitor and transformer like in standard ast: https://docs.python.org/3/library/ast.html#ast.NodeTransformer - improve/create new insert method with inserting to specific position like find_by_position - implement control-flow graph, data-flow-graph and call-graph - add scope (RedBaron, ClassNode, DefNode, LambdaNode and GeneratorComprehensionNode) property - check code for correctness before dumping ### Find/Find\_All (comparison) Magic stuff like: value\_\_dumps that compare the .dumps() with a string? or use lambda for that instead? ### More general stuff * .assign, .map\_concat * .swap, .move on a NodeList * .cut (like .copy but with del self) * .remove on nodelist * method to change style of formatting in a datastructure * .grep method that test on successive .dumps() * auto add quotes for strings ### More refactoring like - find\_name\_binding -> search assign, def (args && name), class, except, with, for ... - find\_identifier -> search name + everything up there ^ ### Wrappers It should be easy to wrap statement, expressions or various structure in other statements, like a statement with a block or an associative parenthesis or those kind of things. ### Magic conversion on setattr Comment: I'm not that much sure that I'll do those one, .replace already quite handle this job. conversion from list/set/dict to comprehension version conversion between binary_operator/boolean_operator/comparison conversion from if/elif/else to if/elif/else (careful about the ifelseblock) conversion from call_argument/def_argument to list_argument or dict_argument and vice versa conversion from string chain to string redbaron-0.9.2/docs/000077500000000000000000000000001344351435400142545ustar00rootroot00000000000000redbaron-0.9.2/docs/Makefile000066400000000000000000000151621344351435400157210ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/RedBaron.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/RedBaron.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/RedBaron" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/RedBaron" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." redbaron-0.9.2/docs/ast.png000066400000000000000000000177441344351435400155660ustar00rootroot00000000000000PNG  IHDRr$gAMA aIDATx^1.9uIŖ,ґz^:h/ڞԛ:W!-E)M""PhDb$Gff^xf_s=> g0:#`V!U/_G+ix_ٟo.#02ΑGǺ#0(Aj#02/{+T';1w%x5Èia/K0u#檙:o>^l7pj0qGy[%~Kp 7L0uz>^7Cuxpnq௣:cMMH7_CѶ@3u J ꂀxz+<٬_M=>h7GqmIyFUͼ^Rn t;OpՑ̹G: v>lcuq{#B԰a ufy.abs&2-q1zBɹlQj^tֶ+Ntv㎵r^+[{`{]SxPJNVE`/ތp'4;i ˉ]N7h=rbEᶞӄr)'M(m$9Oy(@IdTEm VG.f7 Qù(^Hx.#f).qJTƒ4]L}XPry:%tN~EI Hޜ/.8zO~ZMʛ@@Y)^ M9^:e j{Ya8fD td\H9YIduz ~ 757Aǫo$t(\wW^R+HVa1(lʬ%_jHJM]rQ]gOpf=sXlSkEk喉nPŌ7\E0V A\Vg e"埱YޑevM:B-b: G˂+x[):ϝX謾@v Mm z>1?qSlʕZgo뼬4+Yd*[mhkڵ*;G;}'j.VN,M. DvqHMԚp"ܢN019@WO:ޤ6v+#/o^W&Ԗ#][S\a :ϝjR>F_I =@@ wZde!*KLkD]Y,oܷߠ&ͷ`:P)LX ۜ5\GB&HC/23^|x=4א$#86:@;{|덠ۛ &%|5Y4^no,2Q 3FߖC#9Z3O^A>K0u[<[sG6L|wVLȹbj0k~ >Ss=E M'D/bKd :yqC'8QyexXg2,ZTG7F海^]h/ *Ӄ7ЫޖWe|=MшLQJ&$'Ⱥg`Z8N7N\@0:WF?xS˄o c/?ha7ĕXreEVRgjuc0uZqD3Q^R'ęߕH#4ޱS:u[5P6(C* w%@+!GtSfQ)E=UN4L.Mԙtnf<*9ڮ-ꊤwy#fvGuQ^ z5S'SntOj=ޥ] 1F`pδmԩOwan|0m,Sgj3* v-B"Xp"ŔӍ6MLN='ZX|*EyFCp`"M2򜨼L5EmZ@&KvꮕG`:BX[2-kA|ЫZi4:!&F#SskNMK=~!P4 ^;RXgq[C3}W2_r={z/>~mj0 TrMkBÞ%0ďi40rNْivD?%ڜx"0<Hj* }"ԩpb7ٛ oNr#i佱:$G44[zB qLU٠Ё"NY5v4nc~גǕ?`k;;f2<9,DooZ)kV˧Wnzhe$L㌐bEO|nڽ_x$}Ŷs^_9(#F5p8*PN#$ϺbT#JjJ^ uWȭݏ>VOѶmEnUM:Sձ`o1/'C}4y)'C{WŖաburzgf2crΕHLLWuƾy]}zf4fԹDbEMΉX*IX7Թ]c;8.arN4HSrw9,ӨsprB]5G~,:fh똕 =өե=_1<zn1u>@Wyv ewnW`( =xΡn۸Nsh5NBs"ښ]ӱ΢ՙQ9| S%P6 q"~8K13CSOÒR$UmJc2W+Z IJ b={Jܣ'u ].z:oT\EiN@ vG؎@OWnR f1ۼ.Iꭘ笰o7`@OJr9ԩIjB[:S%xDbYTeF`_݊PphL_:S"؃pe~[M=jEozզE\ִ}#U_3,+{eSSH e*ξ8 m28J7ӡ&˱טH`!$.@ge3upMwH,QSk*PT~qd,$Q8hSS Ԙ)rq#ڐq^=@Ɩ\t7l̦=F2k79/ǞΞݵ=c\;L.U&Ǔum`==7a6B2u ku@VOFND,/r \".)Q܍Q Аpngm&g`p1.Z@ܸ WL5\[Lٓ锂4$dم7m͆bOCN W/ntr]LhZmt#J~wWu4zVYQtUӦUppz҆䲫wVmHs8#:z:Fٵ6!%j0M;tpӨ*WY;A<;n4u6 #W0' q?6uk#DŎ:;ŝ-Z^\ۄ"] y:u*so)8lSCQl+ CCөSF <VԾ@-T+} KUNFW}mJBV6ʂ#Sr5Ȯ0NR5Q'W .>TijBI`EiOiiSͭ.Kpkj#Uw02ޝZwy =S)yܑQf')[5ʗ b+g|snU##l :d݀lۻܟ:5#<5Q"DžH3V]8\ږszfy7;S'#ҔAxVS⧱#ϺK3u!Exa븦"O僷s^+ܙ:ej>)+Jhꗉ:6˗7{w $niN(:(gl %uJ.HҞ>.Eac!*XTԂO75uDgy (tBkvy#`@O:0F`S'0"PS5i}c0wJcYl+4F`:`L)I MsU#`Wْ|La=wSgȻ0xp;ת*6u2E~m 72FM?&SZLksy#`3bz #`#tLO0 :@s#`p7px.O3:z^HZx48mNN=y#p)8‘Cu]:Ǒ^j.YY#t2-A4wbÎ՝OIN#E$ƣN2u1FTS'&~x0WA +!Nie/IiW׮:w<2Q 8hyIS\#`[glUKԪ Mm0!m[b,BF/kt/ie8 E z:ເ0!@3eQ".`iԼYT'B=ME]yF9_eLra#`Ek#LNb'%نk#;&z591*:{#^L'͐+i?ؖh0u~A#`#`쏩%#p HKs5Mb+i@gM$6uv⌀8S@gOv!mVN [0!_?|VtS~[0"UHvx ݯaS~Z0!Tb4Sqл%#`H+VuGӚ#pPo}Hc,ynK# i_[K6F, -F:WC FS0F`5Ր0F9`Xs5d`0uz#`V#`\ +#`LF:WC FYc!IENDB`redbaron-0.9.2/docs/basics.rst000066400000000000000000000147761344351435400162710ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron Basics ====== RedBaron is very simple to use, you just need to import it and feed him with a string: .. code-block:: python from redbaron import RedBaron red = RedBaron("print('hello world!')") But what you should be really doing is using RedBaron directly into a shell (I recommend `IPython `_ but `bpython `_ is cool too), it has been thought for it, like BeautifulSoup. .. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False .. ipython:: python from redbaron import RedBaron red = RedBaron("hello = 'Hello World!'\nprint(hello)") red As you can see, when displayed in a shell, a RedBaron instance renders to the actual content so you easily see what you are doing when playing interactively with it (just like a BeautifulSoup instance). There are 2 families of Node in RedBaron: NodeList and standalone Node. Since a Python program is a list of operations, RedBaron will always be a list. This is why when displayed you see integers on the left, those are the index in the list of the nodes of the right, so as expected: .. ipython:: In [4]: red[1] You get the `print` Node that was located at 2. As you can see, here we are on a standalone Node, so we don't get the list of indexes of the left. .. _help(): .help() ------- Another useful function is :file:`.help()`. It displays the RedBaron nodes tree helping you understand how is it composed and how you can use it: .. ipython:: In [5]: red[0] In [6]: red[0].help() Here, as you can see, :file:`hello = 'Hello World!'` is an :file:`AssignmentNode` and it has 2 attributes: :file:`target` and :file:`value`. Those 2 attributes are 2 other nodes, a :file:`NameNode` for the variable :file:`hello` and a :file:`StringNode` for the string. Those 2 nodes each have one attribute :file:`value` that is their content. One rule with Baron: **every node has a value attribute** that contains its value (in case of a node with multiple data, :file:`value` points to the most obvious one, for example, in a function definition it's the body of the function). The **only exceptions** are nodes where it doesn't make any sense, for example a :file:`PassNode` (representing the keyword :file:`pass`) simply doesn't contain anything. Like the :file:`repr`, :file:`.help()` has also a display showing index number when called on a :file:`NodeList`: .. ipython:: In [14]: red.help() The best way to understand how :file:`.help()` works is to remember that RedBaron is mapping from Baron FST which is JSON. This means that RedBaron node can be composed of either: string, bool, numbers, list or other nodes and the key are always string. helpers ~~~~~~~ Some nodes come with helpers method, :file:`.help()` displays them when they are present: .. ipython:: python red = RedBaron("import a, b, c as d") red.help(deep=1) You can read their documentation using the :file:`?` magic of ipython: .. ipython:: python print(red[0].names.__doc__) # you can do "red[0].names?" in IPython shell red[0].names() print(red[0].modules.__doc__) red[0].modules() If you come with cool helpers, don't hesitate to propose them in a `pull request `_! deep ~~~~ :file:`.help()` accept a deep argument on how far in the tree it should show the :file:`.help()` of subnode. By default its value is :file:`2`. You can pass the value :file:`True` if you want to display the whole tree. .. ipython:: python red = RedBaron("a = b if c else d") red.help() red.help(0) red.help(deep=1) # you can name the argument too red.help(True) with_formatting ~~~~~~~~~~~~~~~ :file:`.help()` accepts the option :file:`with_formatting` that is set at :file:`False` by default. If set at :file:`True` it will also display the attributes responsible for holding the formatting of the node (they are always node list): .. ipython:: In [12]: red.help(with_formatting=True) Those attributes are always surrounding syntax element of Python like :file:`[](),.{}` or keywords. You should, normally, not have a lot of reasons to play with them. You can find a detailed version of each nodes here: :doc:`nodes_reference`. nodes structure --------------- Nodes can have 3 kind of attributes (which can be accessed like normal object attributes): * data attributes, which are nearly always strings. They are shown with a :file:`=` in :file:`.help()`. :file:`.value` here for example. .. ipython:: In [1]: red = RedBaron("variable") In [2]: red[0].help() In [3]: red[0].value * node attributes, which are other nodes. They are shown with a :file:`->` followed by the name of the other node at the next line in :file:`.help()`. :file:`.target` and :file:`.value` here for example. .. ipython:: In [19]: red = RedBaron("a = 1") In [20]: red[0].help() In [21]: red[0].target.help() * nodelist attributes, which are lists of other nodes. They are shown with a :file:`->` followed by a series of names of the other nodes starting with a :file:`*` for every item of the list. :file:`.value` here for example: .. ipython:: In [17]: red = RedBaron("[1, 2, 3]") In [18]: red[0].help() In [19]: red[0].value[0].help() .dumps(), transform the tree into source code --------------------------------------------- To transform a RedBaron tree back into source code, use the :file:`.dumps()` method. This will transform the **current selection** back into code. .. ipython:: In [26]: red = RedBaron("a = 1") In [27]: red.dumps() In [28]: red[0].target.dumps() .fst(), transform the RedBaron tree into Baron FST -------------------------------------------------- To transform a RedBaron tree into Baron Full Syntax Tree, just use the :file:`.fst()` method. This will transform the **current selection** into FST. .. ipython:: In [28]: red = RedBaron("a = 1") In [29]: red.fst() In [30]: red[0].target.fst() While I don't see a lot of occasions where you might need this, this will allow you to better understand how Baron and RedBaron are working. .copy() ------- If you want to copy a RedBaron node you can use the :file:`.copy()` method this way: .. ipython:: In [45]: red = RedBaron("a = b") In [52]: red[0].target.copy() Next ~~~~ To learn how to find things in RedBaron read :doc:`querying`. redbaron-0.9.2/docs/conf.py000066400000000000000000000205161344351435400155570ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # RedBaron documentation build configuration file, created by # sphinx-quickstart on Mon Mar 24 06:52:35 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'IPython.sphinxext.ipython_directive', 'IPython.sphinxext.ipython_console_highlighting', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'RedBaron' copyright = u'2014, Laurent Peuch' import sys sys.path.append("..") from redbaron import RedBaron red = RedBaron(open("../setup.py", "r").read()) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = eval(red.find("call_argument", target=lambda x: x and x.dumps() == "version").value.value) # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'RedBarondoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'RedBaron.tex', u'RedBaron Documentation', u'Laurent Peuch', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'redbaron', u'RedBaron Documentation', [u'Laurent Peuch'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'RedBaron', u'RedBaron Documentation', u'Laurent Peuch', 'RedBaron', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False redbaron-0.9.2/docs/dotproxylist.rst000066400000000000000000000042571344351435400176020ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron DotProxyList usage examples =========================== .. ipython:: python red = RedBaron("a.b(c).d[e]") Please refer to `python list documentation `_ if you want to know the exact behavior or those methods (or `send a patch `_ to improve this documentation). append ~~~~~~ .. ipython:: python red red[0].value.append("(stuff)") red red[0].value insert ~~~~~~ .. ipython:: python red red[0].value.insert(1, "[foobar]") red red[0].value extend ~~~~~~ .. ipython:: python red red[0].value.extend(["a", "(hop)", "()"]) red red[0].value pop ~~~ .. ipython:: python red red[0].value.pop() red red[0].value red[0].value.pop(3) red red[0].value __getitem__ ~~~~~~~~~~~ .. ipython:: python red red[0].value red[0].value[2] __setitem__ ~~~~~~~~~~~ .. ipython:: python red red[0].value[2] = "[1:2]" red red[0].value remove ~~~~~~ .. ipython:: python red red[0].value.remove(red[0].value[2]) red red[0].value index ~~~~~ .. ipython:: python red red[0].value red[0].value.index(red[0].value[2]) count ~~~~~ .. ipython:: python red red[0].value red[0].value.count(red[0].value[2]) len ~~~ .. ipython:: python red red[0].value len(red[0].value) __delitem__ ~~~~~~~~~~~ .. ipython:: python red del red[0].value[2] red red[0].value in ~~ .. ipython:: python red red[0].value[2] in red[0].value __iter__ ~~~~~~~~ .. ipython:: python red for i in red[0].value: print(i.dumps()) __getslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value red[0].value[2:4] __setslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value[2:4] = ["(foo)", "a", "b", "c"] red red[0].value __delslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value[2:5] del red[0].value[2:5] red red[0].value redbaron-0.9.2/docs/index.rst000066400000000000000000000123361344351435400161220ustar00rootroot00000000000000Welcome to RedBaron's documentation! ==================================== Introduction ------------ RedBaron is a python library and tool powerful enough to be used into IPython solely that intent to make the process of **writing code that modify source code** as easy and as simple as possible. That include writing custom refactoring, generic refactoring, tools, IDE or directly modifying you source code into IPython with a higher and more powerful abstraction than the advanced texts modification tools that you find in advanced text editors and IDE. RedBaron guaranteed you that **it will only modify your code where you ask him to**. To achieve this, it is based on `Baron `_ a lossless `AST `_ for Python that guarantees the operation :file:`fst_to_code(code_to_fst(source_code)) == source_code`. RedBaron API and feel is heavily inspired by BeautifulSoup. It tries to be simple and intuitive and that once you've get the basics principles, you are good without reading the doc for 80% of your operations. A note about the examples ------------------------- This documentation is full of example for nearly everything. But in fact, those aren't really "example": those are real life code that are executed at the compilation time of this documentation, this guaranteed the example you see to work exactly the same way for you. Funny side effect: this make it possible to "break" this documentation. Code ---- https://github.com/PyCQA/redbaron Installation ------------ :: pip install redbaron[pygments] Or if you don't want to have syntax highlight in your shell or don't need it: :: pip install redbaron Basic usage ----------- .. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False Simple API: give string, get string back. .. ipython:: python from redbaron import RedBaron red = RedBaron("some_value = 42") red.dumps() # get code back Though to be used in IPython directly: .. ipython:: python red # direct feedback like BeautifulSoup, "0" here is the index of the node in our source code red.help() # helper function that describe nodes content so you don't have to read the doc Easy nodes modifications, you already know how to code in python, so pass python code (in a string) on the attribute you want to modify (wonder what :file:`.value` is? look at the output of :file:`.help()` in the previous example): .. ipython:: python red[0].value = "1 + 4" red Easy queries, just like in BeautifulSoup: .. ipython:: python red.find("int", value=4) red.find_all("int") # can also be written red("int") like in BeautifulSoup Queries can be very powerful, you can test each attributes with value/lambda/regex/special syntax for regex/globs. Now let's pretend that we are editing a django settings.py (notice that we are extending our source code using the same API than the one of a python list since we are in a list of lines): .. ipython:: python red.extend(["\n", "INSTALLED_APPLICATIONS = (\n 'django',\n)"]) # here "\n" is to had a blank line red And let's install another django application! (again: same API than a python list) .. ipython:: python red.find("assignment", target=lambda x: x.dumps() == "INSTALLED_APPLICATIONS").value.append("'another_app'") red Notice that the formatting of the tuple has been detected and respected when adding the new django application. And let's see the result of our work: .. ipython:: python print(red.dumps()) Financial support ----------------- Baron and RedBaron are a very advanced piece of engineering that requires a lot of time of concentration to work on. Until the end of 2018, the development has been a full volunteer work mostly done by [Bram](https://github.com/psycojoker), but now, to reach the next level and bring those projects to the stability and quality you expect, we need your support. You can join our contributors and sponsors on our transparent [OpenCollective](https://opencollective.com/redbaron), every contribution will count and will be mainly used to work on the projects stability and quality but also on continuing, on the side, the R&D side of those projects. Our supporters ~~~~~~~~~~~~~~ .. image:: https://opencollective.com/redbaron/tiers/i-like-this,-keep-going!/badge.svg?label=I like this, keep going!&color=brightgreen .. image:: https://opencollective.com/redbaron/tiers/it-looks-cool!/badge.svg?label=It looks cool!&color=brightgreen .. image:: https://opencollective.com/redbaron/tiers/oh-god,-that-saved-me-so-much-time!/badge.svg?label=Oh god, that saved me so much time!&color=brightgreen \ .. image:: https://opencollective.com/redbaron/tiers/i-like-this,-keep-going!.svg?avatarHeight=36&width=600 Become our first sponsor! .. image:: https://opencollective.com/redbaron/tiers/long-term-sponsor.svg?avatarHeight=36&width=600 Table of content ---------------- .. TODO add a tutorial .. toctree:: :maxdepth: 2 tuto why basics querying modifying proxy_list other Reference --------- .. toctree:: :maxdepth: 2 nodes_reference Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` redbaron-0.9.2/docs/lineproxylist.rst000066400000000000000000000047651344351435400177470ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron LineProxyList usage examples ============================ .. ipython:: python red = RedBaron("def a():\n pif\n\n paf\n pouf\n") Please refer to `python list documentation `_ if you want to know the exact behavior or those methods (or `send a patch `_ to improve this documentation). append ~~~~~~ .. ipython:: python red red[0].value.append("") red[0].value.append("stuff") red red[0].value Appending an empty string or a string containing a \n adds a new line. insert ~~~~~~ .. ipython:: python red red[0].value.insert(1, "\n") red[0].value.insert(1, "print(caribou)") red red[0].value Inserting an empty string or a string containing a \n adds a new line. extend ~~~~~~ .. ipython:: python red red[0].value.extend(["a", "\n", "if a:\n pass", "stuff"]) red red[0].value Extending with an empty string or a string containing a \n adds a new line. pop ~~~ .. ipython:: python red red[0].value.pop() red red[0].value red[0].value.pop(3) red red[0].value __getitem__ ~~~~~~~~~~~ .. ipython:: python red red[0].value red[0].value[2] __setitem__ ~~~~~~~~~~~ .. ipython:: python red red[0].value[2] = "plop" red red[0].value remove ~~~~~~ .. ipython:: python red red[0].value.remove(red[0].value[2]) red red[0].value index ~~~~~ .. ipython:: python red red[0].value red[0].value.index(red[0].value[2]) count ~~~~~ .. ipython:: python red red[0].value red[0].value.count(red[0].value[2]) len ~~~ .. ipython:: python red red[0].value len(red[0].value) __delitem__ ~~~~~~~~~~~ .. ipython:: python red del red[0].value[2] red red[0].value in ~~ .. ipython:: python red red[0].value[2] in red[0].value __iter__ ~~~~~~~~ .. ipython:: python red for i in red[0].value: print(i.dumps()) __getslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value red[0].value[2:4] __setslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value[2:4] = ["a", "b", "c"] red red[0].value __delslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value[2:5] del red[0].value[2:5] red red[0].value redbaron-0.9.2/docs/loop.sh000077500000000000000000000001331344351435400155610ustar00rootroot00000000000000#!/bin/bash while true; do clear; make html; sleep 0.1; inotifywait -e modify *.rst; done redbaron-0.9.2/docs/make.bat000066400000000000000000000150611344351435400156640ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\RedBaron.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\RedBaron.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end redbaron-0.9.2/docs/modifying.rst000066400000000000000000000106321344351435400167750ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron Modifying ========= Principle --------- When it comes to modifying the tree, the normal classical way would tell you to use the RedBaron nodes constructors, like this: .. ipython:: In [54]: from redbaron import RedBaron, NameNode In [55]: red = RedBaron("a = 1") In [56]: red[0].value In [57]: red[0].value = NameNode({'first_formatting': [{'type': 'space', 'value': ' '}], 'value': '+', 'second_formatting': [{'type': 'space', 'value': ' '}], 'second': {'section': 'number', 'type': 'int', 'value': '1'}, 'type': 'binary_operator', 'first': {'section': 'number', 'type': 'int', 'value': '1'}}) In [58]: red As you can see, this is totally impracticable. So, to solve this problem, RedBaron adopt a simple logic: you already know how to code in python, so, just send python code in form of a string, RedBaron will takes care or parsing and injecting it into its tree. This give an extremely simple and intuitive API: .. ipython:: In [55]: red = RedBaron("a = 1") In [56]: red[0].value In [57]: red[0].value = "1 + 1" In [58]: red The details on how you can modify **every** nodes can be found here: :doc:`nodes_reference`. Code block modifications ------------------------ The modification of python code block (like the body of a function or a while loop) is also possible this way. RedBaron will takes care for you or formatting you input the right way (adding surrounding blank lines and settings the correct indentation for the every line). Example: .. ipython:: python red = RedBaron("while True: pass") red[0].value = "plop" red red[0].value = " this_will_be_correctly_indented" red You have the full list of cases handled on this page: :doc:`nodes_reference`. Details ------- As you might have already noticed, you can set attributes of a node with a string or a RedBaron node. This is also possible by directly passing FST. Here is an IPython session illustrating all the possibilities (be sure to have read the "node structures" in basics to understand what is happening): .. ipython:: In [70]: from redbaron import RedBaron In [71]: red = RedBaron("a = b") Data attribute, no parsing ~~~~~~~~~~~~~~~~~~~~~~~~~~ .. ipython:: In [72]: red.name.help() In [73]: red.name.value = "something_else" In [74]: red Node attribute with a string: parsing with RedBaron ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. ipython:: In [75]: red[0].help() In [76]: red[0].value = "42 * pouet" In [77]: red Node attribute with FST data: transformation into RedBaron objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. ipython:: In [79]: red[0].value = {"type": "name", "value": "pouet"} In [80]: red List attribute with a string: parsing with RedBaron ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. ipython:: In [81]: red = RedBaron("[1, 2, 3]") In [82]: red[0].help() In [83]: red[0].value = "caramba" In [84]: red In [85]: red[0].value = "4, 5, 6" In [86]: red List node attribute with FST: transformation into RedBaron objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. ipython:: In [87]: red[0].value = {"type": "name", "value": "pouet"} In [88]: red In [89]: red[0].value = [{"type": "name", "value": "pouet"}] In [90]: red List node attribute with mixed content: parsing/transformation depending of the context ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. ipython:: In [103]: red[0].value = [{"type": "name", "value": "pouet"}, {"type": "comma", "first_formatting": [], "second_formatting": []}, "pouet ,", NameNode({"type": "name", "value": "plop"})] In [104]: red Auto assignment of .parent and .on_attribute -------------------------------------------- When you modify an attribute of a node or a node list, RedBaron will take care of setting the :file:`.parent` value of the new attribute to the corresponding node. This will be done if you set the attribute value using either a :file:`string`, a :file:`fst node`, an instance of a node or a node list. The same is done for :file:`.on_attribute`. Next ~~~~ To learn how to work with list of things in RedBaron read :doc:`proxy_list`. redbaron-0.9.2/docs/nodes_reference.rst000066400000000000000000000764261344351435400201530ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron This is the reference page for every node type encountered in RedBaron and their specificities. ===================== Nodes References Page ===================== ======== TopClass ======== .. _CodeBlockNode: CodeBlockNode ============= CodeBlockNode is a type of node that has a body composed of indented code like the DefNode or the IfNode. Great care has been taken on the SetAttr of their value so you don't have to take care about reindenting and other formatting details. Demonstration: .. ipython:: python red = RedBaron("def function():\n pass\n") red red[0].value = "stuff" # first '\n' will be added, indentation will be set red red[0].value = " bad_indent" red red[0].value = " some\n stuff" red Some for indented cases: .. ipython:: python red = RedBaron("class A:\n def __init__():\n pass\n\n def plop():\n pass") red.def_.value = "not_indented" red red.def_.value = "\n badly_indented" red red.def_.value = "some\nstuff\nfoo\nbar\n\npouet" red ===== Nodes ===== ArgumentGeneratorComprehensionNode ================================== A node representing generator passed as an argument during a function call. .. ipython:: python RedBaron("a(x for y in z)")[0].value[1].value[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a(x for y in z)") red red[0].value[1].value[0].result = "pouet" red red[0].value[1].value[0].generators = "for artichaut in courgette" red AssertNode ========== A node representing the assert statement. .. ipython:: python RedBaron("assert test, message")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("assert some_test") red red[0].value = "1 == caramba()" red red[0].message = "'foo bar'" red red[0].message = "" red AssignmentNode ============== A node representing the assign operation in python (:file:`foo = bar`) and the "augmented" assign (:file:`foo += bar`). .. ipython:: python RedBaron("a = b")[0].help(deep=True) RedBaron("a += b")[0].help(deep=True) SetAttr ------- Works as expected: .. ipython:: python red = RedBaron("a = b") red[0].first = "caramba" red red[0].second = "42" red For the operator part, expected input should work: .. ipython:: python red = RedBaron("a = b") red[0].operator = "+=" red red[0].operator = "+" # equivalent to '+=' red red[0].operator = "-" # equivalent to '-=' red red[0].operator = "=" # equivalent to '=' red red[0].operator = "/=" red red[0].operator = "" # equivalent to '=' red AssociativeParenthesisNode ========================== This node represents a statement prioritised on another by being surrounded by parenthesis. For e.g., the first part of this addition: :file:`(1 + 1) * 2`. .. ipython:: python RedBaron("(foo)")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("(foo)") red red[0].value = "1 + 1" red .. _AtomtrailersNode: AtomtrailersNode ================ This node represents a combination of :ref:`NameNode`, :ref:`DotNode`, :ref:`CallNode`, :ref:`GetitemNode` sorted in a list. For e.g.: :file:`a.b().c[d]`. .. ipython:: python RedBaron("a.b().c[d]")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a.b()") red red[0].value = "d.be" red BinaryNode ========== The node represents a binary number value. .. ipython:: python RedBaron("0b10101")[0].help(deep=True) BinaryOperatorNode ================== The node represents a binary operator (an operator (e.g.: :file:`+` :file:`-` :file:`/`..) applied to 2 values) with its operands. For e.g.: :file:`1 + 1`. .. ipython:: python RedBaron("1 + 1")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("1 + 1") red red[0].value = "*" red red[0].first = "(1 + 1)" red red[0].second = "caramba" red BooleanOperatorNode =================== The node represents a boolean operator (an operator (e.g.: :file:`and` :file:`or`) applied to 2 values) with its operands. For e.g.: :file:`x and y`. .. ipython:: python RedBaron("x and y")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("x and y") red red[0].value = "or" red red[0].first = "plop" red red[0].second = "oupsi" red .. _CallNode: CallNode ======== A node representing a call (eg: :file:`a()`, here :file:`a` is called with no arguments). It is always stored in an :ref:`AtomtrailersNode` or a :ref:`DecoratorNode`. .. ipython:: python RedBaron("a(b, c=d)")[0].value[1].help(deep=True) SetAttr ------- SetAttr works as expected: .. ipython:: python red = RedBaron("a()") red[0].value[1].value = "b, c=d, *e, **f" red CallArgumentNode ================ A node representing an argument or a named argument of a :ref:`CallNode` (other nodes that can be in a CallNode are :ref:`ListArgumentNode` and :ref:`DictArgumentNode`). .. ipython:: python RedBaron("a(b, c=d)")[0].value[1].value[0].help(deep=True) RedBaron("a(b, c=d)")[0].value[1].value[1].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a(b)") red red[0].value[1].value[0] = "stuff=foo" red ClassNode ========= A node representing a class definition. .. ipython:: python RedBaron("class SomeAwesomeName(A, B, C): pass")[0].help(deep=True) SetAttr ------- ClassNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. Most other attributes work as expected: .. ipython:: python red = RedBaron("class SomeAwesomeName(A, B, C): pass") red[0].name = "AnotherAwesomeName" red red[0].inherit_from = "object" red CommaNode ========= A node representing a comma, this is the kind of formatting node that you might have to deal with if not enough high level helpers are available. They are generally present in call, function arguments definition and data structure sugar syntactic notation. The comma node is responsible for holding the formatting around it. .. ipython:: python RedBaron("[1, 2, 3]")[0].value.node_list[1].help(deep=True) ComparisonNode ============== The node represents a comparison operation, for e.g.: :file:`42 > 30`. .. ipython:: python RedBaron("42 > 30")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("42 > 30") red red[0].operator = "==" red red[0].first = "(1 + 1)" red red[0].second = "caramba" red ComprehensionIfNode =================== The node represents "if" condition in a comprehension loop. It is always a member of a :ref:`ComprehensionLoopNode`. .. ipython:: python RedBaron("[x for x in x if condition]")[0].generators[0].ifs[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("[x for x in x if condition]") red red[0].generators[0].ifs[0].value = "True" red .. _ComprehensionLoopNode: ComprehensionLoopNode ===================== The node represents the loop part of a comprehension structure. .. ipython:: python RedBaron("[x for y in z]")[0].generators[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("[x for y in z]") red red[0].generators[0].target = "plop" red red[0].generators[0].iterator = "iter" red red[0].generators[0].ifs = "if a if b" red .. _DecoratorNode: DecoratorNode ============= A node representing an individual decorator (of a function or a class). .. ipython:: python RedBaron("@stuff.plop(*a)\ndef b(): pass")[0].decorators[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("@stuff\ndef a(): pass") red red[0].decorators[0].value = "a.b.c" red red[0].decorators[0].call = "(*args)" red red[0].decorators[0].call = "" red DefNode ======= A node representing a function definition. .. ipython:: python RedBaron("def stuff():\n pass\n")[0].help(deep=True) SetAttr ------- DefNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. Most other attributes works as expected: .. ipython:: python red = RedBaron("def stuff():\n body\n") red[0] red[0].name = "awesome_function" red[0].arguments = "a, b=None, *c, **d" red Decorators might be a bit less intuitive: .. ipython:: python red = RedBaron("def stuff():\n body\n") red[0].decorators = "@foo(*plop)" red red[0].decorators = "@foo\n@bar.baz()" red red[0].decorators = " @pouet" # SetAttr will take care of reindenting everything as expected red *New in 0.7*. Async is a boolean attribute that determine if a function is async: .. ipython:: python red = RedBaron("def stuff():\n body\n") red[0].async_ red[0].async_ = True red red[0].async_ = False red .. WARNING:: As of python 3.7 `async` and `await` are now reserved keywords so don't uses `red.async`, it works as expected but won't make your code forward compatible. *New in 0.9* Return annotation management: .. ipython:: python red = RedBaron("def stuff():\n return 42\n") red red[0].return_annotation = "Int" red red[0].return_annotation = "" red DefArgumentNode =============== A node representing an argument in a function definition. .. ipython:: python RedBaron("def a(b, c=d): pass")[0].arguments.help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("def a(b): pass") red red[0].arguments[0].name = "plop" red red[0].arguments[0].value = "1 + 1" red *New in 0.9* Annotations: .. ipython:: python red = RedBaron("def a(b): pass") red red[0].arguments[0].annotation = "Int" red red[0].arguments[0].annotation red DelNode ======= A node representing a :file:`del` statement. .. ipython:: python RedBaron("del stuff")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("del stuff") red red[0].value = "some, other, stuff" red .. _DictArgumentNode: DictArgumentNode ================ A node representing a 'kwargs' defined in a function definition argument or used in a :ref:`CallNode`. .. ipython:: python RedBaron("a(**b)")[0].value[1].value[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a(**b)") red red[0].value[1].value[0].value = "plop" red *New in 0.9* Annotations: .. ipython:: python red = RedBaron("def a(**b): pass") red red[0].arguments[0].annotation = "Int" red red[0].arguments[0].annotation red DictNode ======== A node representing python sugar syntactic notation for dict. .. ipython:: python RedBaron("{'a': 1, 'b': 2, 'c': 3}")[0].help(deep=True) DictComprehensionNode ===================== A node representing dictionary comprehension node. .. ipython:: python RedBaron("{a: b for c in d}")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("{a: b for c in d}") red red[0].result = "plop: poulpe" red red[0].generators = "for zomg in wtf" red DottedAsNameNode ================ A node representing an argument to the import node. .. ipython:: python RedBaron("import a.b.c as d")[0].value[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("import a.b.c as d") red red[0].value[0].value = "some.random.module" red red[0].value[0].target = "stuff" red .. _DotNode: DotNode ======= A node representing a dot '.', generally found in atom trailers (this kind of structure: 'variable.another_variable(call)[getitem]'). This is the kind of formatting node that you might have to deal with if not enough high level helpers are available. The dot node is responsible for holding the formatting around it. .. ipython:: python RedBaron("a.b")[0].value[1].help(deep=True) .. _ElifNode: ElifNode ======== A node representing an elif statement. The ElifNode, like the :ref:`IfNode` or the :ref:`ElseNode` are stored in a :ref:`IfelseblockNode`. .. ipython:: python RedBaron("if a: pass\nelif b: pass")[0].value[1].help(deep=True) SetAttr ------- ElifNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. Other attributes work as expected: .. ipython:: python red = RedBaron("if a: pass\nelif b: pass") red red[0].value[1].test = "1 + 1 == 11" red .. _ElseNode: ElseNode ======== A node representing an else statement. The ElseNode, like the :ref:`IfNode` or the :ref:`ElifNode`, is stored in a :ref:`IfelseblockNode`. .. ipython:: python RedBaron("if a: pass\nelse: pass")[0].value[1].help(deep=True) SetAttr ------- ElifNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. EllipsisNode ============ A node representing "...". .. ipython:: python RedBaron("def a(): ...").ellipsis.help(deep=True) EndlNode ======== A node for the end line ('\n', '\r\n') component. **This node is responsible for holding the indentation AFTER itself**. This node also handles formatting around it, CommentNode **before** an EndlNode will end up in the formatting key of an EndlNode 99% of the time (the exception is if the CommentNode is the last node of the file). .. ipython:: python RedBaron("\n")[0].help() RedBaron("# first node of the file\n# last node of the file").node_list.help() .. _ExceptNode: ExceptNode ========== A node representing an except statement (member of a :ref:`TryNode`). .. ipython:: python RedBaron("try: pass\nexcept FooBar: pass\nexcept Exception: pass\nelse: pass\nfinally: pass\n")[0].excepts[0].help(deep=True) SetAttr ------- ExceptNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. Other attributes work as expected: .. ipython:: python red = RedBaron("try: pass\nexcept: pass") red red[0].excepts[0].exception = "plop" red red[0].excepts[0].target = "stuff" red red[0].excepts[0].exception = "" red # red[0].excepts[0].target = "stuff" <- would raise without a target ExecNode ======== A node representing an exec statement. .. ipython:: python RedBaron("exec '1 + 1' in a, b")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("exec 'stuff'") red red[0].value = 'some_code' red red[0].globals = 'x' red red[0].locals = 'y' red .. _FinallyNode: FinallyNode =========== A node representing a finally statement (member of a :ref:`TryNode`). .. ipython:: python RedBaron("try: pass\nexcept FooBar: pass\nexcept Exception: pass\nelse: pass\nfinally: pass\n").finally_.help(deep=True) SetAttr ------- FinallyNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. ForNode ======= A node representing a for loop. .. ipython:: python RedBaron("for i in b:\n pass")[0].help(deep=True) SetAttr ------- ForNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. The else attributes accept a great ranges of inputs, since :file:`else` is a reserved python keyword, you need to access it using the :file:`else_` attribute. Other attributes work as expected: .. ipython:: python red = RedBaron("for i in b: pass") red red[0].iterator = "i, j, k" red red[0].target = "[x for x in stuff if condition]" red red[0].else_ = "do_stuff" red red[0].else_ = "else: foobar" red red[0].else_ = " else:\n badly_indented_and_trailing\n\n\n\n" red *New in 0.8*. Async is a boolean attribute that determine if a function is async: .. ipython:: python red = RedBaron("for a in b: pass") red[0].async_ red[0].async_ = True red red[0].async_ = False red .. WARNING:: As of python 3.7 `async` and `await` are now reserved keywords so don't uses `red.async`, it works as expected but won't make your code forward compatible. FromImportNode ============== A node representing a "from import" statement. .. ipython:: python RedBaron("from a import b")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("from a import b") red red[0].value = "some.module" red red[0].targets = "a as b, c as d, e" red Helpers ------- To reduce the complexity, 2 helpers method are provided: .. ipython:: python red = RedBaron("from foo.bar import baz as stuff, plop") red[0].names() # names added to the context red[0].modules() # modules imported red[0].full_path_names() # names added to the context with full path red[0].full_path_modules() # modules imported with full path GeneratorComprehensionNode ========================== A node representing a generator comprehension node. .. ipython:: python RedBaron("(x for y in z)")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("(x for y in z)") red red[0].result = "pouet" red red[0].generators = "for artichaut in courgette" red .. _GetitemNode: GetitemNode =========== A node representing a 'get item' access on a python object, in other words the '[stuff]' in 'some_object[stuff]'. .. ipython:: python RedBaron("a[b]")[0].value[1].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a[b]") red red[0].value[1].value = "1 + 1" red GlobalNode ========== A node representing a global statement. .. ipython:: python RedBaron("global a")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("global a") red red[0].value = "stuff, plop" red .. _IfNode: IfNode ====== A node representing an if statement. The IfNode, like the :ref:`ElifNode` or the :ref:`ElseNode`, is stored in an :ref:`IfelseblockNode`. .. ipython:: python RedBaron("if a: pass")[0].value[0].help(deep=True) SetAttr ------- IfNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. Other attributes work as expected: .. ipython:: python red = RedBaron("if a: pass") red red[0].value[0].test = "1 + 1 == 11" red .. _IfelseblockNode: IfelseblockNode =============== A node representing the conditional block composed of at least one if statement, zero or more elif statements and, at the end, an optional else statement. All those statements are stored in a list. .. ipython:: python RedBaron("if a: pass\nelif b: pass\nelse: pass\n")[0].help(deep=True) SetAttr ------- Works as expected and is very flexible on its input: * the input is automatically put at the correct indentation * the input is automatically right strip * if the statement is followed, the correct number of blanks lines are added: 2 when at the root of the file, 1 when indented .. ipython:: python red = RedBaron("if a: pass\n") red red[0].value = "if a:\n pass\nelif b:\n pass\n\n\n" red red[0].value = " if a:\n pass" red .. ipython:: python red = RedBaron("if a:\n pass\n\n\nplop") red red[0].value = " if a:\n pass" red .. ipython:: python red = RedBaron("while True:\n if plop:\n break\n\n stuff") red red[0].value[1].value = "if a:\n pass\nelif b:\n pass\n\n\n" red ImportNode ========== A node representing the import statement of the python language. *Be careful, this node and its subnodes are way more complex than what you can expect*. .. ipython:: python RedBaron("import foo")[0].help(deep=True) RedBaron("import foo.bar.baz as stuff, another_thing.plop")[0].help(deep=True) SetAttr ------- Works as expected: .. ipython:: python red = RedBaron("import foo") red[0].value = "foo.bar.baz as plop, stuff, plop.dot" red red.help(deep=True) Helpers ------- To reduce the complexity, 2 helpers method are provided: .. ipython:: python red = RedBaron("import foo.bar.baz as stuff, another_thing.plop") red[0].modules() # modules imported red[0].names() # names added to the context IntNode ======= A python integer. .. ipython:: python RedBaron("42")[0].help() KwargsOnlyMarkerNode ==================== *New in 0.7*. A node representing the "*" in arguments declaration to force keywords only arguments after itself. .. ipython:: python RedBaron("def a(*): pass")[0].arguments[0].help(deep=True) LambdaNode ========== A node representing a lambda statement. .. ipython:: python RedBaron("lambda x: y")[0].help(deep=True) SetAttr ------- Works as expected: .. ipython:: python red = RedBaron("lambda x: y") red red[0].arguments = "a, b=c, *d, **f" red red[0].value = "plop" red .. _ListArgumentNode: ListArgumentNode ================ A node representing a "star argument" in a function call **or** definition. .. ipython:: python RedBaron("def a(*b): pass")[0].arguments[0].help(deep=True) SetAttr ------- Works as expected: .. ipython:: python red = RedBaron("def a(*b): pass") red red[0].arguments[0].value = "plop" red *New in 0.9* Annotations: .. ipython:: python red = RedBaron("def a(*b): pass") red red[0].arguments[0].annotation = "Int" red red[0].arguments[0].annotation red ListComprehensionNode ===================== A node representing a list comprehension node. .. ipython:: python RedBaron("[x for y in z]")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("[x for y in z]") red red[0].result = "pouet" red red[0].generators = "for artichaut in courgette" red ListNode ======== A node representing python sugar syntactic notation for list. .. ipython:: python RedBaron("[1, 2, 3]")[0].help(deep=True) NameAsNameNode ============== A node representing an argument to the from import statement. .. ipython:: python RedBaron("from x import a as d")[0].targets[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("from x import a as d") red red[0].targets[0].value = "some_random_module" red red[0].targets[0].target = "stuff" red NonlocalNode ============ *New in 0.7*. A node representing a nonlocal statement. .. ipython:: python RedBaron("nonlocal a")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("nonlocal a") red red[0].value = "stuff, plop" red .. _IfNode: PrintNode ========= A node representing a print statement. .. ipython:: python RedBaron("print(stuff)")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("print(stuff)") red red[0].destination = "some_file" red red[0].value = "a, b, c" red red[0].destination = "" red red[0].value = "" red RaiseNode ========= A node representing a raise statement. .. ipython:: python RedBaron("raise Exception(), foo, bar")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("raise stuff") red red[0].value = "foo" red red[0].instance = "bar" red red[0].traceback = "baz" red *New in 0.9* How to deal with the "raise from" notation: (by default a comma is inserted to avoid breaking backward compatibility) .. ipython:: python red = RedBaron("raise stuff") red red[0].instance = "foo" red red[0].comma_or_from = "from" red red[0].comma_or_from = "," red red[0].instance = "" red ReprNode ======== A node representing python sugar syntactic notation for repr. .. ipython:: python RedBaron("`pouet`")[0].help(deep=True) ReturnNode ========== A node representing a return statement. .. ipython:: python RedBaron("return stuff")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("return stuff") red red[0].value = "1 + 1" red red[0].value = "" red SetNode ======= A node representing python sugar syntactic notation for set. .. ipython:: python RedBaron("{1, 2, 3}")[0].help(deep=True) SetComprehensionNode ==================== A node representing a set comprehension node. .. ipython:: python RedBaron("{x for y in z}")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("{x for y in z}") red red[0].result = "pouet" red red[0].generators = "for artichaut in courgette" red SliceNode ========= A node representing a slice, the "1:2:3" that can be found in a :ref:`GetitemNode`. .. ipython:: python RedBaron("a[1:-1:2]")[0].value[1].value.help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a[1:-1:2]") red red[0].value[1].value.lower = "a" red red[0].value[1].value.upper = "b" red red[0].value[1].value.step = "stuff" red red[0].value[1].value.step = "" red SpaceNode ========= A formatting node representing a space. You'll probably never have to deal with it except if you play with the way the file is rendered. **Those nodes will be hidden in formatting keys 99% of the time** (the only exception is if it's the last node of the file). .. ipython:: python RedBaron("1 + 1")[0].first_formatting[0].help() RedBaron("1 + 1").help() StarExpressionNode ================== *New in 0.9* A node representing the result of a deconstruction in an assignment. .. ipython:: python red = RedBaron("a, *b = c") red red[0].target[1].help() StringChainNode =============== This is a special node that handle a particular way of writing a single string in python by putting several strings one after the other while only separated by spaces or endls. .. ipython:: python RedBaron("'a' r'b' b'c'")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("'a' r'b' b'c'") red red[0].value = "'plip' 'plop'" red TernaryOperatorNode =================== A node representing the ternary operator expression. .. ipython:: python RedBaron("a if b else c")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("a if b else c") red red[0].value = "some_test" red red[0].first = "a_value" red red[0].second = "another_value" red .. _TryNode: TryNode ======= A node representing a try statement. This node is responsible for holding the :ref:`ExceptNode`, :ref:`FinallyNode` and :ref:`ElseNode`. .. ipython:: python RedBaron("try: pass\nexcept FooBar: pass\nexcept Exception: pass\nelse: pass\nfinally: pass\n")[0].help(deep=True) SetAttr ------- TryNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. For the :file:`else` and the :file:`finally` and the :file:`excepts` attributes, TryNode is very flexible on the range of inputs it can get, like for a CodeBlockNode value's attribute. **Important**: Since :file:`else` and :file:`finally` are reserved keywords in python, you need to append a :file:`_` to those attributes name to access/modify them: :file:`node.else_` and :file:`node.finally_`. .. ipython:: python red = RedBaron("try:\n pass\nexcept:\n pass\n") red red[0].else_ = "do_stuff" red red[0].else_ = "else: foobar" red red[0].else_ = " else:\n badly_indented_and_trailing\n\n\n\n" red # input management of finally_ works the same way than for else_ red[0].finally_ = "close_some_stuff" red red[0].else_ = "" red red[0].finally_ = "" red red[0].excepts = "except A as b:\n pass" red red[0].excepts = "except X:\n pass\nexcept Y:\n pass" red # You **CAN'T** do this red[0].excepts = "foobar" TupleNode ========= A node representing python sugar syntactic notation for tuple. .. ipython:: python RedBaron("(1, 2, 3)")[0].help(deep=True) UnitaryOperatorNode =================== A node representing a number sign modification operator like :file:`-2` or :file:`+42`. .. ipython:: python RedBaron("-1")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("-1") red red[0].target = "42" red red[0].value = "+" red YieldNode ========= A node representing a yield statement. .. ipython:: python RedBaron("yield 42")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("yield 42") red red[0].value = "stuff" red red[0].value = "" red YieldAtomNode ============= A node representing a yield statement surrounded by parenthesis. .. ipython:: python RedBaron("(yield 42)")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("(yield 42)") red red[0].value = "stuff" red red[0].value = "" red YieldFromNode ============= *New in 0.7*. A node representing a "yield from" statement. .. ipython:: python RedBaron("yield from 42")[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("yield from 42") red red[0].value = "stuff" red WhileNode ========= A node representing a while loop. .. ipython:: python RedBaron("while condition:\n pass")[0].help(deep=True) SetAttr ------- WhileNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. The else attributes accept a great ranges of inputs, since :file:`else` is a reserved python keyword, you need to access it using the :file:`else_` attribute. Other attributes work as expected: .. ipython:: python red = RedBaron("while condition: pass") red red[0].test = "a is not None" red red[0].else_ = "do_stuff" red red[0].else_ = "else: foobar" red red[0].else_ = " else:\n badly_indented_and_trailing\n\n\n\n" red WithContext =========== A node representing a with statement. .. ipython:: python RedBaron("with a: pass")[0].help(deep=True) WithContextItemNode =================== A node representing one of the context manager items in a with statement. .. ipython:: python RedBaron("with a as b: pass")[0].contexts[0].help(deep=True) SetAttr ------- .. ipython:: python red = RedBaron("with a: pass") red red[0].contexts[0].value = "plop" red red[0].contexts[0].as_ = "stuff" red red[0].contexts[0].as_ = "" red WithNode ======== A node representing a with statement. .. ipython:: python RedBaron("with a as b, c: pass")[0].help(deep=True) SetAttr ------- WithNode is a CodeBlockNode which means its value attribute accepts a wide range of values, see :ref:`CodeBlockNode` for more information. Other attributes work as expected: .. ipython:: python red = RedBaron("with a: pass") red red[0].contexts = "b as plop, stuff()" red *New in 0.8*. Async is a boolean attribute that determine if a function is async: .. ipython:: python red = RedBaron("with a as b: pass") red[0].async_ red[0].async_ = True red red[0].async_ = False red .. WARNING:: As of python 3.7 `async` and `await` are now reserved keywords so don't uses `red.async`, it works as expected but won't make your code forward compatible. redbaron-0.9.2/docs/other.rst000066400000000000000000000414311344351435400161320ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron Other ===== List of other features of RedBaron. .. _parent: .parent ------- Every node and node list have a :file:`.parent` attribute that points to the parent node or node list. If the node doesn't have a parent node (for example the node list returned when constructing a new instance using the :file:`RedBaron` class), the :file:`parent` attribute is set at :file:`None`. A new node or node list created using :file:`.copy()` always have its :file:`parent` attribute set at :file:`None`. The attribute on which the node is assigned on the parent node is store in the :file:`on_attribute` attribute. :file:`on_attribute` is set at :file:`"root"` if the parent is a RedBaron instance. .. ipython:: python red = RedBaron("a = 1 + caramba") red.help() red.parent red.on_attribute red[0].parent red[0].on_attribute red[0].target.parent red[0].target.on_attribute red[0].value.parent red[0].value.on_attribute red[0].value.first.parent red[0].value.first.on_attribute .parent_find() -------------- A helper method that allow you to do the equivalent of the :file:`.find()` method but in the chain of the parents of the node. This is the equivalent of doing: :file:`while node has a parent: if node.parent match query: return node.parent, else: node = node.parent`. It returns :file:`None` if no parent match the query. .. ipython:: python red = RedBaron("def a():\n with b:\n def c():\n pass") red.help() r = red.pass_ r r.parent r.parent_find('def') r.parent_find('def', name='a') r.parent_find('def', name='dont_exist') .next .previous .next_recursive .previous_recursive .next_generator() .previous_generator() ------------------------------------------------------------------------------------------- In a similar fashion, nodes have a :file:`.next` and :file:`.previous` attributes that point to the next or previous node if the node is located in a node list. They are set at :file:`None` if there is not adjacent node or if the node is not in a node list. A node list will never have a :file:`.next` or :file:`.previous` node, so those attributes will always be set at :file:`None`. Nodes also have a :file:`.next_generator()` and :file:`.previous_generator()` if you want to iterate on the neighbours of the node. Nodes have also a :file:`.next_recursive` and :file:`.previous_recursive` attribute. It is similar to the non recursive function but differ in the fact that, when using :file:`.next_recursive` on a node at the end of the list, it points to the first adjacent node that exist in the parent hierarchy. .. ipython:: In [42]: red = RedBaron("[1, 2, 3]; a = 1") In [42]: red.help() In [42]: list = red[0] In [42]: print(list.next) In [42]: print(list.previous) In [42]: list.help() In [42]: print(list.value[0]) In [42]: print(list.value[0].next) In [42]: print(list.value[0].next_recursive) In [42]: print(list.value[0].previous) In [42]: print(list.value[0].previous_recursive) In [42]: print(list.value[2]) In [42]: print(list.value[2].next) In [42]: print(list.value[2].next_recursive) In [42]: print(list.value[2].previous) In [42]: print(list.value[2].previous_recursive) In [42]: assign = red[2] In [42]: assign.help() In [42]: print(assign.target.next) In [42]: print(assign.target.previous) In [42]: list.value[2].help(deep=1) In [42]: print([x for x list.value[2].next_generator()]) In [42]: print([x for x list.value[2].previous_generator()]) In [42]: list.value.help(deep=0) In [42]: print([x for x list.value.next_generator()]) In [42]: print([x for x list.value.previous_generator()]) In [42]: print([x for x assign.target.next_generator()]) In [42]: print([x for x assign.target.previous_generator()]) .next_intuitive/.previous_intuitive ----------------------------------- Due to its tree nature, navigating in the FST might not behave as the user expect it. For example: doing a :file:`.next` on a :file:`TryNode` will not return the first :file:`ExceptNode` (or :file:`FinallyNode`) but will return the node after the try-excepts-else-finally node because it is a full node in itself in the FST. See for yourself: .. ipython:: python red = RedBaron("try:\n pass\nexcept:\n pass\nafter") red.try_ red.try_.next red.help() To solve this issue :file:`.next_intuitive` and :file:`.previous_intuitive` have been introduced: .. ipython:: python red red.try_.next_intuitive red.try_.next_intuitive.next_intuitive This also applies to :file:`IfNode`, :file:`ElifNode`, :file:`ElseNode`, :file:`ForNode` and :file:`WhileNode` (both of the last one can have an else statement). This also works coming from nodes outsides of those previous nodes. For :file:`IfNode`, :file:`ElifNode` and :file:`ElseNode` **inside** an :file:`IfelseblockNode`: .. ipython:: python red = RedBaron("before\nif a:\n pass\nelif b:\n pass\nelse:\n pass\nafter") red red[1].help() red[1] red.if_.next red.if_.next_intuitive red.if_.next_intuitive.next_intuitive red.if_.next_intuitive.next_intuitive.next_intuitive red.if_.next_intuitive.next_intuitive.next_intuitive.next_intuitive .. warning:: There is a subtlety: :file:`IfelseblockNode` is **unaffected** by this behavior: you have to use :file:`next_intuitive` or :file:`previous_intuitive` on :file:`IfNode`, :file:`ElifNode` and :file:`ElseNode` **inside** IfelseblockNode. But, if you do a :file:`next_intuitive` or :file:`previous_intuitive` or a node around :file:`IfelseblockNode` it will jump to the first or last node **inside** the :file:`IfelseblockNode`. See this example .. ipython:: python red = RedBaron("before\nif a:\n pass\nelif b:\n pass\nelse:\n pass\nafter") red[1].ifelseblock.next_intuitive # similar to .next red[1].ifelseblock.next.previous # this is the IfelseblockNode red[1].ifelseblock.next.previous_intuitive # this is the ElseNode red[1].ifelseblock.previous.next # this is the IfelseblockNode red[1].ifelseblock.previous.next_intuitive # this is the IfNode For :file:`ForNode`: .. ipython:: python red = RedBaron("for a in b:\n pass\nelse:\n pass\nafter") red red[0].help() red.for_ red.for_.next red.for_.next_intuitive red.for_.next_intuitive.next_intuitive For :file:`WhileNode`: .. ipython:: python red = RedBaron("while a:\n pass\nelse:\n pass\nafter") red red[0].help() red.while_ red.while_.next red.while_.next_intuitive red.while_.next_intuitive.next_intuitive .root ----- Every node have the :file:`.root` attribute (property) that returns the root node in which this node is located: .. ipython:: python red = RedBaron("def a(): return 42") red.int_ assert red.int_.root is red .. _index_on_parent: .index_on_parent ---------------- Every node have the :file:`.index_on_parent` attribute (property) that returns the index at which this node is store in its parent node list. If the node isn't stored in a node list, it returns :file:`None`. If the node is stored in a proxy list (:doc:`proxy_list`), it's the index in the proxy list that is returned. to get the unproxified index use :ref:`index_on_parent_raw`. .. ipython:: python red = RedBaron("a = [1, 2, 3]") red[0].value.value red[0].value.value[2] red[0].value.value[2].index_on_parent red[0].value red[0].value.index_on_parent .. _index_on_parent_raw: .index_on_parent_raw -------------------- Same as :ref:`index_on_parent` except that it always return the unproxified whether the node is stored in a proxy list or not. .. ipython:: python red = RedBaron("a = [1, 2, 3]") red[0].value.value.node_list red[0].value.value.node_list[2] red[0].value.value.node_list[2].index_on_parent_raw .filtered() ----------- Node list comes with a small helper function: :file:`.filtered()` that returns a **tuple** containing the "significant" node (nodes that aren't comma node, dot node, space node or endl node). .. ipython:: python red = RedBaron("[1, 2, 3]") red[0].value red[0].value.filtered() Note: the fact that it's a tuple that is returned will probably evolve in the future into a node list proxy or something like that, I just don't have the time to do something better right now. .indentation ------------ Every node has the property :file:`.indentation` that will return the indentation level of the node: .. ipython:: python red = RedBaron("while a:\n pass") red[0].indentation red[0].test.indentation red.pass_.indentation red = RedBaron("while a: pass") red.pass_.indentation .increase_indentation() and .decrease_indentation() --------------------------------------------------- Those 2 methods allow you to change the indentation of a part of the tree. They expect the number of spaces to add or to remove as first argument. .. ipython:: python red = RedBaron("def a():\n if plop:\n pass") red red[0].value.increase_indentation(15) red red[0].value.decrease_indentation(15) red .to_python() ------------ .. WARNING:: Since RedBaron calls ast.literal_eval it can only parse the python code parsed by the python version you are using. For example if you are using a python version inferior to 3.6, `to_python` will crash on `100_000` because it is only supported since python 3.6 This method safely evaluate the current selected nodes. It wraps `ast.literal_eval `_, therefor, and for security reasons, it only works on a subset of python: numbers, strings, lists, dicts, tuples, boolean and :file:`None`. Of course, using this method on a list/dict/tuple containing values that aren't listed here will raise a :file:`ValueError`. .. ipython:: python RedBaron("42")[0].value # string RedBaron("42")[0].to_python() # python int RedBaron("'a' 'b'")[0].dumps() RedBaron("'a' 'b'")[0].to_python() RedBaron("u'unicode string'")[0].to_python() RedBaron("[1, 2, 3]")[0].to_python() RedBaron("(1, 2, 3)")[0].to_python() RedBaron("{'foo': 'bar'}")[0].to_python() RedBaron("False")[0].to_python() RedBaron("True")[0].to_python() print(RedBaron("None")[0].to_python()) .path() ------- Every node has a :file:`path()` method that will return a :file:`Path` object to it. Every path object has a :file:`.node` attribute that point to the node and a :file:`.to_baron_path` that returns a `Baron Path namedtuple `_. .. ipython:: python red = RedBaron("while a:\n pass") red.pass_ path = red.pass_.path() path path.node path.to_baron_path() Path class ---------- RedBaron provides a Path class that represent a path to a node. .. autoclass:: redbaron.Path .map .filter .apply ------------------- RedBaron nodes list have 3 helper methods :file:`.map`, :file:`.filter` and :file:`.apply` quite similar to python builtins (except for apply). The main difference is that they return a node list instance instead of a python buildin list. * :file:`.map` takes a callable (like a lambda or a function) that receive a node as first argument, this callable is applied on every node of the node list and a node list containing the return of those applies will be returned. * :file:`.filter` works like :file:`.map` but instead of returning a node list of the return of the callable, it returns a node list that contains the nodes for which the callable returned :file:`True` (or something considered :file:`True` in python) * :file:`.apply` works like :file:`.map` but instead of returning the result of the callable, it returns to original node. .. ipython:: python red = RedBaron("[1, 2, 3]") red('int') red('int').map(lambda x: x.to_python() + 1) red('int').filter(lambda x: x.to_python() % 2 == 0) .. ipython:: python red = RedBaron("a()\nb()\nc(x=y)") red('call') # FIXME # red('call').map(lambda x: x.append_value("answer=42")) red('call') red = RedBaron("a()\nb()\nc(x=y)") # FIXME # red('call').apply(lambda x: x.append_value("answer=42")) .replace() ---------- :file:`.replace()` is a method that allow to replace **in place** a node by another one. Like every operation of this nature, you can pass a string, a dict, a list of length one or a node instance. .. ipython:: python red = RedBaron("a()\nb()\nc(x=y)") red[2].replace("1 + 2") red red[-1].replace("plop") red .edit() ------- Helper method that allow to edit the code of the current **node** into an editor. The result is parsed and replace the code of the current node. .. ipython:: python red = RedBaron("def a(): return 42") # should be used like this: (I can't execute this code here, obviously) # red.return_.edit() By default, the editor is taken from the variable :file:`EDITOR` in the environment variables. If this variable is not present, nano is used. You can use a different editor this way: :file:`node.edit(editor="vim")`. .absolute_bounding_box ---------------------- The absolute bounding box of a node represents its top-left and bottom-right position relative to the fst's root node. The position is given as a tuple :file:`(line, column)` with **both starting at 1**. .. ipython:: python red = RedBaron("def a(): return 42") red.funcdef.value.absolute_bounding_box You can also get the bounding box of "string" nodes like the left parenthesis in the example above by giving the attribute's name to the :file:`get_absolute_bounding_box_of_attribute()` method: .. ipython:: python red.funcdef.get_absolute_bounding_box_of_attribute('(') This is impossible to do without giving the attribute's name as an argument since the left parenthesis is not a redbaron Node. .bounding_box ------------- Every node has the :file:`bounding_box` property which holds the top-left and bottom-right position of the node. Compared to the :file:`absolute_bounding_box` property, it assumes the node is the root node so the top-left position is always :file:`(1, 1)`. .. ipython:: python red = RedBaron("def a(): return 42") red.funcdef.value.absolute_bounding_box red.funcdef.value.bounding_box .find_by_position() ------------------- You can find which node is located at a given line and column: .. ipython:: python red = RedBaron("def a(): return 42") red.find_by_position((1, 5)) red.find_by_position((1, 6)) # '(' is not a redbaron node .at() ------------------- Returns first node at specific line .. ipython:: python red = RedBaron("def a():\n return 42") red.at(1) # Gives DefNode red.at(2) # Gives ReturnNode .. _Node.from_fst: Node.from_fst() --------------- :file:`Node.from_fst()` is a helper class method that takes an FST node and return a RedBaron node instance. Except if you need to go down at a low level or that RedBaron doesn't provide the helper you need, you shouldn't use it. .. ipython:: python from redbaron import Node Node.from_fst({"type": "name", "value": "a"}) :file:`Node.from_fst()` takes 2 optional keywords arguments: :file:`parent` and :file:`on_attribute` that should respectively be RedBaron node instance (the parent node) and a string (the attribute of the parent node on which this node is stored). See :ref:`parent` doc for a better understanding of those 2 parameters. .. ipython:: python red = RedBaron("[1,]") new_name = Node.from_fst({"type": "name", "value": "a"}, parent=red[0], on_attribute="value") red[0].value.append(new_name) NodeList.from_fst() ------------------- Similarly to :file:`Node.from_fst()`, :file:`NodeList.from_fst()` is a helper class method that takes an FST node **list** and return a RedBaron node **list** instance. Similarly, you probably don't need to go so low level. .. ipython:: python from redbaron import NodeList NodeList.from_fst([{"type": "name", "value": "a"}, {'first_formatting': [], 'type': 'comma', 'second_formatting': [{'type': 'space', 'value': ' '}]}, {"type": "name", "value": "b"}]) .insert_before .insert_after ---------------------------- One thing you often wants to do is to insert things just after or before the node you've just got via query. Those helpers are here for that: .. ipython:: python red = RedBaron("foo = 42\nprint('bar')\n") red red.print_.insert_before("baz") red red.print_.insert_after("foobar") red Additionally, you can give an optional argument :file:`offset` to insert more than one line after or before: .. ipython:: python red = RedBaron("foo = 42\nprint('bar')\n") red red.print_.insert_before("baz", offset=1) red red[0].insert_after("foobar", offset=1) red redbaron-0.9.2/docs/proxy_list.rst000066400000000000000000000174611344351435400172330ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron Proxy List ========== Problem ------- For a python developer, the list :file:`[1, 2, 3]` has 3 members, which is true in the python world, but in the "source code modification" world, this list has 5 elements because you have to count the 2 commas. Indeed each comma needs to be taken into account separately because they can have a different formatting. This makes things quite annoying to deal with because you have to think about the formatting too! For example, if you want to append an item to a list, you need to take care of a lot of details: * if the list is empty you don't have to put a comma * otherwise yes * but wait, what happens if there is a trailing comma? * also, what to do if the list is declared in an indented way (with :file:`"\\n "` after every comma for example)? * etc... And that's only for a comma separated list of things: you also have the same formatting details to care about for dot separated lists (e.g. :file:`a.b.c().d[plop]`) and endl separated lists (a python code block, or you whole source file). You don't want to have to deal with this. Solution -------- To avoid you to deal with all this boring low level details, RedBaron implements "proxy lists". This abstraction gives you the impression that the list of things you are dealing with behave the same way than in the python world while taking care of all the low level formatting details. The "proxy lists" has the same API than a python list so they should be really intuitive to use. For example: .. ipython:: python red = RedBaron("[1, 2, 3]") red[0].value.append("42") red del red[0].value[2] red There are, for now, 4 kind of proxy lists: * :file:`CommaProxyList` which handles comma separated lists * :file:`DotProxyList` which handles :file:`atomtrailers` (those kind of constructions: :file:`a.b[plop].c()`) * :file:`LineProxyList` which handles lines of code (like the body of a function or the whole source code) * :file:`DecoratorLineProxyList` which handles lists of decorators (they are nearly the same as :file:`LineProxyList`) **Be aware that the proxy list are set on the attribute that is a list, not on the node holding the list. See the 'value' attribute access in the examples below.** Usage ----- As said, proxy lists have the exact same API than python lists (at the exception that they don't implement the :file:`sort` and :file:`reverse` methods). Every method accepts as input the same inputs that you can use to modify a node in RedBaron. This means that you can pass a string containing source code, an FST or a RedBaron node. Here is a session demonstrating every method of a proxy list: .. ipython:: python red = RedBaron("[1, 2, 3]") Please refer to `python list documentation `_ if you want to know the exact behavior or those methods (or `send a patch `_ to improve this documentation). append ~~~~~~ .. ipython:: python red red[0].value.append("plop") red red[0].value insert ~~~~~~ .. ipython:: python red red[0].value.insert(1, "42") red red[0].value extend ~~~~~~ .. ipython:: python red red[0].value.extend(["pif", "paf", "pouf"]) red red[0].value pop ~~~ .. ipython:: python red red[0].value.pop() red red[0].value red[0].value.pop(3) red red[0].value __getitem__ ~~~~~~~~~~~ .. ipython:: python red red[0].value red[0].value[2] __setitem__ ~~~~~~~~~~~ .. ipython:: python red red[0].value[2] = "1 + 1" red red[0].value remove ~~~~~~ .. ipython:: python red red[0].value.remove(red[0].value[2]) red red[0].value index ~~~~~ .. ipython:: python red red[0].value red[0].value.index(red[0].value[2]) count ~~~~~ .. ipython:: python red red[0].value red[0].value.count(red[0].value[2]) len ~~~ .. ipython:: python red red[0].value len(red[0].value) __delitem__ ~~~~~~~~~~~ .. ipython:: python red del red[0].value[2] red red[0].value in ~~ .. ipython:: python red red[0].value[2] in red[0].value __iter__ ~~~~~~~~ .. ipython:: python red for i in red[0].value: print(i.dumps()) __getslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value red[0].value[2:4] __setslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value[2:4] = ["1 + 1", "a", "b", "c"] red red[0].value __delslice__ ~~~~~~~~~~~~ .. ipython:: python red red[0].value[2:5] del red[0].value[2:5] red red[0].value Access the unproxified node list -------------------------------- The unproxified node list is stored under the attribute :file:`node_list` of the proxy list. **Be aware that, for now, the proxy won't detect if you directly modify the unproxified node list, this will cause bugs if you modify the unproxified list then use the proxy list directly**. So, for now, only use one or the other. .. ipython:: python red = RedBaron("[1, 2, 3]") red[0].value.node_list red[0].value Omitting ".value" ----------------- For convenience, and because this is a super common typo error, if a node has a proxy list on its :file:`.value` attribute, you can omit to access it and the method access will be automatically redirect to it. This means that the 2 next lines are equivalent: .. ipython:: python red[0] red[0].value.append("plop") red[0].append("plop") CommaProxyList -------------- CommaProxyList is the most generic and most obvious proxy list, all the examples above are made using it. It is used everywhere where values are separated by commas. DotProxyList ------------ DotProxyList is nearly as generic as the CommaProxyList. The specific case of a DotProxyList is that it is intelligent enough to not add a "." before a "call" (:file:`(a, b=c, *d, **e)`) or a "getitem" (:file:`[foobar]`). .. ipython:: python red = RedBaron("a.b(c).d[e]") red[0].value red[0].extend(["[stuff]", "f", "(g, h)"]) red[0] red[0].value It is used everywhere where values are separated by ".". You can see a complete example with a DotProxyList, like for the CommaProxyList, here: :doc:`dotproxylist`. LineProxyList ------------- LineProxyList is used to handle lines of code, it takes care to place the correct endl node between and to set the correct indentation and not to break the indentation of the next block (if there is one). One particularity of LineProxyList is that it shows you explicitly the empty line (while other proxy lists never show you formatting). This is done because you'll often want to be able to manage those blank lines because you want to put some space in your code or separate group of lines. .. ipython:: python red = RedBaron("while 42:\n stuff\n other_stuff\n\n there_is_an_empty_line_before_me") red red[0].value red[0].append("plouf") red red[0].value You can see a complete example with a LineProxyList, like for the CommaProxyList, here: :doc:`lineproxylist`. DecoratorLineProxyList ---------------------- A DecoratorLineProxyList is exactly the same as a LineProxyList except it has a small modification to indent decorators correctly. Just think of it as a simple LineProxyList and everything will be fine. *Don't forget to add the :file:`@` when you add a new decorator (omitting it will raise an exception)*. Example: .. ipython:: python red = RedBaron("@plop\ndef stuff():\n pass\n") red red[0].decorators.append("@plouf") red[0].decorators red Next ~~~~ To learn about various helpers and features in RedBaron, read :doc:`other`. Be sure to check the :file:`.replace()` method on that page as it can be very useful. redbaron-0.9.2/docs/querying.rst000066400000000000000000000140751344351435400166600ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron Querying ======== As you have seen in the previous section, you can navigate into RedBaron tree only using attribute access and index access on list of nodes with the use of the :file:`.help()` method to know what you can do. However, RedBaron offers way more powerful and convenient tools to do that. .find() ------- To retrieve a single node, you can use the :file:`.find()` method by passing it one of the identifiers listed in :file:`.help()` of node you want to get, this way: .. ipython:: python red = RedBaron("a = 1") red.help() red.find('NameNode').help() red.find('namenode').help() # identifiers are not case sensitive red.find('name') This will recursively travel the tree and return the first node of that type. You can also specify attributes of the node that you want to match: .. ipython:: In [36]: red = RedBaron("a = b") In [37]: red.find('name').help() In [38]: red.find('name', value='b').help() If you don't want a recursive approach but only on the first level on the current node or node list, you can pass :file:`recursive=False` to :file:`.find()`. Like BeautifulSoup, RedBaron provides a shorthand to :file:`.find()`, you can write the name of the target as an attribute of the node and this will do a :file:`.find()` in the same fashion: .. ipython:: In [39]: red = RedBaron("a = b") In [40]: red.find('name') In [41]: red.name You might have noticed that some identifiers end with a :file:`_`, those are for the case where the identifier might be a Python reserved keyword like :file:`if`, or :file:`while` for example. Be aware that if you do a :file:`red.something_that_can_be_a_node_identifier` and this is also not an attribute of a node, this will raise an :file:`AttributeError`. .find_all() ----------- :file:`.find_all()` is extremely similar to :file:`.find()` except it returns a node list containing all the matching queries instead of a single one. Like in BeautifulSoup, :file:`__call__` is aliased to :file:`find_all` (meaning that if you try to *call* the node this way :file:`node(some_arguments)` this will call :file:`.find_all()` with the arguments). .. ipython:: In [45]: red = RedBaron("a = b") In [46]: red.find_all("NameNode") In [47]: red.find_all("name") In [48]: red.findAll("name") In [49]: red.findAll("name", value="b") In [50]: red("name", value="b") :file:`.find_all()` also supports the option :file:`recursive=False`. Advanced querying ----------------- :file:`.find()` and :file:`.find_all()` offer more powerful comparison mean than just equality comparison. Callable (lambda) ~~~~~~~~~~~~~~~~~ Instead of passing a string to test properties of the identifier of a node, you can pass a callable, like a lambda. It will receive the value as first argument: .. ipython:: python red = RedBaron("a = [1, 2, 3, 4]") red.find("int", value=lambda value: int(value) % 2 == 0) red.find_all("int", value=lambda value: int(value) % 2 == 0) red.find(lambda identifier: identifier == "comma") red.find_all(lambda identifier: identifier == "comma") Regex ~~~~~ Instead of passing a string to test properties of a node, you can pass a compiled regex: .. ipython:: python import re red = RedBaron("abcd = plop + pouf") red.find("name", value=re.compile("^p")) red.find_all("name", value=re.compile("^p")) red.find(re.compile("^n")) red.find_all(re.compile("^n")) Having to compile regex is boring, so you can use this shorthand syntax instead (prefixing a string with "re:"): .. ipython:: python red = RedBaron("abcd = plop + pouf") red.find("name", value="re:^p") red.find_all("name", value="re:^p") red.find("re:^n") red.find_all("re:^n") Globs ~~~~~ Same than in a shell, you can use globs by prefixing the string with "g:": .. ipython:: python red = RedBaron("abcd = plop + pouf") red.find("name", value="g:p*") red.find_all("name", value="g:p*") red.find("g:n*") red.find_all("g:n*") In the background, the comparison is done using the `fnmatch `_ module of the standard lib. List or tuple ~~~~~~~~~~~~~ You can pass a list as a shorthand to test if the tested attribute is in any of the member of the list/tuple: .. ipython:: python red = RedBaron("foo\nbar\nbaz") red.find("name", value=["foo", "baz"]) red.find("name", value=("foo", "baz")) red("name", value=["foo", "baz"]) red("name", value=("foo", "baz")) .. ipython:: python red = RedBaron("1\nstuff\n'string'\n") red.find(["int", "string"]) red(["int", "string"]) \*args and default value ~~~~~~~~~~~~~~~~~~~~~~~~ You can also pass as many callable as args (without giving it a key) as you want, those callables will receive the node itself as first argument (and must return a value that will be tested as a boolable): .. ipython:: python red = RedBaron("a = [1, 2, 3, 4]") red.find("int", lambda node: int(node.value) % 2 == 0) red.find_all("int", lambda node: int(node.value) % 2 == 0) red.find("int", lambda node: int(node.value) % 2 == 0, lambda node: int(node.value) == 4) To ease the usage of RedBaron in ipython (and in general), you can pass any of the previous testing methods (**except the lambda**) as the **first** argument of \*args, it will be tested against the default testing attribute which is the "value" attribute by default. This mean that: :file:`red.find("name", "foo")` is the equivalent of :file:`red.find("name", value="foo")`. If the default tested attribute is different, it will be shown in :file:`.help()`. For now, the 2 only cases where this happens is on class node and funcdef node where the attribute is "name". .. ipython:: python red = RedBaron("foo\ndef bar(): pass\nbaz\ndef badger(): pass") red.find("name", "baz") red.find("def", "bar") red.find("def").help() Next ~~~~ To learn how to modify stuff in RedBaron read :doc:`modifying`. redbaron-0.9.2/docs/tuto.rst000066400000000000000000000346411344351435400160110ustar00rootroot00000000000000.. ipython:: python :suppress: import sys sys.path.append("..") import redbaron redbaron.ipython_behavior = False from redbaron import RedBaron Learn how to use RedBaron ========================= This tutorial guides you through the big principles of RedBaron and highlights the most useful helpers and tricks. It is more or less a lighter version of the already existing documentation. A reminder before starting: * **RedBaron doesn't do static analysis** and will never do (but it's very likely that it will be combined with tools that do it, like astroid or rope, to bring static analysis into RedBaron or easy source code modification in the others) The structure of this tutorial is similar to the documentation's: * basic principles and how to use it in a shell * how to query the tree * how to modify the tree * how to play with list of things * miscellaneous but useful stuff Basic principles ---------------- Input and output with the source code in a string: .. code-block:: python from redbaron import RedBaron red = RedBaron("code source as a string") red.dumps() Input and output with the source code in a file: .. code-block:: python from redbaron import RedBaron with open("code.py", "r") as source_code: red = RedBaron(source_code.read()) with open("code.py", "w") as source_code: source_code.write(red.dumps()) Now that you know how to load your code into RedBaron, let's talk about its principles: * RedBaron represents the source code as a tree. This is because when you are writing source code (of any classical language), you are actually writing a tree structure in the source file. * For example: in :file:`1 + 2` the top node is :file:`+`, the left one is :file:`1` and the right one is :file:`2`. * In :file:`(1 + 2) + 3` the top node is, again, :file:`+`, but the left one is actually :file:`(1 + 2)` which is again another :file:`+` node! This structure *is* a tree. * The classical approach to handle such a structure is to use an `Abstract Syntax Tree (AST) `_ (it is used by compilers and interpreters like cpython). * RedBaron, by relying on `Baron `_, uses a *Full* Syntax Tree (FST). It's like an AST except it keeps every information, included formatting, and is then a lossless representation of the source code. Under the hood, the FST produced by Baron is in JSON and has been thought to be read and used by humans (although not as easily as RedBaron). * So, when BeautifulSoup wraps the HTML datastructure into objects, RedBaron does the same thing for the FST datastructure and provides a nice way to interact with the source code. Example of an AST for some language that looks like Go: .. image:: ast.png While you don't have to do that to use RedBaron on a daily basis, seeing the produced FST can help your understand RedBaron better (every key that has "_formatting" in its name is formatting related): .. ipython:: python import json red = RedBaron("1+2") print(json.dumps(red.fst(), indent=4)) # json.dumps is used for pretty printing Use it in a shell ----------------- Now that we stated the concept of the source code as a tree, let's explore it. First, like BeautifulSoup, when used in a shell RedBaron displays the currently selected source code, so you'll have a direct idea of what you are working on: .. ipython:: python red = RedBaron("stuff = 1 + 2\nprint 'Beautiful result:', stuff ") red You might notice the :file:`0` and the :file:`1` on the left: those are the indexes of the 2 nodes in the root of the source code. In fact, a source code is a list of statements so the root node :file:`red` is a list. See by yourself: .. ipython:: python red[0] red[1] But now, how to access the attributes? Since reading the doc for every node is boring, RedBaron comes with a helper method that shows you the underlying structure of the currently selected nodes: .. ipython:: python red[0] red[0].help() The output might be a bit scary at first, but it's simply showing you the underlying structure, mapped to Baron JSON's one. *By the way, RedBaron has nice coloration features if you use ipython as your python shell.* Let's take it step by step: * We are on an :file:`AssignmentNode` (something like :file:`a = b`) that has 3 attributes: :file:`operator`, :file:`target` and :file:`value`. * The :file:`operator` is an empty string (it could have been a python operator like :file:`+` in a case like :file:`a += b`) * :file:`target` points to another node, a :file:`NameNode` (you can see this thanks to the arrow :file:`->` instead of an equal sign :file:`=`) * :file:`value` points to a :file:`BinaryOperatorNode`. To get more information about all the existing kind of nodes, see the documentation: :doc:`nodes_reference`. Let's try it: .. ipython:: python red[0] red[0].operator red[0].target red[0].value For now we saw attributes that are either strings or pointing to other nodes, respectively called leafs and branches in the tree terminology. The last kind of attributes that you will encounter are a special case of the branch nodes: instead of pointing to a single node, they point to a list of nodes. You can see this in the print statement's :file:`value` attribute: .. ipython:: python red[1].help() Notice the :file:`*` before :file:`StringNode` and :file:`NameNode`? It indicates that they are items of a list. Look: .. ipython:: python red[1] red[1].value red[1].value[0] red[1].value[1] And if we show the help of the value attribute, we clearly see that there is a list of nodes. .. ipython:: python red[1].value.help() This is similar for the root node, which is itself also a list of nodes: .. ipython:: python red.help() And *voilà*, you now know how to navigate the tree by attributes without having to read any documentation! If you're curious about the :file:`identifiers` outputted by the :file:`.help()` method, read on to the next section. And one last thing: by default :file:`.help()` stops at a certain "deepness level" and displays :file:`...` instead of going further. To avoid that, simply pass an integer that indicates the "deepness level" you want, or give :file:`True` if you want to display the whole tree. :: red.help(4) red.help(True) You can read the whole documentation of :file:`.help` here: :ref:`help()` Querying -------- Querying is inspired by BeautifulSoup. You have access to 2 methods: :file:`.find` and :file:`.find_all`, accepting the same arguments. The first one returns the first matched node and the second one returns the list of all the matched nodes. The first argument is a string that represent the kind of the node you want to match on. The :file:`identifiers` section displayed by the :file:`.help()` method shows you several strings you can use to identify a kind of node. For example: .. ipython:: python red red.help() red.find("assignment") red.find("print") red.find_all("int") Then, you can pass as many keyword arguments as you want. They will filter the returned list on the attributes of the node and keep only those matching all attributes: .. ipython:: python red.find("int", value=2) The only special argument you can pass is :file:`recursive` that determine if the query is done recursively. By default it is set at :file:`True`, just pass :file:`recursive=False` to :file:`.find` or :file:`.find_all` to avoid that. Queries are very powerful: you can pass lambdas, regexes, a short hand syntax for regexes and globs, a tuple of string instead of a string for the node kind, a global regex that receives the node (instead of a regex per attribute), etc. You can read all of that in the documentation: :doc:`querying`. Finally, :file:`.find` and :file:`.find_all` also have a shortcut syntax (exactly like in BeautifulSoup): .. ipython:: python red.find("int") red.int red.find_all("int", value=2) red("int", value=2) But be aware that if you do a :file:`red.something_that_can_be_a_node_identifier` and this is also not an attribute of a node, this will raise an :file:`AttributeError`. Modification ------------ Nodes modification is extremely simple in RedBaron: you just have to set the attribute of the node you want to modify with a string containing python source code. Just look by yourself: .. ipython:: python red red[0].target = "something_else" red[0].value = "42 * 34" red red[1].value = "'Hello World!'" red Notice that this also works with complex attributes like the body of a function. Here RedBaron makes a lot of effort to correctly format your input so you can pass it pretty much anything: .. ipython:: python red = RedBaron("def a():\n pass") red[0].value = "1 + 1" red # correctly indented red[0].value = "\n\n\n stuff\n" red # again And this works too for more complex situations where the node is indented and followed by another node whose indentation can't be broken and other low level details that you don't want to hear about (but if you wish too, this is detailed in the full documentation). And *voilà*, easy source code modification! You can also pass RedBaron node objects or Baron JSON FST that you have obtain is some way or another, for example by using :file:`.copy()`: .. ipython:: python red = RedBaron("stuff = 1 + 2\nprint(stuff)") red i = red[0].value.copy() red[1].value = i red You can also replace a node *in place* using the :file:`.replace()` method. **Warning**: the :file:`.replace()` expects that the string you pass represents a whole valid python program (so for example: :file:`.replace("*args, **kwargs")` won't work). This limitation should be raised in the future. .. ipython:: python red red[0].value.replace("1234") red This is generally very useful when working on queries. For example (a real life example), here is the code to replace every :file:`print stuff` (prints statement of **one** argument, an example with multiple arguments is left as an exercise to the reader) with :file:`logger.debug(stuff)`: :: red("print", value=lambda x: len(x) == 1).map(lambda x: x.replace("logger.debug(%s)" % x.value.dumps())) (:file:`.map()` will be covered at the end of the tutorial but should speak for itself.) You can read everything about modifications in RedBaron here: :doc:`modifying` Playing with list of nodes -------------------------- The last big concept of RedBaron covered in this tutorial is how to handle list of nodes. The problem for short is that, for a python developer, the list :file:`[1, 2, 3]` has 3 items but it has 5 items in the FST world, because it needs to take into account the commas. It is not sufficient to know that it is a comma separated list because each comma can have a different formatting. This is a pattern you find in every list of nodes, the separator being either commas, dots (eg: :file:`a.b(c)[d]`) or end of line characters (for lines of code). Having to deal with those separators is extremely annoying and error prone, so, RedBaron offers an abstraction that hides all this for you! You just have to deal with those list of nodes like if they were regular python list and everything will be fine. See by yourself: .. ipython:: python red = RedBaron("[1, 2, 3]") red.help() red[0].value # see: no explicit commas to deal with red[0].value.append("4") red # comma has been added for us This abstraction is called a proxy list. They can even detect indentation style for comma separated lists: .. ipython:: python red = RedBaron("[\n 1,\n 2,\n 3,\n]") red red[0].value.append("caramba") red This also work with nodes separated by dots: .. ipython:: python red = RedBaron("a.b(c)[d]") red red[0].value.extend(["e", "(f)", "[g:h]"]) red And lines of code (note that the blank lines are explicitly shown and it is intended as such, see the documentation for more information: :doc:`proxy_list`): .. ipython:: python red = RedBaron("a = 1\n\nprint(a)") red red.insert(1, "if a:\n print('a == 1')") red The important things to remember are that: * Every method and protocol of python lists (except :file:`sort` and :file:`reversed`) works on proxy list. * And every node list in python is wrapped by a proxy list. The raw list is stored on the :file:`.node_list` attribute of the proxy list: .. ipython:: python red = RedBaron("[1, 2, 3]") red[0].node_list **Warning**: the proxyfied list and the proxy list are only synced from the proxy list to the raw list. If you start to modify the raw list, don't use the proxy list anymore or you'll have strange bugs! This might change in the future. One last thing: if the proxy list is stored on the :file:`.value` attribute, you can directly call the methods on the holder node. This is done because it is more intuitive, see by yourself: :: red = RedBaron("[1, 2, 3]") red[0].append("4") # is exactly the same than the next line red[0].value.append("4") Misc things ----------- A short list of useful features of RedBaron: * :file:`.map`, a method of RedBaron lists that takes a callable (like a lambda or a function), apply it to every one of its members and returns a RedBaron list containing the result of the call * :file:`.apply` same than :file:`.map` except it returns a RedBaron list of the nodes on which the callable has been applied (i.e. the members before the call instead of the members after the call) (for simplicity we uses the :file:`int` builtin function here, you might want to look at :file:`to_python` in the future for a more generic conversion operation) .. ipython:: python red = RedBaron("[1, 2, 3]") red("int").map(lambda x: int(x.value) + 42) red("int").apply(lambda x: int(x.value) + 42) * :file:`.filter`, another method of RedBaron list, it takes a callable and return a RedBaron list containing the nodes for which the callable has returned True (or something that is tested has True in python) .. ipython:: python red = RedBaron("[1, 2, 3]") red("int").filter(lambda x: int(x.value) % 2 == 1) # odd numbers * :file:`.next` gives the node just after the current one if the node is in a list * :file:`.previous` does the inverse * :file:`.parent` gives the holder of this node .. ipython:: python red = RedBaron("[1, 2, 3]") red.int_ red.int_.next red.int_.previous # None because nothing is behind it red.int_.parent And you can find all the others various RedBaron features here: :doc:`other` redbaron-0.9.2/docs/why.rst000066400000000000000000000044141344351435400156200ustar00rootroot00000000000000Why is this important? ====================== The usage of an FST might not be obvious at first sight so let's consider a series of problems to illustrate it. Let's say that you want to write a program that will: * rename a variable in a source file... without clashing with things that are not a variable (example: stuff inside a string) * inline a function/method * extract a function/method from a series of line of code * split a class into several classes * split a file into several modules * convert your whole code base from one ORM to another * do custom refactoring operation not implemented by IDE/rope * implement the class browser of smalltalk for python (the whole one where you can edit the code of the methods, not just showing code) It is very likely that you will end up with the awkward feeling of writing clumsy weak code that is very likely to break because you didn't thought about all the annoying special cases and the formatting keeps bothering you. You may end up playing with `ast.py `_ until you realize that it removes too much information to be suitable for those situations. You will probably ditch this task as simple too complicated and really not worth the effort. You are missing a good abstraction that will take care of all of the code structure and formatting for you so you can concentrate on your task. The FST tries to be this abstraction. With it you can now work on a tree which represents your code with its formatting. Moreover, since it is the exact representation of your code, modifying it and converting it back to a string will give you back your code only modified where you have modified the tree. Said in another way, what I'm trying to achieve with Baron is a paradigm change in which writing code that will modify code is now a realistic task that is worth the price (I'm not saying a simple task, but a realistic task, it's still a complex task). Other usages ------------ Having an FST (or at least a good abstraction build on it) also makes it easier to do code generation and code analysis while those two operations are already quite feasible (using `ast.py `_ and a templating engine for example). Next ~~~~ To start playing with RedBaron read :doc:`basics`. redbaron-0.9.2/pylintrc000066400000000000000000000210371344351435400151160ustar00rootroot00000000000000# lint Python modules using external checkers. # # This is the main checker controling the other ones and the reports # generation. It is itself both a raw checker and an astng checker in order # to: # * handle message activation / deactivation at the module level # * handle some basic but necessary stats'data (number of classes, methods...) # [MASTER] # Specify a configuration file. #rcfile= # Profiled execution. profile=no # Add to the black list. It should be a base name, not a # path. You may set this option multiple times. ignore=.git # Pickle collected data for later comparisons. persistent=yes # Set the cache size for astng objects. cache-size=500 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins=redbaron_pylint_plugin [MESSAGES CONTROL] # Enable only checker(s) with the given id(s). This option conflict with the # disable-checker option #enable-checker= # Enable all checker(s) except those with the given id(s). This option conflict # with the disable-checker option #disable-checker= # Enable all messages in the listed categories. #enable-msg-cat= # Disable all messages in the listed categories. #disable-msg-cat= # Enable the message(s) with the given id(s). #enable-msg= # Disable the message(s) with the given id(s). disable-msg=C0323,W0142,C0301,C0103,C0111,E0213,C0302,C0203,W0703,R0201 [REPORTS] # set the output format. Available formats are text, parseable, colorized and # html output-format=colorized # Include message's id in output include-ids=yes # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells wether to display a full report or only the messages reports=yes # Python expression which should return a note less than 10 (10 is the highest # note).You have access to the variables errors warning, statement which # respectivly contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (R0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Add a comment according to your evaluation note. This is used by the global # evaluation report (R0004). comment=no # Enable the report(s) with the given id(s). #enable-report= # Disable the report(s) with the given id(s). #disable-report= # checks for # * unused variables / imports # * undefined variables # * redefinition of variable from builtins or from an outer scope # * use of variable before assigment # [VARIABLES] # Tells wether we should check for unused import in __init__ files. init-import=no # A regular expression matching names used for dummy variables (i.e. not used). dummy-variables-rgx=_|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # try to find bugs in the code using type inference # [TYPECHECK] # Tells wether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # When zope mode is activated, consider the acquired-members option to ignore # access to some undefined attributes. zope=no # List of members which are usually get through zope's acquisition mecanism and # so shouldn't trigger E0201 when accessed (need zope=yes to be considered). acquired-members=REQUEST,acl_users,aq_parent # checks for : # * doc strings # * modules / classes / functions / methods / arguments / variables name # * number of arguments, local variables, branchs, returns and statements in # functions, methods # * required module attributes # * dangerous default values as arguments # * redefinition of function / method / class # * uses of the global statement # [BASIC] # Required attributes for module, separated by a comma required-attributes= # Regular expression which should only match functions or classes name which do # not require a docstring no-docstring-rgx=(__.*__|test_[a-z0-9_]*) # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=([a-z_][a-z0-9_]{2,30}|test_[a-z0-9_]*)$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # List of builtins function names that should not be used, separated by a comma bad-functions=apply,input # checks for sign of poor/misdesign: # * number of methods, attributes, local variables... # * size, complexity of functions, methods # [DESIGN] # Maximum number of arguments for function / method max-args=12 # Maximum number of locals for function / method body max-locals=30 # Maximum number of return / yield for function / method body max-returns=12 # Maximum number of branch for function / method body max-branchs=30 # Maximum number of statements in function / method body max-statements=60 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=20 # Minimum number of public methods for a class (see R0903). min-public-methods=0 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # checks for # * external modules dependencies # * relative / wildcard imports # * cyclic imports # * uses of deprecated modules # [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,string,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report R0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report R0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report R0402 must # not be disabled) int-import-graph= # checks for : # * methods without self as first argument # * overridden methods signature # * access only to existant members via self # * attributes not defined in the __init__ method # * supported interfaces implementation # * unreachable code # [CLASSES] # List of interface methods to ignore, separated by a comma. This is used for # instance to not check methods defines in Zope's Interface base class. ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # checks for similarities and duplicated code. This computation may be # memory / CPU intensive, so you should disable it if you experiments some # problems. # [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=10 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # checks for: # * warning notes in the code like FIXME, XXX # * PEP 263: source code with non ascii character but no encoding declaration # [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO # checks for : # * unauthorized constructions # * strict indentation # * line length # * use of <> instead of != # [FORMAT] # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' redbaron-0.9.2/redbaron/000077500000000000000000000000001344351435400151205ustar00rootroot00000000000000redbaron-0.9.2/redbaron/__init__.py000066400000000000000000000007031344351435400172310ustar00rootroot00000000000000from __future__ import absolute_import from redbaron.redbaron import * from redbaron.utils import * from redbaron.base_nodes import * from redbaron.nodes import * from redbaron import nodes DEBUG = False ALL_IDENTIFIERS = set() ipython_behavior = True force_ipython_behavior = False for name in list(filter(lambda x: x.endswith("Node"), dir(nodes))): list(map(ALL_IDENTIFIERS.add, filter(None, getattr(nodes, name).generate_identifiers()))) redbaron-0.9.2/redbaron/base_nodes.py000066400000000000000000002204641344351435400176040ustar00rootroot00000000000000from __future__ import absolute_import import re import os import sys import ast import inspect import itertools from fnmatch import fnmatch import baron import baron.path from baron.utils import python_version, string_instance from baron.render import nodes_rendering_order import redbaron from redbaron.utils import redbaron_classname_to_baron_type, baron_type_to_redbaron_classname, log, in_a_shell, indent, \ truncate from redbaron.private_config import runned_from_ipython from redbaron.syntax_highlight import help_highlight, python_highlight, python_html_highlight if python_version == 3: from collections import UserList else: from UserList import UserList # python 3.7 compatibility RE_PATTERN_FIELD = re.Pattern if hasattr(re, "Pattern") else re._pattern_type def display_property_atttributeerror_exceptions(function): def wrapper(*args, **kwargs): try: return function(*args, **kwargs) except AttributeError: import traceback traceback.print_exc() raise return wrapper class Path(object): """Holds the path to a FST node Path(node): path coming from the node's root Path.from_baron_path(node, path): path going down the node following the given path Note that the second argument "path" is a baron path, i.e. list of keys that can be given for example by redbaron.Path(node).to_baron_path() The second form is useful when converting a path given by baron to a redbaron node """ def __init__(self, node): self.node = node parent = node path = [] while parent is not None: key = Path.get_holder_on_attribute(parent) if key is not None: path.insert(0, key) parent = Path.get_holder(parent) self.path = path @classmethod def from_baron_path(class_, node, path): if path is None: return class_(node) for key in path: if isinstance(key, string_instance): child = getattr(node, key, None) else: if isinstance(node, ProxyList): node = node.node_list if key >= len(node): return None child = node[key] if child is not None and isinstance(child, (Node, NodeList, ProxyList)): node = child if isinstance(node, ProxyList): node = node.node_list return class_(node) def to_baron_path(self): return self.path def __str__(self): return 'Path(%s @ %s)' % ( self.node.__class__.__name__ + ('(' + self.node.type + ')' if isinstance(self.node, Node) else ''), str(self.path)) def __repr__(self): return '<' + self.__str__() + ' object at ' + str(id(self)) + '>' def __eq__(self, other): if isinstance(other, Path): return self.to_baron_path() == other.to_baron_path() elif isinstance(other, list): return self.to_baron_path() == other else: return False @classmethod def get_holder(class_, node): if node.on_attribute is not None and isinstance(node.parent, Node): possible_parent = getattr(node.parent, node.on_attribute) if isinstance(possible_parent, ProxyList): if possible_parent.node_list is not node: return possible_parent.node_list else: if possible_parent is not node: return possible_parent return node.parent @classmethod def get_holder_on_attribute(class_, node): parent = Path.get_holder(node) if parent is None: return None if isinstance(parent, redbaron.RedBaron): parent = parent.node_list if isinstance(parent, NodeList): if isinstance(node, ProxyList): item = node.node_list else: item = node pos = parent.index(item) return pos if isinstance(node, NodeList): return next((key for (_, key, _) in parent._render() if getattr(parent, key, None) is node or getattr(getattr(parent, key, None), "node_list", None) is node), None) to_return = next((key for (_, key, _) in parent._render() if key == node.on_attribute), None) return to_return class LiteralyEvaluable(object): def to_python(self): try: return ast.literal_eval(self.dumps().strip()) except ValueError as e: message = 'to_python method only works on numbers, strings, list, tuple, dict, boolean and None. (using ast.literal_eval). The piece of code that you are trying to convert contains an illegale value, for example, a variable.' e.message = message e.args = (message,) raise e class GenericNodesUtils(object): """ Mixen top class for Node and NodeList that contains generic methods that are used by both. """ def _convert_input_to_node_object(self, value, parent, on_attribute, generic=False): if isinstance(value, string_instance): if generic: return Node.from_fst(baron.parse(value)[0], parent=parent, on_attribute=on_attribute) else: return self._string_to_node(value, parent=parent, on_attribute=on_attribute) elif isinstance(value, dict): return Node.from_fst(value, parent=parent, on_attribute=on_attribute) elif isinstance(value, Node): value.parent = parent value.on_attribute = on_attribute return value raise NotImplementedError def _string_to_node(self, string, parent, on_attribute): return Node.from_fst(baron.parse(string)[0], parent=parent, on_attribute=on_attribute) def _convert_input_to_node_object_list(self, value, parent, on_attribute): if isinstance(value, string_instance): return self._string_to_node_list(value, parent=parent, on_attribute=on_attribute) if isinstance(value, dict): # assuming that we got some fst # also assuming the user do strange things return NodeList([Node.from_fst(value, parent=parent, on_attribute=on_attribute)]) if isinstance(value, Node): value.parent = parent value.on_attribute = on_attribute return NodeList([value]) if isinstance(value, (NodeList, ProxyList)): for i in value: i.parent = parent i.on_attribute = on_attribute return value if isinstance(value, list): # assume the user can pass a list of random stuff new_value = NodeList() for i in value: new_value.append(self._convert_input_to_node_object(i, parent, on_attribute)) return new_value if isinstance(value, ProxyList): return value raise NotImplementedError @property @display_property_atttributeerror_exceptions def bounding_box(self): return baron.path.node_to_bounding_box(self.fst()) @property @display_property_atttributeerror_exceptions def absolute_bounding_box(self): path = self.path().to_baron_path() return baron.path.path_to_bounding_box(self.root.fst(), path) def find_by_position(self, position): path = Path.from_baron_path(self, baron.path.position_to_path(self.fst(), position)) return path.node if path else None def at(self, line_no): if not 0 <= line_no <= self.absolute_bounding_box.bottom_right.line: raise IndexError("Line number {0} is outside of the file".format(line_no)) node = self.find_by_position((line_no, 1)) if node.absolute_bounding_box.top_left.line == line_no: if hasattr(node.parent, 'absolute_bounding_box') and \ node.parent.absolute_bounding_box.top_left.line == line_no and \ node.parent.parent is not None: return node.parent return node elif node is not None and hasattr(node, 'next_rendered'): return list(self._iter_in_rendering_order(node.next_rendered))[0] elif node.parent is None: node = node.data[0][0] while True: if node.absolute_bounding_box.top_left.line == line_no: return node node = node.next_rendered return node def _string_to_node_list(self, string, parent, on_attribute): return NodeList.from_fst(baron.parse(string), parent=parent, on_attribute=on_attribute) def parse_decorators(self, string, parent, on_attribute): indentation = self.indentation # XXX # This regex is bad because it could generate a bug in a very # rare case when a '@' with space before is inside an argument # of a decorator. This has extremly low chance to happen but # will probably drive crazy someone one day. This is a bad. # The way to solve this is not very simple. I think that the # 'perfect' solution would be use the tokenizer and to have # a mini parser that detect if the '@' is effectivly preceeded # by a space and remove it (the parser have to handle situation where # it is inside a call and outside to detect the good '@' since @ will # probably be a new operator in python in the futur) string = re.sub(" *@", "@", string) fst = baron.parse("%s\ndef a(): pass" % string.strip())[0]["decorators"] fst[-1]["indent"] = indentation result = NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) if indentation: # with re.sub they don't have indentation for i in filter(lambda x: x.type == "endl", result[1:-1]): i.indent = indentation return result @property @display_property_atttributeerror_exceptions def root(self): current = self while not isinstance(current, redbaron.RedBaron): current = current.parent return current def _iter_in_rendering_order(self, node): if not isinstance(node, (Node, NodeList)): return if not (isinstance(node, Node) and node.type == "endl"): yield node for kind, key, display in node._render(): if isinstance(display, string_instance) and not getattr(node, display): continue if kind == "constant": yield node elif kind == "string": if isinstance(getattr(node, key), string_instance): yield node elif kind == "key": for i in self._iter_in_rendering_order(getattr(node, key)): yield i elif kind in ("list", "formatting"): target = getattr(node, key) if isinstance(target, ProxyList): target = target.node_list for i in target: for j in self._iter_in_rendering_order(i): yield j class NodeList(UserList, GenericNodesUtils): # NodeList doesn't have a previous nor a next # avoid common bug in shell by providing None next = None previous = None def __init__(self, initlist=None, parent=None, on_attribute=None): super(NodeList, self).__init__(initlist) self.parent = parent self.on_attribute = on_attribute @classmethod def from_fst(klass, node_list, parent=None, on_attribute=None): return klass(map(lambda x: Node.from_fst(x, parent=parent, on_attribute=on_attribute), node_list), parent=parent, on_attribute=on_attribute) def find(self, identifier, *args, **kwargs): for i in self.data: candidate = i.find(identifier, *args, **kwargs) if candidate is not None: return candidate def __getattr__(self, key): if key not in redbaron.ALL_IDENTIFIERS: raise AttributeError( "%s instance has no attribute '%s' and '%s' is not a valid identifier of another node" % ( self.__class__.__name__, key, key)) return self.find(key) def __setitem__(self, key, value): self.data[key] = self._convert_input_to_node_object(value, parent=self.parent, on_attribute=self.on_attribute) def find_iter(self, identifier, *args, **kwargs): for node in self.data: for matched_node in node.find_iter(identifier, *args, **kwargs): yield matched_node def find_all(self, identifier, *args, **kwargs): return NodeList(list(self.find_iter(identifier, *args, **kwargs))) findAll = find_all __call__ = find_all def find_by_path(self, path): path = Path.from_baron_path(self, path) return path.node if path else None def path(self): return Path(self) def fst(self): return [x.fst() for x in self.data] def dumps(self): return baron.dumps(self.fst()) def __repr__(self): if in_a_shell(): return self.__str__() return "<%s %s, \"%s\" %s, on %s %s>" % ( self.__class__.__name__, self.path().to_baron_path(), truncate(self.dumps().replace("\n", "\\n"), 20), id(self), self.parent.__class__.__name__, id(self.parent) ) def __str__(self): to_return = "" for number, value in enumerate(self.data): to_return += ("%-3s " % number) + "\n ".join(value.__repr__().split("\n")) to_return += "\n" return to_return def _bytes_repr_html_(self): def __repr_html(self): # string addition is slow (and makes copies) yield b"" yield b"" for num, item in enumerate(self): yield b"" yield b"" yield b"" yield b"" yield b"
Indexnode
" yield str(num).encode("Utf-8") yield b"" yield item._bytes_repr_html_() if hasattr(item, "_repr_html_") else str(item).encode("Utf-8") yield b"
" return b''.join(__repr_html(self)) def _repr_html_(self): return self._bytes_repr_html_().decode("Utf-8") def help(self, deep=2, with_formatting=False): for num, i in enumerate(self.data): sys.stdout.write(str(num) + " -----------------------------------------------------\n") i.help(deep=deep, with_formatting=with_formatting) def __help__(self, deep=2, with_formatting=False): return [x.__help__(deep=deep, with_formatting=with_formatting) for x in self.data] def copy(self): # XXX not very optimised but at least very simple return NodeList(map(Node.from_fst, self.fst())) def next_generator(self): # similary, NodeList will never have next items # trick to return an empty generator # I wonder if I should not raise instead :/ return def previous_generator(self): # similary, NodeList will never have next items # trick to return an empty generator # I wonder if I should not raise instead :/ return def apply(self, function): [function(x) for x in self.data] return self def map(self, function): return NodeList([function(x) for x in self.data]) def filter(self, function): return NodeList([x for x in self.data if function(x)]) def filtered(self): return tuple([x for x in self.data if not isinstance(x, (redbaron.nodes.EndlNode, redbaron.nodes.CommaNode, redbaron.nodes.DotNode))]) def _generate_nodes_in_rendering_order(self): previous = None for i in self: for j in self._iter_in_rendering_order(i): if j is previous: continue previous = j yield j def get_absolute_bounding_box_of_attribute(self, index): if index >= len(self.data) or index < 0: raise IndexError() path = self.path().to_baron_path() + [index] return baron.path.path_to_bounding_box(self.root.fst(), path) def increase_indentation(self, number_of_spaces): previous = None done = set() for i in self.data: for node in i._generate_nodes_in_rendering_order(): if node.type != "endl" and previous is not None and previous.type == "endl" and previous not in done: previous.indent += number_of_spaces * " " done.add(previous) previous = node def decrease_indentation(self, number_of_spaces): previous = None done = set() for i in self.data: for node in i._generate_nodes_in_rendering_order(): if node.type != "endl" and previous is not None and previous.type == "endl" and previous not in done: previous.indent = previous.indent[number_of_spaces:] done.add(previous) previous = node class Node(GenericNodesUtils): _other_identifiers = [] _default_test_value = "value" def __init__(self, fst, parent=None, on_attribute=None): self.init = True self.parent = parent self.on_attribute = on_attribute self._str_keys = ["type"] self._list_keys = [] self._dict_keys = [] self.type = fst["type"] for kind, key, _ in filter(lambda x: x[0] != "constant", self._render()): if kind == "key": if fst[key]: setattr(self, key, Node.from_fst(fst[key], parent=self, on_attribute=key)) else: setattr(self, key, None) self._dict_keys.append(key) elif kind in ("bool", "string"): setattr(self, key, fst[key]) self._str_keys.append(key) elif kind in ("list", "formatting"): setattr(self, key, NodeList.from_fst(fst[key], parent=self, on_attribute=key)) self._list_keys.append(key) else: raise Exception(str((fst["type"], kind, key))) self.init = False @classmethod def from_fst(klass, node, parent=None, on_attribute=None): class_name = baron_type_to_redbaron_classname(node["type"]) return getattr(redbaron.nodes, class_name)(node, parent=parent, on_attribute=on_attribute) @property @display_property_atttributeerror_exceptions def next(self): in_list = self._get_list_attribute_is_member_off() if in_list is None: return None next_node = list(itertools.dropwhile(lambda x: x is not self, in_list))[1:] return next_node[0] if next_node else None @property @display_property_atttributeerror_exceptions def next_intuitive(self): next_ = self.next if next_ and next_.type == "ifelseblock": return next_.if_ return next_ @property @display_property_atttributeerror_exceptions def next_rendered(self): previous = None target = self.parent while target is not None: for i in reversed(list(target._generate_nodes_in_rendering_order())): if i is self and previous is not None: return previous previous = i previous = None target = target.parent @property @display_property_atttributeerror_exceptions def next_recursive(self): target = self while not target.next: if not target.parent: break target = target.parent return target.next def next_generator(self): in_list = self._get_list_attribute_is_member_off() if in_list is None: return None generator = itertools.dropwhile(lambda x: x is not self, in_list) next(generator) return generator @property @display_property_atttributeerror_exceptions def previous(self): in_list = self._get_list_attribute_is_member_off() if in_list is None: return None next_node = list(itertools.dropwhile(lambda x: x is not self, reversed(in_list)))[1:] return next_node[0] if next_node else None @property @display_property_atttributeerror_exceptions def previous_intuitive(self): previous_ = self.previous if previous_ and previous_.type == "ifelseblock": return previous_.value[-1] elif previous_ and previous_.type == "try": if previous_.finally_: return previous_.finally_ if previous_.else_: return previous_.else_ if previous_.excepts: return previous_.excepts[-1] elif previous_ and previous_.type in ("for", "while"): if previous_.else_: return previous_.else_ return previous_ @property @display_property_atttributeerror_exceptions def previous_rendered(self): previous = None target = self.parent while target is not None: for i in target._generate_nodes_in_rendering_order(): if i is self: return previous previous = i target = target.parent @property @display_property_atttributeerror_exceptions def previous_recursive(self): target = self while not target.previous: if not target.parent: break target = target.parent return target.previous def previous_generator(self): in_list = self._get_list_attribute_is_member_off() if in_list is None: return None generator = itertools.dropwhile(lambda x: x is not self, reversed(in_list)) next(generator) return generator def get_indentation_node(self): if self.type == "endl": # by convention, an endl node will always have this indentation return None if self.previous_rendered is None: return None if self.previous_rendered.type == "endl": return self.previous_rendered return self.previous_rendered.get_indentation_node() @property @display_property_atttributeerror_exceptions def indentation(self): endl_node = self.get_indentation_node() return endl_node.indent if endl_node is not None else "" def indentation_node_is_direct(self): if self.previous_rendered and self.previous_rendered.type == "endl": return True return False def _get_list_attribute_is_member_off(self): """ Return the list attribute of the parent from which this node is a member. If this node isn't in a list attribute, return None. """ if self.parent is None: return None if self.on_attribute is "root": in_list = self.parent elif self.on_attribute is not None: if isinstance(self.parent, NodeList): in_list = getattr(self.parent.parent, self.on_attribute) else: in_list = getattr(self.parent, self.on_attribute) else: return None if isinstance(in_list, ProxyList): return in_list.node_list if not isinstance(in_list, NodeList): return None return in_list def __getattr__(self, key): if key.endswith("_") and key[:-1] in self._dict_keys + self._list_keys + self._str_keys: return getattr(self, key[:-1]) if key != "value" and hasattr(self, "value") and isinstance(self.value, ProxyList) and hasattr(self.value, key): return getattr(self.value, key) if key not in redbaron.ALL_IDENTIFIERS: raise AttributeError( "%s instance has no attribute '%s' and '%s' is not a valid identifier of another node" % ( self.__class__.__name__, key, key)) return self.find(key) def __getitem__(self, key): if hasattr(self, "value") and isinstance(self.value, ProxyList): return self.value[key] raise TypeError("'%s' object does not support indexing" % self.__class__) def __getslice__(self, i, j): if hasattr(self, "value") and isinstance(self.value, ProxyList): return self.value.__getslice__(i, j) raise AttributeError("__getslice__") def __setitem__(self, key, value): if hasattr(self, "value") and isinstance(self.value, ProxyList): self.value[key] = value else: raise TypeError("'%s' object does not support item assignment" % self.__class__) def __setslice__(self, i, j, value): if hasattr(self, "value") and isinstance(self.value, ProxyList): return self.value.__setslice__(i, j, value) raise TypeError("'%s' object does not support slice setting" % self.__class__) def __len__(self): if hasattr(self, "value") and isinstance(self.value, ProxyList): return self.value.__len__() # XXX bad, because __len__ exists, if will called to check if this object is True return True def __delitem__(self, key): if hasattr(self, "value") and isinstance(self.value, ProxyList): del self.value[key] else: raise AttributeError("__delitem__") def __delslice__(self, i, j): if hasattr(self, "value") and isinstance(self.value, ProxyList): self.value.__delslice__(i, j) else: raise AttributeError("__delitem__") def find_iter(self, identifier, *args, **kwargs): if "recursive" in kwargs: recursive = kwargs["recursive"] kwargs = kwargs.copy() del kwargs["recursive"] else: recursive = True if self._node_match_query(self, identifier, *args, **kwargs): yield self if recursive: for (kind, key, _) in self._render(): if kind == "key": node = getattr(self, key) if not isinstance(node, Node): continue for matched_node in node.find_iter(identifier, *args, **kwargs): yield matched_node elif kind in ("list", "formatting"): nodes = getattr(self, key) if isinstance(nodes, ProxyList): nodes = nodes.node_list for node in nodes: for matched_node in node.find_iter(identifier, *args, **kwargs): yield matched_node def find(self, identifier, *args, **kwargs): return next(self.find_iter(identifier, *args, **kwargs), None) def find_all(self, identifier, *args, **kwargs): return NodeList(list(self.find_iter(identifier, *args, **kwargs))) findAll = find_all __call__ = find_all def parent_find(self, identifier, *args, **kwargs): current = self while current.parent and current.on_attribute != 'root': if self._node_match_query(current.parent, identifier, *args, **kwargs): return current.parent current = current.parent return None def _node_match_query(self, node, identifier, *args, **kwargs): if not self._attribute_match_query(node.generate_identifiers(), identifier.lower() if isinstance(identifier, string_instance) and not identifier.startswith( "re:") else identifier): return False all_my_keys = node._str_keys + node._list_keys + node._dict_keys if args and isinstance(args[0], (string_instance, RE_PATTERN_FIELD, list, tuple)): if not self._attribute_match_query([getattr(node, node._default_test_value)], args[0]): return False args = args[1:] for arg in args: if not arg(node): return False for key, value in kwargs.items(): if key not in all_my_keys: return False if not self._attribute_match_query([getattr(node, key)], value): return False return True def _attribute_match_query(self, attribute_names, query): """ Take a list/tuple of attributes that can match and a query, return True if any of the attributes match the query. """ assert isinstance(attribute_names, (list, tuple)) if isinstance(query, string_instance) and query.startswith("re:"): query = re.compile(query[3:]) for attribute in attribute_names: if callable(query): if query(attribute): return True elif isinstance(query, string_instance) and query.startswith("g:"): if fnmatch(attribute, query[2:]): return True elif isinstance(query, RE_PATTERN_FIELD): if query.match(attribute): return True elif isinstance(query, (list, tuple)): if attribute in query: return True else: if attribute == query: return True return False def find_by_path(self, path): path = Path(self, path).node return path.node if path else None def path(self): return Path(self) @classmethod def generate_identifiers(klass): return sorted(set(map(lambda x: x.lower(), [ redbaron_classname_to_baron_type(klass.__name__), klass.__name__, klass.__name__.replace("Node", ""), redbaron_classname_to_baron_type(klass.__name__) + "_" ] + klass._other_identifiers))) def _get_helpers(self): not_helpers = set([ 'at', 'copy', 'decrease_indentation', 'dumps', 'edit', 'find', 'find_all', 'findAll', 'find_by_path', 'find_by_position', 'find_iter', 'from_fst', 'fst', 'fst', 'generate_identifiers', 'get_absolute_bounding_box_of_attribute', 'get_indentation_node', 'get_indentation_node', 'has_render_key', 'help', 'help', 'increase_indentation', 'indentation_node_is_direct', 'indentation_node_is_direct', 'index_on_parent', 'index_on_parent_raw', 'insert_after', 'insert_before', 'next_generator', 'next_generator', 'parent_find', 'parent_find', 'parse_code_block', 'parse_decorators', 'path', 'path', 'previous_generator', 'previous_generator', 'replace', 'to_python', ]) return [x for x in dir(self) if not x.startswith("_") and x not in not_helpers and inspect.ismethod(getattr(self, x))] def fst(self): to_return = {} for key in self._str_keys: to_return[key] = getattr(self, key) for key in self._list_keys: # Proxy Lists overload __iter__ for a better user interface if isinstance(getattr(self, key), ProxyList): to_return[key] = [node.fst() for node in getattr(self, key).node_list] else: to_return[key] = [node.fst() for node in getattr(self, key)] for key in self._dict_keys: if getattr(self, key) not in (None, "", [], {}): to_return[key] = getattr(self, key).fst() else: to_return[key] = {} return to_return def dumps(self): return baron.dumps(self.fst()) def help(self, deep=2, with_formatting=False): if runned_from_ipython(): sys.stdout.write(help_highlight(self.__help__(deep=deep, with_formatting=with_formatting) + "\n")) else: sys.stdout.write(self.__help__(deep=deep, with_formatting=with_formatting) + "\n") def __help__(self, deep=2, with_formatting=False): new_deep = deep - 1 if not isinstance(deep, bool) else deep to_join = ["%s()" % self.__class__.__name__] if not deep: to_join[-1] += " ..." else: to_join.append("# identifiers: %s" % ", ".join(self.generate_identifiers())) if self._get_helpers(): to_join.append("# helpers: %s" % ", ".join(self._get_helpers())) if self._default_test_value != "value": to_join.append("# default test value: %s" % self._default_test_value) to_join += ["%s=%s" % (key, repr(getattr(self, key))) for key in self._str_keys if key != "type" and "formatting" not in key] to_join += ["%s ->\n %s" % (key, indent( getattr(self, key).__help__(deep=new_deep, with_formatting=with_formatting), " ").lstrip() if getattr(self, key) else getattr(self, key)) for key in self._dict_keys if "formatting" not in key] # need to do this otherwise I end up with stacked quoted list # example: value=[\'DottedAsNameNode(target=\\\'None\\\', as=\\\'False\\\', value=DottedNameNode(value=["NameNode(value=\\\'pouet\\\')"])] for key in filter(lambda x: "formatting" not in x, self._list_keys): to_join.append(("%s ->" % key)) for i in getattr(self, key): to_join.append( " * " + indent(i.__help__(deep=new_deep, with_formatting=with_formatting), " ").lstrip()) if deep and with_formatting: to_join += ["%s=%s" % (key, repr(getattr(self, key))) for key in self._str_keys if key != "type" and "formatting" in key] to_join += ["%s=%s" % (key, getattr(self, key).__help__(deep=new_deep, with_formatting=with_formatting) if getattr(self, key) else getattr( self, key)) for key in self._dict_keys if "formatting" in key] for key in filter(lambda x: "formatting" in x, self._list_keys): to_join.append(("%s ->" % key)) for i in getattr(self, key): to_join.append( " * " + indent(i.__help__(deep=new_deep, with_formatting=with_formatting), " ").lstrip()) return "\n ".join(to_join) def __repr__(self): if in_a_shell(): return self.__str__() return "<%s path=%s, \"%s\" %s, on %s %s>" % ( self.__class__.__name__, self.path().to_baron_path(), truncate(self.dumps().replace("\n", "\\n"), 20), id(self), self.parent.__class__.__name__, id(self.parent) ) def __str__(self): if runned_from_ipython(): return python_highlight(self.dumps()).decode("Utf-8") else: return self.dumps() def _bytes_repr_html_(self): return python_html_highlight(self.dumps()) def _repr_html_(self): return self._bytes_repr_html_().decode("Utf-8") def copy(self): # XXX not very optimised but at least very simple return Node.from_fst(self.fst()) def __setattr__(self, name, value): if name == "init" or self.init: return super(Node, self).__setattr__(name, value) # we don't want to mess with "__class__" for example but convert "async_" to "async" if name.endswith("_") and not name.endswith("__"): name = name[:-1] # FIXME I'm pretty sure that Bool should also be put in the isinstance for cases like with_parenthesis/as if name in self._str_keys and not isinstance(value, (string_instance, int)): value = str(value) elif name in self._dict_keys: value = self._convert_input_to_node_object(value, self, name) elif name in self._list_keys: value = self._convert_input_to_node_object_list(value, self, name) return super(Node, self).__setattr__(name, value) def _render(self): return nodes_rendering_order[self.type] def replace(self, new_node): new_node = self._convert_input_to_node_object(new_node, parent=None, on_attribute=None, generic=True) self.__class__ = new_node.__class__ # YOLO self.__init__(new_node.fst(), parent=self.parent, on_attribute=self.on_attribute) def edit(self, editor=None): if editor is None: editor = os.environ.get("EDITOR", "nano") base_path = os.path.join("/tmp", "baron_%s" % os.getpid()) if not os.path.exists(base_path): os.makedirs(base_path) temp_file_path = os.path.join(base_path, str(id(self))) self_in_string = self.dumps() with open(temp_file_path, "w") as temp_file: temp_file.write(self_in_string) os.system("%s %s" % (editor, temp_file_path)) with open(temp_file_path, "r") as temp_file: result = temp_file.read() if result != self_in_string: self.replace(result) @property @display_property_atttributeerror_exceptions def index_on_parent(self): if not self.parent: return None if not isinstance(getattr(self.parent, self.on_attribute), (NodeList, ProxyList)): return None return getattr(self.parent, self.on_attribute).index(self) @property @display_property_atttributeerror_exceptions def index_on_parent_raw(self): if not self.parent: return None if not isinstance(getattr(self.parent, self.on_attribute), (NodeList, ProxyList)): return None if isinstance(getattr(self.parent, self.on_attribute), ProxyList): return getattr(self.parent, self.on_attribute).node_list.index(self) else: return getattr(self.parent, self.on_attribute).index(self) def _generate_nodes_in_rendering_order(self): previous = None for j in self._iter_in_rendering_order(self): if j is previous: continue previous = j yield j def has_render_key(self, target_key): for _, _, key in baron.render.render(self.fst()): if key == target_key: return True return False def get_absolute_bounding_box_of_attribute(self, attribute): if not self.has_render_key(attribute): raise KeyError() path = self.path().to_baron_path() + [attribute] return baron.path.path_to_bounding_box(self.root.fst(), path) def increase_indentation(self, number_of_spaces): self.get_indentation_node().indent += number_of_spaces * " " def decrease_indentation(self, number_of_spaces): self.get_indentation_node().indent = self.get_indentation_node().indent[:-len(number_of_spaces * " ")] def insert_before(self, value, offset=0): self.parent.insert(self.index_on_parent - offset, value) def insert_after(self, value, offset=0): self.parent.insert(self.index_on_parent + 1 + offset, value) class CodeBlockNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": return self.parse_code_block(string, parent=parent, on_attribute=on_attribute) elif on_attribute.endswith("_formatting"): return super(CodeBlockNode, self)._string_to_node_list(string, parent, on_attribute) else: raise Exception("Unhandled case") def parse_code_block(self, string, parent, on_attribute): # remove heading blanks lines clean_string = re.sub("^ *\n", "", string) if "\n" in string else string indentation = len(re.search("^ *", clean_string).group()) target_indentation = len(self.indentation) + 4 # putting this in the string template will fail, need at least some indent if indentation == 0: clean_string = " " + "\n ".join(clean_string.split("\n")) clean_string = clean_string.rstrip() fst = baron.parse("def a():\n%s\n" % clean_string)[0]["value"] result = NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) # set indentation to the correct level indentation = len(result[0].indent) if indentation > target_indentation: result.decrease_indentation(indentation - target_indentation) elif indentation < target_indentation: result.increase_indentation(target_indentation - indentation) endl_base_node = Node.from_fst({'formatting': [], 'indent': '', 'type': 'endl', 'value': '\n'}, on_attribute=on_attribute, parent=parent) if (self.on_attribute == "root" and self.next) or (not self.next and self.parent and self.parent.next): # I need to finish with 3 endl nodes if not all(map(lambda x: x.type == "endl", result[-1:])): result.append(endl_base_node.copy()) elif not all(map(lambda x: x.type == "endl", result[-2:])): result.append(endl_base_node.copy()) result.append(endl_base_node.copy()) elif not all(map(lambda x: x.type == "endl", result[-3:])): result.append(endl_base_node.copy()) result.append(endl_base_node.copy()) result.append(endl_base_node.copy()) elif self.next: # I need to finish with 2 endl nodes if not all(map(lambda x: x.type == "endl", result[-2:])): result.append(endl_base_node.copy()) elif not all(map(lambda x: x.type == "endl", result[-3:])): result.append(endl_base_node.copy()) result.append(endl_base_node.copy()) result[-1].indent = self.indentation return result def __setattr__(self, key, value): super(CodeBlockNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, LineProxyList): setattr(self, "value", LineProxyList(self.value, on_attribute="value")) elif key == "decorators" and not isinstance(self.decorators, LineProxyList): setattr(self, "decorators", DecoratorsLineProxyList(self.decorators, on_attribute="decorators")) class IfElseBlockSiblingNode(CodeBlockNode): @property @display_property_atttributeerror_exceptions def next_intuitive(self): next_ = super(IfElseBlockSiblingNode, self).next if next_ is None and self.parent: next_ = self.parent.next return next_ @property @display_property_atttributeerror_exceptions def previous_intuitive(self): previous_ = super(IfElseBlockSiblingNode, self).previous if previous_ is None and self.parent: previous_ = self.parent.previous return previous_ class ElseAttributeNode(CodeBlockNode): def _get_last_member_to_clean(self): return self def _convert_input_to_one_indented_member(self, indented_type, string, parent, on_attribute): def remove_trailing_endl(node): if isinstance(node.value, ProxyList): while node.value.node_list[-1].type == "endl": node.value.node_list.pop() else: while node.value[-1].type == "endl": node.value.pop() if not string: last_member = self remove_trailing_endl(last_member) if isinstance(last_member.value, ProxyList): last_member.value.node_list.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=last_member, on_attribute="value")) else: last_member.value.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=last_member, on_attribute="value")) return "" if re.match("^\s*%s" % indented_type, string): # we've got indented text, let's deindent it if string.startswith((" ", " ")): # assuming that the first spaces are the indentation indentation = len(re.search("^ +", string).group()) string = re.sub("(\r?\n)%s" % (" " * indentation), "\\1", string) string = string.lstrip() node = Node.from_fst(baron.parse("try: pass\nexcept: pass\n%s" % string)[0][indented_type], parent=parent, on_attribute=on_attribute) node.value = self.parse_code_block(node.value.dumps(), parent=node, on_attribute="value") else: # XXX quite hackish way of doing this fst = {'first_formatting': [], 'second_formatting': [], 'type': indented_type, 'value': [{'type': 'pass'}, {'formatting': [], 'indent': '', 'type': 'endl', 'value': '\n'}] } node = Node.from_fst(fst, parent=parent, on_attribute=on_attribute) node.value = self.parse_code_block(string=string, parent=parent, on_attribute=on_attribute) # ensure that the node ends with only one endl token, we'll add more later if needed remove_trailing_endl(node) node.value.node_list.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=node, on_attribute="value")) last_member = self._get_last_member_to_clean() # XXX this risk to remove comments if self.next: remove_trailing_endl(last_member) if isinstance(last_member.value, ProxyList): last_member.value.node_list.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=last_member, on_attribute="value")) else: last_member.value.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=last_member, on_attribute="value")) if self.indentation: node.value.node_list.append(redbaron.nodes.EndlNode( {"type": "endl", "indent": self.indentation, "formatting": [], "value": "\n"}, parent=node, on_attribute="value")) else: # we are on root level and followed: we need 2 blanks lines after the node node.value.node_list.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=node, on_attribute="value")) node.value.node_list.append( redbaron.nodes.EndlNode({"type": "endl", "indent": "", "formatting": [], "value": "\n"}, parent=node, on_attribute="value")) if isinstance(last_member.value, ProxyList): last_member.value.node_list[-1].indent = self.indentation else: last_member.value[-1].indent = self.indentation return node def _string_to_node(self, string, parent, on_attribute): if on_attribute != "else": return super(ElseAttributeNode, self)._string_to_node(string, parent=parent, on_attribute=on_attribute) return self._convert_input_to_one_indented_member("else", string, parent, on_attribute) def __setattr__(self, name, value): if name == "else_": name = "else" return super(ElseAttributeNode, self).__setattr__(name, value) class ProxyList(object): def __init__(self, node_list, on_attribute="value"): self.node_list = node_list self.heading_formatting = [] self.data = self._build_inner_list(node_list) self.middle_separator = redbaron.nodes.CommaNode( {"type": "comma", "first_formatting": [], "second_formatting": [{"type": "space", "value": " "}]}) self.on_attribute = on_attribute def _build_inner_list(self, node_list): result = [] for i in node_list: if isinstance(i, (redbaron.nodes.EndlNode, redbaron.nodes.CommaNode, redbaron.nodes.DotNode)): if result: result[-1][1].append(i) else: self.heading_formatting.append(i) else: result.append([i, []]) return result def __call__(self, identifier, *args, **kwargs): return self.node_list.find_all(identifier, *args, **kwargs) def _convert_input_to_node_object(self, value, parent, on_attribute): lst = self.node_list.parent._convert_input_to_node_object_list(value, parent, on_attribute) if all(i.type == 'endl' for i in lst): return lst[0] else: return lst.filtered()[0] def _convert_input_to_node_object_list(self, value, parent, on_attribute): if isinstance(value, string_instance): return self.node_list.parent._convert_input_to_node_object_list(value, parent, on_attribute) else: return NodeList([self._convert_input_to_node_object(x, parent, on_attribute) for x in value]) def _generate_expected_list(self): expected_list = self.heading_formatting[:] for position, i in enumerate(self.data): is_last = position == len(self.data) - 1 expected_list.append(i[0]) # XXX this will need refactoring... if i[1] is not None: # here we encounter a middle value that should have formatting # to separate between the intems but has not so we add it # this happen because a new value has been added after this one if not is_last and not i[1]: separator = self.middle_separator.copy() separator.parent = self.node_list separator.on_attribute = self.on_attribute expected_list.append(separator) # XXX shoud uniformise the list of formatting nodes elif is_last and i[1] and i[1][0].type in ("comma", "dot"): # XXX this will likely break comments if presents at the end of the list pass else: expected_list += i[1] else: # here we generate the new expected formatting # None is used as a sentry value for newly inserted values in the proxy list if not is_last: separator = self.middle_separator.copy() separator.parent = self.node_list separator.on_attribute = self.on_attribute expected_list.append(separator) return expected_list def _synchronise(self): self.node_list.data = self._generate_expected_list()[:] self.data = self._build_inner_list(self.node_list.data) def __len__(self): return len(self.data) def insert(self, index, value): value = self._convert_input_to_node_object(value, parent=self.node_list, on_attribute=self.on_attribute) self.data.insert(index, [value, None]) self._synchronise() def append(self, value): self.insert(len(self), value) def extend(self, values): self.data.extend(map(lambda x: [x, None], self._convert_input_to_node_object_list(values, parent=self.node_list, on_attribute=self.on_attribute))) self._synchronise() def pop(self, index=None): if index is not None: self.data.pop(index) else: self.data.pop() self._synchronise() def remove(self, value): self.pop(self.index(value)) def __delitem__(self, index): if isinstance(index, slice): self.__delslice__(index.start, index.stop) else: self.pop(index) def index(self, value, *args): # XXX would be better if I iterate other the list return [x[0] for x in self.data].index(value, *args) def __getitem__(self, index): if isinstance(index, slice): return self.__getslice__(index.start, index.stop) else: return self.data[index][0] def __contains__(self, *args, **kwargs): return self.data.__contains__(*args, **kwargs) def __iter__(self): return map(lambda x: x[0], self.data).__iter__() def count(self, value): return [x[0] for x in self.data].count(value) def __setitem__(self, key, value): if isinstance(key, slice): self.__setslice__(key.start, key.stop, value) else: self.data[key][0] = self._convert_input_to_node_object(value, parent=self.node_list, on_attribute=self.on_attribute) self._synchronise() def __setslice__(self, i, j, value): self.data[i:j] = map(lambda x: [x, None], self._convert_input_to_node_object_list(value, parent=self.node_list, on_attribute=self.on_attribute)) self._synchronise() def __delslice__(self, i, j): del self.data[i:j] self._synchronise() def __getslice__(self, i, j): to_return = map(lambda x: x[0], self.data[i:j]) return self.__class__(NodeList(to_return)) def __repr__(self): if in_a_shell(): return self.__str__() return "<%s %s, \"%s\" %s, on %s %s>" % ( self.__class__.__name__, self.path().to_baron_path(), truncate(self.dumps().replace("\n", "\\n"), 20), id(self), self.parent.__class__.__name__, id(self.parent) ) def _bytes_repr_html_(self): def __repr_html(self): # string addition is slow (and makes copies) yield b"" yield b"" for num, item in enumerate(self): yield b"" yield b"" yield b"" yield b"" yield b"
Indexnode
" yield str(num).encode("Utf-8") yield b"" yield item._bytes_repr_html_() yield b"
" return b''.join(__repr_html(self)) def _repr_html_(self): return self._bytes_repr_html_().decode("Utf-8") def __str__(self): to_return = "" for number, value in enumerate(self.data): value = value[0] to_return += (("%-3s " % number) + "\n ".join(value.__repr__().split("\n"))) to_return += "\n" return to_return def __getattr__(self, key): return getattr(self.node_list, key) class CommaProxyList(ProxyList): def __init__(self, node_list, on_attribute="value"): super(CommaProxyList, self).__init__(node_list, on_attribute=on_attribute) self.style = "indented" if any(self.node_list('comma', recursive=False).map(lambda x: x('endl'))) else "flat" # XXX will likely break if the user modify the formatting of the list, # I don't like that self.has_trailing = self.node_list and self.node_list[-1].type == "comma" def _get_middle_separator(self): if self.style == "indented": return redbaron.nodes.CommaNode({"type": "comma", "first_formatting": [], "second_formatting": [ {"type": "endl", "indent": self.parent.indentation + " ", "formatting": [], "value": "\n"}]}) return redbaron.nodes.CommaNode( {"type": "comma", "first_formatting": [], "second_formatting": [{"type": "space", "value": " "}]}) def _generate_expected_list(self): def generate_separator(): separator = self._get_middle_separator() separator.parent = self.node_list separator.on_attribute = self.on_attribute return separator # XXX will break comments if not self.data: self.parent.first_formatting = [] self.parent.second_formatting = [] return [] expected_list = [] for position, i in enumerate(self.data): is_last = position == len(self.data) - 1 expected_list.append(i[0]) # XXX this will need refactoring... if i[1] is not None: # here we encounter a middle value that should have formatting # to separate between the intems but has not so we add it # this happen because a new value has been added after this one if not is_last and not i[1]: expected_list.append(generate_separator()) # comma list doesn't have trailing but has a comma at its end, remove it elif is_last and not self.has_trailing and i[1] and i[1][0].type == "comma": # XXX this will likely break comments if presents at the end of the list pass else: expected_list += i[1] # XXX will break comments if self.style == "indented": if not expected_list[-1].second_formatting.endl: raise Exception( "It appears that you have indentation in your CommaList, for now RedBaron doesn't know how to handle this situation (which requires a lot of work), sorry about that. You can find more information here https://github.com/PyCQA/redbaron/issues/100") elif expected_list[-1].second_formatting.endl.indent != self.parent.indentation + " " * 4: expected_list[-1].second_formatting.endl.indent = self.parent.indentation + " " * 4 else: # here we generate the new expected formatting # None is used as a sentry value for newly inserted values in the proxy list if not is_last: expected_list.append(generate_separator()) elif self.has_trailing: expected_list.append(generate_separator()) expected_list[-1].second_formatting[0].indent = "" if expected_list and self.has_trailing and self.style == "indented": if not expected_list[-1].second_formatting.endl: raise Exception( "It appears that you have indentation in your CommaList, for now RedBaron doesn't know how to handle this situation (which requires a lot of work), sorry about that. You can find more information here https://github.com/PyCQA/redbaron/issues/100") elif expected_list[-1].second_formatting.endl.indent != self.parent.indentation: expected_list[-1].second_formatting.endl.indent = self.parent.indentation return expected_list class DotProxyList(ProxyList): def __init__(self, node_list, on_attribute="value"): # XXX this will have its limitations, users will probably wants to be # able to modify those, DotProxyList should be reconsidered for that super(DotProxyList, self).__init__(node_list, on_attribute=on_attribute) self.middle_separator = redbaron.nodes.DotNode({"type": "dot", "first_formatting": [], "second_formatting": []}) def _build_inner_list(self, node_list): # XXX to merge with parent, behavior is the same only formatting nodes changes result = [] for i in node_list: if isinstance(i, redbaron.nodes.DotNode): if not result: self.heading_formatting.append(i) else: result[-1][1].append(i) else: result.append([i, []]) return result def _generate_expected_list(self): expected_list = self.heading_formatting[:] for position, i in enumerate(self.data): if expected_list and i[0].type in ("call", "getitem"): expected_list.pop() is_last = position == len(self.data) - 1 expected_list.append(i[0]) # XXX this will need refactoring... if i[1] is not None: # here we encounter a middle value that should have formatting # to separate between the items but has not so we add it # this happen because a new value has been added after this one if not is_last and not i[1]: separator = self.middle_separator.copy() separator.parent = self.node_list separator.on_attribute = self.on_attribute expected_list.append(separator) # XXX shoud uniformise the list of formatting nodes elif is_last and i[1] and i[1][0].type in ("comma", "dot"): # XXX this will likely break comments if presents at the end of the list pass else: expected_list += i[1] else: # here we generate the new expected formatting # None is used as a sentry value for newly inserted values in the proxy list if not is_last: separator = self.middle_separator.copy() separator.parent = self.node_list separator.on_attribute = self.on_attribute expected_list.append(separator) return expected_list def _convert_input_to_node_object(self, value, parent, on_attribute): if value.startswith(("(", "[")): value = "a%s" % value else: value = "a.%s" % value return self.node_list.parent._convert_input_to_node_object_list(value, parent, on_attribute).filtered()[-1] class LineProxyList(ProxyList): def __init__(self, node_list, on_attribute="value"): self.first_blank_lines = [] super(LineProxyList, self).__init__(node_list, on_attribute=on_attribute) self.middle_separator = redbaron.nodes.DotNode( {"type": "endl", "formatting": [], "value": "\n", "indent": " "}) def _synchronise(self): log("Before synchronise, self.data = '%s' + '%s'", self.first_blank_lines, self.node_list) super(LineProxyList, self)._synchronise() log("After synchronise, self.data = '%s' + '%s'", self.first_blank_lines, self.node_list) def _build_inner_list(self, node_list): result = [] self.first_blank_lines = [] previous = None still_at_beginning = False for i in node_list: if i.type != "endl": result.append([i, []]) still_at_beginning = False elif previous and previous.type == "endl": result.append([i, []]) still_at_beginning = False elif still_at_beginning and self.first_blank_lines: result.append([i, []]) still_at_beginning = False else: if result: result[-1][1].append(i) still_at_beginning = False else: self.first_blank_lines.append(i) still_at_beginning = True if still_at_beginning: previous = None else: previous = i return result def _get_separator_indentation(self): return self.node_list.filtered()[ 0].indentation if self.node_list.filtered() else self.parent.indentation + " " def _generate_expected_list(self): log("Start _generate_expected_list for LineProxyList") log(">>> current list '%s'", self.data) indentation = self._get_separator_indentation() log("Detect indentation has %s", indentation.__repr__()) def generate_separator(): separator = self.middle_separator.copy() separator.parent = self.node_list separator.on_attribute = self.on_attribute separator.indent = indentation return separator def get_real_last(node): try: return node.node_list[-1] except: return node[-1] def modify_last_indentation(node, indentation): try: current_last = get_real_last(node) while current_last.type in ('def', 'class', 'ifelseblock'): current_last = get_real_last(current_last) current_last.indent = indentation except (AttributeError, IndexError, TypeError): node.indent = indentation expected_list = self.first_blank_lines[:] if expected_list: log(">> adding first blank lines to expected_list: '%s'", expected_list) previous = expected_list[-1] if expected_list else None might_need_separator = False has_added_separator = False if expected_list and self.data and self.data[0][0].type == "endl" and not expected_list[-1].formatting.comment: log("first_blank_lines doesn't has comments, reset indentation") expected_list[-1].indent = "" for position, i in enumerate(self.data): log("[%s] %s", position, i) if might_need_separator and i[0].type != "endl" and ( not previous or previous.type != "endl") and not isinstance(previous, ( CodeBlockNode, redbaron.nodes.IfelseblockNode)): log(">> Previous line has content and current needs to be indented, append separator to indent it") expected_list.append(generate_separator()) log("-- current result: %s", ["".join(map(lambda x: x.dumps(), expected_list))]) previous = expected_list[-1] might_need_separator = False if has_added_separator and i[0].type == "endl": # XXX this will break comments if present log("Previous is endl (from a added separator) and current is endl, remove indentation of previous") expected_list[-1].indent = "" if previous and previous.type == "endl" and i[0].type == "endl": # XXX this will break comments log("Previous is endl and current is endl, remove indentation of previous") previous.indent = "" has_added_separator = False is_last = position == len(self.data) - 1 log(">> Append node to expected_list: '%s'", [i[0]]) expected_list.append(i[0]) log("-- current result: %s", ["".join(map(lambda x: x.dumps(), expected_list))]) if previous and previous.type == "endl" and i[0].type != "endl" and previous.indentation != indentation: log("Previous is endl and current isn't endl and identation isn't correct, fix it") previous.indent = indentation if i[0].type != "endl" and previous and isinstance(previous, CodeBlockNode): log("Previous is CodeBlockNode and current isn't endl, ensure previous has the current identation") modify_last_indentation(get_real_last(previous.value), indentation) # XXX this will need refactoring... if i[1] is not None: log("current doesn't have None for formatting") # here we encounter a middle value that should have formatting # to separate between the intems but has not so we add it # this happen because a new value has been added after this one if not is_last and not i[1] and not isinstance(i[0], CodeBlockNode): log( "If current isn't a CodeBlockNode and doesn't have a separator and isn't the last, mark it has might needing a separator") might_need_separator = True # XXX shoud uniformise the list of formatting nodes elif is_last and i[1] and i[1][0].type in ("comma", "dot"): # XXX this will likely break comments if presents at the end of the list log("Current is last and a CodeBlockNode, don't do anything") pass else: log(">> Append formatting to expected_list: %s", i[1]) expected_list += i[1] log("-- current result: %s", ["".join(map(lambda x: x.dumps(), expected_list))]) else: log("current HAS None for formatting") # here we generate the new expected formatting # None is used as a sentry value for newly inserted values in the proxy list # CodeBlockNode are responsible for the last indentation if isinstance(i[0], CodeBlockNode): log("Current is CodeBlockNode, don't do anything") pass elif not is_last and not i[0].type == "endl": log(">> Current is not last and not endl, append a separator") has_added_separator = True expected_list.append(generate_separator()) log("-- current result: %s", ["".join(map(lambda x: x.dumps(), expected_list))]) elif i[0].type == "endl": log(">> Current is endl, don't do anything") elif is_last: log(">> Current is last, don't do anything") previous = expected_list[-1] log("End of loop") log("-- result before end list procedure: %s", map(lambda x: x.dumps(), expected_list)) if self.parent and self.parent.next_intuitive: log("self.parent is followed by another node, last_indentation is indentation of self.parent") last_indentation = self.parent.indentation else: log("self.parent is NOT followed by another node, last indentation is empty string") last_indentation = "" if not expected_list or not isinstance(expected_list[-1], (CodeBlockNode, redbaron.nodes.EndlNode)): log( ">> List is empty or last node is not a CodeBlockNode or EndlNode, append a separator to it and set identation to it") expected_list.append(generate_separator()) expected_list[-1].indent = last_indentation log("-- current result: %s", ["".join(map(lambda x: x.dumps(), expected_list))]) else: if isinstance(expected_list[-1], CodeBlockNode): # In this case, the last \n is owned by the node log("Last node is a CodeBlockNode, ensure that I still have the same last_indentation") modify_last_indentation(get_real_last(expected_list[-1].value), last_indentation) else: log("Last node is NOT CodeBlockNode, ensure that I still have the same last_indentation") expected_list[-1].indent = last_indentation log("-- final result: %s", map(lambda x: x.dumps(), expected_list)) log("End") return expected_list def get_absolute_bounding_box_of_attribute(self, index): if index >= len(self.data) or index < 0: raise IndexError() index = self[index].index_on_parent_raw path = self.path().to_baron_path() + [index] return baron.path.path_to_bounding_box(self.root.fst(), path) class DecoratorsLineProxyList(LineProxyList): def _convert_input_to_node_object_list(self, value, parent, on_attribute): return map(lambda x: self._convert_input_to_node_object(x, parent, on_attribute), value) def _generate_expected_list(self): expected_list = super(DecoratorsLineProxyList, self)._generate_expected_list() expected_list[-1].indent = self.parent.indentation return expected_list def _get_separator_indentation(self): return self.parent.indentation redbaron-0.9.2/redbaron/nodes.py000066400000000000000000001475601344351435400166170ustar00rootroot00000000000000from __future__ import absolute_import import re import baron from baron.utils import string_instance from redbaron.base_nodes import Node, NodeList, LiteralyEvaluable, CodeBlockNode, DotProxyList, CommaProxyList, LineProxyList, IfElseBlockSiblingNode, ElseAttributeNode from redbaron.syntax_highlight import python_html_highlight class ArgumentGeneratorComprehensionNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "generators": fst = baron.parse("(x %s)" % string)[0]["generators"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def _string_to_node(self, string, parent, on_attribute): if on_attribute == "result": return Node.from_fst(baron.parse("(%s for x in x)" % string)[0]["result"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class AssertNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("assert %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "message": if string: self.third_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute=on_attribute, parent=parent)] return Node.from_fst(baron.parse("assert plop, %s" % string)[0]["message"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class AssignmentNode(Node): _other_identifiers = ["assign"] def __setattr__(self, key, value): if key == "operator": if len(value) == 2 and value[1] == "=": value = value[0] elif len(value) == 1 and value == "=": value = "" elif value is None: value = "" elif len(value) not in (0, 1, 2): raise Exception("The value of the operator can only be a string of one or two char, for eg: '+', '+=', '=', ''") return super(AssignmentNode, self).__setattr__(key, value) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "target": return Node.from_fst(baron.parse("%s = a" % string)[0]["target"], parent=parent, on_attribute=on_attribute) elif on_attribute == "value": return Node.from_fst(baron.parse("a = %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "annotation": if not string.strip(): self.annotation_first_formatting = [] self.annotation_second_formatting = [] return "" else: if not self.annotation_first_formatting: self.annotation_first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="return_annotation_first_formatting", parent=self)] if not self.annotation_second_formatting: self.annotation_second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="return_annotation_first_formatting", parent=self)] return Node.from_fst(baron.parse("a: %s = a" % string)[0]["annotation"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class AssociativeParenthesisNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("(%s)" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class AtomtrailersNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": return NodeList.from_fst(baron.parse("(%s)" % string)[0]["value"]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(AtomtrailersNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, DotProxyList): setattr(self, "value", DotProxyList(self.value)) class AwaitNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("await %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class BinaryNode(Node, LiteralyEvaluable): def __setattr__(self, key, value): if key == "value" and isinstance(value, string_instance): assert baron.parse(value)[0]["type"] == "binary" return super(BinaryNode, self).__setattr__(key, value) class BinaryOperatorNode(Node): def __setattr__(self, key, value): if key == "value" and isinstance(value, string_instance): assert baron.parse("a %s b" % value)[0]["type"] == "binary_operator" return super(BinaryOperatorNode, self).__setattr__(key, value) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "first": return Node.from_fst(baron.parse("%s + b" % string)[0]["first"], parent=parent, on_attribute=on_attribute) elif on_attribute == "second": return Node.from_fst(baron.parse("bb + %s" % string)[0]["second"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class BinaryStringNode(Node, LiteralyEvaluable): pass class BinaryRawStringNode(Node, LiteralyEvaluable): pass class BooleanOperatorNode(Node): def __setattr__(self, key, value): if key == "value" and isinstance(value, string_instance): assert baron.parse("a %s b" % value)[0]["type"] == "boolean_operator" return super(BooleanOperatorNode, self).__setattr__(key, value) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "first": return Node.from_fst(baron.parse("%s and b" % string)[0]["first"], parent=parent, on_attribute=on_attribute) elif on_attribute == "second": return Node.from_fst(baron.parse("bb and %s" % string)[0]["second"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class BreakNode(Node): pass class CallNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": return NodeList.from_fst(baron.parse("a(%s)" % string)[0]["value"][1]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(CallNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class CallArgumentNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("a(%s)" % string)[0]["value"][1]["value"][0]["value"], parent=parent, on_attribute=on_attribute) if string else "" elif on_attribute == "target": return Node.from_fst(baron.parse("a(%s=b)" % string)[0]["value"][1]["value"][0]["target"], parent=parent, on_attribute=on_attribute) if string else "" else: raise Exception("Unhandled case") class ClassNode(CodeBlockNode): _default_test_value = "name" def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "decorators": return self.parse_decorators(string, parent=parent, on_attribute=on_attribute) elif on_attribute == "inherit_from": if string: self.parenthesis = True else: self.parenthesis = False return NodeList.from_fst(baron.parse("class a(%s): pass" % string)[0]["inherit_from"], parent=parent, on_attribute=on_attribute) else: return super(ClassNode, self)._string_to_node_list(string, parent, on_attribute) def __setattr__(self, key, value): super(ClassNode, self).__setattr__(key, value) if key == "inherit_from" and not isinstance(self.inherit_from, CommaProxyList): setattr(self, "inherit_from", CommaProxyList(self.inherit_from, on_attribute="inherit_from")) class CommaNode(Node): pass class CommentNode(Node): pass class ComparisonNode(Node): def __setattr__(self, key, value): if key == "value" and isinstance(value, string_instance): assert baron.parse("a %s b" % value)[0]["type"] == "comparison" return super(ComparisonNode, self).__setattr__(key, value) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "first": return Node.from_fst(baron.parse("%s > b" % string)[0]["first"], parent=parent, on_attribute=on_attribute) elif on_attribute == "value": return Node.from_fst(baron.parse("a %s b" % string)[0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "second": return Node.from_fst(baron.parse("bb > %s" % string)[0]["second"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class ComparisonOperatorNode(Node): pass class ComplexNode(Node): pass class ComprehensionIfNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("[x for x in x if %s]" % string)[0]["generators"][0]["ifs"][0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class ComprehensionLoopNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "ifs": return NodeList.from_fst(baron.parse("[x for x in x %s]" % string)[0]["generators"][0]["ifs"], parent=parent, on_attribute=on_attribute) else: return super(ClassNode, self)._string_to_node_list(string, parent, on_attribute) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "iterator": return Node.from_fst(baron.parse("[x for %s in x]" % string)[0]["generators"][0]["iterator"], parent=parent, on_attribute=on_attribute) elif on_attribute == "target": return Node.from_fst(baron.parse("[x for s in %s]" % string)[0]["generators"][0]["target"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class ContinueNode(Node): pass class DecoratorNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("@%s()\ndef a(): pass" % string)[0]["decorators"][0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "call": if string: return Node.from_fst(baron.parse("@a%s\ndef a(): pass" % string)[0]["decorators"][0]["call"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class DefNode(CodeBlockNode): _other_identifiers = ["funcdef", "funcdef_"] _default_test_value = "name" def _string_to_node(self, string, parent, on_attribute): if on_attribute == "return_annotation": if not string.strip(): self.return_annotation_first_formatting = [] self.return_annotation_second_formatting = [] return "" else: fst = baron.parse("def a() -> %s: pass" % string)[0]["return_annotation"] if not self.return_annotation_first_formatting: self.return_annotation_first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="return_annotation_first_formatting", parent=self)] if not self.return_annotation_second_formatting: self.return_annotation_second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="return_annotation_second_formatting", parent=self)] return Node.from_fst(fst, parent=parent, on_attribute=on_attribute) return super(DefNode, self)._string_to_node(string, parent, on_attribute) def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "arguments": fst = baron.parse("def a(%s): pass" % string)[0]["arguments"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) elif on_attribute == "decorators": return self.parse_decorators(string, parent=parent, on_attribute=on_attribute) else: return super(DefNode, self)._string_to_node_list(string, parent, on_attribute) def __setattr__(self, key, value): super(DefNode, self).__setattr__(key, value) if key == "arguments" and not isinstance(self.arguments, CommaProxyList): setattr(self, "arguments", CommaProxyList(self.arguments, on_attribute="arguments")) elif key in ("async", "async_") and getattr(self, "async") and hasattr(self, "async_formatting") and not self.async_formatting: self.async_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="return_annotation_first_formatting", parent=self)] class DefArgumentNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("def a(b=%s): pass" % string)[0]["arguments"][0]["value"], parent=parent, on_attribute=on_attribute) if string else "" elif on_attribute == "target": return Node.from_fst(baron.parse("def a(%s=b): pass" % string)[0]["arguments"][0]["target"], parent=parent, on_attribute=on_attribute) if string else "" elif on_attribute == "annotation": if not self.annotation_first_formatting: self.annotation_first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="annotation_first_formatting", parent=self)] if not self.annotation_second_formatting: self.annotation_second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="annotation_second_formatting", parent=self)] return Node.from_fst(baron.parse("def a(a:%s=b): pass" % string)[0]["arguments"][0]["annotation"], parent=parent, on_attribute=on_attribute) if string else "" else: raise Exception("Unhandled case") class DelNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("del %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class DictArgumentNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("a(**%s)" % string)[0]["value"][1]["value"][0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "annotation": if not self.annotation_first_formatting: self.annotation_first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="annotation_first_formatting", parent=self)] if not self.annotation_second_formatting: self.annotation_second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="annotation_second_formatting", parent=self)] return Node.from_fst(baron.parse("def a(a:%s=b): pass" % string)[0]["arguments"][0]["annotation"], parent=parent, on_attribute=on_attribute) if string else "" else: raise Exception("Unhandled case") class DictitemNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("{a: %s}" % string)[0]["value"][0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "key": return Node.from_fst(baron.parse("{%s: a}" % string)[0]["value"][0]["key"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class DictNode(Node, LiteralyEvaluable): def _string_to_node_list(self, string, parent, on_attribute): fst = baron.parse("{%s}" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) def __setattr__(self, key, value): super(DictNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class DictComprehensionNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "generators": fst = baron.parse("{x %s}" % string)[0]["generators"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def _string_to_node(self, string, parent, on_attribute): if on_attribute == "result": return Node.from_fst(baron.parse("{%s for x in x}" % string)[0]["result"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class DotNode(Node): pass class DottedAsNameNode(Node): def __setattr__(self, key, value): if key == "target": if not (re.match(r'^[a-zA-Z_]\w*$', value) or value in ("", None)): raise Exception("The target of a dotted as name node can only be a 'name' or an empty string or None") if value: self.first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] self.second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] super(DottedAsNameNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, DotProxyList): setattr(self, "value", DotProxyList(self.value)) def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": fst = baron.parse("import %s" % string)[0]["value"][0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class DottedNameNode(Node): pass class ElifNode(IfElseBlockSiblingNode): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "test": return Node.from_fst(baron.parse("if %s: pass" % string)[0]["value"][0]["test"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class EllipsisNode(Node): pass class ElseNode(IfElseBlockSiblingNode): @property def next_intuitive(self): if self.parent.type == "ifelseblock": return super(ElseNode, self).next_intuitive elif self.parent.type == "try": if self.parent.finally_: return self.parent.finally_ else: return self.parent.next elif self.parent.type in ("for", "while"): return self.parent.next @property def previous_intuitive(self): if self.parent.type == "ifelseblock": return super(ElseNode, self).previous_intuitive elif self.parent.type == "try": return self.parent.excepts[-1] elif self.parent.type in ("for", "while"): return self.parent class EndlNode(Node): def __repr__(self): return repr(baron.dumps([self.fst()])) def _bytes_repr_html_(self): return python_html_highlight(self.__repr__()) class ExceptNode(CodeBlockNode): @property def next_intuitive(self): next_ = self.next if next_: return next_ if self.parent.else_: return self.parent.else_ if self.parent.finally_: return self.parent.finally_ if self.parent.next: return self.parent.next @property def previous_intuitive(self): previous_ = self.previous if previous_: return previous_ return self.parent def __setattr__(self, key, value): if key == "delimiter": if value == ",": self.second_formatting = [] self.third_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] elif value == "as": self.second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] self.third_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] elif value: raise Exception("Delimiters of an except node can only be 'as' or ',' (without spaces around it).") super(ExceptNode, self).__setattr__(key, value) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "exception": if string: self.first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute=on_attribute, parent=parent)] return Node.from_fst(baron.parse("try: pass\nexcept %s: pass" % string)[0]["excepts"][0]["exception"], parent=parent, on_attribute=on_attribute) else: self.first_formatting = [] self.delimiter = "" self.target = "" return "" elif on_attribute == "target": if not self.exception: raise Exception("Can't set a target to an exception node that doesn't have an exception set") if string: self.delimiter = "as" self.second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute=on_attribute, parent=parent)] self.third_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute=on_attribute, parent=parent)] return Node.from_fst(baron.parse("try: pass\nexcept a as %s: pass" % string)[0]["excepts"][0]["target"], parent=parent, on_attribute=on_attribute) else: self.delimiter = "" self.second_formatting = [] self.third_formatting = [] return "" else: raise Exception("Unhandled case") class ExecNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("exec %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "globals": if string: self.second_formatting = [{"type": "space", "value": " "}] self.third_formatting = [{"type": "space", "value": " "}] return Node.from_fst(baron.parse("exec a in %s" % string)[0]["globals"], parent=parent, on_attribute=on_attribute) elif on_attribute == "locals": if not self.globals: raise Exception("I can't set locals when globals aren't set.") if string: self.fifth_formatting = [{"type": "space", "value": " "}] return Node.from_fst(baron.parse("exec a in b, %s" % string)[0]["locals"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class FinallyNode(CodeBlockNode): @property def next_intuitive(self): return self.parent.next @property def previous_intuitive(self): if self.parent.else_: return self.parent.else_ if self.parent.excepts: return self.parent.excepts[-1] return self.parent def __setattr__(self, key, value): super(FinallyNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, LineProxyList): setattr(self, "value", LineProxyList(self.value, on_attribute="value")) class ForNode(ElseAttributeNode): @property def next_intuitive(self): if self.else_: return self.else_ return self.next def __setattr__(self, key, value): super(ForNode, self).__setattr__(key, value) if key in ("async", "async_") and getattr(self, "async") and hasattr(self, "async_formatting") and not self.async_formatting: self.async_formatting = " " def _string_to_node(self, string, parent, on_attribute): if on_attribute == "target": return Node.from_fst(baron.parse("for i in %s: pass" % string)[0]["target"], parent=parent, on_attribute=on_attribute) elif on_attribute == "iterator": return Node.from_fst(baron.parse("for %s in i: pass" % string)[0]["iterator"], parent=parent, on_attribute=on_attribute) else: return super(ForNode, self)._string_to_node(string, parent, on_attribute) class FloatNode(Node, LiteralyEvaluable): pass class FloatExponantNode(Node, LiteralyEvaluable): pass class FloatExponantComplexNode(Node, LiteralyEvaluable): pass class FromImportNode(Node): def names(self): """Return the list of new names imported For example: RedBaron("from qsd import a, c, e as f").names() == ['a', 'c', 'f'] """ return [x.target if getattr(x, "target", None) else x.value for x in self.targets if not isinstance(x, (LeftParenthesisNode, RightParenthesisNode))] def modules(self): """Return the list of the targets imported For example (notice 'e' instead of 'f'): RedBaron("from qsd import a, c, e as f").names() == ['a', 'c', 'e'] """ return [x.value for x in self.targets] def full_path_names(self): """Return the list of new names imported with the full module path For example (notice 'e' instead of 'f'): RedBaron("from qsd import a, c, e as f").names() == ['qsd.a', 'qsd.c', 'qsd.f'] """ return [self.value.dumps() + "." + (x.target if x.target else x.value) for x in self.targets if not isinstance(x, (LeftParenthesisNode, RightParenthesisNode))] def full_path_modules(self): """Return the list of the targets imported with the full module path For example (notice 'e' instead of 'f'): RedBaron("from qsd import a, c, e as f").names() == ['qsd.a', 'qsd.c', 'qsd.e'] """ return [self.value.dumps() + "." + x.value for x in self.targets if not isinstance(x, (LeftParenthesisNode, RightParenthesisNode))] def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "targets": fst = baron.parse("from a import %s" % string)[0]["targets"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) if on_attribute == "value": fst = baron.parse("from %s import s" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(FromImportNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, DotProxyList): setattr(self, "value", DotProxyList(self.value, on_attribute="value")) if key == "targets" and not isinstance(self.targets, CommaProxyList): setattr(self, "targets", CommaProxyList(self.targets, on_attribute="targets")) class GeneratorComprehensionNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "generators": fst = baron.parse("(x %s)" % string)[0]["generators"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def _string_to_node(self, string, parent, on_attribute): if on_attribute == "result": return Node.from_fst(baron.parse("(%s for x in x)" % string)[0]["result"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class GetitemNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("a[%s]" % string)[0]["value"][1]["value"], parent=parent, on_attribute=on_attribute) class GlobalNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": fst = baron.parse("global %s" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(GlobalNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value, on_attribute="value")) class HexaNode(Node, LiteralyEvaluable): pass class IfNode(IfElseBlockSiblingNode): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "test": return Node.from_fst(baron.parse("if %s: pass" % string)[0]["value"][0]["test"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class IfelseblockNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute != "value": return super(IfelseblockNode, self)._string_to_node_list(string, parent=parent, on_attribute=on_attribute) string = string.rstrip() string += "\n" if self.next and self.on_attribute == "root": string += "\n\n" elif self.next: string += "\n" clean_string = re.sub("^ *\n", "", string) if "\n" in string else string indentation = len(re.search("^ *", clean_string).group()) if indentation: string = "\n".join(map(lambda x: x[indentation:], string.split("\n"))) result = NodeList.from_fst(baron.parse(string)[0]["value"], parent=parent, on_attribute=on_attribute) if self.indentation: result.increase_indentation(len(self.indentation)) if self.next: result[-1].value.node_list[-1].indent = self.indentation return result class ImportNode(Node): def modules(self): "return a list of string of modules imported" return [x.value.dumps()for x in self('dotted_as_name')] def names(self): "return a list of string of new names inserted in the python context" return [x.target if x.target else x.value.dumps() for x in self('dotted_as_name')] def _string_to_node_list(self, string, parent, on_attribute): fst = baron.parse("import %s" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) def __setattr__(self, key, value): super(ImportNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value, on_attribute="value")) class IntNode(Node, LiteralyEvaluable): def fst(self): return { "type": "int", "value": self.value, "section": "number", } class InterpolatedStringNode(Node, LiteralyEvaluable): _other_identifiers = ["fstring"] class InterpolatedRawStringNode(Node, LiteralyEvaluable): _other_identifiers = ["raw_fstring"] class KwargsOnlyMarkerNode(Node): pass class LambdaNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "arguments": self.first_formatting = [{"type": "space", "value": " "}] if string else [] fst = baron.parse("lambda %s: x" % string)[0]["arguments"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: return super(DefNode, self)._string_to_node_list(string, parent, on_attribute) def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("lambda: %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(LambdaNode, self).__setattr__(key, value) if key == "arguments" and not isinstance(self.arguments, CommaProxyList): setattr(self, "arguments", CommaProxyList(self.arguments, on_attribute="arguments")) class LeftParenthesisNode(Node): pass class ListArgumentNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("lambda *%s: x" % string)[0]["arguments"][0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "annotation": if not self.annotation_first_formatting: self.annotation_first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="annotation_first_formatting", parent=self)] if not self.annotation_second_formatting: self.annotation_second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="annotation_second_formatting", parent=self)] return Node.from_fst(baron.parse("def a(a:%s=b): pass" % string)[0]["arguments"][0]["annotation"], parent=parent, on_attribute=on_attribute) if string else "" else: raise Exception("Unhandled case") class ListComprehensionNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "generators": fst = baron.parse("[x %s]" % string)[0]["generators"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def _string_to_node(self, string, parent, on_attribute): if on_attribute == "result": return Node.from_fst(baron.parse("[%s for x in x]" % string)[0]["result"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class ListNode(Node, LiteralyEvaluable): def _string_to_node_list(self, string, parent, on_attribute): fst = baron.parse("[%s]" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) def __setattr__(self, key, value): super(ListNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class LongNode(Node, LiteralyEvaluable): pass class NameNode(Node, LiteralyEvaluable): pass class TypedNameNode(Node): pass class NameAsNameNode(Node): def __setattr__(self, key, value): if key == "target": if not (re.match(r'^[a-zA-Z_]\w*$', value) or value in ("", None)): raise Exception("The target of a name as name node can only be a 'name' or an empty string or None") if value: self.first_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] self.second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="delimiter", parent=self)] elif key == "value": if not (re.match(r'^[a-zA-Z_]\w*$', value) or value in ("", None)): raise Exception("The value of a name as name node can only be a 'name' or an empty string or None") return super(NameAsNameNode, self).__setattr__(key, value) class NonlocalNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": fst = baron.parse("global %s" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(NonlocalNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value, on_attribute="value")) class OctaNode(Node, LiteralyEvaluable): pass class PassNode(Node): pass class PrintNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "destination": if string and not self.value: self.formatting = [{"type": "space", "value": " "}] return Node.from_fst(baron.parse("print >>%s" % string)[0]["destination"], parent=parent, on_attribute=on_attribute) elif string and self.value: self.formatting = [{"type": "space", "value": " "}] result = Node.from_fst(baron.parse("print >>%s" % string)[0]["destination"], parent=parent, on_attribute=on_attribute) if len(self.value.node_list) and not self.value.node_list[0].type == "comma": self.value = NodeList([Node.from_fst({"type": "comma", "second_formatting": [{"type": "space", "value": " "}], "first_formatting": []}, parent=parent, on_attribute=on_attribute)]) + self.value return result elif self.value.node_list and self.value.node_list[0].type == "comma": self.formatting = [{"type": "space", "value": " "}] self.value = self.value.node_list[1:] else: self.formatting = [] else: raise Exception("Unhandled case") def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": if string: self.formatting = [{"type": "space", "value": " "}] fst = baron.parse(("print %s" if not self.destination else "print >>a, %s") % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: self.formatting = [] if not string and not self.destination else [{"type": "space", "value": " "}] return NodeList() else: raise Exception("Unhandled case") def __setattr__(self, key, value): super(PrintNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class RaiseNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": self.first_formatting = [{"type": "space", "value": " "}] if string else [] if string: return Node.from_fst(baron.parse("raise %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "instance": if not self.value: raise Exception("Can't set instance if there is not value") if string: self.third_formatting = [{"type": "space", "value": " "}] if not self.comma_or_from: self.comma_or_from = "," return Node.from_fst(baron.parse("raise a, %s" % string)[0]["instance"], parent=parent, on_attribute=on_attribute) elif on_attribute == "traceback": if not self.instance: raise Exception("Can't set traceback if there is not instance") if string: self.fifth_formatting = [{"type": "space", "value": " "}] return Node.from_fst(baron.parse("raise a, b, %s" % string)[0]["traceback"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def __setattr__(self, key, value): current = getattr(self, "comma_or_from", None) super(RaiseNode, self).__setattr__(key, value) if key == "comma_or_from": if value == current: return if value == "from": self.second_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="second_formatting", parent=self)] self.third_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="third_formatting", parent=self)] elif value == ",": self.second_formatting = [] self.third_formatting = [Node.from_fst({"type": "space", "value": " "}, on_attribute="third_formatting", parent=self)] class RawStringNode(Node, LiteralyEvaluable): pass class RightParenthesisNode(Node): pass class ReprNode(Node): def _string_to_node_list(self, string, parent, on_attribute): fst = baron.parse("`%s`" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) def __setattr__(self, key, value): super(ReprNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class ReturnNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": self.formatting = [{"type": "space", "value": " "}] if string else [] if string: return Node.from_fst(baron.parse("return %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class SemicolonNode(Node): pass class SetNode(Node): def _string_to_node_list(self, string, parent, on_attribute): fst = baron.parse("{%s}" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) def __setattr__(self, key, value): super(SetNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class SetComprehensionNode(Node): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "generators": fst = baron.parse("{x %s}" % string)[0]["generators"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") def _string_to_node(self, string, parent, on_attribute): if on_attribute == "result": return Node.from_fst(baron.parse("{%s for x in x}" % string)[0]["result"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class SliceNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "lower": if string: return Node.from_fst(baron.parse("a[%s:]" % string)[0]["value"][1]["value"]["lower"], parent=parent, on_attribute=on_attribute) elif on_attribute == "upper": if string: return Node.from_fst(baron.parse("a[:%s]" % string)[0]["value"][1]["value"]["upper"], parent=parent, on_attribute=on_attribute) elif on_attribute == "step": self.has_two_colons = bool(string) if string: return Node.from_fst(baron.parse("a[::%s]" % string)[0]["value"][1]["value"]["step"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class SpaceNode(Node): def __repr__(self): return repr(baron.dumps([self.fst()])) class StandaloneAnnotationNode(Node): pass class StarExpressionNode(Node): pass class StarNode(Node): pass class StringNode(Node, LiteralyEvaluable): pass class StringChainNode(Node, LiteralyEvaluable): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "value": fst = baron.parse("a = %s" % string)[0]["value"]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class TernaryOperatorNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "first": return Node.from_fst(baron.parse("%s if b else c" % string)[0]["first"], parent=parent, on_attribute=on_attribute) elif on_attribute == "second": return Node.from_fst(baron.parse("a if b else %s" % string)[0]["second"], parent=parent, on_attribute=on_attribute) elif on_attribute == "value": return Node.from_fst(baron.parse("a if %s else s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class TryNode(ElseAttributeNode): @property def next_intuitive(self): if self.excepts: return self.excepts[0] if self.finally_: return self.finally_ raise Exception("incoherent state of TryNode, try should be followed either by except or finally") def _string_to_node_list(self, string, parent, on_attribute): if on_attribute != "excepts": return super(TryNode, self)._string_to_node_list(string, parent=parent, on_attribute=on_attribute) clean_string = re.sub("^ *\n", "", string) if "\n" in string else string indentation = len(re.search("^ *", clean_string).group()) if indentation: string = "\n".join(map(lambda x: x[indentation:], string.split("\n"))) string = string.rstrip() string += "\n" if self.next and self.on_attribute == "root": string += "\n\n" elif self.next: string += "\n" result = NodeList.from_fst(baron.parse("try:\n pass\n%sfinally:\n pass" % string)[0]["excepts"], parent=parent, on_attribute=on_attribute) if self.indentation: result.increase_indentation(len(self.indentation)) if self._get_last_member_to_clean().type != "except": # assume that this is an endl node, this might break result[-1].value.node_list[-1].indent = self.indentation elif self.next: result[-1].value.node_list[-1].indent = self.indentation return result def _string_to_node(self, string, parent, on_attribute): if on_attribute == "finally": return self._convert_input_to_one_indented_member("finally", string, parent, on_attribute) else: return super(TryNode, self)._string_to_node(string, parent=parent, on_attribute=on_attribute) def __setattr__(self, name, value): if name == "finally_": name = "finally" return super(TryNode, self).__setattr__(name, value) def _get_last_member_to_clean(self): if self.finally_: return self.finally_ if self.else_: return self.else_ return self.excepts[-1] def __getattr__(self, name): if name == "finally_": return getattr(self, "finally") return super(TryNode, self).__getattr__(name) class TupleNode(Node, LiteralyEvaluable): def _string_to_node_list(self, string, parent, on_attribute): fst = baron.parse("(%s)" % string)[0]["value"] # I assume that I've got an AssociativeParenthesisNode here instead of a tuple # because string is only one single element if not isinstance(fst, list): fst = baron.parse("(%s,)" % string)[0]["value"] return NodeList.from_fst(fst, parent=parent, on_attribute=on_attribute) def __setattr__(self, key, value): super(TupleNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, CommaProxyList): setattr(self, "value", CommaProxyList(self.value)) class UnicodeStringNode(Node, LiteralyEvaluable): pass class UnicodeRawStringNode(Node, LiteralyEvaluable): pass class UnitaryOperatorNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "target": return Node.from_fst(baron.parse("-%s" % string)[0]["target"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class YieldNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": self.formatting = [{"type": "space", "value": " "}] if string else [] if string: return Node.from_fst(baron.parse("yield %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class YieldFromNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("yield from %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class YieldAtomNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": self.second_formatting = [{"type": "space", "value": " "}] if string else [] if string: return Node.from_fst(baron.parse("yield %s" % string)[0]["value"], parent=parent, on_attribute=on_attribute) else: raise Exception("Unhandled case") class WhileNode(ElseAttributeNode): @property def next_intuitive(self): if self.else_: return self.else_ return self.next def _string_to_node(self, string, parent, on_attribute): if on_attribute == "test": return Node.from_fst(baron.parse("while %s: pass" % string)[0]["test"], parent=parent, on_attribute=on_attribute) else: return super(WhileNode, self)._string_to_node(string, parent, on_attribute) def __setattr__(self, key, value): super(WhileNode, self).__setattr__(key, value) if key == "value" and not isinstance(self.value, LineProxyList): setattr(self, "value", LineProxyList(self.value, on_attribute="value")) class WithContextItemNode(Node): def _string_to_node(self, string, parent, on_attribute): if on_attribute == "value": return Node.from_fst(baron.parse("with %s: pass" % string)[0]["contexts"][0]["value"], parent=parent, on_attribute=on_attribute) elif on_attribute == "as": if string: self.first_formatting = [{"type": "space", "value": " "}] self.second_formatting = [{"type": "space", "value": " "}] return Node.from_fst(baron.parse("with a as %s: pass" % string)[0]["contexts"][0]["as"], parent=parent, on_attribute=on_attribute) else: self.first_formatting = [] self.second_formatting = [] return "" else: raise Exception("Unhandled case") def __getattr__(self, name): if name == "as_": return getattr(self, "as") return super(WithContextItemNode, self).__getattr__(name) def __setattr__(self, name, value): if name == "as_": name = "as" return super(WithContextItemNode, self).__setattr__(name, value) class WithNode(CodeBlockNode): def _string_to_node_list(self, string, parent, on_attribute): if on_attribute == "contexts": return NodeList.from_fst(baron.parse("with %s: pass" % string)[0]["contexts"], parent=parent, on_attribute=on_attribute) else: return super(WithNode, self)._string_to_node_list(string, parent, on_attribute) def __setattr__(self, key, value): super(WithNode, self).__setattr__(key, value) if key == "contexts" and not isinstance(self.contexts, CommaProxyList): setattr(self, "contexts", CommaProxyList(self.contexts, on_attribute="contexts")) if key in ("async", "async_") and getattr(self, "async") and hasattr(self, "async_formatting") and not self.async_formatting: self.async_formatting = " " redbaron-0.9.2/redbaron/private_config.py000066400000000000000000000004731344351435400204750ustar00rootroot00000000000000from __future__ import absolute_import import redbaron def runned_from_ipython(): # for testing if redbaron.force_ipython_behavior: return True if not redbaron.ipython_behavior: return False try: __IPYTHON__ return True except NameError: return False redbaron-0.9.2/redbaron/redbaron.py000066400000000000000000000051731344351435400172740ustar00rootroot00000000000000from __future__ import absolute_import import baron import baron.path from baron.utils import string_instance from redbaron import nodes, base_nodes # TODO # LineProxyList: handle comments # should a 'pass' be put if the list would be empty? # add blank line arround in certain cases? Like arround function/class at first level and second level # expected behavior on append when blank lines at the end of the block (-> append before blank lines) # more explicit display for blank lines in line proxy .help() # if node_list is modified, the proxy list won't update itself -> bugs # CommaProxyList indented # "change formatting style" # the "\n" after the "[{(" is hold by the parent node, this parent node should have a method to tell the CommaProxyList where this is # FIXME: doc others.rst line 244 # FIXME: __setattr__ is broken on formatting # XXX # should .next and .previous behavior should be changed to drop formatting # nodes? I guess so if I consider that with enough abstraction the user will # never have to play with formatting node unless he wants to class RedBaron(base_nodes.GenericNodesUtils, base_nodes.LineProxyList): def __init__(self, source_code): self.first_blank_lines = [] # XXX might need changes if isinstance(source_code, string_instance): self.node_list = base_nodes.NodeList.from_fst(baron.parse(source_code), parent=self, on_attribute="root") self.middle_separator = nodes.DotNode({"type": "endl", "formatting": [], "value": "\n", "indent": ""}) self.data = [] previous = None for i in self.node_list: if i.type != "endl": self.data.append([i, []]) elif previous and previous.type == "endl": self.data.append([previous, []]) elif previous is None and i.type == "endl": self.data.append([i, []]) elif self.data: self.data[-1][1].append(i) previous = i self.node_list.parent = None else: # Might be init from same object, or slice super(RedBaron, self).__init__(source_code) self.on_attribute = None self.parent = None def _convert_input_to_node_object(self, value, parent, on_attribute): return base_nodes.GenericNodesUtils._convert_input_to_node_object(self, value, self, "root") def _convert_input_to_node_object_list(self, value, parent, on_attribute): return base_nodes.GenericNodesUtils._convert_input_to_node_object_list(self, value, self, "root") redbaron-0.9.2/redbaron/syntax_highlight.py000066400000000000000000000033611344351435400210520ustar00rootroot00000000000000HAS_PYGMENTS = True try: import pygments except ImportError: HAS_PYGMENTS = False if HAS_PYGMENTS: from pygments.token import Comment, Text, String, Keyword, Name, Operator, Generic from pygments.lexer import RegexLexer, bygroups from pygments import highlight from pygments.lexers import PythonLexer from pygments.formatters import Terminal256Formatter, HtmlFormatter class HelpLexer(RegexLexer): name = 'Lexer for RedBaron .help() method output' tokens = { 'root': [ (r'\x1b(.*?)\[(\d+)m', Generic), # avoid escaping twice, see issue#180 (r"#.*$", Comment), (r"('([^\\']|\\.)*'|\"([^\\\"]|\\.)*\")", String), (r"(None|False|True)", String), (r'(\*)( \w+Node)', bygroups(Operator, Keyword)), (r'\w+Node', Name.Function), (r'(\*|=|->|\(|\)|\.\.\.)', Operator), (r'\w+', Text), (r'\s+', Text), ] } def help_highlight(string): return highlight(string, HelpLexer(), Terminal256Formatter(style='monokai')) def python_highlight(string): return highlight(string, PythonLexer(encoding="Utf-8"), Terminal256Formatter(style='monokai', encoding="Utf-8")) def python_html_highlight(string): return highlight(string, PythonLexer(encode="Utf-8"), HtmlFormatter(noclasses=True, encoding="UTf-8")) else: def help_highlight(string): return string.encode("Utf-8") def python_highlight(string): return string.encode("Utf-8") def python_html_highlight(string): return string.encode("Utf-8") redbaron-0.9.2/redbaron/utils.py000066400000000000000000000027561344351435400166440ustar00rootroot00000000000000from __future__ import absolute_import import os import re import sys from baron.utils import python_version import redbaron if python_version == 3: from io import StringIO else: from StringIO import StringIO def baron_type_to_redbaron_classname(baron_type): return "".join(map(lambda x: x.capitalize(), baron_type.split("_"))) + "Node" def redbaron_classname_to_baron_type(name): name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name.replace("Node", "")) return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower() def log(string, *args): if redbaron.DEBUG: sys.stdout.write("%s\n" % (string % args)) def in_a_shell(): # the isinstance here is for building sphinx doc if redbaron.DEBUG or isinstance(sys.stdout, StringIO): return True try: if hasattr(sys.stdout, 'fileno') and os.isatty(sys.stdout.fileno()): return True except Exception: # someone is doing strange things with stdout (eg: bpython or ipython notebook) return False return False def indent(block_of_text, indentation): """ Helper function to indent a block of text. Take a block of text, an indentation string and return the indented block. """ return "\n".join(map(lambda x: indentation + x, block_of_text.split("\n"))) def truncate(text, n): if n < 5 or len(text) <= n: return text truncated = list(text) truncated[-3:-1] = ['.', '.', '.'] del truncated[n-4 : -4] return "".join(truncated) redbaron-0.9.2/redbaron_pylint_plugin.py000066400000000000000000000036151344351435400204540ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ pylint helper plugin for validating RedBaron Handles special cases like RedBaron's magic use of imports to create missing nodes. Taken in part from https://bitbucket.org/pfctdayelise/pylint-pytest/downloads """ from astroid import MANAGER from astroid import nodes from astroid.builder import AstroidBuilder PYTEST_STUB = """ class marker(object): def __getattr__(self, name): return name mark = marker() """ PLACEHOLDER_CLASS_STUB = """ class {name}(object): def __init__(self, *args, **kwargs): pass """ NODE_PLACEHOLDER_CLASS_STUB = """ class {name}(object): def __init__(self, node, *args, **kwargs): pass """ def pytest_transform(module): """ Let pylint know the pytest module """ pytest = ('pytest', 'py.test') if module.name not in pytest: return astroid_mgr = AstroidBuilder(MANAGER) fake = astroid_mgr.string_build(PYTEST_STUB) for complex_stub in ('mark',): module.locals[complex_stub] = fake.locals[complex_stub] for stub in ('skip', 'xfail', 'fixture', 'test', 'raises'): text = PLACEHOLDER_CLASS_STUB.format(name=stub) fake = astroid_mgr.string_build(text) module.locals[stub] = fake.locals[stub] def redbaron_transform(module): """ Let pylint know the redbaron module """ if module.name != 'redbaron': return astroid_mgr = AstroidBuilder(MANAGER) fake = astroid_mgr.string_build(PYTEST_STUB) for stub in ('NameNode', 'PassNode'): text = NODE_PLACEHOLDER_CLASS_STUB.format(name=stub) fake = astroid_mgr.string_build(text) module.locals[stub] = fake.locals[stub] def register(_): """ Registers this plugin to pylint pylint calls this function when loading """ MANAGER.register_transform(nodes.Module, pytest_transform) MANAGER.register_transform(nodes.Module, redbaron_transform) redbaron-0.9.2/requirements-docs.txt000066400000000000000000000001761344351435400175420ustar00rootroot00000000000000git+https://github.com/Psycojoker/baron.git git+https://github.com/Psycojoker/redbaron.git pygments ipython matplotlib sphinx redbaron-0.9.2/requirements.txt000066400000000000000000000000261344351435400166060ustar00rootroot00000000000000baron pytest pygments redbaron-0.9.2/setup.cfg000066400000000000000000000000271344351435400151440ustar00rootroot00000000000000[wheel] universal = 1 redbaron-0.9.2/setup.py000066400000000000000000000031071344351435400150370ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- from setuptools import setup try: from pypandoc import convert_file read_md = lambda f: convert_file(f, 'rst') except ImportError: print("warning: pypandoc module not found, could not convert Markdown to RST") read_md = lambda f: open(f, 'r').read() setup(name='redbaron', version='0.9.2', description='Abstraction on top of baron, a FST for python to make writing refactoring code a realistic task', author='Laurent Peuch', long_description=read_md("README.md") + "\n\n" + open("CHANGELOG", "r").read(), author_email='cortex@worlddomination.be', url='https://github.com/PyCQA/redbaron', install_requires=['baron>=0.7'], extras_require={ "notebook": ["pygments"], }, license='lgplv3+', packages=["redbaron"], keywords='baron fst ast refactoring', classifiers=['Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 'Topic :: Software Development', 'Topic :: Software Development :: Code Generators', 'Topic :: Software Development :: Libraries', ], ) redbaron-0.9.2/test_doc.sh000066400000000000000000000003661344351435400154710ustar00rootroot00000000000000#!/bin/bash set +x if [ "$(python --version | grep 2.6)" ] then exit 0 fi pip install -r requirements-docs.txt cd docs rm -rf _build result=$(make html 2>&1) echo $result if [ "$(echo $result | grep 'Exception in')" ] then exit 1 fi redbaron-0.9.2/tests/000077500000000000000000000000001344351435400144665ustar00rootroot00000000000000redbaron-0.9.2/tests/__init__.py000066400000000000000000000000001344351435400165650ustar00rootroot00000000000000redbaron-0.9.2/tests/test_at.py000066400000000000000000000014371344351435400165100ustar00rootroot00000000000000# -*- coding:Utf-8 -*- """Test for at method""" import redbaron from redbaron import RedBaron redbaron.DEBUG = True red = RedBaron("""\ class Foo(object): def __init__(self): self.a = None def bar(self): for x in range(5): yield self.a + x setup(name='redbaron', version='0.6.1') """) def test_at(): assert red.at(1) is red.class_ assert red.at(2) is red.find_all('DefNode')[0] assert red.at(3) is red.find('AssignmentNode') assert red.at(4) is red.find_all('DefNode')[1] assert red.at(5) is red.find('ForNode') assert red.at(6) is red.find('YieldNode') assert red.at(7) is red.find_all('EndlNode')[6] assert red.at(8) is red.find_all('AtomTrailersNode')[3] assert red.at(9) is red.find_all('CallArgumentNode')[2] redbaron-0.9.2/tests/test_bounding_box.py000066400000000000000000000127271344351435400205650ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the bounding_box feature """ import pytest # pylint: disable=redefined-outer-name from redbaron import RedBaron @pytest.fixture def red(): return RedBaron("""\ @deco def a(c, d): b = c + d """) fst = red() bounding_boxes = [ (((1, 1), (4, 0)), ((1, 1), (4, 0)), fst), (((1, 1), (4, 0)), ((1, 1), (4, 0)), fst.def_), (((1, 1), (2, 0)), ((1, 1), (2, 0)), fst.def_.decorators.node_list), (((1, 1), (1, 5)), ((1, 1), (1, 5)), fst.def_.decorators.node_list[0]), (((1, 2), (1, 5)), ((1, 1), (1, 4)), fst.def_.decorators.node_list[0].value), (((1, 2), (1, 5)), ((1, 1), (1, 4)), fst.def_.decorators.node_list[0].value.value), (((1, 2), (1, 5)), ((1, 1), (1, 4)), fst.def_.decorators.node_list[0].value.value[0]), (((1, 6), (2, 0)), ((1, 1), (2, 0)), fst.def_.decorators.node_list[1]), (((2, 4), (2, 4)), ((1, 1), (1, 1)), fst.def_.first_formatting), (((2, 4), (2, 4)), ((1, 1), (1, 1)), fst.def_.first_formatting[0]), (((2, 6), (2, 5)), ((1, 1), (1, 0)), fst.def_.second_formatting), (((2, 7), (2, 6)), ((1, 1), (1, 0)), fst.def_.third_formatting), (((2, 7), (2, 10)), ((1, 1), (1, 4)), fst.def_.arguments), (((2, 7), (2, 7)), ((1, 1), (1, 1)), fst.def_.arguments.node_list[0]), (((2, 8), (2, 9)), ((1, 1), (1, 2)), fst.def_.arguments.node_list[1]), (((2, 10), (2, 10)), ((1, 1), (1, 1)), fst.def_.arguments.node_list[2]), (((2, 11), (2, 10)), ((1, 1), (1, 0)), fst.def_.fourth_formatting), (((2, 12), (2, 11)), ((1, 1), (1, 0)), fst.def_.fifth_formatting), (((2, 13), (2, 12)), ((1, 1), (1, 0)), fst.def_.sixth_formatting), (((2, 13), (4, 0)), ((1, 1), (3, 0)), fst.def_.value), (((2, 13), (3, 4)), ((1, 1), (2, 4)), fst.def_.value.node_list[0]), (((3, 5), (3, 13)), ((1, 1), (1, 9)), fst.def_.value.node_list[1]), (((3, 5), (3, 5)), ((1, 1), (1, 1)), fst.def_.value.node_list[1].target), (((3, 9), (3, 13)), ((1, 1), (1, 5)), fst.def_.value.node_list[1].value), (((3, 9), (3, 9)), ((1, 1), (1, 1)), fst.def_.value.node_list[1].value.first), (((3, 13), (3, 13)), ((1, 1), (1, 1)), fst.def_.value.node_list[1].value.second), (((3, 14), (4, 0)), ((1, 1), (2, 0)), fst.def_.value.node_list[2]) ] @pytest.fixture(params=bounding_boxes) def bounding_box_fixture(request): return request.param def test_bounding_box(bounding_box_fixture): absolute_bounding_box, bounding_box, node = bounding_box_fixture assert bounding_box == node.bounding_box assert absolute_bounding_box == node.absolute_bounding_box def test_bounding_box_of_attribute(red): assert ((2, 1), (2, 3)) == red.def_.get_absolute_bounding_box_of_attribute("def") def test_bounding_box_of_attribute_no_attribute(red): with pytest.raises(KeyError): red.def_.get_absolute_bounding_box_of_attribute("xxx") def test_bounding_box_of_attribute_no_index(red): with pytest.raises(IndexError): red.get_absolute_bounding_box_of_attribute(1) with pytest.raises(IndexError): red.get_absolute_bounding_box_of_attribute(-1) def test_bounding_box_empty(): red = RedBaron("a()") assert ((1, 3), (1, 2)) == red.atomtrailers.value[1].value.absolute_bounding_box RED = RedBaron("""\ class A: ''' Class docstring Class description ''' attrA = [ a, b, c, d] def a(self): ''' Function a docstring Function description ''' pass attrB = valB @myDecorator def b(self): ''' Function b docstring Function description ''' pass attrC = [ a, b, c, d]\ """) def test_bounding_box_with_proxy_list(): assert ((1, 1), (32, 0)) == RED.absolute_bounding_box assert ((1, 1), (32, 0)) == RED.class_.absolute_bounding_box assert ((2, 5), (5, 7)) == RED.class_.value[0].absolute_bounding_box assert ((6, 5), (9, 17)) == RED.class_.value[1].absolute_bounding_box assert ((10, 1), (11, 4)) == RED.class_.value[2].absolute_bounding_box assert ((11, 5), (18, 4)) == RED.class_.value[3].absolute_bounding_box assert ((18, 5), (18, 16)) == RED.class_.value[4].absolute_bounding_box assert ((19, 1), (20, 4)) == RED.class_.value[5].absolute_bounding_box assert ((20, 5), (28, 4)) == RED.class_.value[6].absolute_bounding_box assert ((28, 5), (31, 17)) == RED.class_.value[7].absolute_bounding_box with pytest.raises(IndexError): RED.class_.value[8] def test_bounding_box_of_attribute_with_proxy_list(): assert ((1, 1), (32, 0)) == RED.absolute_bounding_box assert ((1, 1), (32, 0)) == RED.class_.absolute_bounding_box assert ((2, 5), (5, 7)) == RED.class_.value.get_absolute_bounding_box_of_attribute(0) assert ((6, 5), (9, 17)) == RED.class_.value.get_absolute_bounding_box_of_attribute(1) assert ((10, 1), (11, 4)) == RED.class_.value.get_absolute_bounding_box_of_attribute(2) assert ((11, 5), (18, 4)) == RED.class_.value.get_absolute_bounding_box_of_attribute(3) assert ((18, 5), (18, 16)) == RED.class_.value.get_absolute_bounding_box_of_attribute(4) assert ((19, 1), (20, 4)) == RED.class_.value.get_absolute_bounding_box_of_attribute(5) assert ((20, 5), (28, 4)) == RED.class_.value.get_absolute_bounding_box_of_attribute(6) assert ((28, 5), (31, 17)) == RED.class_.value.get_absolute_bounding_box_of_attribute(7) with pytest.raises(IndexError): RED.class_.value.get_absolute_bounding_box_of_attribute(8) redbaron-0.9.2/tests/test_helpers.py000066400000000000000000000113051344351435400175410ustar00rootroot00000000000000import sys from redbaron import RedBaron def test_import_modules(): red = RedBaron("import a, b.c, d.e as f") assert red[0].modules() == ['a', 'b.c', 'd.e'] def test_import_names(): red = RedBaron("import a, b.c, d.e as f") assert red[0].names() == ['a', 'b.c', 'f'] def test_from_import_names(): red = RedBaron("from qsd import a, c, e as f") assert red[0].names() == ['a', 'c', 'f'] def test_from_import_names_parenthesis(): red = RedBaron("from qsd import (a, c, e as f)") assert red[0].names() == ['a', 'c', 'f'] def test_from_import_modules(): red = RedBaron("from qsd import a, c, e as f") assert red[0].modules() == ['a', 'c', 'e'] def test_from_import_full_path_names(): red = RedBaron("from qsd import a, c, e as f") assert red[0].full_path_names() == ['qsd.a', 'qsd.c', 'qsd.f'] def test_from_import_full_path_names_parenthesis(): red = RedBaron("from qsd import (a, c, e as f)") assert red[0].full_path_names() == ['qsd.a', 'qsd.c', 'qsd.f'] def test_from_import_full_path_modules(): red = RedBaron("from qsd import a, c, e as f") assert red[0].full_path_modules() == ['qsd.a', 'qsd.c', 'qsd.e'] def test_from_import_full_path_modules_parenthesis(): red = RedBaron("from qsd import (a, c, e as f)") assert red[0].full_path_modules() == ['qsd.a', 'qsd.c', 'qsd.e'] def test_to_python_int_node(): red = RedBaron("1") assert red[0].value == "1" assert red[0].to_python() == 1 def test_to_python_float_node(): red = RedBaron("1.1") assert red[0].value == "1.1" assert red[0].to_python() == 1.1 def test_to_python_octa_node(): red = RedBaron("0011") assert red[0].value == "0011" if sys.version < '3': assert red[0].to_python() == 9 def test_to_python_hexa_node(): red = RedBaron("0xFF") assert red[0].value == "0xFF" assert red[0].to_python() == 255 def test_to_python_long_node(): # long doesn't exist anymore in python3 if sys.version < '3': red = RedBaron("10L") assert red[0].value == "10L" assert red[0].to_python() == long("10L") def test_to_python_binary_node(): red = RedBaron("0b101010101") assert red[0].value == "0b101010101" assert red[0].to_python() == 341 def test_to_python_float_exponant_node(): red = RedBaron("1.1e1") assert red[0].value == "1.1e1" assert red[0].to_python() == 11.0 def test_to_python_string_node(): red = RedBaron("'pouet'") assert red[0].value == "'pouet'" assert red[0].to_python() == 'pouet' def test_to_python_string_chain_node(): red = RedBaron("'pouet' 'pop'") assert red[0].dumps() == "'pouet' 'pop'" assert red[0].to_python() == 'pouetpop' def test_to_python_raw_string_node(): red = RedBaron("r'pouet'") assert red[0].value == "r'pouet'" assert red[0].to_python() == r'pouet' def test_to_python_binary_string_node(): red = RedBaron("b'pouet'") assert red[0].value == "b'pouet'" assert red[0].to_python() == b'pouet' def test_to_python_unicode_string_node(): red = RedBaron("u'pouet'") assert red[0].value == "u'pouet'" assert red[0].to_python() == u'pouet' def test_to_python_binary_raw_string_node(): if sys.version < '3': red = RedBaron("br'pouet'") assert red[0].value == "br'pouet'" assert red[0].to_python() == eval("br'pouet'") def test_to_python_unicode_raw_string_node(): if sys.version < '3': red = RedBaron("ur'pouet'") assert red[0].value == "ur'pouet'" assert red[0].to_python() == eval("ur'pouet'") def test_to_python_tuple_node(): red = RedBaron("(1, 2, 3)") assert red[0].to_python() == (1, 2, 3) def test_to_python_list_node(): red = RedBaron("[1, 2, 3]") assert red[0].to_python() == [1, 2, 3] def test_to_python_dict_node(): red = RedBaron("{1: 2, 2: 3, 3: 4}") assert red[0].to_python() == {1: 2, 2: 3, 3: 4} def test_to_python_name_node_boolean(): red = RedBaron("False") assert red[0].to_python() == False red = RedBaron("True") assert red[0].to_python() == True def test_to_python_name_node_None(): red = RedBaron("None") assert red[0].to_python() == None def test_to_python_with_spacing(): red = RedBaron("{ 'pouet': d}") assert red.find("string").to_python() == 'pouet' def test_to_python_name_node_otherwise_raise(): red = RedBaron("foo") try: red[0].to_python() except Exception as e: message = 'to_python method only works on numbers, strings, list, tuple, dict, boolean and None. (using ast.literal_eval). The piece of code that you are trying to convert contains an illegale value, for example, a variable.' assert e.message == message assert e.args == (message,) redbaron-0.9.2/tests/test_indentation.py000066400000000000000000000020701344351435400204120ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the rendering feature """ from redbaron import RedBaron test_indent_code = """ def a(): # plop 1 + 2 if caramba: plop pouf """ def test_increase_indentation(): red = RedBaron(test_indent_code) red.increase_indentation(4) indented_code = "\n" + "\n".join(map(lambda x: " " + x, test_indent_code.split("\n")[1:-2])) + "\n\n" assert red.dumps() == indented_code def test_decrease_indentation(): red = RedBaron(test_indent_code) red.decrease_indentation(4) indented_code = "\ndef a():\n" + "\n".join(map(lambda x: x[4:], test_indent_code.split("\n")[2:-2])) + "\n\n" assert red.dumps() == indented_code def test_increase_indentation_single_node(): red = RedBaron(test_indent_code) red.if_.value[0].increase_indentation(3) assert len(red.if_.value[0].indentation) == 8 + 3 def test_decrease_indentation_single_node(): red = RedBaron(test_indent_code) red.if_.value[0].decrease_indentation(3) assert len(red.if_.value[0].indentation) == 5 redbaron-0.9.2/tests/test_initial_parsing.py000066400000000000000000000776151344351435400212730ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests initial parsing through the RedBaron() base function """ import pytest import baron import re import redbaron from baron.render import nodes_rendering_order from redbaron import (RedBaron, NameNode, EndlNode, IntNode, AssignmentNode, PassNode, NodeList, CommaNode, DotNode, CallNode, CommaProxyList, baron_type_to_redbaron_classname) def test_all_class_are_declared(): for node_type in nodes_rendering_order: class_name = baron_type_to_redbaron_classname(node_type) assert hasattr(redbaron, class_name) def test_empty(): RedBaron("") def test_is_list(): assert [] == list(RedBaron("")) def test_name(): red = RedBaron("a\n") assert len(red.node_list) == 2 assert isinstance(red.node_list[0], NameNode) assert isinstance(red.node_list[1], EndlNode) assert red[0].value == "a" def test_int(): red = RedBaron("1\n") assert isinstance(red[0], IntNode) assert red[0].value == "1" def test_assign(): red = RedBaron("a = 2") assert isinstance(red[0], AssignmentNode) assert isinstance(red[0].value, IntNode) assert red[0].value.value == "2" assert isinstance(red[0].target, NameNode) assert red[0].target.value == "a" def test_binary_operator(): red = RedBaron("z + 42") assert red[0].value == "+" assert isinstance(red[0].first, NameNode) assert red[0].first.value == "z" assert isinstance(red[0].second, IntNode) assert red[0].second.value == "42" red = RedBaron("z - 42") assert red[0].value == "-" assert isinstance(red[0].first, NameNode) assert red[0].first.value == "z" assert isinstance(red[0].second, IntNode) assert red[0].second.value == "42" def test_pass(): red = RedBaron("pass") assert isinstance(red[0], PassNode) def test_copy(): red = RedBaron("a") name = red[0] assert name.value == name.copy().value assert name is not name.copy() def test_dumps(): some_code = "ax + (z * 4)" red = RedBaron(some_code) assert some_code == red.dumps() def test_fst(): some_code = "ax + (z * 4)" red = RedBaron(some_code) assert baron.parse(some_code) == red.fst() def test_get_helpers(): red = RedBaron("a") assert red[0]._get_helpers() == [] red = RedBaron("import a") assert red[0]._get_helpers() == ['modules', 'names'] def test_help_is_not_crashing1(): some_code = "ax + (z * 4)" red = RedBaron(some_code) red.help() red[0].help() red.help(5) red[0].help(5) red.help(True) red[0].help(True) def test_help_is_not_crashing2(): some_code = "a(b)" red = RedBaron(some_code) red.help() red[0].help() red.help(5) red[0].help(5) red.help(True) red[0].help(True) def test_help_is_not_crashing3(): some_code = "a(b, c)" red = RedBaron(some_code) red.help() red[0].help() red.help(5) red[0].help(5) red.help(True) red[0].help(True) def test_help_is_not_crashing4(): some_code = "a(b)" red = RedBaron(some_code) red[0].call.append("c") red.help() red[0].help() red.help(5) red[0].help(5) red.help(True) red[0].help(True) def test_assign_on_string_value(): some_code = "ax + (z * 4)" red = RedBaron(some_code) binop = red[0] assert binop.first.value == "ax" binop.first.value = "pouet" assert binop.first.value == "pouet" def test_assign_on_object_value(): some_code = "ax + (z * 4)" red = RedBaron(some_code) binop = red[0] assert binop.first.value == "ax" binop.first = "pouet" # will be parsed as a name assert binop.first.value == "pouet" assert binop.first.type == "name" binop.first = "42" # will be parsed as a int assert binop.first.value == "42" assert binop.first.type == "int" def test_assign_on_object_value_fst(): some_code = "ax + (z * 4)" red = RedBaron(some_code) binop = red[0] binop.first = {"type": "name", "value": "pouet"} assert binop.first.value == "pouet" assert binop.first.type == "name" def test_generate_helpers(): red = RedBaron("def a(): pass") assert set(red[0].generate_identifiers()) == set([ "funcdef", "funcdef_", "defnode", "def", "def_" ]) def test_assign_node_list(): red = RedBaron("[1, 2, 3]") l = red[0] l.value = "pouet" assert l.value[0].value == "pouet" assert l.value[0].type == "name" assert isinstance(l.value.node_list, NodeList) assert isinstance(l.value, CommaProxyList) l.value = ["pouet"] assert l.value[0].value == "pouet" assert l.value[0].type == "name" assert isinstance(l.value.node_list, NodeList) assert isinstance(l.value, CommaProxyList) def test_assign_node_list_fst(): red = RedBaron("[1, 2, 3]") l = red[0] l.value = {"type": "name", "value": "pouet"} assert l.value[0].value == "pouet" assert l.value[0].type == "name" assert isinstance(l.value.node_list, NodeList) assert isinstance(l.value, CommaProxyList) l.value = [{"type": "name", "value": "pouet"}] assert l.value[0].value == "pouet" assert l.value[0].type == "name" assert isinstance(l.value.node_list, NodeList) assert isinstance(l.value, CommaProxyList) def test_assign_node_list_mixed(): red = RedBaron("[1, 2, 3]") l = red[0] l.value = ["plop", {"type": "comma", "first_formatting": [], "second_formatting": []}, {"type": "name", "value": "pouet"}] assert l.value[0].value == "plop" assert l.value[0].type == "name" assert l.value.node_list[1].type == "comma" assert l.value[1].value == "pouet" assert l.value[1].type == "name" assert l.value.node_list[2].value == "pouet" assert l.value.node_list[2].type == "name" assert isinstance(l.value.node_list, NodeList) assert isinstance(l.value, CommaProxyList) def test_parent(): red = RedBaron("a = 1 + caramba") assert red.parent is None assert red[0].parent is red assert red[0].on_attribute == "root" assert red[0].target.parent is red[0] assert red[0].target.on_attribute == "target" assert red[0].value.parent is red[0] assert red[0].value.on_attribute == "value" assert red[0].value.first.parent is red[0].value assert red[0].value.first.on_attribute == "first" assert red[0].value.second.parent is red[0].value assert red[0].value.second.on_attribute == "second" red = RedBaron("[1, 2, 3]") assert red.parent is None assert red[0].parent is red assert [x.parent for x in red[0].value.node_list] == [red[0]] * 5 assert [x.on_attribute for x in red[0].value.node_list] == ["value"] * 5 assert [x.parent for x in red[0].value] == [red[0]] * 3 assert [x.on_attribute for x in red[0].value] == ["value"] * 3 def test_parent_copy(): red = RedBaron("a = 1 + caramba") assert red[0].value.copy().parent is None def test_parent_assign(): red = RedBaron("a = 1 + caramba") assert red[0].target.parent is red[0] red[0].target = "plop" assert red[0].target.parent is red[0] assert red[0].target.on_attribute == "target" red[0].target = {"type": "name", "value": "pouet"} assert red[0].target.parent is red[0] assert red[0].target.on_attribute == "target" red[0].target = NameNode({"type": "name", "value": "pouet"}) assert red[0].target.parent is red[0] assert red[0].target.on_attribute == "target" red = RedBaron("[1, 2, 3]") assert [x.parent for x in red[0].value] == [red[0]] * 3 assert [x.on_attribute for x in red[0].value] == ["value"] * 3 assert [x.parent for x in red[0].value.node_list] == [red[0]] * 5 assert [x.on_attribute for x in red[0].value.node_list] == ["value"] * 5 red[0].value = "pouet" assert [x.parent for x in red[0].value] == [red[0]] assert [x.on_attribute for x in red[0].value] == ["value"] red[0].value = ["pouet"] assert [x.parent for x in red[0].value] == [red[0]] assert [x.on_attribute for x in red[0].value] == ["value"] red[0].value = {"type": "name", "value": "plop"} assert [x.parent for x in red[0].value] == [red[0]] assert [x.on_attribute for x in red[0].value] == ["value"] red[0].value = [{"type": "name", "value": "plop"}] assert [x.parent for x in red[0].value] == [red[0]] assert [x.on_attribute for x in red[0].value] == ["value"] red[0].value = NameNode({"type": "name", "value": "pouet"}) assert isinstance(red[0].value.node_list, NodeList) assert isinstance(red[0].value, CommaProxyList) assert [x.parent for x in red[0].value] == [red[0]] assert [x.on_attribute for x in red[0].value] == ["value"] red[0].value = [NameNode({"type": "name", "value": "pouet"})] assert [x.parent for x in red[0].value] == [red[0]] assert [x.on_attribute for x in red[0].value] == ["value"] def test_node_next(): red = RedBaron("[1, 2, 3]") assert red.next is None assert red[0].next is None inner = red[0].value.node_list assert inner[0].next == inner[1] assert inner[1].next == inner[2] assert inner[2].next == inner[3] assert inner[3].next == inner[4] assert inner[4].next is None def test_node_next_recursive(): red = RedBaron("def a():\n b = 1\ndef c():\n d = 1") assert red[1].next is None assert red[1].next_recursive is None first, second = red.find_all('def') assert first.next is second inner = first.value.node_list assert inner[0].next == inner[1] assert inner[0].next_recursive == inner[1] assert inner[1].next == inner[2] assert inner[1].next_recursive == inner[2] assert inner[2].next == None assert inner[2].next_recursive == second def test_node_previous(): red = RedBaron("[1, 2, 3]") assert red.previous is None assert red[0].previous is None inner = red[0].value.node_list assert inner[4].previous == inner[3] assert inner[3].previous == inner[2] assert inner[2].previous == inner[1] assert inner[1].previous == inner[0] assert inner[0].previous is None def test_node_previous_recursive(): red = RedBaron("def a():\n b = 1\ndef c():\n d = 1") assert red[0].previous is None assert red[0].previous_recursive is None first, second = red.find_all('def') assert second.previous is first inner = second.value.node_list assert inner[2].previous == inner[1] assert inner[2].previous_recursive == inner[1] assert inner[1].previous == inner[0] assert inner[1].previous_recursive == inner[0] assert inner[0].previous == None assert inner[0].previous_recursive == first def test_node_next_generator(): red = RedBaron("[1, 2, 3]") assert list(red[0].value[2].next_generator()) == list(red[0].value[3:]) def test_node_previous_generator(): red = RedBaron("[1, 2, 3]") assert list(red[0].value.node_list[2].previous_generator()) \ == list(reversed(red[0].value.node_list[:2])) def test_node_next_intuitive(): red = RedBaron("[1, 2, 3]") assert red[0].value[0].next_intuitive == red[0].node_list[1] def test_node_previous_intuitive(): red = RedBaron("[1, 2, 3]") assert red[0].value[1].previous_intuitive == red[0].node_list[1] def test_node_if_ifelseblock_next_intuitive(): red = RedBaron("if a:\n pass") assert red.if_.next_intuitive is None red = RedBaron("if a:\n pass\nelse:\n pass") assert red.if_.next_intuitive is red.else_ red = RedBaron("if a:\n pass\nchocolat") assert red.if_.next_intuitive is red.find("name", "chocolat") def test_node_if_ifelseblock_previous_intuitive(): red = RedBaron("if a:\n pass") assert red.if_.previous_intuitive is None red = RedBaron("chocolat\nif a:\n pass") assert red.if_.previous_intuitive is red.find("endl") red = RedBaron("pouet\nif a:\n pass\nelif a:\n pass\nelse:\n pass") assert red.else_.previous_intuitive is red.elif_ assert red.if_.previous is None def test_node_elif_ifelseblock_next_intuitive(): red = RedBaron("if a:\n pass\nelif a:\n pass") assert red.elif_.next_intuitive is None red = RedBaron("if a:\n pass\nelif a:\n pass\nelse:\n pass") assert red.elif_.next_intuitive is red.else_ red = RedBaron("if a:\n pass\nelif a:\n pass\nchocolat") assert red.elif_.next_intuitive is red.find("name", "chocolat") def test_node_elif_elifelseblock_previous_intuitive(): # not a very interesting test red = RedBaron("if a:\n pass\nelif a:\n pass") assert red.elif_.previous_intuitive is red.if_ red = RedBaron("chocolat\nif a:\n pass\nelif a:\n pass") assert red.elif_.previous_intuitive is red.if_ def test_node_else_ifelseblock_next_intuitive(): red = RedBaron("if a:\n pass\nelse:\n pass") assert red.else_.next_intuitive is None red = RedBaron("if a:\n pass\nelse:\n pass\nchocolat") assert red.else_.next_intuitive is red.find("name", "chocolat") def test_node_else_elseelseblock_previous_intuitive(): red = RedBaron("if a:\n pass\nelse:\n pass") assert red.else_.previous_intuitive is red.if_ red = RedBaron("chocolat\nif a:\n pass\nelse:\n pass") assert red.else_.previous_intuitive is red.if_ def test_node_if_ifelseblock_outside_next_intuitive(): red = RedBaron("outside\nif a:\n pass") assert red.endl_.next_intuitive is red.if_ def test_node_if_ifelseblock_outside_previous_intuitive(): red = RedBaron("if a:\n pass\nafter") assert red.find("name", "after").previous_intuitive is red.if_ def test_node_if_ifelseblock_outside_previous_intuitive_elif(): red = RedBaron("if a:\n pass\nelif a: pass\nafter") assert red.find("name", "after").previous_intuitive is red.elif_ def test_node_if_ifelseblock_outside_previous_intuitive_elif_elif(): red = RedBaron("if a:\n pass\nelif a: pass\nelif a: pass\nafter") assert red.find("name", "after").previous_intuitive is red("elif")[1] def test_node_if_ifelseblock_outside_previous_intuitive_else(): red = RedBaron("if a:\n pass\nelse: pass\nafter") assert red.find("name", "after").previous_intuitive is red.else_ def test_node_trynode_next_intuitive_except(): red = RedBaron("try: pass\nexcept: pass") assert red.try_.next_intuitive is red.except_ def test_node_trynode_next_intuitive_except_else(): red = RedBaron("try: pass\nexcept: pass\nelse: pass") assert red.try_.next_intuitive is red.except_ def test_node_trynode_next_intuitive_except_else_finally(): red = RedBaron("try: pass\nexcept: pass\nelse: pass\nfinally: pass") assert red.try_.next_intuitive is red.except_ def test_node_trynode_next_intuitive_finally(): red = RedBaron("try: pass\nfinally: pass") assert red.try_.next_intuitive is red.finally_ def test_node_exceptnode_next_intuitive_except(): red = RedBaron("try: pass\nexcept: pass") assert red.except_.next_intuitive is None def test_node_exceptnode_next_intuitive_except_after(): red = RedBaron("try: pass\nexcept: pass\nafter") assert red.except_.next_intuitive is red[1] def test_node_exceptnode_next_intuitive_except_except(): red = RedBaron("try: pass\nexcept: pass\nexcept: pass") assert red.except_.next_intuitive is red("except")[1] def test_node_exceptnode_next_intuitive_else(): red = RedBaron("try: pass\nexcept: pass\nelse: pass") assert red.except_.next_intuitive is red.else_ def test_node_exceptnode_next_intuitive_except_else(): red = RedBaron("try: pass\nexcept: pass\nexcept: pass\nelse: pass") assert red.except_.next_intuitive is red("except")[1] def test_node_exceptnode_next_intuitive_finally(): red = RedBaron("try: pass\nexcept: pass\nfinally: pass") assert red.except_.next_intuitive is red.finally_ def test_node_exceptnode_next_intuitive_else_finally(): red = RedBaron("try: pass\nexcept: pass\nelse: pass\nfinally: pass") assert red.except_.next_intuitive is red.else_ def test_node_exceptnode_previous_intuitive_except(): red = RedBaron("try: pass\nexcept: pass") assert red.except_.previous_intuitive is red.try_ def test_node_exceptnode_previous_intuitive_except_except(): red = RedBaron("try: pass\nexcept: pass\nexcept: pass") assert red("except")[1].previous_intuitive is red.except_ def test_node_try_elsenode_next_intuitive(): red = RedBaron("try: pass\nexcept: pass\nelse: pass") assert red.else_.next_intuitive is None def test_node_try_elsenode_next_intuitive_after(): red = RedBaron("try: pass\nexcept: pass\nelse: pass\nafter") assert red.else_.next_intuitive is red.find("name", "after") def test_node_try_elsenode_next_intuitive_finally(): red = RedBaron("try: pass\nexcept: pass\nelse: pass\nfinally: pass") assert red.else_.next_intuitive is red.finally_ def test_node_try_elsenode_previous_intuitive(): red = RedBaron("try: pass\nexcept: pass\nelse: pass") assert red.else_.previous_intuitive is red.except_ def test_node_finally_next_intuitive(): red = RedBaron("try: pass\nexcept: pass\nfinally: pass") assert red.finally_.next_intuitive is None def test_node_finally_next_intuitive_after(): red = RedBaron("try: pass\nexcept: pass\nfinally: pass\nafter") assert red.finally_.next_intuitive is red.find("name", "after") def test_node_finally_previous_intuitive(): red = RedBaron("try: pass\nfinally: pass\n") assert red.finally_.previous_intuitive is red.try_ def test_node_finally_previous_intuitive_except(): red = RedBaron("try: pass\nexcept: pass\nfinally: pass\n") assert red.finally_.previous_intuitive is red.except_ def test_node_finally_previous_intuitive_excepts(): red = RedBaron("try: pass\nexcept: pass\nexcept: pass\nfinally: pass\n") assert red.finally_.previous_intuitive is red("except")[-1] def test_node_finally_previous_intuitive_except_else(): red = RedBaron("try: pass\nexcept: pass\nelse: pass\nfinally: pass\n") assert red.finally_.previous_intuitive is red.else_ def test_node_trynode_outside_next_intuitive(): red = RedBaron("outside\ntry:\n pass\nexcept: pass") assert red.endl_.next_intuitive is red.try_ def test_node_trynode_outside_previous_intuitive_except(): red = RedBaron("try:\n pass\nexcept: pass\nafter") assert red.find("name", "after").previous_intuitive is red.except_ def test_node_trynode_outside_previous_intuitive_except_except(): red = RedBaron("try:\n pass\nexcept: pass\nexcept: pass\nafter") assert red.find("name", "after").previous_intuitive is red("except")[1] def test_node_trynode_outside_previous_intuitive_except_except_else(): red = RedBaron("try:\n pass\nexcept: pass\nexcept: pass\nelse: pass\nafter") assert red.find("name", "after").previous_intuitive is red.else_ def test_node_trynode_outside_previous_intuitive_except_except_else_finally(): red = RedBaron("try:\n pass\nexcept: pass\nexcept: pass\nelse: pass\nfinally: pass\nafter") assert red.find("name", "after").previous_intuitive is red.finally_ def test_node_trynode_outside_previous_intuitive_except_except_finally(): red = RedBaron("try:\n pass\nexcept: pass\nexcept: pass\nfinally: pass\nafter") assert red.find("name", "after").previous_intuitive is red.finally_ def test_node_trynode_outside_previous_intuitive_finally(): red = RedBaron("try:\n pass\nfinally: pass\nafter") assert red.find("name", "after").previous_intuitive is red.finally_ def test_node_for_next_intuitive(): red = RedBaron("for a in b: pass") assert red.for_.next_intuitive is None def test_node_for_next_intuitive_after(): red = RedBaron("for a in b: pass\nafter") assert red.for_.next_intuitive is red[1] def test_node_for_next_intuitive_else_after(): red = RedBaron("for a in b: pass\nelse: pass\nafter") assert red.for_.next_intuitive is red.else_ def test_node_for_previous_intuitive_after(): red = RedBaron("before\nfor a in b: pass\nafter") assert red.for_.previous_intuitive is red.endl_ def test_node_for_else_next_intuitive(): red = RedBaron("for a in b: pass\nelse: pass") assert red.else_.next_intuitive is None def test_node_for_else_next_intuitive_after(): red = RedBaron("for a in b: pass\nelse: pass\nafter") assert red.else_.next_intuitive is red[1] def test_node_for_else_previous_intuitive_after(): red = RedBaron("before\nfor a in b: pass\nelse: pass\nafter") assert red.else_.previous_intuitive is red.for_ def test_node_fornode_outside_next_intuitive(): red = RedBaron("outside\nfor a in b:\n pass\n") assert red.endl_.next_intuitive is red.for_ def test_node_fornode_outside_next_intuitive_else(): red = RedBaron("outside\nfor a in b:\n pass\nelse: pass") assert red.endl_.next_intuitive is red.for_ def test_node_fornode_outside_previous_intuitive(): red = RedBaron("for a in b:\n pass\nafter") assert red.find("name", "after").previous_intuitive is red.for_ def test_node_fornode_outside_previous_intuitive_else(): red = RedBaron("for a in b:\n pass\nelse: pass\nafter") assert red.find("name", "after").previous_intuitive is red.else_ def test_node_while_next_intuitive(): red = RedBaron("while a: pass") assert red.while_.next_intuitive is None def test_node_while_next_intuitive_after(): red = RedBaron("while a: pass\nafter") assert red.while_.next_intuitive is red[1] def test_node_while_next_intuitive_else_after(): red = RedBaron("while a: pass\nelse: pass\nafter") assert red.while_.next_intuitive is red.else_ def test_node_while_previous_intuitive_after(): red = RedBaron("before\nwhile a: pass\nafter") assert red.while_.previous_intuitive is red.endl_ def test_node_while_else_next_intuitive(): red = RedBaron("while a in b: pass\nelse: pass") assert red.else_.next_intuitive is None def test_node_while_else_next_intuitive_after(): red = RedBaron("while a in b: pass\nelse: pass\nafter") assert red.else_.next_intuitive is red[1] def test_node_while_else_previous_intuitive_after(): red = RedBaron("bewhilee\nwhile a in b: pass\nelse: pass\nafter") assert red.else_.previous_intuitive is red.while_ def test_node_whilenode_outside_next_intuitive(): red = RedBaron("outside\nwhile a:\n pass\n") assert red.endl_.next_intuitive is red.while_ def test_node_whilenode_outside_next_intuitive_else(): red = RedBaron("outside\nwhile a:\n pass\nelse: pass") assert red.endl_.next_intuitive is red.while_ def test_node_whilenode_outside_previous_intuitive(): red = RedBaron("while a:\n pass\nafter") assert red.find("name", "after").previous_intuitive is red.while_ def test_node_whilenode_outside_previous_intuitive_else(): red = RedBaron("while a:\n pass\nelse: pass\nafter") assert red.find("name", "after").previous_intuitive is red.else_ def test_map(): red = RedBaron("[1, 2, 3]") assert red('int').map(lambda x: x.value) == NodeList(["1", "2", "3"]) def test_apply(): red = RedBaron("a()\nb()") assert red('call').apply(lambda x: str(x)) == red('call') def test_filter(): red = RedBaron("[1, 2, 3]") assert red[0].value.filter(lambda x: x.type != "comma") == red('int') assert isinstance(red[0].value.filter(lambda x: x.type != "comma"), NodeList) def test_indent_root(): red = RedBaron("pouet") assert red[0].indentation == "" red = RedBaron("pouet\nplop\npop") assert [x.indentation for x in red.node_list] == ["", "", "", "", ""] assert [x.get_indentation_node() for x in red.node_list] \ == [None, None, red.node_list[1], None, red.node_list[3]] def test_in_while(): red = RedBaron("while a:\n pass\n") node_list = red[0].value.node_list assert node_list[-2].indentation == " " assert node_list[-1].indentation == "" assert node_list[-2].get_indentation_node() is red[0].value.node_list[-3] assert node_list[-1].get_indentation_node() is None assert node_list[-3].get_indentation_node() is None assert node_list[-2].indentation_node_is_direct() def test_one_line_while(): red = RedBaron("while a: pass\n") assert red[0].value.node_list[0].indentation == "" assert red[0].value.node_list[-2].get_indentation_node() is None assert not red[0].value.node_list[-2].indentation_node_is_direct() def test_inner_node(): red = RedBaron("while a: pass\n") assert red[0].test.indentation == "" assert red[0].value.node_list[-2].get_indentation_node() is None assert not red[0].value.node_list[-2].indentation_node_is_direct() def test_indentation_endl(): red = RedBaron("a.b.c.d") assert red[0].value[-3].indentation == "" assert red[0].value[-2].get_indentation_node() is None assert not red[0].value[-2].indentation_node_is_direct() def test_filtered_endl(): red = RedBaron("while a:\n pass\n") assert red[0].value.node_list.filtered() == (red[0].value.node_list[-2],) def test_filtered_comma(): red = RedBaron("[1, 2, 3]") assert red[0].value.filtered() \ == tuple(red[0].value.filter(lambda x: not isinstance(x, CommaNode))) def test_filtered_dot(): red = RedBaron("a.b.c(d)") assert red[0].value.filtered() \ == tuple(red[0].value.filter(lambda x: not isinstance(x, DotNode))) SOME_DATA_FOR_TEST = """\ def plop(): def a(): with b as c: d = e """ def test_parent_find_empty(): red = RedBaron("a") assert red[0].parent_find('a') is None def test_parent_find_direct(): red = RedBaron(SOME_DATA_FOR_TEST) target = red.assignment.target assert target.parent_find('with') is red.with_ def test_parent_find_two_levels(): red = RedBaron(SOME_DATA_FOR_TEST) target = red.assignment.target assert target.parent_find('def') is red.find('def', name='a') def test_parent_find_two_levels_options(): red = RedBaron(SOME_DATA_FOR_TEST) target = red.assignment.target assert target.parent_find('def', name='plop') is red.def_ assert target.parent_find('def', name='dont_exist') is None def test_find_empty(): red = RedBaron("") assert red.find("stuff") is None assert red.find("something_else") is None assert red.find("something_else", useless="pouet") is None with pytest.raises(AttributeError): red.will_raises def test_find(): red = RedBaron("def a(): b = c") assert red.find("name") is red[0].value[0].target assert red.find("name", value="c") is red[0].value[0].value assert red.name is red[0].value[0].target def test_find_other_properties(): red = RedBaron("def a(): b = c") assert red.def_ == red[0] assert red.funcdef == red[0] assert red.funcdef_ == red[0] def test_find_case_insensitive(): red = RedBaron("a") assert red.find("NameNode") is red[0] assert red.find("NaMeNoDe") is red[0] assert red.find("namenode") is red[0] def test_find_kwarg_lambda(): red = RedBaron("[1, 2, 3, 4]") assert red.find("int", value=lambda x: int(x) % 2 == 0) == red("int")[1] assert red("int", value=lambda x: int(x) % 2 == 0) == red('int')[1::2] def test_find_lambda(): red = RedBaron("[1, 2, 3, 4]") assert red.find("int", lambda x: int(x.value) % 2 == 0) == red('int')[1] assert red("int", lambda x: int(x.value) % 2 == 0) == red('int')[1::2] def test_find_kwarg_regex_instance(): red = RedBaron("plop\npop\npouf\nabcd") assert red.find("name", value=re.compile("^po")) == red[1] def test_find_all_kwarg_regex_instance(): red = RedBaron("plop\npop\npouf\nabcd") assert red("name", value=re.compile("^po")) \ == red("name", value=lambda x: x.startswith("po")) def test_find_kwarg_regex_syntaxe(): red = RedBaron("plop\npop\npouf\nabcd") assert red.find("name", value="re:^po") == red[1] def test_find_all_kwarg_regex_syntaxe(): red = RedBaron("plop\npop\npouf\nabcd") assert red("name", value="re:^po") \ == red("name", value=lambda x: x.startswith("po")) def test_find_kwarg_glob_syntaxe(): red = RedBaron("plop\npop\npouf\nabcd") assert red.find("name", value="g:po*") == red[1] def test_find_all_kwarg_glob_syntaxe(): red = RedBaron("plop\npop\npouf\nabcd") assert red("name", value="g:po*") \ == red("name", value=lambda x: x.startswith("po")) def test_identifier_find_kwarg_lambda(): red = RedBaron("stuff\n1\n'string'") assert red.find(lambda x: x in ["name", "int"]) == red[0] assert red(lambda x: x in ["name", "int"]) == red[:2].node_list def test_identifier_find_kwarg_regex_instance(): red = RedBaron("stuff\n1\n'string'") assert red.find(re.compile("^[ni]")) == red[0] def test_identifier_find_all_kwarg_regex_instance(): red = RedBaron("stuff\n1\n'string'") assert red(re.compile("^[ni]")) == red[:2].node_list def test_identifier_find_kwarg_regex_syntaxe(): red = RedBaron("stuff\n1\n'string'") assert red.find("re:^[ni]") == red[0] def test_identifier_find_all_kwarg_regex_syntaxe(): red = RedBaron("stuff\n1\n'string'") assert red("re:^[ni]") == red[:2].node_list def test_identifier_find_kwarg_glob_syntaxe(): red = RedBaron("stuff\n1\n'string'") assert red.find("g:s*") == red[-1] def test_identifier_find_all_kwarg_glob_syntaxe(): red = RedBaron("stuff\n1\n'string'") assert red("g:s*") == red[2:].node_list def test_find_kwarg_list_tuple_instance(): red = RedBaron("pouet\n'string'\n1") assert red.find("name", value=["pouet", 1]) == red[0] assert red.find("name", value=("pouet", 1)) == red[0] def test_find_all_kwarg_list_tuple_instance(): red = RedBaron("pouet\nstuff\n1") assert red("name", value=["pouet", "stuff"]) == red[:2].node_list assert red("name", value=("pouet", "stuff")) == red[:2].node_list def test_identifier_find_kwarg_list_tuple_instance(): red = RedBaron("pouet\n'string'\n1") assert red.find(["name", "string"]) == red[0] assert red.find(("name", "string")) == red[0] def test_identifier_find_all_kwarg_list_tuple_instance(): red = RedBaron("pouet\n'string'\n1") assert red(["name", "string"]) == red[:2].node_list assert red(("name", "string")) == red[:2].node_list def test_default_test_value_find(): red = RedBaron("badger\nmushroom\nsnake") assert red.find("name", "snake") == red.find("name", value="snake") def test_default_test_value_find_all(): red = RedBaron("badger\nmushroom\nsnake") assert red("name", "snake") == red("name", value="snake") def test_find_comment_node(): red = RedBaron("def f():\n #a\n pass\n#b") assert red.find('comment').value == '#a' def test_find_all_comment_nodes(): red = RedBaron("def f():\n #a\n pass\n#b") assert [x.value for x in red.find_all('comment')] == ['#a', '#b'] def test_default_test_value_find_def(): red = RedBaron("def a(): pass\ndef b(): pass") assert red.find("def", "b") == red.find("def", name="b") def test_default_test_value_find_class(): red = RedBaron("class a(): pass\nclass b(): pass") assert red.find("class", "b") == red.find("class", name="b") def test_copy_correct_isntance(): red = RedBaron("a()") assert isinstance(red[0].value[1].copy(), CallNode) def test_indentation_no_parent(): red = RedBaron("a") assert red[0].copy().get_indentation_node() is None assert red[0].copy().indentation == '' def test_replace(): red = RedBaron("1 + 2") red[0].replace("caramba") assert isinstance(red[0], NameNode) assert red.dumps() == "caramba" def test_insert_before(): red = RedBaron("a = 1\nprint(pouet)\n") red.print_.insert_before("chocolat") assert red.dumps() == "a = 1\nchocolat\nprint(pouet)\n" def test_insert_after(): red = RedBaron("a = 1\nprint(pouet)\n") red.print_.insert_after("chocolat") assert red.dumps() == "a = 1\nprint(pouet)\nchocolat\n" def test_insert_before_offset(): red = RedBaron("a = 1\nprint(pouet)\n") red.print_.insert_before("chocolat", offset=1) assert red.dumps() == "chocolat\na = 1\nprint(pouet)\n" def test_insert_after_offset(): red = RedBaron("a = 1\nprint(pouet)\n") red[0].insert_after("chocolat", offset=1) assert red.dumps() == "a = 1\nprint(pouet)\nchocolat\n" def test_kwargs_only_marker_node(): RedBaron("def a(*): pass") redbaron-0.9.2/tests/test_insert.py000066400000000000000000000204211344351435400174020ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the code insertion features """ import pytest # pylint: disable=redefined-outer-name import redbaron from redbaron import RedBaron # (alekum): switch off debug mode, to reproduce a bug with __repr__ implicit recursion redbaron.DEBUG = False def assert_with_indent(left, right): # Replace is not strictly necessary but shows indents assert left.dumps().replace(' ', '.') == right.replace(' ', '.') @pytest.fixture def red_A_B(): return RedBaron("""\ class A: pass class B: pass """) @pytest.fixture def red_nested(): return RedBaron("""\ class A: class B: pass """) def test_insert_with_class_0(red_A_B): red_A_B.insert(0, "a = 1") assert_with_indent(red_A_B, """\ a = 1 class A: pass class B: pass """) def test_insert_with_class_1(red_A_B): red_A_B.insert(1, "a = 1") assert_with_indent(red_A_B, """\ class A: pass a = 1 class B: pass """) def test_insert_with_class_2(red_A_B): red_A_B.insert(2, "a = 1") assert_with_indent(red_A_B, """\ class A: pass class B: pass a = 1 """) def test_insert_with_class_3(red_A_B): red_A_B.insert(3, "a = 1") assert_with_indent(red_A_B, """\ class A: pass class B: pass a = 1 """) def test_insert_class_with_class_0(red_A_B): red_A_B.insert(0, "class C:\n pass") assert_with_indent(red_A_B, """\ class C: pass class A: pass class B: pass """) def test_insert_class_with_class_1(red_A_B): red_A_B.insert(1, "class C:\n pass") assert_with_indent(red_A_B, """\ class A: pass class C: pass class B: pass """) def test_insert_class_with_class_2(red_A_B): red_A_B.insert(2, "class C:\n pass") assert_with_indent(red_A_B, """\ class A: pass class B: pass class C: pass """) def test_insert_class_with_class_3(red_A_B): red_A_B.insert(3, "class C:\n pass") assert_with_indent(red_A_B, """\ class A: pass class B: pass class C: pass """) def test_insert_with_nested_class_0(red_nested): red_nested.insert(0, "a = 1") assert_with_indent(red_nested, """\ a = 1 class A: class B: pass """) def test_insert_with_nested_class_1(red_nested): red_nested.insert(1, "a = 1") assert_with_indent(red_nested, """\ class A: class B: pass a = 1 """) def test_insert_inside_nested_class_0(red_nested): red_nested[0].insert(0, "a = 1") assert_with_indent(red_nested, """\ class A: a = 1 class B: pass """) def test_insert_inside_nested_class_1(red_nested): red_nested[0].insert(1, "a = 1") assert_with_indent(red_nested, """\ class A: class B: pass a = 1 """) def test_insert_inside_nested_class_2(red_nested): red_nested[0].insert(0, "def a(self):\n pass") assert_with_indent(red_nested, """\ class A: def a(self): pass class B: pass """) def test_insert_class_inside_nested_class_0(red_nested): red_nested[0].insert(0, "class C:\n pass") assert_with_indent(red_nested, """\ class A: class C: pass class B: pass """) def test_insert_class_inside_nested_class_1(red_nested): red_nested[0].insert(1, "class C:\n pass") assert_with_indent(red_nested, """\ class A: class B: pass class C: pass """) def test_append_inside_nested_class(red_nested): red_nested[0].append("a = 1") assert_with_indent(red_nested, """\ class A: class B: pass a = 1 """) def test_append_class_inside_nested_class(red_nested): red_nested[0].append("class C:\n pass") assert_with_indent(red_nested, """\ class A: class B: pass class C: pass """) def test_append_method_in_nested_with_methods(): red = RedBaron("""\ class A: def a(self): pass def b(self): pass """) red[0].append("def c(self):\n pass") assert_with_indent(red, """\ class A: def a(self): pass def b(self): pass def c(self): pass """) def test_append_class_in_nested_with_methods(): red = RedBaron("""\ class A: def a(self): pass def b(self): pass """) red[0].append("class C:\n pass") assert_with_indent(red, """\ class A: def a(self): pass def b(self): pass class C: pass """) def test_insert_line_in_def_with_if(): red = RedBaron("""\ def a(self, a): if a == 42: return True return False """) red.def_.insert(0, "a = 1") assert_with_indent(red, """\ def a(self, a): a = 1 if a == 42: return True return False """) def test_insert_nested_line_in_def_with_if(): red = RedBaron("""\ def a(self, a): if a == 42: return True return False """) red.def_.if_.insert(0, "a = 1") assert_with_indent(red, """\ def a(self, a): if a == 42: a = 1 return True return False """) def test_insert_newline_in_def_with_if(): red = RedBaron("""\ def a(self, a): if a == 42: return True return False """) red.def_.if_.insert(0, "a = 1") assert_with_indent(red, """\ def a(self, a): if a == 42: a = 1 return True return False """) red.def_.if_.insert(0, "") assert_with_indent(red, """\ def a(self, a): if a == 42: a = 1 return True return False """) red.def_.if_.insert(0, "b = 2") assert_with_indent(red, """\ def a(self, a): if a == 42: b = 2 a = 1 return True return False """) def test_append_newline_line_in_def_with_if(): red = RedBaron("""\ def a(self, a): if a == 42: return True return False """) red.def_.if_.append("") red.def_.if_.extend(["", "a = 1", ""]) assert_with_indent(red, """\ def a(self, a): if a == 42: return True a = 1 return False """) def test_extend_newline_and_def_in_def(): red = RedBaron("""\ def a(self, a): return False """) red.def_.extend(["", "def b():\n return True", ""]) red.def_.extend(["", "def b():\n return True", ""]) assert_with_indent(red, """\ def a(self, a): return False def b(): return True def b(): return True """) def test_append_newline_and_def_in_nested_class(): red = RedBaron("""\ class A: class B: pass """) # red.class_.class_.append("def b():\n return True") red.class_.class_.append("a = 1") assert_with_indent(red, """\ class A: class B: pass a = 1 """) def test_append_newline_and_def_in_class_with_space(): red = RedBaron("""\ def a(self, a): return False """) red.def_.append("") red.def_.append("class b:\n def c(self):\n return True") red.def_.append("") red.def_.append("class b:\n def c(self):\n return True") red.def_.append("") assert_with_indent(red, """\ def a(self, a): return False class b: def c(self): return True class b: def c(self): return True """) def test_append_newline_and_async_def_in_class_with_space(): red = RedBaron("""\ async def a(self, a): return False """) red.def_.append("") red.def_.append("class b:\n def c(self):\n return True") red.def_.append("") red.def_.append("class b:\n async def c(self):\n return True") red.def_.append("") assert_with_indent(red, """\ async def a(self, a): return False class b: def c(self): return True class b: async def c(self): return True """) def test_append_newline_and_def_in_class_without_space(): red = RedBaron("""\ def a(self, a): return False """) red.def_.append("") red.def_.append("class b:\n def c(self):\n return True") red.def_.append("class b:\n def c(self):\n return True") red.def_.append("") assert_with_indent(red, """\ def a(self, a): return False class b: def c(self): return True class b: def c(self): return True """) def test_dont_add_newlines_after_import(): red = RedBaron("import a\n\nimport b\n\npouet\n") red.append("plop") assert red.dumps() == "import a\n\nimport b\n\npouet\nplop\n" redbaron-0.9.2/tests/test_no_pygments.py000066400000000000000000000046551344351435400204530ustar00rootroot00000000000000import pytest import redbaron from redbaron import RedBaron, private_config class Test(): def setup_method(self, method): private_config.force_ipython_behavior = True private_config.DEBUG = True def teardown_method(self, method): private_config.force_ipython_behavior = False private_config.DEBUG = False def test_repr(self): RedBaron("a = 1").__str__() RedBaron("a = 1")[0].__str__() RedBaron("a = 1").__repr__() RedBaron("a = 1")[0].__repr__() def test_help(self): RedBaron("a = 1").help() RedBaron("a = 1")[0].help() def test_endl_html(self): RedBaron("a\n").node_list[-1]._repr_html_() def test_regression_repr(self): red = RedBaron("a = 1 + caramba") red[0].value.first.parent str(red[0].value.first.parent) class TestClassical(Test): def setup_method(self, method): pass def teardown_method(self, method): pass def test_highlight(capsys, monkeypatch): try: import pygments # noqa except ImportError: pytest.skip('missing pygments.') monkeypatch.setattr(redbaron, 'force_ipython_behavior', True) RedBaron("a = []").help() captured = capsys.readouterr() if tuple(map(int, pytest.__version__.split('.'))) <= (3, 3): out = captured[0] else: out = captured.out assert out == """\ 0 ----------------------------------------------------- \x1b[38;5;148mAssignmentNode\x1b[39m\x1b[38;5;197m(\x1b[39m\x1b[38;5;197m)\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;242m# identifiers: assign, assignment, assignment_, assignmentnode\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;15moperator\x1b[39m\x1b[38;5;197m=\x1b[39m\x1b[38;5;186m''\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;15mtarget\x1b[39m\x1b[38;5;15m \x1b[39m\x1b[38;5;197m->\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;148mNameNode\x1b[39m\x1b[38;5;197m(\x1b[39m\x1b[38;5;197m)\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;242m# identifiers: name, name_, namenode\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;15mvalue\x1b[39m\x1b[38;5;197m=\x1b[39m\x1b[38;5;186m'a'\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;15mannotation\x1b[39m\x1b[38;5;15m \x1b[39m\x1b[38;5;197m->\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;186mNone\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;15mvalue\x1b[39m\x1b[38;5;15m \x1b[39m\x1b[38;5;197m->\x1b[39m \x1b[38;5;15m \x1b[39m\x1b[38;5;15m[\x1b[39m\x1b[38;5;15m]\x1b[39m """ redbaron-0.9.2/tests/test_path.py000066400000000000000000000105151344351435400170350ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the path method """ import pytest # pylint: disable=redefined-outer-name from redbaron import RedBaron @pytest.fixture def red(): return RedBaron("""\ @deco def a(c, d): b = c + d """) def check_path(root, node, path): assert node.path() == path assert root.find_by_path(path) is node def test_path_root(red): check_path(red, red.node_list, []) def test_path_none(red): assert red.find_by_path([7]) is None def test_path_first_statement(red): check_path(red, red.def_, [0] ) def test_path_def__decorators(red): check_path(red, red.def_.decorators.node_list, [0, "decorators"] ) def test_path_decorators_first(red): check_path(red, red.def_.decorators.node_list[0], [0, "decorators", 0] ) def test_path_decorators_first_dotted_name(red): check_path(red, red.def_.decorators.node_list[0].value, [0, "decorators", 0, "value"] ) def test_path_decorators_first_dotted_name_value(red): check_path(red, red.def_.decorators.node_list[0].value.value, [0, "decorators", 0, "value", "value"] ) def test_path_decorators_first_dotted_name_value_first(red): check_path(red, red.def_.decorators.node_list[0].value.value[0], [0, "decorators", 0, "value", "value", 0] ) def test_path_decorators_endl(red): check_path(red, red.def_.decorators.node_list[1], [0, "decorators", 1] ) def test_path_first_formatting(red): check_path(red, red.def_.first_formatting, [0, "first_formatting"] ) def test_path_first_formatting_value(red): check_path(red, red.def_.first_formatting[0], [0, "first_formatting", 0] ) def test_path_second_formatting(red): check_path(red, red.def_.second_formatting, [0, "second_formatting"] ) def test_path_third_formatting(red): check_path(red, red.def_.third_formatting, [0, "third_formatting"] ) def test_path_arguments(red): check_path(red, red.def_.arguments.node_list, [0, "arguments"] ) def test_path_arguments_first(red): check_path(red, red.def_.arguments.node_list[0], [0, "arguments", 0] ) def test_path_arguments_comma(red): check_path(red, red.def_.arguments.node_list[1], [0, "arguments", 1] ) def test_path_arguments_second(red): check_path(red, red.def_.arguments.node_list[2], [0, "arguments", 2] ) def test_path_fourth_formatting(red): check_path(red, red.def_.fourth_formatting, [0, "fourth_formatting"] ) def test_path_fifth_formatting(red): check_path(red, red.def_.fifth_formatting, [0, "fifth_formatting"] ) def test_path_sixth_formatting(red): check_path(red, red.def_.sixth_formatting, [0, "sixth_formatting"] ) def test_path_value(red): check_path(red, red.def_.value.node_list, [0, "value"] ) def test_path_value_first_endl(red): check_path(red, red.def_.value.node_list[0], [0, "value", 0] ) def test_path_value_assignment(red): check_path(red, red.def_.value.node_list[1], [0, "value", 1] ) def test_path_value_assignment_target(red): check_path(red, red.def_.value.node_list[1].target, [0, "value", 1, "target"] ) def test_path_value_assignment_value(red): check_path(red, red.def_.value.node_list[1].value, [0, "value", 1, "value"] ) def test_path_value_assignment_value_first(red): check_path(red, red.def_.value.node_list[1].value.first, [0, "value", 1, "value", "first"] ) def test_path_value_assignment_value_second(red): check_path(red, red.def_.value.node_list[1].value.second, [0, "value", 1, "value", "second"] ) def test_path_value_second_endl(red): check_path(red, red.def_.value.node_list[2], [0, "value", 2] ) redbaron-0.9.2/tests/test_position.py000066400000000000000000000054711344351435400177520ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the position feature """ import pytest import redbaron # pylint: disable=redefined-outer-name from redbaron import RedBaron, Path redbaron.DEBUG = True fst = RedBaron("""\ @deco def a(c, d): b = c + d e = 1 """) positions = [ (fst.def_.decorators[0], [(1, 1)]), (fst.def_.decorators[0].value.value[0], [(1, 2), (1, 3), (1, 4), (1, 5)]), # How to get this one ? (2, 0) and (2, 1) does not work, see out of scope #(fst.def_.decorators[1], [(?, ?)]), (fst.def_, [(3, 1), (3, 2), (3, 3)]), (fst.def_.first_formatting[0], [(3, 4)]), (fst.def_, [(3, 5), (3, 6)]), (fst.def_.arguments.node_list[0].target, [(3, 7)]), (fst.def_.arguments.node_list[1], [(3, 8)]), (fst.def_.arguments.node_list[1].second_formatting[0], [(3, 9)]), (fst.def_.arguments.node_list[2].target, [(3, 10)]), (fst.def_, [(3, 11), (3, 12)]), (fst.def_.value.node_list[0], [(4, 1), (4, 2), (4, 3), (4, 4)]), (fst.def_.value.node_list[1].target, [(4, 5)]), (fst.def_.value.node_list[1].first_formatting[0], [(4, 6)]), (fst.def_.value.node_list[1], [(4, 7)]), (fst.def_.value.node_list[1].second_formatting[0], [(4, 8)]), (fst.def_.value.node_list[1].value.first, [(4, 9)]), (fst.def_.value.node_list[1].value.first_formatting[0], [(4, 10)]), (fst.def_.value.node_list[1].value, [(4, 11)]), (fst.def_.value.node_list[1].value.second_formatting[0], [(4, 12)]), (fst.def_.value.node_list[1].value.second, [(4, 13)]), (fst.def_.value.node_list[2], [(5, 1), (5, 2), (5, 3), (5, 4)]), (fst.def_.value.node_list[3].target, [(5, 5)]), (fst.def_.value.node_list[3].first_formatting[0], [(5, 6)]), (fst.def_.value.node_list[3], [(5, 7)]), (fst.def_.value.node_list[3].second_formatting[0], [(5, 8)]), (fst.def_.value.node_list[3].value, [(5, 9)]), # out of scope (fst, [(2, 0), (2, 1)]), ] @pytest.fixture(params=positions) def position_fixture(request): return request.param def test_find_by_position(position_fixture): node, positions = position_fixture for position in positions: assert node == fst.find_by_position(position) def test_path_str(): red = RedBaron("name") assert str(Path(red[0])) redbaron-0.9.2/tests/test_proxy_list.py000066400000000000000000001032451344351435400203200ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the rendering feature """ import redbaron from redbaron import (RedBaron, NodeList, CommaProxyList, DotProxyList, LineProxyList, DecoratorsLineProxyList) redbaron.DEBUG = True def test_comma_proxy_list_len_empty(): red = RedBaron("[]") comma_proxy_list = red[0].value assert len(comma_proxy_list) == 0 def test_comma_proxy_list_len_not_empty(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value assert len(comma_proxy_list) == 3 def test_comma_proxy_list_insert(): red = RedBaron("[]") comma_proxy_list = red[0].value comma_proxy_list.insert(0, "1") assert red.dumps() == "[1]" def test_comma_proxy_list_insert_2_at_top(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list.insert(0, "2") assert red.dumps() == "[2, 1]" def test_comma_proxy_list_insert_2(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list.insert(1, "2") assert red.dumps() == "[1, 2]" def test_comma_proxy_list_insert_2_middle(): red = RedBaron("[1, 3]") comma_proxy_list = red[0].value comma_proxy_list.insert(1, "2") assert red.dumps() == "[1, 2, 3]" def test_comma_proxy_list_append(): red = RedBaron("[]") comma_proxy_list = red[0].value comma_proxy_list.append("1") assert red.dumps() == "[1]" def test_comma_proxy_list_append_2(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list.append("2") assert red.dumps() == "[1, 2]" def test_comma_proxy_list_append_3(): red = RedBaron("[1, 2]") comma_proxy_list = red[0].value comma_proxy_list.append("3") assert red.dumps() == "[1, 2, 3]" def test_comma_proxy_list_pop(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list.pop(0) assert red.dumps() == "[]" def test_comma_proxy_list_pop_2_at_top(): red = RedBaron("[2, 1]") comma_proxy_list = red[0].value comma_proxy_list.pop(0) assert red.dumps() == "[1]" def test_comma_proxy_list_pop_2(): red = RedBaron("[1, 2]") comma_proxy_list = red[0].value comma_proxy_list.pop(1) assert red.dumps() == "[1]" def test_comma_proxy_list_pop_2_middle(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value comma_proxy_list.pop(1) assert red.dumps() == "[1, 3]" def test_comma_proxy_list_pop_no_index(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value comma_proxy_list.pop() assert red.dumps() == "[1, 2]" def test_comma_proxy_list_del(): red = RedBaron("[1]") comma_proxy_list = red[0].value del comma_proxy_list[0] assert red.dumps() == "[]" def test_comma_proxy_list_del_2_at_top(): red = RedBaron("[2, 1]") comma_proxy_list = red[0].value del comma_proxy_list[0] assert red.dumps() == "[1]" def test_comma_proxy_list_del_2(): red = RedBaron("[1, 2]") comma_proxy_list = red[0].value del comma_proxy_list[1] assert red.dumps() == "[1]" def test_comma_proxy_list_del_2_middle(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value del comma_proxy_list[1] assert red.dumps() == "[1, 3]" def test_comma_proxy_list_remove(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list.remove(comma_proxy_list[0]) assert red.dumps() == "[]" def test_comma_proxy_list_remove_2_at_top(): red = RedBaron("[2, 1]") comma_proxy_list = red[0].value comma_proxy_list.remove(comma_proxy_list[0]) assert red.dumps() == "[1]" def test_comma_proxy_list_remove_2(): red = RedBaron("[1, 2]") comma_proxy_list = red[0].value comma_proxy_list.remove(comma_proxy_list[1]) assert red.dumps() == "[1]" def test_comma_proxy_list_remove_2_middle(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value comma_proxy_list.remove(comma_proxy_list[1]) assert red.dumps() == "[1, 3]" def test_comma_proxy_list_set_item(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list[0] = "42" assert comma_proxy_list[0].type == "int" assert comma_proxy_list[0].value == "42" comma_proxy_list[0] = "plop" assert comma_proxy_list[0].type == "name" assert comma_proxy_list[0].value == "plop" assert red.dumps() == "[plop]" def test_comma_proxy_list_set_slice(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value comma_proxy_list[1:2] = ["42", "31", "23"] assert red.dumps() == "[1, 42, 31, 23, 3]" def test_comma_proxy_list_delslice(): red = RedBaron("[1, 2, 3, 4, 5, 6]") comma_proxy_list = red[0].value del comma_proxy_list[1:4] assert red.dumps() == "[1, 5, 6]" def test_comma_proxy_list_getslice(): red = RedBaron("[1, 2, 3, 4, 5, 6]") comma_proxy_list = red[0].value result = comma_proxy_list[1:2] expected_result = CommaProxyList(NodeList([comma_proxy_list[1]])) assert len(result) == len(expected_result) assert result[0] == expected_result[0] def test_comma_proxy_list_on_attribute_default_on_value(): # this is only for testing, the correct on_attribute is "value" red = RedBaron("[]") comma_proxy_list = red[0].value comma_proxy_list.append("1") assert comma_proxy_list[0].on_attribute == "value" def test_comma_proxy_list_on_attribute(): # this is only for testing, the correct on_attribute is "value" red = RedBaron("[]") comma_proxy_list = CommaProxyList(red[0].value.node_list, on_attribute="plop") comma_proxy_list.append("1") comma_proxy_list.append("1") assert comma_proxy_list[0].on_attribute == "plop" assert comma_proxy_list[1].on_attribute == "plop" assert comma_proxy_list.node_list[1].on_attribute == "plop" def test_comma_proxy_list_extend(): red = RedBaron("[]") comma_proxy_list = red[0].value comma_proxy_list.extend(["1"]) assert red.dumps() == "[1]" def test_comma_proxy_list_extend_2(): red = RedBaron("[1]") comma_proxy_list = red[0].value comma_proxy_list.extend(["2", "plop", "42"]) assert red.dumps() == "[1, 2, plop, 42]" def test_comma_proxy_list_extend_3(): red = RedBaron("[1, 2]") comma_proxy_list = red[0].value comma_proxy_list.extend(["3"]) assert red.dumps() == "[1, 2, 3]" def test_comma_proxy_list_dictionary(): red = RedBaron("{1: 2}") # no assert, will fail if parsing is not good red[0].value.append("3: 4") def test_comma_proxy_list_call(): red = RedBaron("a(b)") red[0].value[1].value.append("**kwargs") assert red.dumps() == "a(b, **kwargs)" def test_comma_proxy_list_class_inherit(): red = RedBaron("class A(): pass") red[0].inherit_from.append("plop") assert red.dumps() == "class A(plop): pass\n" def test_comma_proxy_list_from_import_targets(): red = RedBaron("from a.b import c as d") red[0].targets.append("e") red[0].targets.append("f as g") assert red.dumps() == "from a.b import c as d, e, f as g" def test_comma_proxy_list_def_arguments(): red = RedBaron("def a(b): pass") red[0].arguments.append("**kwargs") assert red.dumps() == "def a(b, **kwargs): pass\n" def test_comma_proxy_list_global_value(): red = RedBaron("global a") red[0].value.append("b") assert red.dumps() == "global a, b" def test_comma_proxy_list_nonlocal_value(): red = RedBaron("nonlocal a") red[0].value.append("b") assert red.dumps() == "nonlocal a, b" def test_comma_proxy_list_import_value(): red = RedBaron("import a") red[0].value.append("b.c.d as e") assert red.dumps() == "import a, b.c.d as e" def test_comma_proxy_list_lambda_arguments(): red = RedBaron("lambda x: 1 + 1") red[0].arguments.append("**kwargs") assert red.dumps() == "lambda x, **kwargs: 1 + 1" def test_comma_proxy_list_print_value(): red = RedBaron("print a") red[0].value.append("plop") assert red.dumps() == "print a, plop" def test_comma_proxy_list_repr_value(): red = RedBaron("`a`") red[0].value.append("plop") assert red.dumps() == "`a, plop`" def test_comma_proxy_list_with_contexts(): red = RedBaron("with a: pass") red[0].contexts.append("b as c") assert red.dumps() == "with a, b as c: pass\n" def test_comma_proxy_list_delegation_from_parent_node_on_value(): red = RedBaron("{1: 2}") # you don't need to do a .value here! red[0].append("3: 4") assert red.dumps() == "{1: 2, 3: 4}" def test_comma_proxy_list_delegation_from_parent_node_on_value_getitem(): red = RedBaron("{1: 2}") # you don't need to do a .value here! red[0][0] def test_comma_proxy_list_delegation_from_parent_node_on_value_setitem(): red = RedBaron("{1: 2}") # you don't need to do a .value here! red[0].append("3: 4") red[0][1] = "42: plop" assert red.dumps() == "{1: 2, 42: plop}" def test_comma_proxy_list_delegation_from_parent_node_on_value_insert(): red = RedBaron("[]") red[0].insert(0, "caramba") def test_comma_proxy_list_delegation_from_parent_node_on_value_extend(): red = RedBaron("[]") red[0].extend(["3", "42"]) def test_comma_proxy_list_delegation_from_parent_node_on_value_pop(): red = RedBaron("[42]") red[0].pop() def test_comma_proxy_list_delegation_from_parent_node_on_value_remove(): red = RedBaron("[pouet]") red[0].remove(red[0][0]) def test_comma_proxy_list_delegation_from_parent_node_on_value_index(): red = RedBaron("[42]") assert red[0].index(red[0][0]) == 0 def test_comma_proxy_list_delegation_from_parent_node_on_value_len(): red = RedBaron("[pouf]") assert len(red[0]) == 1 def test_comma_proxy_list_delegation_from_parent_node_on_value_del(): red = RedBaron("[abc, zop]") del red[0][0] assert len(red[0]) == 1 def test_comma_proxy_list_delegation_from_parent_node_on_value_contains(): red = RedBaron("[a, b, c]") assert red[0][0] in red[0] def test_comma_proxy_list_delegation_from_parent_node_on_value_iter(): red = RedBaron("[42]") assert [x.value for x in red[0]] == ["42"] def test_comma_proxy_list_delegation_from_parent_node_on_value_count(): red = RedBaron("[pouet]") assert red[0].count(red[0][0]) == 1 def test_comma_proxy_list_delegation_from_parent_node_on_value_setslice(): red = RedBaron("[]") red[0][1:1] = ["pouet", "plop"] def test_comma_proxy_list_delegation_from_parent_node_on_value_delslice(): red = RedBaron("[pif, paf, pouf]") del red[0][1:2] def test_comma_proxy_list_delegation_from_parent_node_on_value_getslice(): red = RedBaron("[plop, pouet]") assert isinstance(red[0][1:1], CommaProxyList) def test_dot_proxy_list_len(): red = RedBaron("a.b.c") assert len(red[0].value) == 3 def test_dot_proxy_list_insert(): red = RedBaron("a.b") red[0].value.insert(0, "c") assert red.dumps() == "c.a.b" def test_dot_proxy_list_insert_2_at_top(): red = RedBaron("a.b") red[0].value.insert(2, "c") assert red.dumps() == "a.b.c" def test_dot_proxy_list_append(): red = RedBaron("a.b") red[0].value.append("c") assert red.dumps() == "a.b.c" def test_dot_proxy_list_pop(): red = RedBaron("a.b.c.d") red[0].value.pop(0) assert red.dumps() == "b.c.d" def test_dot_proxy_list_pop_2(): red = RedBaron("a.b.c") red[0].value.pop(1) assert red.dumps() == "a.c" def test_dot_proxy_list_pop_no_index(): red = RedBaron("a.b.c") red[0].value.pop() assert red.dumps() == "a.b" def test_dot_proxy_list_del(): red = RedBaron("a.b.c") del red[0].value[0] assert red.dumps() == "b.c" def test_dot_proxy_list_del_2(): red = RedBaron("a.b.c") del red[0].value[1] assert red.dumps() == "a.c" def test_dot_proxy_list_remove(): red = RedBaron("a.b.c") red[0].value.remove(red[0].value[0]) assert red.dumps() == "b.c" def test_dot_proxy_list_remove_2(): red = RedBaron("a.b.c") red[0].value.remove(red[0].value[1]) assert red.dumps() == "a.c" def test_dot_proxy_list_set_item(): red = RedBaron("a.b.c") red[0].value[0] = "plop" assert red[0].value[0].type == "name" assert red[0].value[0].value == "plop" assert red.dumps() == "plop.b.c" def test_dot_proxy_list_set_slice(): red = RedBaron("a.b.c") red[0].value[1:2] = ["caramba", "compote"] assert red.dumps() == "a.caramba.compote.c" def test_dot_proxy_list_delslice(): red = RedBaron("a.b.c.d.e.f") del red[0].value[1:4] assert red.dumps() == "a.e.f" def test_dot_proxy_list_getslice(): red = RedBaron("a.b.c.d") result = red[0].value[1:3] expected_result = DotProxyList(NodeList([red[0].value[1], red[0].value[2]])) assert len(result) == len(expected_result) assert result[0] == expected_result[0] def test_dot_proxy_list_extend(): red = RedBaron("a.b.c") red[0].value.extend(["zob"]) assert red.dumps() == "a.b.c.zob" def test_dot_proxy_list_extend_2(): red = RedBaron("a.b.c") red[0].value.extend(["f", "plop", "ss"]) assert red.dumps() == "a.b.c.f.plop.ss" def test_dot_proxy_list_append_call(): red = RedBaron("a.b") red[0].value.append("()") assert red.dumps() == "a.b()" def test_dot_proxy_list_dotted_name_as_name(): red = RedBaron("import a.b as c") red[0][0].append("plop") assert red.dumps() == "import a.b.plop as c" def test_dot_proxy_list_from_import_node(): red = RedBaron("from a.b.c import d") red[0].append("plop") assert red.dumps() == "from a.b.c.plop import d" def test_dot_proxy_list_append_getitem(): red = RedBaron("a.b") red[0].value.append("[stuff]") assert red.dumps() == "a.b[stuff]" def test_dot_proxy_list_dotted_name_as_name_heading_dots(): red = RedBaron("import .a.b") red[0][0].append("plop") assert red.dumps() == "import .a.b.plop" def test_dot_proxy_list_dotted_name_as_name_heading_dots_remove(): red = RedBaron("import .a.b") red[0][0].pop() assert red.dumps() == "import .a" def test_dot_proxy_list_dotted_name_as_name_heading_two_dots_remove(): red = RedBaron("import ..a.b") red[0][0].pop() assert red.dumps() == "import ..a" def test_dot_proxy_list_dotted_name_as_name_heading_two_dots_remove_first(): red = RedBaron("import ..a.b") red[0][0].pop(0) assert red.dumps() == "import ..b" def test_line_proxy_list_len(): red = RedBaron("while a:\n pass\n") assert len(red[0].value) == 1 def test_line_proxy_list_insert(): red = RedBaron("while a:\n pass\n") red[0].value.insert(0, "c") assert red.dumps() == "while a:\n c\n pass\n" def test_line_proxy_list_insert_2_at_top(): red = RedBaron("while a:\n pass\n") red[0].value.insert(1, "c") assert red.dumps() == "while a:\n pass\n c\n" def test_line_proxy_list_insert_2_at_middle(): red = RedBaron("while a:\n pass\n pass\n") red[0].value.insert(1, "c") assert red.dumps() == "while a:\n pass\n c\n pass\n" def test_line_proxy_list_append(): red = RedBaron("while a:\n pass\n") red[0].value.append("c") assert red.dumps() == "while a:\n pass\n c\n" def test_line_proxy_list_pop(): red = RedBaron("while a:\n c\n pass\n") red[0].value.pop(0) assert red.dumps() == "while a:\n pass\n" def test_line_proxy_list_pop_2(): red = RedBaron("while a:\n pass\n c\n pass\n") red[0].value.pop(1) assert red.dumps() == "while a:\n pass\n pass\n" def test_line_proxy_list_pop_no_index(): red = RedBaron("while a:\n pass\n c\n pass\n") red[0].value.pop() assert red.dumps() == "while a:\n pass\n c\n" def test_line_proxy_list_del(): red = RedBaron("while a:\n pass\n c\n pass\n") del red[0].value[0] assert red.dumps() == "while a:\n c\n pass\n" def test_line_proxy_list_del_2(): red = RedBaron("while a:\n pass\n c\n pass\n") del red[0].value[2] assert red.dumps() == "while a:\n pass\n c\n" def test_line_proxy_list_remove(): red = RedBaron("while a:\n pass\n c\n") red[0].value.remove(red[0].value[0]) assert red.dumps() == "while a:\n c\n" def test_line_proxy_list_remove_2(): red = RedBaron("while a:\n pass\n c\n") red[0].value.remove(red[0].value[1]) assert red.dumps() == "while a:\n pass\n" def test_line_proxy_list_set_item(): red = RedBaron("while a:\n pass\n") red[0].value[0] = "plop" assert red[0].value[0].type == "name" assert red[0].value[0].value == "plop" assert red.dumps() == "while a:\n plop\n" def test_line_proxy_list_set_slice(): red = RedBaron("while a:\n pass\n a\n plop\n z\n") red[0].value[1:2] = ["caramba", "compote"] assert red.dumps() == "while a:\n pass\n caramba\n compote\n plop\n z\n" def test_line_proxy_list_delslice(): red = RedBaron("while a:\n pass\n caramba\n compote\n plop\n z\n") del red[0].value[1:4] assert red.dumps() == "while a:\n pass\n z\n" def test_line_proxy_list_getslice(): red = RedBaron("while a:\n pass\n caramba\n compote\n plop\n z\n") result = red[0].value[1:3] expected_result = LineProxyList(NodeList([red[0].value[1], red[0].value[2]])) assert len(result) == len(expected_result) assert result[0] == expected_result[0] def test_line_proxy_list_extend(): red = RedBaron("while a:\n pass\n") red[0].value.extend(["zob"]) assert red.dumps() == "while a:\n pass\n zob\n" def test_line_proxy_list_extend_2(): red = RedBaron("while a:\n pass\n") red[0].value.extend(["f", "plop", "ss"]) assert red.dumps() == "while a:\n pass\n f\n plop\n ss\n" def test_line_proxy_list_different_indentation(): red = RedBaron("while a:\n pass\n") red[0].value.append("c") assert red.dumps() == "while a:\n pass\n c\n" forwarded_indented_code = """ class A(): while b: pass while c: pass """ forwarded_indented_code_result = """ class A(): while b: pass plop while c: pass """ def test_line_proxy_dont_break_next_block_identation(): red = RedBaron(forwarded_indented_code) red.while_.append("plop") assert red.dumps() == forwarded_indented_code_result def test_line_proxy_with_blank_line_list_len(): red = RedBaron("while a:\n pass\n\n plop\n") assert len(red[0].value) == 3 def test_line_proxy_with_blank_line_list_insert(): red = RedBaron("while a:\n pass\n\n plop\n") red[0].value.insert(1, "c") assert red.dumps() == "while a:\n pass\n c\n\n plop\n" def test_line_proxy_with_blank_line_list_insert_2_at_middle(): red = RedBaron("while a:\n pass\n\n plop\n pass\n") red[0].value.insert(1, "c") assert red.dumps() == "while a:\n pass\n c\n\n plop\n pass\n" def test_line_proxy_with_blank_line_list_append(): red = RedBaron("while a:\n pass\n\n") red[0].value.append("c") assert red.dumps() == "while a:\n pass\n\n c\n" def test_line_proxy_with_blank_line_list_pop_blank_line(): red = RedBaron("while a:\n pass\n qsd\n\n plop\n c\n pass\n") red[0].value.pop(2) assert red.dumps() == "while a:\n pass\n qsd\n plop\n c\n pass\n" def test_line_proxy_with_blank_line_list_pop(): red = RedBaron("while a:\n pass\n\n plop\n c\n pass\n") red[0].value.pop() assert red.dumps() == "while a:\n pass\n\n plop\n c\n" def test_line_proxy_with_blank_line_list_pop_2(): red = RedBaron("while a:\n pass\n\n pass\n pass\n") red[0].value.pop(0) assert red.dumps() == "while a:\n\n pass\n pass\n" def test_line_proxy_with_blank_line_list_del(): red = RedBaron("while a:\n pass\n\n plop\n c\n pass\n") del red[0].value[0] assert red.dumps() == "while a:\n\n plop\n c\n pass\n" def test_line_proxy_with_blank_line_list_del_blank_line(): red = RedBaron("while a:\n pass\n\n plop\n c\n pass\n") del red[0].value[1] assert red.dumps() == "while a:\n pass\n plop\n c\n pass\n" def test_line_proxy_with_blank_line_list_remove(): red = RedBaron("while a:\n pass\n\n plop\n c\n pass\n") red[0].value.remove(red[0].value[0]) assert red.dumps() == "while a:\n\n plop\n c\n pass\n" def test_line_proxy_with_blank_line_list_remove_2(): red = RedBaron("while a:\n pass\n\n plop\n c\n pass\n") red[0].value.remove(red[0].value[1]) assert red.dumps() == "while a:\n pass\n plop\n c\n pass\n" def test_line_proxy_with_blank_line_list_set_slice(): red = RedBaron("while a:\n pass\n\n plop\n a\n plop\n z\n") red[0].value[1:2] = ["caramba", "compote"] assert red.dumps() == "while a:\n pass\n caramba\n compote\n plop\n a\n plop\n z\n" def test_line_proxy_with_blank_line_list_delslice(): red = RedBaron("while a:\n pass\n\n plop\n caramba\n compote\n plop\n z\n") del red[0].value[1:4] assert red.dumps() == "while a:\n pass\n compote\n plop\n z\n" def test_line_proxy_with_blank_line_list_getslice(): red = RedBaron("while a:\n pass\n\n plop\n caramba\n compote\n plop\n z\n") result = red[0].value[1:3] expected_result = LineProxyList(NodeList([red[0].value[1], red[0].value[2]])) assert len(result) == len(expected_result) assert result[0] == expected_result[0] def test_line_proxy_with_blank_line_list_extend(): red = RedBaron("while a:\n pass\n\n plop\n") red[0].value.extend(["zob"]) assert red.dumps() == "while a:\n pass\n\n plop\n zob\n" def test_line_proxy_with_blank_line_list_different_indentation(): red = RedBaron("while a:\n pass\n\n plop\n") red[0].value.append("c") assert red.dumps() == "while a:\n pass\n\n plop\n c\n" forwarded_indented_code = """ class A(): while b: pass pass while c: pass """ forwarded_indented_code_result = """ class A(): while b: pass pass plop while c: pass """ def test_line_proxy_with_blank_line_dont_break_next_block_identation(): red = RedBaron(forwarded_indented_code) red.while_.append("plop") assert red.dumps() == forwarded_indented_code_result def test_line_proxy_with_blank_line_class_node(): red = RedBaron("class A:\n pass\n\n plop\n") assert len(red[0].value) == 3 def test_line_proxy_with_blank_line_elif_node(): red = RedBaron("if a:\n pass\nelif A:\n pass\n\n plop\n") assert len(red[0].value[1].value) == 3 def test_line_proxy_with_blank_line_else_node(): red = RedBaron("if a:\n pass\nelse:\n pass\n\n plop\n") assert len(red[0].value[1].value) == 3 def test_line_proxy_with_blank_line_except_node(): red = RedBaron("try:\n pass\nexcept:\n pass\n\n plop\n") assert len(red[0].excepts[0].value) == 3 def test_line_proxy_with_blank_line_finally_node(): red = RedBaron("try:\n pass\nfinally:\n pass\n\n plop\n") assert len(red[0].finally_.value) == 3 def test_regression_print_empty_proxy_list(): red = RedBaron("a = {}") print(red) def test_regression_tuple_proxy_list_append(): red = RedBaron("(1, 2)") red[0].append("3") def test_regression_help_proxy_list(): red = RedBaron("(1, 2)") red[0].value.node_list.help() def test_comma_proxy_list_indented_len_not_empty(): red = RedBaron("[\n 1,\n 2,\n 3,\n]") comma_proxy_list = red[0].value assert len(comma_proxy_list) == 3 def test_comma_proxy_list_detect_style(): red = RedBaron("[1, 2, 3]") comma_proxy_list = red[0].value assert comma_proxy_list.style == "flat" def test_comma_proxy_list_indented_detect_style(): red = RedBaron("[\n 1,\n 2,\n 3,\n]") comma_proxy_list = red[0].value assert comma_proxy_list.style == "indented" # XXX I have to reconsider this behavior with the new algo # XXX this isn't making that much sens anymore # def test_comma_proxy_list_indented_insert(): # red = RedBaron("[]") # comma_proxy_list = red[0].value # comma_proxy_list.style = "indented" # comma_proxy_list.insert(0, "1") # assert red.dumps() == "[\n 1,\n]" def test_comma_proxy_list_indented_insert_2_at_top(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.insert(0, "2") assert red.dumps() == "[\n 2,\n 1,\n]" def test_comma_proxy_list_indented_insert_2(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.insert(1, "2") assert comma_proxy_list.style == "indented" assert red.dumps() == "[\n 1,\n 2,\n]" def test_comma_proxy_list_indented_insert_2_middle(): red = RedBaron("[\n 1,\n 3,\n]") comma_proxy_list = red[0].value comma_proxy_list.insert(1, "2") assert red.dumps() == "[\n 1,\n 2,\n 3,\n]" # XXX need to rethink this behavior # def test_comma_proxy_list_indented_append(): # red = RedBaron("[]") # comma_proxy_list = red[0].value # comma_proxy_list.style = "indented" # comma_proxy_list.append("1") # assert red.dumps() == "[\n 1,\n]" def test_comma_proxy_list_indented_append_2(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.append("2") assert red.dumps() == "[\n 1,\n 2,\n]" def test_comma_proxy_list_indented_pop(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.pop(0) assert red.dumps() == "[]" def test_comma_proxy_list_indented_pop_2_at_top(): red = RedBaron("[\n 2,\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.pop(0) assert red.dumps() == "[\n 1,\n]" def test_comma_proxy_list_indented_pop_2(): red = RedBaron("[\n 1,\n 2,\n]") comma_proxy_list = red[0].value comma_proxy_list.pop(1) assert red.dumps() == "[\n 1,\n]" def test_comma_proxy_list_indented_pop_2_middle(): red = RedBaron("[\n 1,\n 2,\n 3,\n]") comma_proxy_list = red[0].value comma_proxy_list.pop(1) assert red.dumps() == "[\n 1,\n 3,\n]" def test_comma_proxy_list_indented_pop_no_index(): red = RedBaron("[\n 1,\n 2,\n 3,\n]") comma_proxy_list = red[0].value comma_proxy_list.pop() assert red.dumps() == "[\n 1,\n 2,\n]" def test_comma_proxy_list_indented_del(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value del comma_proxy_list[0] assert red.dumps() == "[]" def test_comma_proxy_list_indented_del_2_at_top(): red = RedBaron("[\n 2,\n 1,\n]") comma_proxy_list = red[0].value del comma_proxy_list[0] assert red.dumps() == "[\n 1,\n]" def test_comma_proxy_list_indented_remove(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.remove(comma_proxy_list[0]) assert red.dumps() == "[]" def test_comma_proxy_list_indented_remove_2_at_top(): red = RedBaron("[\n 2,\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list.remove(comma_proxy_list[0]) assert red.dumps() == "[\n 1,\n]" def test_comma_proxy_list_indented_set_item(): red = RedBaron("[\n 1,\n]") comma_proxy_list = red[0].value comma_proxy_list[0] = "42" assert comma_proxy_list[0].type == "int" assert comma_proxy_list[0].value == "42" comma_proxy_list[0] = "plop" assert comma_proxy_list[0].type == "name" assert comma_proxy_list[0].value == "plop" assert red.dumps() == "[\n plop,\n]" def test_comma_proxy_list_indented_set_slice(): red = RedBaron("[\n 1,\n 2,\n 3,\n]") comma_proxy_list = red[0].value comma_proxy_list[1:2] = ["42", "31", "23"] assert red.dumps() == "[\n 1,\n 42,\n 31,\n 23,\n 3,\n]" def test_comma_proxy_list_indented_delslice(): red = RedBaron("[\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n]") comma_proxy_list = red[0].value del comma_proxy_list[1:4] assert red.dumps() == "[\n 1,\n 5,\n 6,\n]" comma_proxy_list_indented_code_to_test = """ with stuff: a = [ 1, ] """ comma_proxy_list_indented_code_to_test_expected_result = """ with stuff: a = [ 1, 2, ] """ def test_comma_proxy_list_indented_in_indentation_case(): red = RedBaron(comma_proxy_list_indented_code_to_test) red.list_.append("2") assert red.dumps() == comma_proxy_list_indented_code_to_test_expected_result def test_decorator_line_proxy_with_blank_line_list_len_empty(): red = RedBaron("def a():\n pass\n") assert len(red[0].decorators) == 0 def test_decorator_line_proxy_list_len(): red = RedBaron("@plop\n@pouet\ndef a():\n pass\n") assert len(red[0].decorators) == 2 def test_decorator_line_proxy_list_insert(): red = RedBaron("def a():\n pass\n") red[0].decorators.insert(0, "@plop") assert red.dumps() == "@plop\ndef a():\n pass\n" def test_decorator_line_proxy_list_insert_2_at_middle(): red = RedBaron("@plop\n@plouf\ndef a():\n pass\n") red[0].decorators.insert(1, "@pop") assert red.dumps() == "@plop\n@pop\n@plouf\ndef a():\n pass\n" def test_decorator_line_proxy_list_append(): red = RedBaron("@plop\ndef a():\n pass\n\n") red[0].decorators.append("@c.d.e") assert red.dumps() == "@plop\n@c.d.e\ndef a():\n pass\n\n" def test_decorator_line_proxy_list_pop(): red = RedBaron("@a\n@b\ndef a():\n pass\n") red[0].decorators.pop(0) assert red.dumps() == "@b\ndef a():\n pass\n" def test_decorator_line_proxy_list_pop_2(): red = RedBaron("@a\n@b\n@c\ndef a():\n pass\n") red[0].decorators.pop(2) assert red.dumps() == "@a\n@b\ndef a():\n pass\n" def test_decorator_line_proxy_list_del(): red = RedBaron("@plop\n@qsd\ndef a():\n pass\n") del red[0].decorators[0] assert red.dumps() == "@qsd\ndef a():\n pass\n" def test_decorator_line_proxy_list_remove(): red = RedBaron("@a\n@b\ndef a():\n pass\n") red[0].decorators.remove(red[0].decorators[0]) assert red.dumps() == "@b\ndef a():\n pass\n" def test_decorator_line_proxy_list_set_slice(): red = RedBaron("def a():\n pass\n") red[0].decorators[1:2] = ["@caramba", "@compote"] assert red.dumps() == "@caramba\n@compote\ndef a():\n pass\n" assert isinstance(red[0].decorators, DecoratorsLineProxyList) def test_decorator_line_proxy_list_delslice(): red = RedBaron("@a\n@b\n@c\ndef a():\n pass\n") del red[0].decorators[1:4] assert red.dumps() == "@a\ndef a():\n pass\n" def test_decorator_line_proxy_list_getslice(): red = RedBaron("@a\n@b\n@c\ndef a():\n pass\n") result = red[0].decorators[1:3] expected_result = DecoratorsLineProxyList(NodeList([red[0].decorators[1], red[0].decorators[2]])) assert len(result) == len(expected_result) assert result[0] == expected_result[0] def test_decorator_line_proxy_list_extend(): red = RedBaron("def a():\n pass\n") red[0].decorators.extend(["@zob"]) assert red.dumps() == "@zob\ndef a():\n pass\n" forwarded_indented_code_decorators = """ class A(): def b(self): pass def c(self): pass """ forwarded_indented_code_result_decorators = """ class A(): @plop def b(self): pass def c(self): pass """ def test_decorator_line_proxy_dont_break_next_block_identation(): red = RedBaron(forwarded_indented_code_decorators) red.def_.decorators.append("@plop") assert red.dumps() == forwarded_indented_code_result_decorators def test_line_proxy_correctly_indent_code_block(): red = RedBaron("while True:\n pass\n") red[0].extend(["if a:\n pass\n\n"]) assert red.dumps() == "while True:\n pass\n if a:\n pass\n\n" def test_root_as_line_proxy_list_len(): red = RedBaron("a\nb\nc\n") assert len(red) == 3 def test_root_as_line_proxy_list_insert(): red = RedBaron("a\nb\nc\n") red.insert(1, "c") assert red.dumps() == "a\nc\nb\nc\n" def test_root_as_line_proxy_list_append(): red = RedBaron("a\nb\nc\n") red.append("c") assert red.dumps() == "a\nb\nc\nc\n" def test_root_as_line_proxy_list_pop(): red = RedBaron("a\nb\nc\nc\n") red.pop() assert red.dumps() == "a\nb\nc\n" def test_root_as_line_proxy_list_pop_2(): red = RedBaron("a\nb\nc\n") red.pop(0) assert red.dumps() == "b\nc\n" def test_root_as_line_proxy_list_del(): red = RedBaron("b\nc\n") del red[0] assert red.dumps() == "c\n" def test_root_as_line_proxy_list_del_blank_line(): red = RedBaron("\na\nb\nc\n") del red[1] assert red.dumps() == "\nb\nc\n" def test_root_as_line_proxy_list_remove(): red = RedBaron("\n\na\nb\nc\n") red.remove(red[0]) assert red.dumps() == "\na\nb\nc\n" def test_root_as_line_proxy_list_remove_2(): red = RedBaron("\n\na\nb\nc\n") red.remove(red[2]) assert red.dumps() == "\n\nb\nc\n" def test_root_as_line_proxy_list_set_slice(): red = RedBaron("\n\na\nb\nc\n") red[1:2] = ["caramba", "compote"] assert red.dumps() == "\ncaramba\ncompote\na\nb\nc\n" def test_root_as_line_proxy_list_delslice(): red = RedBaron("\n\na\nb\nc\n") del red[1:4] assert red.dumps() == "\nc\n" def test_root_as_line_proxy_list_getslice(): red = RedBaron("\n\na\nb\nc\n") result = red[1:3] expected_result = LineProxyList(NodeList([red[1], red[2]])) assert len(result) == len(expected_result) assert result[0] == expected_result[0] def test_root_as_line_proxy_list_extend(): red = RedBaron("\n\na\nb\nc\n") red.extend(["zob"]) assert red.dumps() == "\n\na\nb\nc\nzob\n" def test_regression_first_method_of_a_class_decorators_append(): red = RedBaron("class A:\n def foo():\n pass") red.def_.decorators.append("@staticmethod") assert red.dumps() == "class A:\n @staticmethod\n def foo():\n pass\n" redbaron-0.9.2/tests/test_redbaron.py000066400000000000000000000017441344351435400177010ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Main redbaron test module """ from redbaron import RedBaron, truncate def test_other_name_assignment(): red = RedBaron("a = b") assert red.assign is red[0] def test_index(): red = RedBaron("a = [1, 2, 3]") assert red[0].value.value[2].index_on_parent == 2 assert red[0].index_on_parent == 0 assert red[0].value.index_on_parent is None def test_index_raw(): red = RedBaron("a = [1, 2, 3]") assert red[0].value.value.node_list[2].index_on_parent_raw == 2 assert red[0].index_on_parent == 0 assert red[0].value.index_on_parent_raw is None def test_regression_find_all_recursive(): red = RedBaron("a.b()") assert red[0].value("name", recursive=False) == [red.name, red("name")[1]] def test_truncate(): assert "1234" == truncate("1234", 2) assert "12345" == truncate("12345", 4) assert "1...6" == truncate("123456", 5) assert "123456...0" == truncate("12345678901234567890", 10) redbaron-0.9.2/tests/test_regressions.py000066400000000000000000000012771344351435400204510ustar00rootroot00000000000000from redbaron import RedBaron def test_mixmatch_with_redbaron_base_node_and_proxy_list_on_parent(): red = RedBaron("foo = 42\nprint('bar')\n") red.insert(0, "baz") assert red[0].on_attribute == "root" assert red[0].parent is red def test_can_modify_formatting_attributes_on_codeblocknodes(): red = RedBaron("class Foo:\n def bar(): pass") red.class_.first_formatting = " " # shouldn't raise red.def_.second_formatting = " " # same def test_on_copied_blocknode_set_body(): red = RedBaron("def foobar(): pass") z = red.def_.copy() z.value = "pouet" def test_find_empty_call(): red = RedBaron("a()") assert red.find("call") is red[0][1] redbaron-0.9.2/tests/test_render.py000066400000000000000000000047661344351435400173730ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the rendering feature """ from redbaron import RedBaron def test_rendering_iter(): red = RedBaron("a + 2") assert_red = RedBaron("assert a == 5") assert list(red._generate_nodes_in_rendering_order()) == \ [red[0], red.name, red[0].first_formatting[0], red[0], red[0].second_formatting[0], red.int] assert list(red[0]._generate_nodes_in_rendering_order()) == \ [red[0], red.name, red[0].first_formatting[0], red[0], red[0].second_formatting[0], red.int] assert list(assert_red._generate_nodes_in_rendering_order()) == \ [assert_red[0], assert_red[0].first_formatting[0], # SpaceNode in AssertNode assert_red[0].value, # ComparisonNode assert_red.name, assert_red[0].value.first_formatting[0], # SpaceNode in ComparisonNode assert_red[0].value.value, # ComparisonOperatorNode assert_red[0].value.second_formatting[0], # SpaceNode in ComparisonNode assert_red.int] assert list(assert_red[0]._generate_nodes_in_rendering_order()) == \ [assert_red[0], assert_red[0].first_formatting[0], # SpaceNode in AssertNode assert_red[0].value, # ComparisonNode assert_red.name, assert_red[0].value.first_formatting[0], # SpaceNode in ComparisonNode assert_red[0].value.value, # ComparisonOperatorNode assert_red[0].value.second_formatting[0], # SpaceNode in ComparisonNode assert_red.int] def test_next_rendered(): red = RedBaron("a + 2") f = red.name assert f.next_rendered is red[0].first_formatting[0] assert f.next_rendered.next_rendered is red[0] assert f.next_rendered.next_rendered.next_rendered is red[0].second_formatting[0] assert f.next_rendered.next_rendered.next_rendered.next_rendered is red.int def test_previous_rendered(): red = RedBaron("a + 2") f = red.int assert f.previous_rendered is red[0].second_formatting[0] assert f.previous_rendered.previous_rendered is red[0] assert red[0].first_formatting[0].previous_rendered is red.name test_indent_code = """ def a(): # plop 1 + 2 if caramba: plop pouf """ def test_next_rendered_trapped(): red = RedBaron(test_indent_code) assert red("endl")[5].next_rendered is red.find("name", "pouf") redbaron-0.9.2/tests/test_root.py000066400000000000000000000027061344351435400170670ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the root method """ import pytest # pylint: disable=redefined-outer-name from redbaron import RedBaron @pytest.fixture def red(): return RedBaron("""\ @deco def a(c, d): b = c + d """) def test_root(red): nodes = [ red.def_, red.def_.decorators, red.def_.decorators.node_list[0], red.def_.decorators.node_list[0].value, red.def_.decorators.node_list[0].value.value, red.def_.decorators.node_list[0].value.value[0], red.def_.decorators.node_list[1], red.def_.first_formatting, red.def_.first_formatting[0], red.def_.second_formatting, red.def_.third_formatting, red.def_.arguments, red.def_.arguments.node_list[0], red.def_.arguments.node_list[1], red.def_.arguments.node_list[2], red.def_.fourth_formatting, red.def_.fifth_formatting, red.def_.sixth_formatting, red.def_.value.node_list, red.def_.value.node_list[0], red.def_.value.node_list[1], red.def_.value.node_list[1].target, red.def_.value.node_list[1].value, red.def_.value.node_list[1].value.first, red.def_.value.node_list[1].value.second, red.def_.value.node_list[2] ] for node in nodes: assert red is node.root def test_get_root(): red = RedBaron("def a(b=c):\n return 42") assert red is red.find("int").root redbaron-0.9.2/tests/test_setter.py000066400000000000000000001743651344351435400174250ustar00rootroot00000000000000#!/usr/bin/python # -*- coding:Utf-8 -*- """ Tests the setter methods """ import pytest # pylint: disable=redefined-outer-name from redbaron import RedBaron from baron.utils import string_instance def test_setitem_nodelist(): red = RedBaron("[1, 2, 3]") red[0].value.node_list[2] = "2 + 'pouet'" red.dumps() assert red[0].value.node_list[2].type == "binary_operator" assert red[0].value.node_list[2].parent is red[0] assert red[0].value.node_list[2].on_attribute == "value" def test_set_attr_on_import(): red = RedBaron("import a") red[0].value = "a.b.c as d, qsd, plop as pouet" assert red.dumps() == "import a.b.c as d, qsd, plop as pouet" def test_set_attr_on_list(): red = RedBaron("[]") red[0].value = "1, 2, 3" assert red[0].value[0].type == "int" def test_set_attr_on_list_empty(): red = RedBaron("[1, 2, 3]") red[0].value = "" assert len(red[0].value) == 0 def test_set_attr_on_set(): red = RedBaron("{1,}") red[0].value = "1, 2, 3" assert red[0].value[0].type == "int" def test_set_attr_on_tuple(): red = RedBaron("(1,)") red[0].value = "1, 2, 3" assert red[0].value[0].type == "int" def test_set_attr_on_tuple_empty(): red = RedBaron("(1,)") red[0].value = "" assert len(red[0].value) == 0 def test_set_attr_on_repr(): red = RedBaron("`1`") red[0].value = "1, 2, 3" assert red[0].value[0].type == "int" def test_set_attr_on_dict(): red = RedBaron("{}") red[0].value = "1: 2, 3: 4" assert red[0].value[0].key.type == "int" def test_set_attr_on_dict_empty(): red = RedBaron("{1: 2, 3: 4}") red[0].value = "" assert len(red[0].value) == 0 def test_set_attr_def_name(): red = RedBaron("def a(): pass") red[0].name = "plop" assert isinstance(red[0].name, string_instance) def test_set_attr_def_arguments(): red = RedBaron("def a(): pass") red[0].arguments = "x, y=z, *args, **kwargs" assert len(red[0].arguments.filtered()) == 4 def test_set_attr_def_value_simple(): red = RedBaron("def a(): pass") red[0].value = "plop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_indented(): red = RedBaron("def a(): pass") red[0].value = " plop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_endl(): red = RedBaron("def a(): pass") red[0].value = "\nplop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_space_endl(): red = RedBaron("def a(): pass") red[0].value = " \nplop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_space_endl_space(): red = RedBaron("def a(): pass") red[0].value = " \n plop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_too_much_space(): red = RedBaron("def a(): pass") red[0].value = " plop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_endl_too_much_space(): red = RedBaron("def a(): pass") red[0].value = "\n plop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_simple_space_endl_too_much_space(): red = RedBaron("def a(): pass") red[0].value = " \n plop" assert red[0].value.dumps() == "\n plop\n" def test_set_attr_def_value_complex(): red = RedBaron("def a(): pass") red[0].value = "plop\nplouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_value_endl_complex(): red = RedBaron("def a(): pass") red[0].value = "\nplop\nplouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_value_indent_complex(): red = RedBaron("def a(): pass") red[0].value = " plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_value_endl_indent_complex(): red = RedBaron("def a(): pass") red[0].value = "\n plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_value_space_endl_indent_complex(): red = RedBaron("def a(): pass") red[0].value = " \n plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_too_small_indent_complex(): red = RedBaron("def a(): pass") red[0].value = " plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_endl_too_small_indent_complex(): red = RedBaron("def a(): pass") red[0].value = "\n plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_space_endl_too_small_indent_complex(): red = RedBaron("def a(): pass") red[0].value = " \n plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_too_much_indent_complex(): red = RedBaron("def a(): pass") red[0].value = " plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_endl_too_much_indent_complex(): red = RedBaron("def a(): pass") red[0].value = "\n plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_space_endl_too_much_indent_complex(): red = RedBaron("def a(): pass") red[0].value = " \n plop\n plouf" assert red[0].value.dumps() == "\n plop\n plouf\n" def test_set_attr_def_space_complex_with_more_complex_indent(): red = RedBaron("def a(): pass") red[0].value = "plop\nif a:\n pass\n" assert red[0].value.dumps() == "\n plop\n if a:\n pass\n" code_for_block_setattr = """ class A(): def a(): pass def b(): pass def c(): def zomg(): pass plop def d(): pass """ def test_set_attr_def_advanced_dont_break_next_block_indent(): red = RedBaron(code_for_block_setattr) red.find("def", name="c").value = "return 42" assert len(red.find("def", name="c")("endl")) == 4 assert red.find("def", name="c").value.node_list[-1].indent == "" def test_set_attr_def_advanced_dont_break_next_block_indent_one_endl(): red = RedBaron(code_for_block_setattr) red.find("def", name="c").value = "return 42\n" assert len(red.find("def", name="c")("endl")) == 4 assert red.find("def", name="c").value.node_list[-1].indent == "" def test_set_attr_def_advanced_dont_break_next_block_indent_two_endl(): red = RedBaron(code_for_block_setattr) red.find("def", name="c").value = "return 42\n\n" assert len(red.find("def", name="c")("endl")) == 4 assert red.find("def", name="c").value.node_list[-1].indent == "" def test_set_attr_def_advanced_in_class_dont_break_next_block_indent(): red = RedBaron(code_for_block_setattr) red.find("def", name="a").value = "return 42" assert len(red.find("def", name="a")("endl")) == 3 assert red.find("def", name="a").value.node_list[-1].indent == " " def test_set_attr_def_advanced_in_class_dont_break_next_block_indent_one_endl(): red = RedBaron(code_for_block_setattr) red.find("def", name="a").value = "return 42\n" assert len(red.find("def", name="a")("endl")) == 3 assert red.find("def", name="a").value.node_list[-1].indent == " " def test_set_attr_def_advanced_in_class_at_the_end_dont_break_next_block_indent(): red = RedBaron(code_for_block_setattr) red.find("def", name="b").value = "return 42" assert len(red.find("def", name="b")("endl")) == 4 assert red.find("def", name="b").value.node_list[-1].indent == "" def test_set_attr_def_advanced_in_class_at_the_end_dont_break_next_block_indent_one_endl(): red = RedBaron(code_for_block_setattr) red.find("def", name="b").value = "return 42\n" assert len(red.find("def", name="b")("endl")) == 4 assert red.find("def", name="b").value.node_list[-1].indent == "" def test_set_attr_def_advanced_in_class_at_the_end_dont_break_next_block_indent_two_endl(): red = RedBaron(code_for_block_setattr) red.find("def", name="b").value = "return 42\n\n" assert len(red.find("def", name="b")("endl")) == 4 assert red.find("def", name="b").value.node_list[-1].indent == "" def test_set_attr_def_advanced_inline_dont_break_next_block_indent(): red = RedBaron(code_for_block_setattr) red.find("def", name="zomg").value = "return 42" assert len(red.find("def", name="zomg")("endl")) == 3 assert red.find("def", name="zomg").value.node_list[-1].indent == " " def test_set_attr_def_advanced_inline_dont_break_next_block_indent_one_endl(): red = RedBaron(code_for_block_setattr) red.find("def", name="zomg").value = "return 42\n" assert len(red.find("def", name="zomg")("endl")) == 3 assert red.find("def", name="zomg").value.node_list[-1].indent == " " def test_set_attr_def_async_dont_break_initial_formatting(): red = RedBaron("async def a(): pass") assert red.dumps() == "async def a(): pass\n" def test_set_attr_def_set_async(): red = RedBaron("def a(): pass") red[0].async_ = True assert red.dumps() == "async def a(): pass\n" def test_set_attr_def_unset_async(): red = RedBaron("async def a(): pass") red[0].async_ = False assert red.dumps() == "def a(): pass\n" def test_set_attr_def_async_dont_break_initial_formatting_indent(): red = RedBaron("class A:\n async def a(): pass") assert red.dumps() == "class A:\n async def a(): pass\n" def test_set_attr_def_set_async_indent(): red = RedBaron("class A:\n def a(): pass") red.def_.async_ = True assert red.dumps() == "class A:\n async def a(): pass\n" def test_set_attr_def_unset_async_indent(): red = RedBaron("class A:\n async def a(): pass") red.def_.async_ = False assert red.dumps() == "class A:\n def a(): pass\n" def test_set_attr_def_set_return_annotation(): red = RedBaron("def a(): pass") red[0].return_annotation = "Int" assert red.dumps() == "def a() -> Int: pass\n" def test_set_attr_def_set_return_annotation_keep_formatting(): red = RedBaron("def a() -> Int: pass") red[0].return_annotation = "pouet" assert red.dumps() == "def a() -> pouet: pass\n" def test_set_attr_def_unset_return_annotation(): red = RedBaron("def a() -> Int: pass") red[0].return_annotation = "" assert red.dumps() == "def a(): pass\n" def test_set_decorator_def(): red = RedBaron("def a(): pass") red[0].decorators = "@decorator" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_endl(): red = RedBaron("def a(): pass") red[0].decorators = "@decorator\n" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_indent(): red = RedBaron("def a(): pass") red[0].decorators = " @decorator" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_indent_endl(): red = RedBaron("def a(): pass") red[0].decorators = " @decorator\n" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_too_small_indent(): red = RedBaron("def a(): pass") red[0].decorators = " @decorator" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_too_small_indent_endl(): red = RedBaron("def a(): pass") red[0].decorators = " @decorator\n" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_too_big_indent(): red = RedBaron("def a(): pass") red[0].decorators = " @decorator" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_too_big_indent_endl(): red = RedBaron("def a(): pass") red[0].decorators = " @decorator\n" assert len(red[0].decorators.node_list) == 2 assert red[0].decorators.dumps() == "@decorator\n" def test_set_decorator_def_complex(): red = RedBaron("def a(): pass") red[0].decorators = "@plop\n@plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_indent(): red = RedBaron("def a(): pass") red[0].decorators = " @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_endl_indent(): red = RedBaron("def a(): pass") red[0].decorators = "\n @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_space_endl_indent(): red = RedBaron("def a(): pass") red[0].decorators = " \n @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_too_small_indent(): red = RedBaron("def a(): pass") red[0].decorators = " @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_endl_too_small_indent(): red = RedBaron("def a(): pass") red[0].decorators = "\n @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_space_endl_too_small_indent(): red = RedBaron("def a(): pass") red[0].decorators = " \n @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_too_big_indent(): red = RedBaron("def a(): pass") red[0].decorators = " @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_endl_too_big_indent(): red = RedBaron("def a(): pass") red[0].decorators = "\n @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_def_complex_space_endl_too_big_indent(): red = RedBaron("def a(): pass") red[0].decorators = " \n @plop\n @plouf" assert len(red[0].decorators.node_list) == 4 assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_set_decorator_indented_def(): red = RedBaron(code_for_block_setattr) red.find("def", "b").decorators = "@pouet" assert len(red.find("def", "b").decorators.node_list) == 2 assert red.find("def", "b").decorators.node_list[-1].indent == " " def test_set_decorators_indented_def(): red = RedBaron(code_for_block_setattr) red.find("def", "b").decorators = "@pouet\n@plop" assert len(red.find("def", "b").decorators.node_list) == 4 assert red.find("def", "b").decorators.node_list[-1].indent == " " assert red.find("def", "b").decorators.node_list[-3].indent == " " def test_assign_node_setattr_target(): red = RedBaron("a = b") red[0].target = "plop" assert red.dumps() == "plop = b" with pytest.raises(Exception): red[0].target = "raise" def test_assign_node_setattr_value(): red = RedBaron("a = b") red[0].value = "plop" assert red.dumps() == "a = plop" with pytest.raises(Exception): red[0].value = "raise" def test_assign_node_setattr_operator(): red = RedBaron("a = b") red[0].operator = '+' assert red.dumps() == "a += b" red[0].operator = '+=' assert red.dumps() == "a += b" red[0].operator = '=' assert red.dumps() == "a = b" red[0].operator = '-' assert red.dumps() == "a -= b" red[0].operator = '' assert red.dumps() == "a = b" with pytest.raises(Exception): red[0].operator = "raise" def test_assign_node_setattr_annotation(): red = RedBaron("a = b") red[0].annotation = "Int" assert red.dumps() == "a : Int = b" def test_assign_node_setattr_annotation_existing(): red = RedBaron("a : Str = b") red[0].annotation = "Int" assert red.dumps() == "a : Int = b" def test_assign_node_setattr_remove(): red = RedBaron("a : Int = b") red[0].annotation = "" assert red.dumps() == "a = b" def test_standalone_annotation(): red = RedBaron("a : Int") red[0].annotation = "Str" assert red.dumps() == "a : Str" def test_star_var(): red = RedBaron("a, *b = c") red[0].target[1].value = "(x, y)" assert red.dumps() == "a, *(x, y) = c" def test_await_setattr_value(): red = RedBaron("await a") red[0].value = "b" assert red[0].dumps() == "await b" def test_await_setattr_value_expr(): red = RedBaron("await a") with pytest.raises(Exception): red[0].value = "def a(): pass" def test_for_setattr_value(): red = RedBaron("for i in a: pass") red[0].value = "continue" assert red[0].value.dumps() == "\n continue\n" def test_for_setattr_target(): red = RedBaron("for i in a: pass") red[0].target = "caramba" assert red.dumps() == "for i in caramba: pass\n" assert red[0].target.type == "name" with pytest.raises(Exception): red[0].target = "raise" def test_for_setattr_iterator(): red = RedBaron("for i in a: pass") red[0].iterator = "caramba" assert red.dumps() == "for caramba in a: pass\n" assert red[0].iterator.type == "name" with pytest.raises(Exception): red[0].iterator = "raise" def test_set_attr_for_async_dont_break_initial_formatting(): red = RedBaron("async for a in b: pass") assert red.dumps() == "async for a in b: pass\n" def test_set_attr_for_set_async(): red = RedBaron("for a in b: pass") red[0].async_ = True assert red.dumps() == "async for a in b: pass\n" def test_set_attr_for_unset_async(): red = RedBaron("async for a in b: pass") red[0].async_ = False assert red.dumps() == "for a in b: pass\n" def test_set_attr_for_async_dont_break_initial_formatting_indent(): red = RedBaron("class A:\n async for a in b: pass") assert red.dumps() == "class A:\n async for a in b: pass\n" def test_set_attr_for_set_async_indent(): red = RedBaron("class A:\n for a in b: pass") red.for_.async_ = True assert red.dumps() == "class A:\n async for a in b: pass\n" def test_set_attr_for_unset_async_indent(): red = RedBaron("class A:\n async for a in b: pass") red.for_.async_ = False assert red.dumps() == "class A:\n for a in b: pass\n" def test_while_setattr_value(): red = RedBaron("while a: pass") red[0].value = "continue" assert red[0].value.dumps() == "\n continue\n" def test_while_setattr_test(): red = RedBaron("while a: pass") red[0].test = "caramba" assert red.dumps() == "while caramba: pass\n" assert red[0].test.type == "name" with pytest.raises(Exception): red[0].test = "raise" def test_class_setattr_value(): red = RedBaron("class a: pass") red[0].value = "def z(): pass" assert red[0].value.dumps() == "\n def z(): pass\n" def test_class_setattr_decorators(): red = RedBaron("class a: pass") red[0].decorators = "@plop\n@plouf" assert red[0].decorators.dumps() == "@plop\n@plouf\n" def test_class_setattr_inherit_from(): red = RedBaron("class a: pass") red[0].inherit_from = "A" assert red[0].dumps() == "class a(A): pass\n" def test_with_setattr_value(): red = RedBaron("with a: pass") red[0].value = "def z(): pass" assert red[0].value.dumps() == "\n def z(): pass\n" def test_with_setattr_context(): red = RedBaron("with a: pass") red[0].contexts = "a as b, b as c" assert red[0].dumps() == "with a as b, b as c: pass\n" def test_set_attr_with_async_dont_break_initial_withmatting(): red = RedBaron("async with a as b: pass") assert red.dumps() == "async with a as b: pass\n" def test_set_attr_with_set_async(): red = RedBaron("with a as b: pass") red[0].async_ = True assert red.dumps() == "async with a as b: pass\n" def test_set_attr_with_unset_async(): red = RedBaron("async with a as b: pass") red[0].async_ = False assert red.dumps() == "with a as b: pass\n" def test_set_attr_with_async_dont_break_initial_withmatting_indent(): red = RedBaron("class A:\n async with a as b: pass") assert red.dumps() == "class A:\n async with a as b: pass\n" def test_set_attr_with_set_async_indent(): red = RedBaron("class A:\n with a as b: pass") red.with_.async_ = True assert red.dumps() == "class A:\n async with a as b: pass\n" def test_set_attr_with_unset_async_indent(): red = RedBaron("class A:\n async with a as b: pass") red.with_.async_ = False assert red.dumps() == "class A:\n with a as b: pass\n" def test_with_context_item_value(): red = RedBaron("with a: pass") red[0].contexts[0].value = "plop" assert red[0].dumps() == "with plop: pass\n" def test_with_context_item_as(): red = RedBaron("with a: pass") red[0].contexts[0].as_ = "plop" assert red[0].contexts[0].as_ != "" assert red[0].dumps() == "with a as plop: pass\n" def test_with_context_item_as_empty_string(): red = RedBaron("with a as b: pass") red[0].contexts[0].as_ = "" assert red[0].contexts[0].as_ is "" assert red[0].dumps() == "with a: pass\n" def test_if_setattr_value(): red = RedBaron("if a: pass") red[0].value[0].value = "continue" assert red[0].value[0].value.dumps() == "\n continue\n" def test_setattr_if_test(): red = RedBaron("if a: pass") red[0].value[0].test = "caramba" assert red.dumps() == "if caramba: pass\n" assert red[0].value[0].test.type == "name" with pytest.raises(Exception): red[0].value[0].test = "raise" def test_elif_setattr_value(): red = RedBaron("if a: pass\nelif b: pass") red[0].value[1].value = "continue" assert red[0].value[1].value.dumps() == "\n continue\n" def test_setattr_elif_test(): red = RedBaron("if a: pass\nelif b: pass") red[0].value[1].test = "caramba" assert red.dumps() == "if a: pass\nelif caramba: pass\n" assert red[0].value[1].test.type == "name" with pytest.raises(Exception): red[0].value[1].test = "raise" def test_else_setattr_value(): red = RedBaron("if a: pass\nelse: pass") red[0].value[1].value = "continue" assert red[0].value[1].value.dumps() == "\n continue\n" def test_try_setattr_value(): red = RedBaron("try: pass\nexcept: pass\n") red[0].value = "continue" assert red[0].value.dumps() == "\n continue\n" def test_finally_setattr_value(): red = RedBaron("try: pass\nfinally: pass\n") red[0].finally_.value = "continue" assert red[0].finally_.value.dumps() == "\n continue\n" def test_finally_getattr_on_try(): red = RedBaron("try: pass\nfinally: pass\n") assert red[0].finally_ is getattr(red[0], "finally") def test_except_setattr_value(): red = RedBaron("try: pass\nexcept: pass\n") red[0].excepts[0].value = "continue" assert red[0].excepts[0].value.dumps() == "\n continue\n" def test_except_setattr_exception(): red = RedBaron("try: pass\nexcept: pass\n") red[0].excepts[0].exception = "Plop" assert red[0].excepts[0].dumps() == "except Plop: pass\n" def test_except_setattr_exception_none(): red = RedBaron("try: pass\nexcept Pouet: pass\n") red[0].excepts[0].exception = "" assert red[0].excepts[0].dumps() == "except: pass\n" def test_except_setattr_exception_none_with_target(): red = RedBaron("try: pass\nexcept Pouet as plop: pass\n") red[0].excepts[0].exception = "" assert red[0].excepts[0].dumps() == "except: pass\n" def test_except_setattr_target(): red = RedBaron("try: pass\nexcept Pouet: pass\n") red[0].excepts[0].target = "plop" assert red[0].excepts[0].dumps() == "except Pouet as plop: pass\n" def test_except_setattr_target_raise_no_exception(): red = RedBaron("try: pass\nexcept: pass\n") with pytest.raises(Exception): red[0].excepts[0].target = "plop" def test_except_setattr_target_none(): red = RedBaron("try: pass\nexcept Pouet as plop: pass\n") red[0].excepts[0].target = "" assert red[0].excepts[0].delimiter == "" assert red[0].excepts[0].dumps() == "except Pouet: pass\n" def test_except_setattr_delimiter_comma(): red = RedBaron("try: pass\nexcept Pouet as plop: pass\n") red[0].excepts[0].delimiter = "," assert red[0].excepts[0].delimiter == "," assert red[0].excepts[0].dumps() == "except Pouet, plop: pass\n" def test_except_setattr_delimiter_as(): red = RedBaron("try: pass\nexcept Pouet, plop: pass\n") red[0].excepts[0].delimiter = "as" assert red[0].excepts[0].delimiter == "as" assert red[0].excepts[0].dumps() == "except Pouet as plop: pass\n" def test_except_setattr_delimiter_bad(): red = RedBaron("try: pass\nexcept Pouet, plop: pass\n") with pytest.raises(Exception): red[0].excepts[0].delimiter = "pouet" def test_call_setattr_value(): red = RedBaron("a()") red[0].value[1].value = "b=2, *pouet" assert red.dumps() == "a(b=2, *pouet)" def test_assert_setattr_value(): red = RedBaron("assert a") red[0].value = "42 + pouet" assert red.dumps() == "assert 42 + pouet" with pytest.raises(Exception): red[0].value = "def a(): pass" def test_assert_setattr_message(): red = RedBaron("assert a") red[0].message = "plop" assert red.dumps() == "assert a, plop" def test_assert_setattr_message_none(): red = RedBaron("assert a, plop") red[0].message = "" assert red.dumps() == "assert a" def test_associative_parenthesis_setattr_value(): red = RedBaron("(plop)") red[0].value = "1 + 43" assert red.dumps() == "(1 + 43)" with pytest.raises(Exception): red[0].value = "def a(): pass" def test_atom_trailers_setattr_value(): red = RedBaron("a(plop)") red[0].value = "a.plop[2](42)" assert red.dumps() == "a.plop[2](42)" with pytest.raises(Exception): red[0].value = "def a(): pass" def test_binary_setattr_value(): red = RedBaron("0b101001") red[0].value = "0b1100" assert red.dumps() == "0b1100" with pytest.raises(Exception): red[0].value = "not_binary" def test_binary_operator_setattr_value(): red = RedBaron("a - b") red[0].value = "+" assert red.dumps() == "a + b" with pytest.raises(Exception): red[0].value = "some illegal stuff" def test_binary_operator_setattr_first(): red = RedBaron("a + b") red[0].first = "caramba" assert red.dumps() == "caramba + b" with pytest.raises(Exception): red[0].first = "def a(): pass" def test_binary_operator_setattr_second(): red = RedBaron("a + b") red[0].second = "caramba" assert red.dumps() == "a + caramba" with pytest.raises(Exception): red[0].second = "def a(): pass" def test_boolean_operator_setattr_value(): red = RedBaron("a and b") red[0].value = "or" assert red.dumps() == "a or b" with pytest.raises(Exception): red[0].value = "some illegal stuff" def test_boolean_operator_setattr_first(): red = RedBaron("a and b") red[0].first = "caramba" assert red.dumps() == "caramba and b" with pytest.raises(Exception): red[0].first = "def a(): pass" def test_boolean_operator_setattr_second(): red = RedBaron("a and b") red[0].second = "caramba" assert red.dumps() == "a and caramba" with pytest.raises(Exception): red[0].second = "def a(): pass" def test_comparison_setattr_value(): red = RedBaron("a > b") red[0].value = "<" assert red.dumps() == "a < b" with pytest.raises(Exception): red[0].value = "some illegal stuff" def test_comparison_setattr_first(): red = RedBaron("a > b") red[0].first = "caramba" assert red.dumps() == "caramba > b" with pytest.raises(Exception): red[0].first = "def a(): pass" def test_comparison_setattr_second(): red = RedBaron("a > b") red[0].second = "caramba" assert red.dumps() == "a > caramba" with pytest.raises(Exception): red[0].second = "def a(): pass" def test_call_argument_setattr_value(): red = RedBaron("a(b)") red[0].value[1].value[0].value = "caramba" assert red.dumps() == "a(caramba)" with pytest.raises(Exception): red[0].value[1].value[0].value = "def a(): pass" def test_call_argument_setattr_name(): red = RedBaron("a(b)") red[0].value[1].value[0].target = "caramba" assert red.dumps() == "a(caramba=b)" red[0].value[1].value[0].target = "" assert red.dumps() == "a(b)" with pytest.raises(Exception): red[0].value[1].value[0].value = "def a(): pass" def test_decorator_setattr_value(): red = RedBaron("@pouet\ndef a(): pass\n") red[0].decorators[0].value = "a.b.c" assert red.dumps() == "@a.b.c\ndef a(): pass\n" assert red[0].decorators[0].value.type == "dotted_name" with pytest.raises(Exception): red[0].decorators[0].value = "def a(): pass" with pytest.raises(Exception): red[0].decorators[0].value = "a()" def test_decorator_setattr_call(): red = RedBaron("@pouet\ndef a(): pass\n") red[0].decorators[0].call = "(*a)" assert red.dumps() == "@pouet(*a)\ndef a(): pass\n" with pytest.raises(Exception): red[0].decorators[0].call = "def a(): pass" with pytest.raises(Exception): red[0].decorators[0].call = ".stuff" def test_decorator_setattr_call_none(): red = RedBaron("@pouet(zob)\ndef a(): pass\n") red[0].decorators[0].call = "" assert red.dumps() == "@pouet\ndef a(): pass\n" def test_def_argument_setattr_value(): red = RedBaron("def a(b): pass") red[0].arguments[0].value = "plop" assert red.dumps() == "def a(b=plop): pass\n" with pytest.raises(Exception): red[0].arguments[0].value = "def a(): pass\n" def test_def_argument_setattr_annotation(): red = RedBaron("def a(b): pass") red[0].arguments[0].annotation = "Int" assert red.dumps() == "def a(b : Int): pass\n" def test_def_argument_setattr_annotation_value(): red = RedBaron("def a(b : Int): pass") red[0].arguments[0].value = "plop" assert red.dumps() == "def a(b : Int=plop): pass\n" def test_def_argument_setattr_remove_annotation(): red = RedBaron("def a(b : Int): pass") red[0].arguments[0].annotation = "" assert red.dumps() == "def a(b): pass\n" def test_list_argument_setattr_annotation(): red = RedBaron("def a(*b): pass") red[0].arguments[0].annotation = "Int" assert red.dumps() == "def a(*b : Int): pass\n" def test_list_argument_setattr_remove_annotation(): red = RedBaron("def a(*b : Int): pass") red[0].arguments[0].annotation = "" assert red.dumps() == "def a(*b): pass\n" def test_dict_argument_setattr_annotation(): red = RedBaron("def a(**b): pass") red[0].arguments[0].annotation = "Int" assert red.dumps() == "def a(**b : Int): pass\n" def test_dict_argument_setattr_remove_annotation(): red = RedBaron("def a(**b : Int): pass") red[0].arguments[0].annotation = "" assert red.dumps() == "def a(**b): pass\n" def test_del_setattr_value(): red = RedBaron("del a") red[0].value = "a, b, c" assert red.dumps() == "del a, b, c" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_dict_argument_setattr_value(): red = RedBaron("a(**b)") red[0].value[1].value[0].value = "plop" assert red.dumps() == "a(**plop)" with pytest.raises(Exception): red[0].value[1].value[0].value = "def a(): pass\n" def test_dict_item_setattr_value(): red = RedBaron("{a: b}") red[0].value[0].value = "plop" assert red.dumps() == "{a: plop}" with pytest.raises(Exception): red[0].value[0].value = "def a(): pass\n" def test_dict_item_setattr_key(): red = RedBaron("{a: b}") red[0].value[0].key = "plop" assert red.dumps() == "{plop: b}" with pytest.raises(Exception): red[0].value[0].key = "def a(): pass\n" def test_exec_setattr_value(): red = RedBaron("exec a") red[0].value = "plop" assert red.dumps() == "exec plop" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_exec_setattr_globals(): red = RedBaron("exec a in b") red[0].globals = "pouet" assert red.dumps() == "exec a in pouet" with pytest.raises(Exception): red[0].globals = "def a(): pass\n" def test_exec_setattr_globals_wasnt_set(): red = RedBaron("exec a") red[0].globals = "pouet" assert red.dumps() == "exec a in pouet" with pytest.raises(Exception): red[0].globals = "def a(): pass\n" def test_exec_setattr_globals_none(): red = RedBaron("exec a in b") red[0].globals = "" assert red.dumps() == "exec a" with pytest.raises(Exception): red[0].globals = "def a(): pass\n" def test_exec_setattr_locals(): red = RedBaron("exec a in b") red[0].locals = "pouet" assert red.dumps() == "exec a in b, pouet" with pytest.raises(Exception): red[0].locals = "def a(): pass\n" def test_exec_setattr_locals_none(): red = RedBaron("exec a in b, c") red[0].locals = "" assert red.dumps() == "exec a in b" with pytest.raises(Exception): red[0].locals = "def a(): pass\n" def test_exec_setattr_locals_no_globals_raise(): red = RedBaron("exec a") with pytest.raises(Exception): red[0].locals = "pouet" def test_from_import_setattr_value(): red = RedBaron("from a import b") red[0].value = "a.b.c" assert red.dumps() == "from a.b.c import b" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_from_import_setattr_targets(): red = RedBaron("from a import b") red[0].targets = "a as plop, d as oufti" assert red.dumps() == "from a import a as plop, d as oufti" with pytest.raises(Exception): red[0].targets = "def a(): pass\n" def test_getitem_setattr_value(): red = RedBaron("a[b]") red[0].value[1].value = "a.b.c" assert red.dumps() == "a[a.b.c]" with pytest.raises(Exception): red[0].value[1].value = "def a(): pass\n" def test_nonlocal_setattr_value(): red = RedBaron("nonlocal a") red[0].value = "a, b, c" assert red.dumps() == "nonlocal a, b, c" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_global_setattr_value(): red = RedBaron("global a") red[0].value = "a, b, c" assert red.dumps() == "global a, b, c" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_lambda_setattr_value(): red = RedBaron("lambda: plop") red[0].value = "42 * 3" assert red.dumps() == "lambda: 42 * 3" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_lambda_setattr_arguments(): red = RedBaron("lambda: plop") red[0].arguments = "a, b=c, *d, **e" assert red.dumps() == "lambda a, b=c, *d, **e: plop" with pytest.raises(Exception): red[0].arguments = "def a(): pass\n" def test_lambda_setattr_arguments_none(): red = RedBaron("lambda a, b=c, *d, **e: plop") red[0].arguments = "" assert red.dumps() == "lambda: plop" def test_list_argument_setattr_value(): red = RedBaron("lambda *b: plop") red[0].arguments[0].value = "hop" assert red.dumps() == "lambda *hop: plop" with pytest.raises(Exception): red[0].arguments[0].value = "def a(): pass\n" def test_print_setattr_value(): red = RedBaron("print a") red[0].value = "hop, plop" assert red.dumps() == "print hop, plop" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_print_setattr_value_none(): red = RedBaron("print a") red[0].value = "" assert red.dumps() == "print" def test_print_setattr_value_none_to_not_none(): red = RedBaron("print") red[0].value = "a" assert red.dumps() == "print a" def test_print_setattr_destination(): red = RedBaron("print >>zop") red[0].destination = "hop" assert red.dumps() == "print >>hop" with pytest.raises(Exception): red[0].destination = "def a(): pass\n" def test_print_setattr_destination_none(): red = RedBaron("print >>zop") red[0].destination = "" assert red.dumps() == "print" def test_print_setattr_destination_none_to_not_none(): red = RedBaron("print") red[0].destination = "hop" assert red.dumps() == "print >>hop" def test_print_setattr_value_was_none_and_had_destination(): red = RedBaron("print >>zop") red[0].value = "plop" assert red.dumps() == "print >>zop, plop" def test_print_setattr_value_none_had_destination(): red = RedBaron("print >>zop, plop") red[0].value = "" assert red.dumps() == "print >>zop" def test_print_setattr_dest_none_had_value(): red = RedBaron("print >>zop, plop") red[0].destination = "" assert red.dumps() == "print plop" def test_print_setattr_dest_was_none_had_value(): red = RedBaron("print zop") red[0].destination = "plop" assert red.dumps() == "print >>plop, zop" def test_raise_setattr_value(): red = RedBaron("raise a") red[0].value = "hop" assert red.dumps() == "raise hop" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_raise_setattr_value_none(): red = RedBaron("raise a") red[0].value = "" assert red.dumps() == "raise" def test_raise_setattr_value_was_none(): red = RedBaron("raise") red[0].value = "a" assert red.dumps() == "raise a" def test_raise_setattr_instance(): red = RedBaron("raise a, b") red[0].instance = "hop" assert red.dumps() == "raise a, hop" with pytest.raises(Exception): red[0].instance = "def a(): pass\n" def test_raise_setattr_instance_none(): red = RedBaron("raise a, b") red[0].instance = "" assert red.dumps() == "raise a" def test_raise_setattr_instance_was_none(): red = RedBaron("raise a") red[0].instance = "b" assert red.dumps() == "raise a, b" def test_raise_setattr_instance_no_value_raise(): red = RedBaron("raise") with pytest.raises(Exception): red[0].instance = "b" def test_raise_setattr_traceback(): red = RedBaron("raise a, b, c") red[0].traceback = "hop" assert red.dumps() == "raise a, b, hop" with pytest.raises(Exception): red[0].traceback = "def a(): pass\n" def test_raise_setattr_traceback_none(): red = RedBaron("raise a, b, c") red[0].traceback = "" assert red.dumps() == "raise a, b" def test_raise_setattr_traceback_was_none(): red = RedBaron("raise a, b") red[0].traceback = "c" assert red.dumps() == "raise a, b, c" def test_raise_setattr_traceback_raise(): red = RedBaron("raise") with pytest.raises(Exception): red[0].traceback = "c" red = RedBaron("raise a") with pytest.raises(Exception): red[0].traceback = "c" def test_raise_from_setattr_instance(): red = RedBaron("raise a from b") red[0].instance = "hop" assert red.dumps() == "raise a from hop" def test_raise_from_setattr_instance_remove(): red = RedBaron("raise a from b") red[0].instance = "" assert red.dumps() == "raise a" def test_raise_from_setattr_set_instance(): red = RedBaron("raise a") red[0].instance = "b" assert red.dumps() == "raise a, b" red[0].comma_or_from = "from" assert red.dumps() == "raise a from b" red[0].comma_or_from = "," assert red.dumps() == "raise a, b" def test_raise_from_setattr_set_comma(): red = RedBaron("raise a from b") red[0].comma_or_from = "," assert red.dumps() == "raise a, b" def test_raise_from_setattr_set_from(): red = RedBaron("raise a, b") red[0].comma_or_from = "from" assert red.dumps() == "raise a from b" def test_return_setattr_value(): red = RedBaron("return a") red[0].value = "hop" assert red.dumps() == "return hop" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_return_setattr_value_none(): red = RedBaron("return a") red[0].value = "" assert red.dumps() == "return" def test_return_setattr_value_was_none(): red = RedBaron("return") red[0].value = "a" assert red.dumps() == "return a" def test_slice_setattr_lower(): red = RedBaron("a[:]") red[0].value[1].value.lower = "hop" assert red.dumps() == "a[hop:]" with pytest.raises(Exception): red[0].value[1].value.lower = "def a(): pass\n" def test_slice_setattr_lower_none(): red = RedBaron("a[a:]") red[0].value[1].value.lower = "" assert red.dumps() == "a[:]" def test_slice_setattr_upper(): red = RedBaron("a[:]") red[0].value[1].value.upper = "hop" assert red.dumps() == "a[:hop]" with pytest.raises(Exception): red[0].value[1].value.upper = "def a(): pass\n" def test_slice_setattr_upper_none(): red = RedBaron("a[:hop]") red[0].value[1].value.upper = "" assert red.dumps() == "a[:]" def test_slice_setattr_step(): red = RedBaron("a[:]") red[0].value[1].value.step = "hop" assert red.dumps() == "a[::hop]" with pytest.raises(Exception): red[0].value[1].value.step = "def a(): pass\n" def test_slice_setattr_step_none(): red = RedBaron("a[::hop]") red[0].value[1].value.step = "" assert red.dumps() == "a[:]" def test_ternary_operator_setattr_first(): red = RedBaron("a if b else c") red[0].first = "hop" assert red.dumps() == "hop if b else c" with pytest.raises(Exception): red[0].first = "def a(): pass\n" def test_ternary_operator_setattr_second(): red = RedBaron("a if b else c") red[0].second = "hop" assert red.dumps() == "a if b else hop" with pytest.raises(Exception): red[0].second = "def a(): pass\n" def test_ternary_operator_setattr_value(): red = RedBaron("a if b else c") red[0].value = "hop" assert red.dumps() == "a if hop else c" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_unitary_operator_setattr_target(): red = RedBaron("-a") red[0].target = "hop" assert red.dumps() == "-hop" with pytest.raises(Exception): red[0].target = "def a(): pass\n" def test_yield_setattr_value(): red = RedBaron("yield a") red[0].value = "hop" assert red.dumps() == "yield hop" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_yield_setattr_value_none(): red = RedBaron("yield a") red[0].value = "" assert red.dumps() == "yield" def test_yield_setattr_value_was_none(): red = RedBaron("yield") red[0].value = "a" assert red.dumps() == "yield a" def test_yield_atom_setattr_value(): red = RedBaron("(yield a)") red[0].value = "hop" assert red.dumps() == "(yield hop)" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_yield_atom_setattr_value_none(): red = RedBaron("(yield a)") red[0].value = "" assert red.dumps() == "(yield)" def test_yield_atom_setattr_value_was_none(): red = RedBaron("(yield)") red[0].value = "a" assert red.dumps() == "(yield a)" def test_yield_from_setattr_value(): red = RedBaron("yield from a") red[0].value = "hop" assert red.dumps() == "yield from hop" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_list_comprehension_set_attr_result(): red = RedBaron("[a for b in c]") red[0].result = "hop" assert red.dumps() == "[hop for b in c]" with pytest.raises(Exception): red[0].result = "def a(): pass\n" def test_list_comprehension_set_attr_generators(): red = RedBaron("[a for b in c]") red[0].generators = "for pouet in plop if zuto" assert red.dumps() == "[a for pouet in plop if zuto]" with pytest.raises(Exception): red[0].generators = "def a(): pass\n" def test_generator_comprehension_set_attr_result(): red = RedBaron("(a for b in c)") red[0].result = "hop" assert red.dumps() == "(hop for b in c)" with pytest.raises(Exception): red[0].result = "def a(): pass\n" def test_generator_comprehension_set_attr_generators(): red = RedBaron("(a for b in c)") red[0].generators = "for pouet in plop if zuto" assert red.dumps() == "(a for pouet in plop if zuto)" with pytest.raises(Exception): red[0].generators = "def a(): pass\n" def test_set_comprehension_set_attr_result(): red = RedBaron("{a for b in c}") red[0].result = "hop" assert red.dumps() == "{hop for b in c}" with pytest.raises(Exception): red[0].result = "def a(): pass\n" def test_set_comprehension_set_attr_generators(): red = RedBaron("{a for b in c}") red[0].generators = "for pouet in plop if zuto" assert red.dumps() == "{a for pouet in plop if zuto}" with pytest.raises(Exception): red[0].generators = "def a(): pass\n" def test_dict_comprehension_set_attr_result(): red = RedBaron("{a: z for b in c}") red[0].result = "hop: pop" assert red.dumps() == "{hop: pop for b in c}" with pytest.raises(Exception): red[0].result = "def a(): pass\n" def test_dict_comprehension_set_attr_generators(): red = RedBaron("{a: z for b in c}") red[0].generators = "for pouet in plop if zuto" assert red.dumps() == "{a: z for pouet in plop if zuto}" with pytest.raises(Exception): red[0].generators = "def a(): pass\n" def test_comprehension_loop_setattr_iterator(): red = RedBaron("{a: z for b in c}") red[0].generators[0].iterator = "plop" assert red.dumps() == "{a: z for plop in c}" with pytest.raises(Exception): red[0].generators[0].iterator = "def a(): pass\n" def test_comprehension_loop_setattr_target(): red = RedBaron("{a: z for b in c}") red[0].generators[0].target = "plop" assert red.dumps() == "{a: z for b in plop}" with pytest.raises(Exception): red[0].generators[0].target = "def a(): pass\n" def test_comprehension_loop_setattr_ifs(): red = RedBaron("{a: z for b in c}") red[0].generators[0].ifs = "if x if y if z" assert red.dumps() == "{a: z for b in c if x if y if z}" with pytest.raises(Exception): red[0].generators[0].ifs = "def a(): pass\n" def test_comprehension_loop_setattr_ifs_none(): red = RedBaron("{a: z for b in c if x if y if z}") red[0].generators[0].ifs = "" assert red.dumps() == "{a: z for b in c}" def test_comprehension_if_setattr_value(): red = RedBaron("[a for b in c if plop]") red[0].generators[0].ifs[0].value = "1 + 1 == 2" assert red.dumps() == "[a for b in c if 1 + 1 == 2]" with pytest.raises(Exception): red[0].generators[0].ifs[0].value = "def a(): pass\n" def test_argument_generator_comprehension_set_attr_result(): red = RedBaron("a(a for b in c)") red[0].value[1].value[0].result = "hop" assert red.dumps() == "a(hop for b in c)" with pytest.raises(Exception): red[0].value[1].value[0].result = "def a(): pass\n" def test_argument_generator_comprehension_set_attr_generators(): red = RedBaron("a(a for b in c)") red[0].value[1].value[0].generators = "for pouet in plop if zuto" assert red.dumps() == "a(a for pouet in plop if zuto)" with pytest.raises(Exception): red[0].value[1].value[0].generators = "def a(): pass\n" def test_string_chain_set_attr_value(): red = RedBaron("'a' 'b'") red[0].value = "'a' 'b' 'c'" assert red.dumps() == "'a' 'b' 'c'" with pytest.raises(Exception): red[0].value = "def a(): pass\n" def test_dotted_as_name_setattr_value(): red = RedBaron("import a") red[0].value[0].value = "a.b.c" assert red.dumps() == "import a.b.c" with pytest.raises(Exception): red[0].value[0].value = "def a(): pass\n" def test_dotted_as_name_setattr_target(): red = RedBaron("import a as qsd") red[0].value[0].target = "plop" assert red.dumps() == "import a as plop" with pytest.raises(Exception): red[0].value[0].target = "def a(): pass\n" def test_dotted_as_name_setattr_target_none(): red = RedBaron("import a as qsd") red[0].value[0].target = "" assert red.dumps() == "import a" def test_dotted_as_name_setattr_target_was_none(): red = RedBaron("import a") red[0].value[0].target = "qsd" assert red.dumps() == "import a as qsd" def test_name_as_name_setattr_value(): red = RedBaron("from x import a") red[0].targets[0].value = "a" assert red.dumps() == "from x import a" with pytest.raises(Exception): red[0].targets[0].value = "def a(): pass\n" def test_name_as_name_setattr_target(): red = RedBaron("from x import a as qsd") red[0].targets[0].target = "plop" assert red.dumps() == "from x import a as plop" with pytest.raises(Exception): red[0].targets[0].target = "def a(): pass\n" def test_name_as_name_setattr_target_none(): red = RedBaron("from x import a as qsd") red[0].targets[0].target = "" assert red.dumps() == "from x import a" def test_name_as_name_setattr_target_was_none(): red = RedBaron("from x import a") red[0].targets[0].target = "qsd" assert red.dumps() == "from x import a as qsd" has_else_member_list = [("while True:\n pass\n", "else"), ("for a in a:\n pass\n", "else"),("try:\n pass\nexcept:\n pass\n", "else"), ("try:\n pass\nexcept:\n pass\n", "finally")] @pytest.fixture(params=has_else_member_list) def has_else_member(request): return request.param simple_body = ["plop", " plop", "\nplop", " \nplop", " \n plop", " plop", "\n plop", " \n plop", "plop\n", "plop\n\n", "plop\n\n\n\n\n", ] @pytest.fixture(params=simple_body) def else_simple_body(request): return request.param two_lines_body = ["plop\nplouf", "\nplop\nplouf", " plop\n plouf", "\n plop\n plouf", " \n plop\n plouf", " plop\n plouf", "\n plop\n plouf", " \n plop\n plouf", " plop\n plouf", "\n plop\n plouf", " \n plop\n plouf"] @pytest.fixture(params=two_lines_body) def else_two_line_body(request): return request.param simple_body_starting_with_else = [ "%s:\n pass", "%s:\n pass\n", " %s:\n pass\n", "%s:\n pass\n\n", "%s:\n pass\n\n\n\n\n", "%s:\n pass\n \n", "%s:\n pass\n \n\n\n\n", "%s:\n pass", "%s:\n pass\n", " %s:\n pass\n", " %s:\n pass\n\n", " %s:\n pass\n\n\n\n\n", " %s:\n pass\n \n", " %s:\n pass\n \n\n\n\n", ] @pytest.fixture(params=simple_body_starting_with_else) def else_simple_body_starting_with_else(request): return request.param def test_while_else_simple(else_simple_body_starting_with_else, has_else_member): red = RedBaron(has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body_starting_with_else % has_else_member[1]) assert red.dumps() == "%s%s:\n pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_simple_root_level(else_simple_body, has_else_member): red = RedBaron("%s\n\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body) assert red.dumps() == "%s%s:\n plop\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_not_simple_root_level(else_simple_body_starting_with_else, has_else_member): red = RedBaron("%s\n\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body_starting_with_else % has_else_member[1]) assert red.dumps() == "%s%s:\n pass\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_root_level_too_few_blanks_lines(else_simple_body, has_else_member): red = RedBaron("%s\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body) assert red.dumps() == "%s%s:\n plop\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_root_level_too_few_blanks_lines_starting_with_else(else_simple_body_starting_with_else, has_else_member): red = RedBaron("%s\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body_starting_with_else % has_else_member[1]) assert red.dumps() == "%s%s:\n pass\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_root_level_too_much_blanks_lines(else_simple_body, has_else_member): red = RedBaron("%s\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body) assert red.dumps() == "%s%s:\n plop\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_root_level_too_much_blanks_lines_starting_with_else(else_simple_body_starting_with_else, has_else_member): red = RedBaron("%s\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body_starting_with_else % has_else_member[1]) assert red.dumps() == "%s%s:\n pass\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else_root_level_too_much_blanks_lines_starting_two_line_body(else_two_line_body, has_else_member): red = RedBaron("%s\ndef other_stuff(): pass\n" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_two_line_body) assert red.dumps() == "%s%s:\n plop\n plouf\n\n\ndef other_stuff(): pass\n" % (has_else_member[0], has_else_member[1]) def test_while_else(else_simple_body, has_else_member): red = RedBaron("%s" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_simple_body) assert red.dumps() == "%s%s:\n plop\n" % (has_else_member[0], has_else_member[1]) def test_while_else_two_line_body(else_two_line_body, has_else_member): red = RedBaron("%s" % has_else_member[0]) setattr(red[0], has_else_member[1] + "_", else_two_line_body) assert red.dumps() == "%s%s:\n plop\n plouf\n" % (has_else_member[0], has_else_member[1]) code_else_block_setattr_one_level = """\ def pouet(): %s """ code_else_block_setattr_one_level_result = """\ def pouet(): %s %s: pass """ def test_while_else_setattr_one_level_simple_body(else_simple_body, has_else_member): result_keyword = has_else_member[1] has_else_member = "\n ".join(has_else_member[0].split("\n")).rstrip() red = RedBaron(code_else_block_setattr_one_level % has_else_member) setattr(red[0].value.node_list[1], result_keyword, else_simple_body.replace("plop", "pass")) assert red.dumps() == code_else_block_setattr_one_level_result % (has_else_member, result_keyword) def test_while_else_setattr_one_level_simple_body_start_with_else(else_simple_body_starting_with_else, has_else_member): result_keyword = has_else_member[1] has_else_member = "\n ".join(has_else_member[0].split("\n")).rstrip() red = RedBaron(code_else_block_setattr_one_level % has_else_member) setattr(red[0].value.node_list[1], result_keyword, else_simple_body_starting_with_else % result_keyword) assert red.dumps() == code_else_block_setattr_one_level_result % (has_else_member, result_keyword) code_else_block_setattr_one_level_followed = """\ def pouet(): %s pass """ code_else_block_setattr_one_level_followed_result = """\ def pouet(): %s %s: pass pass """ def test_while_else_setattr_one_level_simple_body_followed(else_simple_body, has_else_member): result_keyword = has_else_member[1] has_else_member = "\n ".join(has_else_member[0].split("\n")).rstrip() red = RedBaron(code_else_block_setattr_one_level_followed % has_else_member) setattr(red[0].value.node_list[1], result_keyword, else_simple_body.replace("plop", "pass")) assert red.dumps() == code_else_block_setattr_one_level_followed_result % (has_else_member, result_keyword) def test_while_else_setattr_one_level_simple_body_start_with_else_followed(else_simple_body_starting_with_else, has_else_member): result_keyword = has_else_member[1] has_else_member = "\n ".join(has_else_member[0].split("\n")).rstrip() red = RedBaron(code_else_block_setattr_one_level_followed % has_else_member) setattr(red[0].value.node_list[1], result_keyword, else_simple_body_starting_with_else % result_keyword) assert red.dumps() == code_else_block_setattr_one_level_followed_result % (has_else_member, result_keyword) def test_get_last_member_to_clean_while(): red = RedBaron("while True: pass") assert red[0]._get_last_member_to_clean() is red[0] def test_get_last_member_to_clean_for(): red = RedBaron("for a in a: pass") assert red[0]._get_last_member_to_clean() is red[0] def test_get_last_member_to_clean_try_except(): red = RedBaron("try: pass\nexcept: pass") assert red[0]._get_last_member_to_clean() is red[0].excepts[-1] def test_get_last_member_to_clean_try_excepts(): red = RedBaron("try: pass\nexcept: pass\nexcept: pass") assert red[0]._get_last_member_to_clean() is red[0].excepts[-1] def test_get_last_member_to_clean_try_else(): red = RedBaron("try: pass\nexcept: pass\nelse: pass") assert red[0]._get_last_member_to_clean() is red[0].else_ def test_get_last_member_to_clean_try_finally(): red = RedBaron("try: pass\nexcept: pass\nelse: pass\nfinally: pass") assert red[0]._get_last_member_to_clean() is red[0].finally_ def test_get_last_member_to_clean_try_else_finally(): red = RedBaron("try: pass\nexcept: pass\nfinally: pass") assert red[0]._get_last_member_to_clean() is red[0].finally_ def test_get_last_member_to_clean_try_finally_only(): red = RedBaron("try: pass\nfinally: pass") assert red[0]._get_last_member_to_clean() is red[0].finally_ def test_remove_else_setattr(): red = RedBaron("while True: pass\nelse: pass\n") red[0].else_ = "" assert red.dumps() == "while True: pass\n" def test_remove_else_setattr_followed(): red = RedBaron("while True: pass\nelse: pass\n\n\nstuff") red[0].else_ = "" assert red.dumps() == "while True: pass\n\n\nstuff" def test_remove_else_setattr_indented(): red = RedBaron("def a():\n while True: pass\n else: pass\n") red.while_.else_ = "" assert red.dumps() == "def a():\n while True: pass\n" def test_remove_else_setattr_indented_followed(): red = RedBaron("def a():\n while True: pass\n else: pass\n\n\n stuff\n") red.while_.else_ = "" assert red.dumps() == "def a():\n while True: pass\n\n\n stuff\n" def test_try_setattr_excepts(): red = RedBaron("try:\n pass\nfinally:\n pass") red[0].excepts = "except:\n pass\n" assert red.dumps() == "try:\n pass\nexcept:\n pass\nfinally:\n pass\n" def test_try_setattr_excepts_replace(): red = RedBaron("try:\n pass\nexcept:\n pouet\n") red[0].excepts = "except:\n pass\n" assert red.dumps() == "try:\n pass\nexcept:\n pass\n" def test_try_setattr_excepts_remove(): red = RedBaron("try:\n pass\nexcept:\n pass\nfinally:\n pass\n") red[0].excepts = "" assert red.dumps() == "try:\n pass\nfinally:\n pass\n" def test_try_setattr_excepts_indented_input(): red = RedBaron("try:\n pass\nfinally:\n pass") red[0].excepts = " except:\n pass\n" assert red.dumps() == "try:\n pass\nexcept:\n pass\nfinally:\n pass\n" def test_try_setattr_excepts_replace_followed(): red = RedBaron("try:\n pass\nexcept:\n pouet\n\n\nplop\n") red[0].excepts = "except:\n pass\n" assert red.dumps() == "try:\n pass\nexcept:\n pass\n\n\nplop\n" def test_try_setattr_excepts_replace_followed_strip(): red = RedBaron("try:\n pass\nexcept:\n pouet\n\n\nplop\n") red[0].excepts = "except:\n pass\n\n\n\n" assert red.dumps() == "try:\n pass\nexcept:\n pass\n\n\nplop\n" def test_try_setattr_excepts_replace_strip(): red = RedBaron("try:\n pass\nexcept:\n pouet\n") red[0].excepts = "except:\n pass\n\n\n\n" assert red.dumps() == "try:\n pass\nexcept:\n pass\n" def test_try_setattr_excepts_indented(): red = RedBaron("def a():\n try:\n pass\n finally:\n pass") red.try_.excepts = " except:\n pass\n" assert red.dumps() == "def a():\n try:\n pass\n except:\n pass\n finally:\n pass\n" def test_try_setattr_excepts_indented_replace(): red = RedBaron("def a():\n try:\n pass\n except:\n pouet") red.try_.excepts = " except:\n pass\n" assert red.dumps() == "def a():\n try:\n pass\n except:\n pass\n" def test_try_setattr_excepts_indented_replace_followed(): red = RedBaron("def a():\n try:\n pass\n except:\n pouet\n\n plop\n") red.try_.excepts = " except:\n pass\n" assert red.dumps() == "def a():\n try:\n pass\n except:\n pass\n\n plop\n" def test_ifelseblock_setattr(): red = RedBaron("if a:\n pass\n") red[0].value = "if 1 + 1:\n qsd\n" assert red.dumps() == "if 1 + 1:\n qsd\n" def test_ifelseblock_setattr_input_indented(): red = RedBaron("if a:\n pass\n") red[0].value = " if 1 + 1:\n qsd\n" assert red.dumps() == "if 1 + 1:\n qsd\n" def test_ifelseblock_setattr_trailing(): red = RedBaron("if a:\n pass\n") red[0].value = "if 1 + 1:\n qsd\n\n\n\n\n" assert red.dumps() == "if 1 + 1:\n qsd\n" def test_ifelseblock_setattr_followed(): red = RedBaron("if a:\n pass\n\n\npouet\n") red[0].value = "if 1 + 1:\n qsd\n\n\n\n\n" assert red.dumps() == "if 1 + 1:\n qsd\n\n\npouet\n" def test_ifelseblock_setattr_indented(): red = RedBaron("def a():\n if a:\n pass\n") red[0].value.node_list[1].value = "if 1 + 1:\n qsd\n" assert red.dumps() == "def a():\n if 1 + 1:\n qsd\n" def test_ifelseblock_setattr_indented_trailing(): red = RedBaron("def a():\n if a:\n pass\n") red[0].value.node_list[1].value = "if 1 + 1:\n qsd\n\n\n\n" assert red.dumps() == "def a():\n if 1 + 1:\n qsd\n" def test_ifelseblock_setattr_indented_followed(): red = RedBaron("def a():\n if a:\n pass\n\n\n pouet\n") red[0].value.node_list[1].value = "if 1 + 1:\n qsd\n" assert red.dumps() == "def a():\n if 1 + 1:\n qsd\n\n pouet\n" redbaron-0.9.2/utils/000077500000000000000000000000001344351435400144645ustar00rootroot00000000000000redbaron-0.9.2/utils/README000066400000000000000000000001401344351435400153370ustar00rootroot00000000000000Folder containing some random script tests I write. Might proves itself useful for some people. redbaron-0.9.2/utils/indentation_test.py000066400000000000000000000007421344351435400204140ustar00rootroot00000000000000""" Recursivly traverse a python script to test if .indentation seems to be working everywhere """ from redbaron import RedBaron red = RedBaron(open("../redbaron.py", "r").read()) # red = RedBaron(open(__file__, "r").read()) def walk(node): if node is None: return print([node.indentation, node]) for i in node._dict_keys: walk(getattr(node, i)) for i in node._list_keys: map(walk, getattr(node, i)) map(walk, red) # print(walk(red[0])) redbaron-0.9.2/utils/test_distribution.sh000077500000000000000000000005541344351435400206050ustar00rootroot00000000000000#!/bin/zsh source ~/.zshrc if [ -e "./test_distribution" ]; then rm -rf ./test_distribution fi mkdir test_distribution cd test_distribution mkvee source ./ve/bin/active upgrade_pip pip install redbaron pytest wget https://raw.githubusercontent.com/Psycojoker/redbaron/135071427967ee8cd97c3298da0b60a0923b7caa/tests/test_redbaron.py py.test test_redbaron.py