diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..5417ab2
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,28 @@
+# .coveragerc to control coverage.py
+[run]
+branch = True
+source=myql
+
+[report]
+# Regexes for lines to exclude from consideration
+exclude_lines =
+ # Have to re-enable the standard pragma
+ pragma: no cover
+
+ # Don't complain about missing debug-only code:
+ def __repr__
+ if self\.debug
+
+ # Don't complain if tests don't hit defensive assertion code:
+ raise AssertionError
+ raise NotImplementedError
+
+ # Don't complain if non-runnable code isn't run:
+ if 0:
+ if __name__ == .__main__.:
+
+ignore_errors = True
+
+[html]
+directory = htmlcov
+
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
index 25dfc84..49b33e8
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,7 @@ coverage.xml
# Sphinx documentation
docs/_build/
+myconfig.py
+*.xml
+site
+*.json
diff --git a/.travis.yml b/.travis.yml
index c15d94b..40c424c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,23 @@
+sudo: false
language: python
python:
- - "2.7"
-
-install:
- - pip install -r requirements.txt --use-mirrors
-
+ - '2.7'
+ - '3.3'
+ - '3.4'
+ - '3.5'
+ - pypy
+ - pypy3
+install:
+ - pip install -r requirements.txt
+ - pip install coverage coveralls pytest
+script:
+ - coverage run --source=myql -m pytest -v tests/tests.py
+env:
+ global:
+ secure: hXpkZqclyUXMX586jS4BtJmYsrszVr/jWbMiLWLOZ2z7n5LK9INziKkOqYu0JTBskAHVEmhxJ7oNOD9gI/06btLO5NLBONN3qtsHq4UruCo0Zlx2BgaDfR5FqnrVqk+fMbLCbzWgo0wShM4o8jTGy7l22xqhhYAsuubmayqEfPk=
+before_install:
+- openssl aes-256-cbc -K $encrypted_60f42691f4f2_key -iv $encrypted_60f42691f4f2_iv
+ -in credentials.json.enc -out credentials.json -d
+after_success:
+ - coverage report -m
+ - coveralls
diff --git a/LICENSE b/LICENSE
old mode 100644
new mode 100755
index d7f1051..c304a72
--- a/LICENSE
+++ b/LICENSE
@@ -1,339 +1,22 @@
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+The MIT License (MIT)
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
+Copyright (c) 2015 josuebrunel
- Preamble
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- {description}
- Copyright (C) {year} {fullname}
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- {signature of Ty Coon}, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..8e5e8a9
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include requirements.txt
+include README.rst
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index 30174c8..32a6e96
--- a/README.md
+++ b/README.md
@@ -1,9 +1,20 @@
-lokingYQL
+[mYQL](http://myql.readthedocs.org/en/latest/)
=========
-LokingYQL is a Python wrapper of the Yahoo Query Language.
+[![Build Status](https://travis-ci.org/josuebrunel/myql.svg?branch=master)](https://travis-ci.org/josuebrunel/myql) [![Documentation Status](https://readthedocs.org/projects/myql/badge/?version=latest)](https://myql.readthedocs.org)
+[![Code Health](https://landscape.io/github/josuebrunel/myql/master/landscape.svg?style=flat)](https://landscape.io/github/josuebrunel/myql/master)
+[![PyPI](https://img.shields.io/pypi/status/myql.svg?style=flat)](https://pypi.python.org/pypi/myql)
+[![PyPI](https://img.shields.io/pypi/v/myql.svg?style=flat)](https://pypi.python.org/pypi/myql)
+[![PyPI](https://img.shields.io/pypi/dm/myql.svg?style=flat)](https://pypi.python.org/pypi/myql)
+[![PyPI](https://img.shields.io/pypi/pyversions/myql.svg)](https://pypi.python.org/pypi/myql)
+[![PyPI](https://img.shields.io/pypi/implementation/myql.svg?style=flat)](https://pypi.python.org/pypi/myql)
+[![Coverage Status](https://coveralls.io/repos/josuebrunel/myql/badge.svg?branch=testing)](https://coveralls.io/r/josuebrunel/myql?branch=master)
+[![PyPI](https://img.shields.io/pypi/l/myql.svg?style=flat)](https://pypi.python.org/pypi/myql)
-Yahoo! Query Langauge Documentation and Support
+
+mYQL is a Python wrapper of the Yahoo Query Language.
+
+Yahoo! Query Language Documentation and Support
===============================================
* Yahoo! Query Language - http://developer.yahoo.com/yql/
@@ -12,78 +23,154 @@ Yahoo! Query Langauge Documentation and Support
* Yahoo! Social APIs - http://developer.yahoo.com/social/
* Yahoo! QUery Language Console https://developer.yahoo.com/yql/console/
-version 1.0
-===========
-
-* Access to resources requiring authentication
-
-version 0.5.6
-=============
-* fetch data
-* access to community data
-* select data format (xml/json)
-* change data source
-* filter data
+### Features
-fixes:
-------
-* fix handling of default and on the fly response format
-* fix limit on ***select(...).where(...)*** when no limit value is passed
-* fix limit on ***get(...)***
+* Simple YQL Query
+* Authenticated YQL Query ( OAuth )
+* StockScraper
+* YQL Open Table (Classes and Metaclasses) Generator
+* Response prettyfier
-installation
+Installation
============
```shell
-$ python setup.py install
-```
-
-how to use
-==========
-
-```python
->>> import lokingyql
->>> yql = lokingyql.LokingYQL()
->>> yql.diagnostics = True # To turn diagnostics on
+$ pip install myql
```
-access to community tables
---------------------------
+Quick Start
+===========
-```python
->>> yql = lokingyql.LokingYQL()
->>> rep = yql.rawQuery('desc yahoo.finance.quotes ')
->>> rep.json()
-{u'error': {u'lang': u'en-US', u'description': u'No definition found for Table yahoo.finance.quotes'}}
->>> yql.community= True # Setting up access to community
->>> rep = yql.rawQuery('desc yahoo.finance.quotes ')
->>> rep.json()
-{u'query': {u'count': 1, u'lang': u'en-US', u'results': {u'table': {u'src': u'http://www.datatables.org/yahoo/finance/yahoo.finance.quotes.xml', u'hash': u'061616a1c033ae89aaf2cbe83790b979', u'name': u'yahoo.finance.quotes', u'request': {u'select': {u'key': {u'required': u'true', u'type': u'xs:string', u'name': u'symbol'}}}, u'meta': {u'sampleQuery': u'\n\t\t\tselect * from yahoo.finance.quotes where symbol in ("YHOO","AAPL","GOOG","MSFT")\n\t\t'}, u'security': u'ANY'}}, u'created': u'2014-08-24T11:26:48Z'}}
->>>
-```
+It's important to know that **response** is a just **requests.models.Response** object.
+Yes indeed, ***mYQL*** uses ***requests*** :smile:
-***OR***
+By default, you have access to the **community tables**. If for whatsoever reason you would like to not have access to those tables
```python
->>> import lokingyql
->>> yql = lokingyql.LokingYQL(community=True)
->>> # do your magic
+>>> import myql
+>>> yql = myql.MYQL(community=False)
```
-changing response format (xml or json)
---------------------------------------
+####Changing response format (xml or json)
The response format is by default ***json***.
```python
->>> import lokingyql
->>> yql = lokingyql.LokingYQL(format='xml', community=True)
->>> rep = yql.rawQuery('select name, woeid from geo.states where place="Congo"')
->>> rep.text
-u'\nCuvette-Ouest Department55998384Cuvette Department2344968Plateaux District2344973Sangha2344974Lekoumou2344970Pool Department2344975Likouala Department2344971Niari Department2344972Brazzaville2344976Bouenza Department2344967Kouilou2344969\n\n'
->>> rep = yql.rawQuery('select name, woeid from geo.states where place="Congo"', format='json')
->>> rep.json()
-{u'query': {u'count': 11, u'lang': u'en-US', u'results': {u'place': [{u'woeid': u'55998384', u'name': u'Cuvette-Ouest Department'}, {u'woeid': u'2344968', u'name': u'Cuvette Department'}, {u'woeid': u'2344973', u'name': u'Plateaux District'}, {u'woeid': u'2344974', u'name': u'Sangha'}, {u'woeid': u'2344970', u'name': u'Lekoumou'}, {u'woeid': u'2344975', u'name': u'Pool Department'}, {u'woeid': u'2344971', u'name': u'Likouala Department'}, {u'woeid': u'2344972', u'name': u'Niari Department'}, {u'woeid': u'2344976', u'name': u'Brazzaville'}, {u'woeid': u'2344967', u'name': u'Bouenza Department'}, {u'woeid': u'2344969', u'name': u'Kouilou'}]}, u'created': u'2014-08-27T04:52:38Z'}}
+>>> import myql
+>>> from myql.utils import pretty_json, pretty_xml
+>>> yql = myql.MYQL(format='xml', community=True)
+>>> resp = yql.raw_query('select name, woeid from geo.states where place="Congo"')
+>>> print(pretty_xml(resp.content))
+
+
+
+
+ Cuvette-Ouest Department
+ 55998384
+
+
+ Cuvette Department
+ 2344968
+
+
+ Plateaux District
+ 2344973
+
+
+ Sangha
+ 2344974
+
+
+ Lekoumou
+ 2344970
+
+
+ Pool Department
+ 2344975
+
+
+ Likouala Department
+ 2344971
+
+
+ Niari Department
+ 2344972
+
+
+ Brazzaville
+ 2344976
+
+
+ Bouenza Department
+ 2344967
+
+
+ Kouilou
+ 2344969
+
+
+
+
+
+
+>>> resp = yql.raw_query('select name, woeid from geo.states where place="Congo"', format='json')
+>>> print(pretty_json(resp.content))
+{
+ "query": {
+ "count": 11,
+ "created": "2015-06-07T11:58:20Z",
+ "lang": "en-US",
+ "results": {
+ "place": [
+ {
+ "name": "Cuvette-Ouest Department",
+ "woeid": "55998384"
+ },
+ {
+ "name": "Cuvette Department",
+ "woeid": "2344968"
+ },
+ {
+ "name": "Plateaux District",
+ "woeid": "2344973"
+ },
+ {
+ "name": "Sangha",
+ "woeid": "2344974"
+ },
+ {
+ "name": "Lekoumou",
+ "woeid": "2344970"
+ },
+ {
+ "name": "Pool Department",
+ "woeid": "2344975"
+ },
+ {
+ "name": "Likouala Department",
+ "woeid": "2344971"
+ },
+ {
+ "name": "Niari Department",
+ "woeid": "2344972"
+ },
+ {
+ "name": "Brazzaville",
+ "woeid": "2344976"
+ },
+ {
+ "name": "Bouenza Department",
+ "woeid": "2344967"
+ },
+ {
+ "name": "Kouilou",
+ "woeid": "2344969"
+ }
+ ]
+ }
+ }
+}
+
>>>
```
@@ -91,89 +178,298 @@ u'\n>>
```
-rawQuery(query)
-----------------
+####raw_query(query)
Allows you to directly type your query
```python
->>> response = yql.rawQuery("select * from geo.countries where place='North America'")
+>>> response = yql.raw_query("select * from geo.countries where place='North America'")
>>> # deal with the response
```
-select(table, fields, limit).where(filters, ...)
-------------------------------------------------
-Select a table i.e *weather.forecast*.
-If *table* not provided, it will use the default table. If there's no such thing as a default table, it will raise a *NoTableSelectedError*
+####select(table, fields, limit).where(filters, ...)
***NB*** : A simple select doesn't return any data. Use ***GET*** instead.
```python
->>> response = yql.select('geo.countries', [name, code, woeid]).where(['name', '=', 'Canada'])
->>> response.json()
-{u'query': {u'count': 1, u'lang': u'en-US', u'results': {u'place': {u'woeid': u'23424775', u'name': u'Canada'}}, u'created': u'2014-08-16T19:04:08Z'}}
+>>> response = yql.select('geo.countries', ['name', 'code', 'woeid']).where(['name', '=', 'Canada'])
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:10:39Z",
+ "lang": "en-US",
+ "results": {
+ "place": {
+ "name": "Canada",
+ "woeid": "23424775"
+ }
+ }
+ }
+}
+
>>> ...
->>> rep = yql.select('geo.countries', ['name', 'woeid'], 2).where(['place', '=', 'Africa'])
->>> rep.json()
-{u'query': {u'count': 2, u'lang': u'en-US', u'results': {u'place': [{u'woeid': u'23424740', u'name': u'Algeria'}, {u'woeid': u'23424745', u'name': u'Angola'}]}, u'created': u'2014-08-17T10:52:49Z'}}
->>>
->>> rep = yql.select('geo.countries', ['name', 'woeid'], 2).where(['place', 'in', ('Africa', 'Europe')])
->>> rep.json()
-{u'query': {u'count': 2, u'lang': u'en-US', u'results': {u'place': [{u'woeid': u'23424740', u'name': u'Algeria'}, {u'woeid': u'23424745', u'name': u'Angola'}]}, u'created': u'2014-08-17T11:22:49Z'}}
+>>> response = yql.select('geo.countries', ['name', 'woeid'], 2).where(['place', 'in', ('Africa', 'Europe')])
+>>> from myql.utils import dump
+>>> dump(response)
+{
+ "query": {
+ "count": 2,
+ "created": "2015-06-07T12:27:04Z",
+ "lang": "en-US",
+ "results": {
+ "place": [
+ {
+ "name": "Algeria",
+ "woeid": "23424740"
+ },
+ {
+ "name": "Angola",
+ "woeid": "23424745"
+ }
+ ]
+ }
+ }
+}
+
>>>
```
-get(table, fields, limit)
---------------------------
-
+####get(table, fields, limit)
Same as ***SELECT***, but instead returns data.
**REMINDER** : Some tables require a **where clause**, therefore ***GET*** won't work on those tables, use *select(...).where(...)* instead .
```python
->>> yql.get('geo.countries', ['name', 'woeid'], 1)
->>> rep.json()
-{u'query': {u'count': 1, u'lang': u'en-US', u'results': {u'place': {u'woeid': u'23424966', u'name': u'Sao Tome and Principe'}}, u'created': u'2014-08-17T10:32:25Z'}}
+>>> from myql.utils import dump
+>>> response = yql.get('geo.countries', ['name', 'woeid'], 1)
+>>> dump(response)
+{
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:29:01Z",
+ "lang": "en-US",
+ "results": {
+ "place": {
+ "name": "Sao Tome and Principe",
+ "woeid": "23424966"
+ }
+ }
+ }
+}
+
>>>
```
+####insert(table, (field1, field2, ..., fieldN),(value1, value2, ..., valueN))
+Insert values into a table. Arguments 2 and 3 may be **tuples** or **list**.
-create()
----------
+```python
+>>> from myql.utils import pretty_json
+>>> response = yql.insert('yql.storage.admin',('value',),('http://josuebrunel.org',))
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:25:56Z",
+ "lang": "en-US",
+ "results": {
+ "inserted": {
+ "execute": "store://KkkC5xDw4v32IcWWSQ4YRe",
+ "select": "store://Zc5LHXcmYM7XBfSbo9tzFL",
+ "update": "store://Rqb5fbQyDvrfHJiClWnZ6q"
+ }
+ }
+ }
+}
+```
-insert()
----------
+####update(table,[field1, ..., fieldN],[value1, ..., ...valueN]).where(filters, ...)
+Update fields values. This method __is always followed by ***where()***__. Arguments 2 and 3 may be **tuples** or **list**.
-update()
---------
+```python
+>>> from myql.utils import pretty_json
+>>> response = yql.update('yql.storage',('value',),('https://josuebrunel.org',)).where(['name','=','store://Rqb5fbQyDvrfHJiClWnZ6q'])
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:32:52Z",
+ "lang": "en-US",
+ "results": {
+ "success": "Updated store://KkkC5xDw4v32IcWWSQ4YRe"
+ }
+ }
+}
+```
+
+####delete(table).where(filters, ...)
+Delete records
+```python
+>>> from myql.utils import pretty_json
+>>> response = self.yql.delete('yql.storage').where(['name','=','store://Rqb5fbQyDvrfHJiClWnZ6q'])
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:38:28Z",
+ "lang": "en-US",
+ "results": {
+ "success": "store://Rqb5fbQyDvrfHJiClWnZ6q deleted"
+ }
+ }
+}
+
+```
+
+####Using OAuth
+
+***mYQL*** comes with ***[yahoo_oauth](http://yahoo-oauth.readthedocs.org/en/master/)***, which is an OAuth library for Yahoo! APIs.
+
+```python
+>>> from yahoo_oauth import OAuth1
+>>> oauth = OAuth1(None, None, from_file='credentials.json') # only consumer_key and consumer_secret are required.
+>>> from myql import MYQL
+>>> yql = MYQL(format='xml', oauth=oauth)
+>>> response = yql.get_guid('josue_brunel') # Deal with the response
+```
+
+#### Stocks Scraper
+
+The full documentation on ***StockScraper*** is [here](https://myql.readthedocs.org/en/latest/stockscraper/)
+
+#### Release Notes
+
+
+##### 1.2.6
+-----------
-delete()
----------
+* Fixed [#148](https://github.com/josuebrunel/myql/issues/148)
+##### 1.2.5
+-----------
+* camelCase dropped for underscore
+* Support for substitution variable i.e @myvar
+* Support of Remote Filters
+* Support of Post Query Filters
+##### 1.2.4
+-----------
+* Weather module added
+* StockScraper now under Finance namespace
+##### 1.2.3
+-----------
+
+* Fixed issue related to date in StockRetriver.get_historical_info [#107](https://github.com/josuebrunel/myql/issues/107)
+* Fixed issue with **IN** condition in **where** clause [#106](https://github.com/josuebrunel/myql/issues/107)
+* Fix definition of raw_input for python3 [#105](https://github.com/josuebrunel/myql/issues/105)
+* Yahoo-OAuth included as main oauth library [#112](https://github.com/josuebrunel/myql/issues/112)
+
+##### 1.2.2
+-------
+* **Python3** support OK [#71](https://github.com/josuebrunel/myql/issues/71)
+* **PyPy/PyPy3** support OK
+* Fixed issue with **IN** condition in **where** clause
+* Fixed issue when passing an empty list/tuple (**[]/()**) in a **where** clause besides first argument
+* Import of ***[StockParser](https://github.com/gurch101/StockScraper)*** from Gurchet Rai OK [#68](https://github.com/josuebrunel/myql/issues/68)
+* Insert, Update, Delete methods added [#67](https://github.com/josuebrunel/myql/issues/67)
+* Dummy *try/except* removed from main module
+* Fixed **Invalid OAuth Signature** when using a refreshed token [#64](https://github.com/josuebrunel/myql/issues/64)
+* Fixed misused of ***MYQL.use(...)*** [#76](https://github.com/josuebrunel/myql/issues/76)
+* Fixed format issue [#82](https://github.com/josuebrunel/myql/issues/82)
+* Added useful functions in utils [#81](https://github.com/josuebrunel/myql/issues/81)
+* Default access to community tables
+* Response prettyfier : *pretty_json, pretty_xml*
+
+##### v 1.2.1
+------
+* Multiple requests while using OAuth fixed
+
+##### 1.2.0
+-------
+* OpenTable classes
+* Access to resources requiring authentication
+
+##### 0.5.6
+-------------
+* fetch data
+* access to community data
+* select data format (xml/json)
+* change data source
+* filter data
+* fix handling of default response format on the fly
+* fix limit on ***select(...).where(...)*** when no limit value is passed
+* fix limit on ***get(...)***
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..54c0553
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,532 @@
+`mYQL `__
+=================================================
+
+|Build Status| |Documentation Status| |Code Health| |PyPI| |PyPI| |PyPI|
+|PyPI| |PyPI| |Coverage Status| |PyPI|
+
+mYQL is a Python wrapper of the Yahoo Query Language.
+
+Yahoo! Query Language Documentation and Support
+===============================================
+
+- Yahoo! Query Language - http://developer.yahoo.com/yql/
+- Yahoo! Developer Network: http://developer.yahoo.com
+- Yahoo! Application Platform - http://developer.yahoo.com/yap/
+- Yahoo! Social APIs - http://developer.yahoo.com/social/
+- Yahoo! QUery Language Console
+ https://developer.yahoo.com/yql/console/
+
+Features
+~~~~~~~~
+
+- Simple YQL Query
+- Authenticated YQL Query ( OAuth )
+- StockScraper
+- YQL Open Table (Classes and Metaclasses) Generator
+- Response prettyfier
+
+Installation
+============
+
+.. code:: shell
+
+ $ pip install myql
+
+Quick Start
+===========
+
+It's important to know that **response** is a just
+**requests.models.Response** object. Yes indeed, ***mYQL*** uses
+***requests*** :smile:
+
+By default, you have access to the **community tables**. If for
+whatsoever reason you would like to not have access to those tables
+
+.. code:: python
+
+ >>> import myql
+ >>> yql = myql.MYQL(community=False)
+
+Changing response format (xml or json)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The response format is by default ***json***.
+
+.. code:: python
+
+ >>> import myql
+ >>> from myql.utils import pretty_json, pretty_xml
+ >>> yql = myql.MYQL(format='xml', community=True)
+ >>> resp = yql.raw_query('select name, woeid from geo.states where place="Congo"')
+ >>> print(pretty_xml(resp.content))
+
+
+
+
+ Cuvette-Ouest Department
+ 55998384
+
+
+ Cuvette Department
+ 2344968
+
+
+ Plateaux District
+ 2344973
+
+
+ Sangha
+ 2344974
+
+
+ Lekoumou
+ 2344970
+
+
+ Pool Department
+ 2344975
+
+
+ Likouala Department
+ 2344971
+
+
+ Niari Department
+ 2344972
+
+
+ Brazzaville
+ 2344976
+
+
+ Bouenza Department
+ 2344967
+
+
+ Kouilou
+ 2344969
+
+
+
+
+
+
+ >>> resp = yql.raw_query('select name, woeid from geo.states where place="Congo"', format='json')
+ >>> print(pretty_json(resp.content))
+ {
+ "query": {
+ "count": 11,
+ "created": "2015-06-07T11:58:20Z",
+ "lang": "en-US",
+ "results": {
+ "place": [
+ {
+ "name": "Cuvette-Ouest Department",
+ "woeid": "55998384"
+ },
+ {
+ "name": "Cuvette Department",
+ "woeid": "2344968"
+ },
+ {
+ "name": "Plateaux District",
+ "woeid": "2344973"
+ },
+ {
+ "name": "Sangha",
+ "woeid": "2344974"
+ },
+ {
+ "name": "Lekoumou",
+ "woeid": "2344970"
+ },
+ {
+ "name": "Pool Department",
+ "woeid": "2344975"
+ },
+ {
+ "name": "Likouala Department",
+ "woeid": "2344971"
+ },
+ {
+ "name": "Niari Department",
+ "woeid": "2344972"
+ },
+ {
+ "name": "Brazzaville",
+ "woeid": "2344976"
+ },
+ {
+ "name": "Bouenza Department",
+ "woeid": "2344967"
+ },
+ {
+ "name": "Kouilou",
+ "woeid": "2344969"
+ }
+ ]
+ }
+ }
+ }
+
+ >>>
+
+Methods
+-------
+
+use(yql\_table\_url,name=yql\_table\_name)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Maps a table name to the URL of an Open Data Table.
+
+.. code:: python
+
+ >>> yql.use('http://www.josuebrunel.org//users.xml', name='myusers')
+
+desc(tablename)
+^^^^^^^^^^^^^^^
+
+Returns table description
+
+.. code:: python
+
+ >>> response = yql.desc('weather.forecast')
+ >>> print(pretty_json(response.content))
+ {
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:00:27Z",
+ "lang": "en-US",
+ "results": {
+ "table": {
+ "hash": "aae78b1462a6a8fbc748aec4cf292767",
+ "meta": {
+ "author": "Yahoo! Inc",
+ "description": "Weather forecast table",
+ "documentationURL": "http://developer.yahoo.com/weather/",
+ "sampleQuery": "select * from weather.forecast where woeid=2502265"
+ },
+ "name": "weather.forecast",
+ "request": {
+ "select": [
+ {
+ "key": [
+ {
+ "name": "location",
+ "required": "true",
+ "type": "xs:string"
+ },
+ {
+ "name": "u",
+ "type": "xs:string"
+ }
+ ]
+ },
+ {
+ "key": [
+ {
+ "name": "woeid",
+ "required": "true",
+ "type": "xs:string"
+ },
+ {
+ "name": "u",
+ "type": "xs:string"
+ }
+ ]
+ }
+ ]
+ },
+ "security": "ANY"
+ }
+ }
+ }
+ }
+
+ >>>
+
+raw\_query(query)
+^^^^^^^^^^^^^^^^^
+
+Allows you to directly type your query
+
+.. code:: python
+
+ >>> response = yql.raw_query("select * from geo.countries where place='North America'")
+ >>> # deal with the response
+
+select(table, fields, limit).where(filters, ...)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+***NB*** : A simple select doesn't return any data. Use ***GET***
+instead.
+
+.. code:: python
+
+ >>> response = yql.select('geo.countries', ['name', 'code', 'woeid']).where(['name', '=', 'Canada'])
+ >>> print(pretty_json(response.content))
+ {
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:10:39Z",
+ "lang": "en-US",
+ "results": {
+ "place": {
+ "name": "Canada",
+ "woeid": "23424775"
+ }
+ }
+ }
+ }
+
+ >>> ...
+ >>> response = yql.select('geo.countries', ['name', 'woeid'], 2).where(['place', 'in', ('Africa', 'Europe')])
+ >>> from myql.utils import dump
+ >>> dump(response)
+ {
+ "query": {
+ "count": 2,
+ "created": "2015-06-07T12:27:04Z",
+ "lang": "en-US",
+ "results": {
+ "place": [
+ {
+ "name": "Algeria",
+ "woeid": "23424740"
+ },
+ {
+ "name": "Angola",
+ "woeid": "23424745"
+ }
+ ]
+ }
+ }
+ }
+
+ >>>
+
+get(table, fields, limit)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Same as ***SELECT***, but instead returns data.
+
+**REMINDER** : Some tables require a **where clause**, therefore
+***GET*** won't work on those tables, use *select(...).where(...)*
+instead .
+
+.. code:: python
+
+ >>> from myql.utils import dump
+ >>> response = yql.get('geo.countries', ['name', 'woeid'], 1)
+ >>> dump(response)
+ {
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:29:01Z",
+ "lang": "en-US",
+ "results": {
+ "place": {
+ "name": "Sao Tome and Principe",
+ "woeid": "23424966"
+ }
+ }
+ }
+ }
+
+ >>>
+
+insert(table, (field1, field2, ..., fieldN),(value1, value2, ..., valueN))
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Insert values into a table. Arguments 2 and 3 may be **tuples** or
+**list**.
+
+.. code:: python
+
+ >>> from myql.utils import pretty_json
+ >>> response = yql.insert('yql.storage.admin',('value',),('http://josuebrunel.org',))
+ >>> print(pretty_json(response.content))
+ {
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:25:56Z",
+ "lang": "en-US",
+ "results": {
+ "inserted": {
+ "execute": "store://KkkC5xDw4v32IcWWSQ4YRe",
+ "select": "store://Zc5LHXcmYM7XBfSbo9tzFL",
+ "update": "store://Rqb5fbQyDvrfHJiClWnZ6q"
+ }
+ }
+ }
+ }
+
+update(table,[field1, ..., fieldN],[value1, ..., ...valueN]).where(filters, ...)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Update fields values. This method **is always followed by
+***where()*****. Arguments 2 and 3 may be **tuples** or **list**.
+
+.. code:: python
+
+ >>> from myql.utils import pretty_json
+ >>> response = yql.update('yql.storage',('value',),('https://josuebrunel.org',)).where(['name','=','store://Rqb5fbQyDvrfHJiClWnZ6q'])
+ >>> print(pretty_json(response.content))
+ {
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:32:52Z",
+ "lang": "en-US",
+ "results": {
+ "success": "Updated store://KkkC5xDw4v32IcWWSQ4YRe"
+ }
+ }
+ }
+
+delete(table).where(filters, ...)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Delete records
+
+.. code:: python
+
+ >>> from myql.utils import pretty_json
+ >>> response = self.yql.delete('yql.storage').where(['name','=','store://Rqb5fbQyDvrfHJiClWnZ6q'])
+ >>> print(pretty_json(response.content))
+ {
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:38:28Z",
+ "lang": "en-US",
+ "results": {
+ "success": "store://Rqb5fbQyDvrfHJiClWnZ6q deleted"
+ }
+ }
+ }
+
+Using OAuth
+^^^^^^^^^^^
+
+***mYQL*** comes with
+***`yahoo\_oauth `__***,
+which is an OAuth library for Yahoo! APIs.
+
+.. code:: python
+
+ >>> from yahoo_oauth import OAuth1
+ >>> oauth = OAuth1(None, None, from_file='credentials.json') # only consumer_key and consumer_secret are required.
+ >>> from myql import MYQL
+ >>> yql = MYQL(format='xml', oauth=oauth)
+ >>> response = yql.get_guid('josue_brunel') # Deal with the response
+
+Stocks Scraper
+^^^^^^^^^^^^^^
+
+The full documentation on ***StockScraper*** is
+`here `__
+
+Release Notes
+^^^^^^^^^^^^^
+
+##### 1.2.6
+-----------
+
+- Fixed `#148 `__
+
+##### 1.2.5
+-----------
+
+- camelCase dropped for underscore
+- Support for substitution variable i.e @myvar
+- Support of Remote Filters
+- Support of Post Query Filters
+
+##### 1.2.4
+-----------
+
+- Weather module added
+- StockScraper now under Finance namespace
+
+##### 1.2.3
+-----------
+
+- Fixed issue related to date in StockRetriver.get\_historical\_info
+ `#107 `__
+- Fixed issue with **IN** condition in **where** clause
+ `#106 `__
+- Fix definition of raw\_input for python3
+ `#105 `__
+- Yahoo-OAuth included as main oauth library
+ `#112 `__
+
+##### 1.2.2
+-----------
+
+- **Python3** support OK
+ `#71 `__
+- **PyPy/PyPy3** support OK
+- Fixed issue with **IN** condition in **where** clause
+- Fixed issue when passing an empty list/tuple (**[]/()**) in a
+ **where** clause besides first argument
+- Import of
+ ***`StockParser `__*** from
+ Gurchet Rai OK
+ `#68 `__
+- Insert, Update, Delete methods added
+ `#67 `__
+- Dummy *try/except* removed from main module
+- Fixed **Invalid OAuth Signature** when using a refreshed token
+ `#64 `__
+- Fixed misused of ***MYQL.use(...)***
+ `#76 `__
+- Fixed format issue
+ `#82 `__
+- Added useful functions in utils
+ `#81 `__
+- Default access to community tables
+- Response prettyfier : *pretty\_json, pretty\_xml*
+
+##### v 1.2.1
+-------------
+
+- Multiple requests while using OAuth fixed
+
+##### 1.2.0
+-----------
+
+- OpenTable classes
+- Access to resources requiring authentication
+
+##### 0.5.6
+-----------
+
+- fetch data
+- access to community data
+- select data format (xml/json)
+- change data source
+- filter data
+- fix handling of default response format on the fly
+- fix limit on ***select(...).where(...)*** when no limit value is
+ passed
+- fix limit on ***get(...)***
+
+.. |Build Status| image:: https://travis-ci.org/josuebrunel/myql.svg?branch=master
+ :target: https://travis-ci.org/josuebrunel/myql
+.. |Documentation Status| image:: https://readthedocs.org/projects/myql/badge/?version=latest
+ :target: https://myql.readthedocs.org
+.. |Code Health| image:: https://landscape.io/github/josuebrunel/myql/master/landscape.svg?style=flat
+ :target: https://landscape.io/github/josuebrunel/myql/master
+.. |PyPI| image:: https://img.shields.io/pypi/status/myql.svg?style=flat
+ :target: https://pypi.python.org/pypi/myql
+.. |PyPI| image:: https://img.shields.io/pypi/v/myql.svg?style=flat
+ :target: https://pypi.python.org/pypi/myql
+.. |PyPI| image:: https://img.shields.io/pypi/dm/myql.svg?style=flat
+ :target: https://pypi.python.org/pypi/myql
+.. |PyPI| image:: https://img.shields.io/pypi/pyversions/myql.svg
+ :target: https://pypi.python.org/pypi/myql
+.. |PyPI| image:: https://img.shields.io/pypi/implementation/myql.svg?style=flat
+ :target: https://pypi.python.org/pypi/myql
+.. |Coverage Status| image:: https://coveralls.io/repos/josuebrunel/myql/badge.svg?branch=testing
+ :target: https://coveralls.io/r/josuebrunel/myql?branch=master
+.. |PyPI| image:: https://img.shields.io/pypi/l/myql.svg?style=flat
+ :target: https://pypi.python.org/pypi/myql
diff --git a/convert_to_rst.sh b/convert_to_rst.sh
new file mode 100755
index 0000000..99b9c58
--- /dev/null
+++ b/convert_to_rst.sh
@@ -0,0 +1,13 @@
+##################################################
+#
+# Author : josuebrunel
+# Filename : convert_to_rst.sh
+# Description : use pandoc to convert md file to rst
+# Creation Date : 10-05-2015
+# Last Modified : Thu 21 May 2015 11:17:35 AM CEST
+#
+##################################################
+
+rm -rf index.html
+wget http://myql.readthedocs.org/en/latest/index.html
+pandoc index.html -t rst -o README.rst
diff --git a/credentials.json.enc b/credentials.json.enc
new file mode 100644
index 0000000..062ed7f
Binary files /dev/null and b/credentials.json.enc differ
diff --git a/dev_requirements.txt b/dev_requirements.txt
new file mode 100644
index 0000000..3907346
--- /dev/null
+++ b/dev_requirements.txt
@@ -0,0 +1,30 @@
+Jinja2>=2.8
+Markdown>=2.6.2
+MarkupSafe>=0.23
+PyYAML>=3.11
+argparse>=1.2.1
+backports.ssl-match-hostname>=3.4.0.2
+certifi>=2015.9.6.2
+click>=5.1
+coverage>=4.0
+coveralls>=1.0
+docopt>=0.6.2
+ghp-import>=0.4.1
+livereload>=2.4.0
+mccabe>=0.3.1
+mkdocs>=0.14.0
+oauthlib>=1.0.3
+pep8>=1.6.2
+pluggy>=0.3.1
+py>=1.4.30
+pyflakes>=1.0.0
+pytest>=2.8.1
+python-dateutil>=2.4.2
+rauth>=0.7.1
+requests>=2.7.0
+requests-oauthlib>=0.5.0
+six>=1.9.0
+tornado>=4.2.1
+tox>=2.1.1
+virtualenv>=13.1.2
+yahoo-oauth>=0.1.7
diff --git a/docs/contrib.md b/docs/contrib.md
new file mode 100644
index 0000000..d6301c7
--- /dev/null
+++ b/docs/contrib.md
@@ -0,0 +1,37 @@
+##How to contribute
+
+It's easy to contribute to ***MYQL***.
+
+1. Fork the repository
+2. Develop your patches/fixes/features
+3. Test your changes ( > py2.6 )
+4. Submit a pull request
+
+That's all
+
+###Tips
+
+If you want to add a new feature to the library, you better put it in ***myql/contrib/my_awesome_feature/***
+
+Let's say i want to add a **weather** module.
+
+```shell
+$ mkdir myql/contrib/weather/
+$ vim myql/contrib/__init__.py
+```
+
+```python
+...
+import weather
+```
+
+```shell
+$ vim myql/contrib/weather/__init__.py
+from weather import my_stuff
+$ vim myql/contrib/weather/weather.py
+```
+
+```python
+from myql.myql import MYQL # If ever you want to use the module
+# Your code
+```
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..5d9fcab
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,399 @@
+mYQL
+=========
+
+mYQL is a Python wrapper of the Yahoo Query Language.
+
+## Yahoo! Query Language Documentation and Support
+
+* [Yahoo! Query Language](http://developer.yahoo.com/yql/)
+* [Yahoo! Developer Network](http://developer.yahoo.com)
+* [Yahoo! Application Platform](http://developer.yahoo.com/yap/)
+* [Yahoo! Social APIs](http://developer.yahoo.com/social/)
+* [Yahoo! Query Language Console](https://developer.yahoo.com/yql/console/)
+
+Installation
+============
+
+```shell
+$ pip install myql
+```
+
+Quick Start
+===========
+
+It's important to know that **response** is a just **requests.models.Response** object.
+Yes indeed, ***mYQL*** uses ***requests*** :smile:
+
+By default, you have access to the **community tables**. If for whatsoever reason you would like to not have access to those tables
+
+```python
+>>> import myql
+>>> yql = myql.MYQL(community=False)
+```
+
+#### Response format (xml or json)
+
+The response format is by default ***json***.
+
+```python
+>>> import myql
+>>> from myql.utils import pretty_json, pretty_xml
+>>> yql = myql.MYQL(format='xml', community=True)
+>>> resp = yql.raw_query('select name, woeid from geo.states where place="Congo"')
+>>> print(pretty_xml(resp.content))
+
+
+
+
+ Cuvette-Ouest Department
+ 55998384
+
+
+ Cuvette Department
+ 2344968
+
+
+ Plateaux District
+ 2344973
+
+
+ Sangha
+ 2344974
+
+
+ Lekoumou
+ 2344970
+
+
+ Pool Department
+ 2344975
+
+
+ Likouala Department
+ 2344971
+
+
+ Niari Department
+ 2344972
+
+
+ Brazzaville
+ 2344976
+
+
+ Bouenza Department
+ 2344967
+
+
+ Kouilou
+ 2344969
+
+
+
+
+
+
+>>> resp = yql.raw_query('select name, woeid from geo.states where place="Congo"', format='json')
+>>> print(pretty_json(resp.content))
+{
+ "query": {
+ "count": 11,
+ "created": "2015-06-07T11:58:20Z",
+ "lang": "en-US",
+ "results": {
+ "place": [
+ {
+ "name": "Cuvette-Ouest Department",
+ "woeid": "55998384"
+ },
+ {
+ "name": "Cuvette Department",
+ "woeid": "2344968"
+ },
+ {
+ "name": "Plateaux District",
+ "woeid": "2344973"
+ },
+ {
+ "name": "Sangha",
+ "woeid": "2344974"
+ },
+ {
+ "name": "Lekoumou",
+ "woeid": "2344970"
+ },
+ {
+ "name": "Pool Department",
+ "woeid": "2344975"
+ },
+ {
+ "name": "Likouala Department",
+ "woeid": "2344971"
+ },
+ {
+ "name": "Niari Department",
+ "woeid": "2344972"
+ },
+ {
+ "name": "Brazzaville",
+ "woeid": "2344976"
+ },
+ {
+ "name": "Bouenza Department",
+ "woeid": "2344967"
+ },
+ {
+ "name": "Kouilou",
+ "woeid": "2344969"
+ }
+ ]
+ }
+ }
+}
+
+>>>
+```
+
+
+Methods
+-------
+
+####use(yql_table_url,name=yql_table_name)
+Maps a table name to the URL of an Open Data Table.
+
+```python
+>>> yql.use('http://www.josuebrunel.org//users.xml', name='myusers')
+```
+
+####desc(tablename)
+Returns table description
+
+```python
+>>> response = yql.desc('weather.forecast')
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:00:27Z",
+ "lang": "en-US",
+ "results": {
+ "table": {
+ "hash": "aae78b1462a6a8fbc748aec4cf292767",
+ "meta": {
+ "author": "Yahoo! Inc",
+ "description": "Weather forecast table",
+ "documentationURL": "http://developer.yahoo.com/weather/",
+ "sampleQuery": "select * from weather.forecast where woeid=2502265"
+ },
+ "name": "weather.forecast",
+ "request": {
+ "select": [
+ {
+ "key": [
+ {
+ "name": "location",
+ "required": "true",
+ "type": "xs:string"
+ },
+ {
+ "name": "u",
+ "type": "xs:string"
+ }
+ ]
+ },
+ {
+ "key": [
+ {
+ "name": "woeid",
+ "required": "true",
+ "type": "xs:string"
+ },
+ {
+ "name": "u",
+ "type": "xs:string"
+ }
+ ]
+ }
+ ]
+ },
+ "security": "ANY"
+ }
+ }
+ }
+}
+
+>>>
+```
+
+####raw_query(query)
+
+Allows you to directly type your query
+
+```python
+>>> response = yql.raw_query("select * from geo.countries where place='North America'")
+>>> # deal with the response
+```
+
+
+####select(table, fields, limit, **kwargs).where(filters, ...)
+
+***NB*** : A simple select doesn't return any data. Use ***GET*** instead.
+
+```python
+>>> response = yql.select('geo.countries', ['name', 'code', 'woeid']).where(['name', '=', 'Canada'])
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:10:39Z",
+ "lang": "en-US",
+ "results": {
+ "place": {
+ "name": "Canada",
+ "woeid": "23424775"
+ }
+ }
+ }
+}
+
+>>> ...
+>>> response = yql.select('geo.countries', ['name', 'woeid'], 2).where(['place', 'in', ('Africa', 'Europe')])
+>>> from myql.utils import dump
+>>> dump(response)
+{
+ "query": {
+ "count": 2,
+ "created": "2015-06-07T12:27:04Z",
+ "lang": "en-US",
+ "results": {
+ "place": [
+ {
+ "name": "Algeria",
+ "woeid": "23424740"
+ },
+ {
+ "name": "Angola",
+ "woeid": "23424745"
+ }
+ ]
+ }
+ }
+}
+
+>>>
+```
+
+####get(table, fields, limit, **kwargs)
+Same as ***SELECT***, but instead returns data.
+
+**REMINDER** : Some tables require a **where clause**, therefore ***GET*** won't work on those tables, use *select(...).where(...)* instead .
+
+```python
+>>> from myql.utils import dump
+>>> response = yql.get('geo.countries', ['name', 'woeid'], 1)
+>>> dump(response)
+{
+ "query": {
+ "count": 1,
+ "created": "2015-06-07T12:29:01Z",
+ "lang": "en-US",
+ "results": {
+ "place": {
+ "name": "Sao Tome and Principe",
+ "woeid": "23424966"
+ }
+ }
+ }
+}
+
+>>>
+```
+
+####insert(table, (field1, field2, ..., fieldN),(value1, value2, ..., valueN))
+Insert values into a table. Arguments 2 and 3 may be **tuples** or **list**.
+
+```python
+>>> from myql.utils import pretty_json
+>>> response = yql.insert('yql.storage.admin',('value',),('http://josuebrunel.org',))
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:25:56Z",
+ "lang": "en-US",
+ "results": {
+ "inserted": {
+ "execute": "store://KkkC5xDw4v32IcWWSQ4YRe",
+ "select": "store://Zc5LHXcmYM7XBfSbo9tzFL",
+ "update": "store://Rqb5fbQyDvrfHJiClWnZ6q"
+ }
+ }
+ }
+}
+```
+
+####update(table,[field1, ..., fieldN],[value1, ..., ...valueN]).where(filters, ...)
+Update fields values. This method __is always followed by ***where()***__. Arguments 2 and 3 may be **tuples** or **list**.
+
+```python
+>>> from myql.utils import pretty_json
+>>> response = yql.update('yql.storage',('value',),('https://josuebrunel.org',)).where(['name','=','store://Rqb5fbQyDvrfHJiClWnZ6q'])
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:32:52Z",
+ "lang": "en-US",
+ "results": {
+ "success": "Updated store://KkkC5xDw4v32IcWWSQ4YRe"
+ }
+ }
+}
+```
+
+####delete(table).where(filters, ...)
+Delete records
+```python
+>>> from myql.utils import pretty_json
+>>> response = self.yql.delete('yql.storage').where(['name','=','store://Rqb5fbQyDvrfHJiClWnZ6q'])
+>>> print(pretty_json(response.content))
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-14T13:38:28Z",
+ "lang": "en-US",
+ "results": {
+ "success": "store://Rqb5fbQyDvrfHJiClWnZ6q deleted"
+ }
+ }
+}
+
+```
+
+## Using OAuth
+
+***mYQL*** comes with ***[yahoo_oauth](https://pypi.python.org/pypi/myql)***, which is an OAuth library for Yahoo! APIs.
+
+```python
+>>> from yahoo_oauth import OAuth1
+>>> oauth = OAuth1(None, None, from_file='credentials.json') # only consumer_key and consumer_secret are required.
+>>> from myql import MYQL
+>>> yql = MYQL(format='xml', oauth=oauth)
+>>> response = yql.get_guid('josue_brunel') # Deal with the response
+```
+
+## Utils
+
+***mYQL*** comes with some useful functions, such as:
+
+#### *prettyty(response, format)*
+ According to the format, call *pretty_json* or *pretty_xml*
+
+#### *pretty_json(response.content)*
+ prettyfy a JSON response content
+
+#### *pretty_xml(response.content)*
+ Prettyfy a XML response content
+
+#### *dump(response)*
+ Print a prettyfied response
diff --git a/docs/myql.md b/docs/myql.md
new file mode 100644
index 0000000..3dc1ece
--- /dev/null
+++ b/docs/myql.md
@@ -0,0 +1,208 @@
+MYQL
+====
+
+### **Definition**
+
+#### *MYQL(community=True, format='json', jsonCompact=False, crossProduct=None, debug=False, oauth=None)*
+
+### **Methods**
+
+#### *MYQL.payload_builder(query, format='json')*
+
+Return a dictionary of parameters
+
+* ***query*** : the YQL Query
+* ***format*** : xml or json
+
+#### *MQYL.execute_query(payload)*
+
+Execute the query and returns and response
+
+* ***payload*** : Dict of parameters
+
+
+#### *MYQL.raw_query(query, format=None, pretty=False)*
+
+Call *payloadBuilder* to build paramaters and *executeQuery* to execute que *query* then return a response.
+
+* ***query*** : the YQL Query
+* ***format*** : xml or json
+
+#### *MQYL.use(yql_table_url, name=yql_table_name)*
+
+ Change the service provider
+
+* ***url*** : url of the service provider
+
+```python
+>>> from myql import YQL
+>>> yql = YQL(format='json')
+>>> yql.use('http://www.josuebrunel.org/users.xml',name='users')
+>>> response = self.yql.raw_query('select * from users', format='xml')
+```
+
+#### *MYQL.set({key:value, ..., keyN:valueN})*
+
+Set variable to use in your YQL statement
+
+```python
+>>> from myql import YQL
+>>> yql = YQL()
+>>> yql.set({'home':'Congo'})
+>>> states = yql.select('geo.states', remote_filter=(5,)).where(['place', '=', '@home'])
+```
+
+#### *MQYL.desc(table)*
+
+Get the description of a table.
+
+* ***table*** : Table name
+
+#### *MQYL.get(table, items=[], limit=None, **kwargs)*
+
+Get **items** from **table**.
+
+* ***table*** : Table name
+* ***items*** : Element/columns to get from the table
+* ***limit*** : limit of element to fetch
+
+
+#### *MQYL.select(table, items=[], limit=None, **kwargs)*
+This method is always followed by a **where**. It doesn't return a response if called alone.
+
+* ***table*** : Table name
+* ***items*** : Element/columns to get from the table
+* ***limit*** : limit of element to fetch
+
+```python
+>>> yql.select('social.profile', ['guid', 'givenName', 'gender'])
+```
+
+#### *MYQL.insert(table,[field1, field2, ..., fieldN],[value1, value2, ..., valueN])*
+* ***table***: Table name
+* ***fields***: List or Tuple of fields
+* ***values***: List or Tuple of values
+
+```python
+>>> response = yql.insert('yql.storage.admin',('value',),('http://josuebrunel.org',))
+```
+
+#### *MYQL.update(table,[field1, field2, ..., fieldN],[value1, value2, ..., valueN])*
+This method is always followed by a **where**. It doesn't return a response if called alone.
+
+* ***table***: Table name
+* ***fields***: List or Tuple of fields to update
+* ***values***: List or Tuple of new values
+
+```python
+>>> response = yql.update('yql.storage',('value',),('https://josuebrunel.org',)).where(['name','=',"store://Rqb5fbQyDvrfHJiClWnZ6q"])
+```
+
+#### *MYQL.delete(table)*
+This method is always followed by a **where**. It doesn t return a response if called alone.
+
+* ***table***: Table name
+
+```python
+>>> response = self.yql.delete('yql.storage').where(['name','=',"store://Rqb5fbQyDvrfHJiClWnZ6q"])
+```
+
+#### *MQYL.where(\*args)*
+
+* ***\*args*** : List of conditions
+
+```python
+>>> yql.select('mytable.friends').where(['name', '=', 'alain'], ['location', '!=', 'paris'])
+```
+
+#### *MQYL.show_tables()*
+
+List all tables
+
+#### *MQYL.get_guid(username)*
+
+Return a user *guid*
+
+* ***username*** : yahoo id i.e 'josue_brunel'
+
+
+### **Filters**
+
+mYQL implements 2 types of filters :
+
+* Remote filters
+* Post Query Filters
+
+##### **Remote Filters**
+***Remote filters*** are defined as **tuple**, such as ***()*** or ***(, )***.
+
+- *Python Code* :
+```python
+from myql import YQL
+yql = YQL()
+data = self.yql.get('geo.countries', remote_filter=(10,))
+```
+
+- *YQL Statement* :
+```sql
+> SELECT * FROM geo.countries(10) ;
+```
+
+- *Python Code* :
+
+```python
+data = self.yql.get('geo.countries', remote_filter=(10,20))
+```
+
+- *YQL Statement* :
+```sql
+> SELECT * FROM geo.countries(10,20) ;
+```
+
+
+##### **Post Query Filters**
+
+**Filters** or **Function** applied to the result of the ***Query***.
+
+- ***reverse***
+```python
+func_filters = ['reverse']
+data = yql.select('geo.states', func_filters=func_filters).where(['place', '=', 'Congo'])
+```
+
+- ***tail***
+```python
+func_filters = [('tail', 2)]
+data = yql.select('geo.states', func_filters=func_filters).where(['place', '=', 'Congo'])
+```
+
+- ***truncate***
+```python
+func_filters = [('truncate', 2)]
+data = yql.select('geo.states', func_filters=func_filters).where(['place', '=', 'Congo'])
+```
+
+- ***unique***
+```python
+func_filters = [
+ {'unique': [
+ ('field','content'),
+ ('hideRepeatCount','false')
+ ]},
+ ('truncate', 5)
+]
+data = yql.get('yql.table.list', func_filters=func_filters)
+```
+
+- ***sort***
+```python
+func_filters = [
+ {'sort': [
+ ('field','name'),
+ ('descending','true')
+ ]},
+ ('tail', 10),
+ #('reverse')
+]
+data = yql.select('geo.counties', func_filters=func_filters).where(['place', '=', 'CA'])
+```
diff --git a/docs/oauth.md b/docs/oauth.md
new file mode 100644
index 0000000..8e25358
--- /dev/null
+++ b/docs/oauth.md
@@ -0,0 +1,19 @@
+Yahoo-OAuth
+=====================
+
+The ***YOAuth*** module is not supported anymore. mYQL comes with
+ ***[Yahoo-OAuth](http://yahoo-oauth.readthedocs.org/en/master/)***.
+ From now on, this will be the library to use to when you want to use **OAuth**.
+ Nothing has really changed anyway, since *yahoo-oauth* is based on *YOAuth*.
+
+You can read the full documentation [here](http://yahoo-oauth.readthedocs.org/en/master/)
+
+```python
+>>> import myql
+>>> from yahoo_oauth import OAuth1
+>>> oauth = OAuth1(None, None, from_file='credentials.json')
+>>> yql = myql.MYQL(format='xml',oauth=oauth)
+>>> response = yql.get_guid('josue_brunel')
+...
+```
+
diff --git a/docs/stockscraper.md b/docs/stockscraper.md
new file mode 100644
index 0000000..bcf96af
--- /dev/null
+++ b/docs/stockscraper.md
@@ -0,0 +1,586 @@
+StockScraper
+============
+
+***[StockScraper](https://github.com/gurch101/StockScraper)*** is a module written by **[Gurchet Rai](https://github.com/gurch101/)** and has just been imported into *mYQL*.
+
+Full [Documentation](http://www.gurchet-rai.net/dev/yahoo-finance-yql)
+
+### **Definition**
+
+#### *StockRetriever(format='json', debug=False, oauth=None)*
+
+* ***format*** : xml or json
+* ***debug*** : True or False
+* ***oauth*** : yahoo_oauth (OAuth1)
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+```
+
+### **Methods**
+
+#### *StockRetriever.get_current_info(symbolList, columns=None)*
+
+* ***symbolList*** : List of symbol to retrieve
+* ***columns*** : List of column to fetch
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_current_info(["YHOO","AAPL","GOOG"])
+```
+
+```json
+{
+ "query": {
+ "count": 3,
+ "created": "2015-05-20T12:56:27Z",
+ "lang": "en-US",
+ "results": {
+ "quote": [
+ {
+ "AfterHoursChangeRealtime": null,
+ "AnnualizedGain": null,
+ "Ask": "42.22",
+ "AskRealtime": null,
+ "AverageDailyVolume": "13763800",
+ "Bid": "42.20",
+ "BidRealtime": null,
+ "BookValue": "35.91",
+ "Change": "-3.38",
+ "ChangeFromFiftydayMovingAverage": "-3.03",
+ "ChangeFromTwoHundreddayMovingAverage": "-5.46",
+ "ChangeFromYearHigh": "-11.64",
+ "ChangeFromYearLow": "8.05",
+ "ChangePercentRealtime": null,
+ "ChangeRealtime": null,
+ "Change_PercentChange": "-3.38 - -7.62%",
+ "ChangeinPercent": "-7.62%",
+ "Commission": null,
+ "Currency": "USD",
+ "DaysHigh": "44.66",
+ "DaysLow": "39.12",
+ "DaysRange": "39.12 - 44.66",
+ "DaysRangeRealtime": null,
+ "DaysValueChange": null,
+ "DaysValueChangeRealtime": null,
+ "DividendPayDate": null,
+ "DividendShare": null,
+ "DividendYield": null,
+ "EBITDA": "598.70M",
+ "EPSEstimateCurrentYear": "0.78",
+ "EPSEstimateNextQuarter": "0.21",
+ "EPSEstimateNextYear": "0.79",
+ "EarningsShare": "7.32",
+ "ErrorIndicationreturnedforsymbolchangedinvalid": null,
+ "ExDividendDate": null,
+ "FiftydayMovingAverage": "44.01",
+ "HighLimit": null,
+ "HoldingsGain": null,
+ "HoldingsGainPercent": null,
+ "HoldingsGainPercentRealtime": null,
+ "HoldingsGainRealtime": null,
+ "HoldingsValue": null,
+ "HoldingsValueRealtime": null,
+ "LastTradeDate": "5/19/2015",
+ "LastTradePriceOnly": "40.98",
+ "LastTradeRealtimeWithTime": null,
+ "LastTradeTime": "4:00pm",
+ "LastTradeWithTime": "4:00pm - 40.98",
+ "LowLimit": null,
+ "MarketCapRealtime": null,
+ "MarketCapitalization": "38.46B",
+ "MoreInfo": null,
+ "Name": "Yahoo! Inc.",
+ "Notes": null,
+ "OneyrTargetPrice": "54.45",
+ "Open": "44.48",
+ "OrderBookRealtime": null,
+ "PEGRatio": "-4.24",
+ "PERatio": "5.60",
+ "PERatioRealtime": null,
+ "PercebtChangeFromYearHigh": "-22.12%",
+ "PercentChange": "-7.62%",
+ "PercentChangeFromFiftydayMovingAverage": "-6.89%",
+ "PercentChangeFromTwoHundreddayMovingAverage": "-11.75%",
+ "PercentChangeFromYearLow": "+24.45%",
+ "PreviousClose": "44.36",
+ "PriceBook": "1.24",
+ "PriceEPSEstimateCurrentYear": "52.54",
+ "PriceEPSEstimateNextYear": "51.22",
+ "PricePaid": null,
+ "PriceSales": "8.84",
+ "SharesOwned": null,
+ "ShortRatio": "2.10",
+ "StockExchange": "NMS",
+ "Symbol": "YHOO",
+ "TickerTrend": null,
+ "TradeDate": null,
+ "TwoHundreddayMovingAverage": "46.44",
+ "Volume": "48892169",
+ "YearHigh": "52.62",
+ "YearLow": "32.93",
+ "YearRange": "32.93 - 52.62",
+ "symbol": "YHOO"
+ },
+ ...
+ ]
+ }
+ }
+}
+```
+
+#### *StockRetriever.get_news_feed(symbol)*
+
+* ***symbol*** : Symbol news to retrieve
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_news_feed('YHOO')
+```
+
+```json
+{
+ "query": {
+ "count": 2,
+ "created": "2015-05-20T13:05:27Z",
+ "lang": "en-US",
+ "results": {
+ "item": [
+ {
+ "description": null,
+ "link": "http://us.rd.yahoo.com/finance/news/rss/story/*http://finance.yahoo.com/news/video-may-20-premarket-briefing-110800770.html",
+ "title": "May 20 Premarket Briefing: 10 Things You Should Know"
+ },
+ {
+ "description": "[at MarketWatch] - How alarmed should be about a former Fed\u2019s warning on a taper tantrum and volatility, from China to Yahoo.",
+ "link": "http://us.rd.yahoo.com/finance/external/cbsm/rss/SIG=11iiumket/*http://www.marketwatch.com/News/Story/Story.aspx?guid=F8AC52CC-FEAB-11E4-8608-290076337AAF&siteid=yhoof2",
+ "title": "Why it might pay to listen to a Fed old timer\u2019s tantrum warning"
+ }
+ ]
+ }
+ }
+}
+```
+
+#### *StockRetriever.get_historical_info(symbol, items=None, startDate=None, endDate=None, limit=None)*
+
+* ***symbol*** : Symbol news to retrieve
+* ***items*** : columns to retrieve
+* ***startDate*** : starting date
+* ***endDate*** : ending date
+* ***limit*** : number of results to return
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_historical_info('YHOO',items=['Open','Close','High','Low'], limit=5,startDate='2014-09-11',endDate='2015-02-10')
+```
+
+```json
+{
+ "query": {
+ "count": 5,
+ "created": "2015-05-24T05:12:21Z",
+ "lang": "en-US",
+ "results": {
+ "quote": [
+ {
+ "Close": "43.07",
+ "High": "43.18",
+ "Low": "42.66",
+ "Open": "42.90"
+ },
+ {
+ "Close": "42.57",
+ "High": "43.15",
+ "Low": "42.54",
+ "Open": "42.61"
+ },
+ {
+ "Close": "42.94",
+ "High": "43.66",
+ "Low": "42.67",
+ "Open": "43.57"
+ },
+ {
+ "Close": "43.55",
+ "High": "44.26",
+ "Low": "43.03",
+ "Open": "44.08"
+ },
+ {
+ "Close": "44.05",
+ "High": "44.98",
+ "Low": "43.88",
+ "Open": "44.80"
+ }
+ ]
+ }
+ }
+}
+
+```
+
+#### *StockRetriever.get_options_info(symbol, items=[], expiration=None)*
+
+* ***symbol*** : Symbol news to retrieve
+* ***items*** : list of attributes to retrieve
+* ***expiration*** : Date of expiration (type : str)
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_options_info('YHOO')
+```
+
+```json
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-20T13:09:02Z",
+ "lang": "en-US",
+ "results": {
+ "optionsChain": {
+ "symbol": "YHOO"
+ }
+ }
+ }
+}
+```
+
+#### *StockRetriever.get_index_summary(symbol, items=[])*
+
+* ***symbol*** : Symbol news to retrieve
+* ***items*** : list of attributes to retrieve
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_index_summary('GOOG',('Volume','Change'))
+```
+
+```json
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-20T13:09:48Z",
+ "lang": "en-US",
+ "results": {
+ "quote": {
+ "Change": null,
+ "Volume": "16"
+ }
+ }
+ }
+}
+```
+
+#### *StockRetriever.get_industry_index(index_id,items=[])*
+
+* ***index_id*** : index id
+* ***items*** : list of attributes to retrieve
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_industry_index(112)
+```
+
+```json
+{
+ "query": {
+ "count": 1,
+ "created": "2015-05-20T13:10:55Z",
+ "lang": "en-US",
+ "results": {
+ "industry": {
+ "company": [
+ {
+ "name": "Adarsh\nPlant Protect Ltd",
+ "symbol": "ADARSHPL.BO"
+ },
+ {
+ "name": "African\nPotash Ltd",
+ "symbol": "AFPO.L"
+ },
+ {
+ "name": "Agrium\nInc",
+ "symbol": "AGU.DE"
+ },
+ {
+ "name": "Agrium\nInc",
+ "symbol": "AGU.TO"
+ },
+ ...
+ {
+ "name": "Zuari\nAgro Chemicals Ltd",
+ "symbol": "ZUARI.NS"
+ },
+ {
+ "name": "Zuari\nGlobal Ltd",
+ "symbol": "ZUARIAGRO.NS"
+ },
+ {
+ "name": "Zuari\nGlobal Ltd",
+ "symbol": "ZUARIIND.BO"
+ }
+ ],
+ "id": "112",
+ "name": ""
+ }
+ }
+ }
+}
+```
+
+#### *StockRetriever.get_xchange_rate(pairs, items=None)*
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_xchange_rate(['EURUSD','GBPUSD'])
+```
+
+```json
+{
+ "query": {
+ "count": 2,
+ "created": "2015-06-27T13:48:51Z",
+ "lang": "en-US",
+ "results": {
+ "rate": [
+ {
+ "Ask": "1.1174",
+ "Bid": "1.1162",
+ "Date": "6/27/2015",
+ "Name": "EUR/USD",
+ "Rate": "1.1168",
+ "Time": "12:53pm",
+ "id": "EURUSD"
+ },
+ {
+ "Ask": "1.5756",
+ "Bid": "1.5738",
+ "Date": "6/27/2015",
+ "Name": "GBP/USD",
+ "Rate": "1.5747",
+ "Time": "12:53pm",
+ "id": "GBPUSD"
+ }
+ ]
+ }
+ }
+}
+
+```
+
+#### *StockRetriever.get_dividendhistory(symbol, startDate, endDate)*
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_dividendhistory('AAPL',"2008-01-01", "2015-06-15")
+```
+
+```json
+{
+ "query": {
+ "count": 12,
+ "created": "2015-06-27T13:42:27Z",
+ "lang": "en-US",
+ "results": {
+ "quote": [
+ {
+ "Date": "2015-05-07",
+ "Dividends": "0.520000",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2015-02-05",
+ "Dividends": "0.470000",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2014-11-06",
+ "Dividends": "0.470000",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2014-08-07",
+ "Dividends": "0.470000",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2014-05-08",
+ "Dividends": "0.470000",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2014-02-06",
+ "Dividends": "0.435710",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2013-11-06",
+ "Dividends": "0.435710",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2013-08-08",
+ "Dividends": "0.435710",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2013-05-09",
+ "Dividends": "0.435710",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2013-02-07",
+ "Dividends": "0.378570",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2012-11-07",
+ "Dividends": "0.378570",
+ "Symbol": "AAPL"
+ },
+ {
+ "Date": "2012-08-09",
+ "Dividends": "0.378570",
+ "Symbol": "AAPL"
+ }
+ ]
+ }
+ }
+}
+
+```
+
+#### *StockRetriever.get_balancesheet(symbol)*
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = self.stock.get_balancesheet('YHOO')
+```
+
+```json
+{
+ "query": {
+ "count": 1,
+ "created": "2015-07-08T09:01:12Z",
+ "lang": "en-US",
+ "results": {
+ "balancesheet": {
+ "symbol": "YHOO",
+ "timeframe": "quarterly"
+ }
+ }
+ }
+}
+```
+
+#### *StockRetriever.get_symbols(company_name)*
+
+ **Always returns data as JSON**
+
+```python
+from myql.contrib.finance.stockscraper import StockRetriever
+stocks = StockRetriever(format='json')
+data = stocks.get_symbols('Google')
+```
+
+```json
+{
+ "ResultSet": {
+ "Query": "google",
+ "Result": [
+ {
+ "exch": "NMS",
+ "exchDisp": "NASDAQ",
+ "name": "Google Inc.",
+ "symbol": "GOOG",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "NMS",
+ "exchDisp": "NASDAQ",
+ "name": "Google Inc.",
+ "symbol": "GOOGL",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "GER",
+ "exchDisp": "XETRA",
+ "name": "Google Inc.",
+ "symbol": "GGQ7.DE",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "MEX",
+ "exchDisp": "Mexico",
+ "name": "Google Inc.",
+ "symbol": "GOOG.MX",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "MEX",
+ "exchDisp": "Mexico",
+ "name": "GOOGLE-A",
+ "symbol": "GOOGL.MX",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "BUE",
+ "exchDisp": "Buenos Aires",
+ "name": "Google Inc.",
+ "symbol": "GOOGL.BA",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "FRA",
+ "exchDisp": "Frankfurt",
+ "name": "GOOGLE-A",
+ "symbol": "GGQ1.F",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "MUN",
+ "exchDisp": "Munich",
+ "name": "GOOGLE-A",
+ "symbol": "GGQ1.MU",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "EBS",
+ "exchDisp": "Swiss",
+ "name": "GOOGLE-A",
+ "symbol": "GOOGL.SW",
+ "type": "S",
+ "typeDisp": "Equity"
+ },
+ {
+ "exch": "MUN",
+ "exchDisp": "Munich",
+ "name": "GOOGLE-C",
+ "symbol": "GGQ7.MU",
+ "type": "S",
+ "typeDisp": "Equity"
+ }
+ ]
+ }
+}
+
+```
diff --git a/docs/table.md b/docs/table.md
new file mode 100644
index 0000000..85be75a
--- /dev/null
+++ b/docs/table.md
@@ -0,0 +1,271 @@
+YQL Open Table
+==============
+
+## Table
+This class represents the **root** element of a YQL Table Definition File. You can read about the full documentation [here](https://developer.yahoo.com/yql/guide/yql-opentables-reference.html#yql-opentables-tables-element)
+
+### **Definition**
+
+#### *Table(name, author, apiKeyURL, documentationURL, sampleQuery=[], description=None, table_attr=None, bindings=[])*
+
+```python
+>>> from myql.contrib.table import Table
+>>> mytable = Table('mytable', 'Josue Kouka', 'http://josuerunel.org/mytable/','http://josuerunel.org/mytable/docs.html',sampleQuery = ['SELECT * FROM mytable', 'SELECT name FROM mytable WHERE id = 77'], description='Just a simple tabe', table_attr={'xmlns':'http://query.yahooapis.com/v1/schema/table.xsd', 'securityLevel':'any', 'https':'false'})
+```
+
+### **Methods**
+
+#### *Table.addBinder(binder_object)*
+Add a binder to the table
+```python
+>>> mytable.addBinder(select_binder)
+```
+#### *Table.removeBinder(binder_object)*
+Remove a binder from the table
+```python
+>>> mytable.removeBinder(select_binder)
+```
+#### *Table.save(name=None, path=None)*
+Save the table as a *xml file* with Table Object name if *name* is not provided. If *path*, saves the *xml file* to the specified location
+```python
+>>> mytable.save(name='test',path='/var/www/josuebrunel.org/mytable/')
+```
+
+## Inputs
+There are 3 kind of *inputs* as described in the [documentation](https://developer.yahoo.com/yql/guide/yql-opentables-reference.html#yql-opentables-key) :
+
+* ***key***
+* ***map***
+* ***value***
+
+### **Definitions**
+
+* #### *InputKey(id, type, paramType, like='', required=False, default='', private=False, const=False, batchable=False, maxBatchItems=0)*
+```python
+song = InputKey(id='song', type='xs:string', paramType='path', required=True)
+```
+* #### *InputValue(id, type, paramType, like='', required=False, default='', private=False, const=False, batchable=False, maxBatchItems=0)*
+```python
+song = InputValue(id='song', type='xs:string', paramType='path', required=True, const='12' )
+```
+* #### *InputMap(id, type, paramType, like='', required=False, default='', private=False, const=False, batchable=False, maxBatchItems=0)*
+
+All of those classes are based on ***BaseInput***.
+
+***like*** is a replacement for ***as*** which is a python keyword. In the *xml* file, ***as*** will be displayed.
+
+
+
+### **Methods**
+No methods defined
+
+## Paging
+This class describe a ***paging*** element. A ***paging*** is deifined by one of the 3 classes below :
+
+* ***PagingPage***
+* ***PagingUrl***
+* ***PagingOffset***
+
+Check out the full [documentation](https://developer.yahoo.com/yql/guide/yql-opentables-reference.html#yql-opentables-paging)
+### **Definitions**
+
+* #### *PagingPage(start={}, pageSize={}, total={})*
+```python
+>>> mypage = PagingPage({'id': 'ItemPage', 'default': '1'}, {'id':'Count' ,'max':'25'},{'default': '10'})
+```
+* #### *PagingUrl(nextpage)*
+```python
+>>> mypage = PagingUrl("ysearchresponse.nextpage")
+```
+* #### *PagingOffset(matrix, start={}, pageSize={}, total={})*
+```python
+>>> mypage = PagingOffset({'id': 'ItemPage', 'default': '1'}, {'id':'Count' ,'max':'25'},{'default': '10'})
+```
+
+All these classes above subclass ***BasePaging*** .
+
+### **Methods**
+No methods defined
+
+## Binder
+This class represents an element under ****. Which means :
+
+* select
+* insert
+* update
+* delete
+
+
+You can read about the full documentation [here](https://developer.yahoo.com/yql/guide/yql-opentables-reference.html#yql-opentables-select)
+
+### **Definition**
+
+#### *Binder(name, itemPath, produces, pollingFrequencySeconds=0, urls=[], inputs=[], paging=None)*
+
+```python
+>>> select = Binder('select', 'products.product', 'xml')
+```
+
+### **Methods**
+
+#### *Binder.addInput(input_object)* :
+Add an input object to the binder
+```python
+>>> song = InputKey(id='song', type='xs:string', paramType='path', required=True)
+>>> select.addBinder(song)
+```
+#### *Binder.removeInput(input_id, input_type)*
+Remove an input object from the binder. ***input_type*** may be ***key, value or map***
+```python
+>>> select.removeBinder('song','select')
+```
+#### *Binder.addUrl(url)*
+Add an url to the binder
+```python
+>>> select.addUrl('http://lol.com/{song}')
+```
+#### *Binder.removeUrl(url)*
+Remove an url from the binder
+```python
+>>> select.removeUrl('http://lol.com/{song}')
+```
+#### *Binder.addPaging(paging_instance)*
+Add a paging to the binder
+```python
+>>> mypage = PagingUrl("ysearchresponse.nextpage")
+>>> select.addPaging(mypage)
+```
+#### *Binder.removePaging()*
+Remove a paging from the binder
+```python
+>>> select.removePaging()
+```
+
+## BinderFunction
+
+This class represents a stored function. Read the full documentation [here](https://developer.yahoo.com/yql/guide/yql-opentables-reference.html#reference-function)
+
+### **Definition**
+
+#### *BinderFunction(func_name, func_code='', func_file=None, inputs=[])*
+
+* ***func_name*** : function name
+* ***func_code*** : function code passed as string
+* ***func_file*** : file containing the function
+* ***inputs*** : list of inputs
+
+```python
+>>> myfunc = BinderFunction('concat', func_code="console.log('Hello Josh!!!')")
+```
+
+### **Methods**
+
+As ***Binder***, ***BinderFunction*** is a subclass of ***BaseBinder***. They both share the same methods
+
+## The MetaClass API
+
+***BinderModel*** and ***TableModel*** are the only classes to keep in mind here. They're respectively subclasses of ***BinderMeta*** and ***TableMeta***. Those last two help providing a powerful API to define YQL Table.
+
+They say *"A picture is worth a thousand of words"* and I say *"A code snippet
+is worth ..."* . You got it (^_^).
+
+Copy and paste the code snippet in the *example.py* below
+
+```python
+from myql.contrib.table import BinderModel, InputKey, PagingPage, PagingUrl, InputValue, BinderFunction
+from myql.contrib.table import TableModel, BinderFrom
+
+class SelectBinder(BinderModel):
+ name = 'select'
+ itemPath = 'products.product'
+ produces = 'xml'
+ pollingFrequencySeconds = 30
+ urls = ['http://lol.com/services?artist={artis}','http://lol.com/services/song={song}']
+ paging = PagingPage({'id': 'ItemPage', 'default': '1'}, {'id':'Count' ,'max':'25'},{'default': '10'})
+ artist = InputKey(id='artist', type='xs:string', paramType='path')
+ song = InputKey(id='song', type='xs:string', paramType='path', required=True)
+
+class InsertBinder(BinderModel):
+ name = 'insert'
+ itemPath = 'products.product'
+ produces = 'xml'
+ pollingFrequencySeconds = 30
+ urls = ['http://lol.com/services?artist={artis}','http://lol.com/services/song={song}']
+ paging = PagingUrl(nextpage={'path':'yqlsearch.nextpage'})
+ artist = InputKey(id='artist', type='xs:string', paramType='path')
+ song = InputValue(id='song', type='xs:string', paramType='path', required=True)
+
+
+class TestTable(TableModel):
+ name = 'Test'
+ author = 'Josue Kouka'
+ apiKeyURL = 'http://josuebrunel.org/api'
+ documentationURL = 'http://josuebrunel.org/doc.html'
+ description = "Just a test table"
+ sampleQuery = ['SELECT * FROM mytable','SELECT name FROM mytable WHERE id=4656', "SELECT * FROM mytable WHERE name='Josh'"]
+ select = BinderFrom(SelectBinder)
+ insert = BinderFrom(InsertBinder)
+ func1 = BinderFunction('concat', func_code="console.log('Hello Josh!!!')")
+
+TestTable.table.save(name='Example')
+```
+
+Run
+
+```shell
+$ python example.py
+$ cat Example.xml
+```
+
+```xml
+
+
+
+ http://josuebrunel.org/api
+ Josue Kouka
+ Just a test table
+ http://josuebrunel.org/doc.html
+ SELECT * FROM mytable
+ SELECT name FROM mytable WHERE id=4656
+ SELECT * FROM mytable WHERE name='Josh'
+
+
+
+
+ ![CDATA]console.log('Hello Josh!!!')]]
+
+
+
+
+ http://lol.com/services?artist={artis}
+ http://lol.com/services/song={song}
+
+
+
+
+
+
+
+
+
+
+
+