Hello world !
4 | 5 |hello python !
6 | 7 | 8 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | # use glob syntax. 2 | syntax: glob 3 | 4 | develop-eggs/ 5 | bin/ 6 | dist/ 7 | build/ 8 | parts/ 9 | docs/_build/ 10 | .tox/ 11 | .installed.cfg 12 | *.egg-info 13 | *.pyc 14 | *.swp 15 | *~ 16 | -------------------------------------------------------------------------------- /tests/geckodriver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | driver="https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz" 4 | 5 | [ -f geckodriver ] || wget -cqO- $driver | tar xvzf - 6 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft docs 2 | prune docs/_build 3 | graft pyquery 4 | graft tests 5 | include *.py 6 | include *.txt 7 | include *_fixt.py *.rst *.cfg *.ini 8 | global-exclude *.pyc 9 | global-exclude __pycache__ 10 | -------------------------------------------------------------------------------- /tests/invalid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |Hello world !
4 | 5 |6 | hello python ! 7 |
8 | 9 |10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/selenium.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # script to run selenium tests 3 | 4 | # get geckodriver 5 | ./tests/geckodriver.sh 6 | 7 | # run tox with py3.7 8 | MOZ_HEADLESS=1 PATH=$PATH:$PWD tox -e py37 tests/test_real_browser.py 9 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | 2 | [pytest] 3 | filterwarnings = 4 | ignore::DeprecationWarning 5 | doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL 6 | addopts = --doctest-modules --doctest-glob="*.rst" --ignore=docs/conf.py 7 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | ================================================ 2 | :mod:`~pyquery.pyquery` -- PyQuery complete API 3 | ================================================ 4 | 5 | .. automodule:: pyquery.pyquery 6 | 7 | .. autoclass:: PyQuery 8 | :members: 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Distribution / packaging 6 | develop-eggs/ 7 | bin/ 8 | dist/ 9 | build/ 10 | parts/ 11 | .tox/ 12 | .installed.cfg 13 | *.egg-info 14 | *.swp 15 | 16 | # Temporary files 17 | *~ 18 | geckodriver 19 | 20 | # Log files 21 | geckodriver.log 22 | 23 | # Sphinx documentation 24 | docs/_build/ 25 | -------------------------------------------------------------------------------- /docs/testing.rst: -------------------------------------------------------------------------------- 1 | Testing 2 | ------- 3 | 4 | If you want to run the tests that you can see above you should do:: 5 | 6 | $ git clone git://github.com/gawel/pyquery.git 7 | $ cd pyquery 8 | $ python bootstrap.py 9 | $ bin/buildout install tox 10 | $ bin/tox 11 | 12 | You can build the Sphinx documentation by doing:: 13 | 14 | $ cd docs 15 | $ make html 16 | -------------------------------------------------------------------------------- /docs/future.rst: -------------------------------------------------------------------------------- 1 | Future 2 | ------- 3 | 4 | - SELECTORS: done 5 | 6 | - ATTRIBUTES: done 7 | 8 | - CSS: done 9 | 10 | - HTML: done 11 | 12 | - MANIPULATING: missing the wrapInner method 13 | 14 | - TRAVERSING: about half done 15 | 16 | - EVENTS: nothing to do with server side might be used later for automatic ajax 17 | 18 | - CORE UI EFFECTS: did hide and show the rest doesn't really makes sense on 19 | server side 20 | 21 | - AJAX: some with wsgi app 22 | 23 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | from webtest import http 4 | from webtest.debugapp import debug_app 5 | from urllib.request import urlopen 6 | 7 | 8 | @pytest.fixture 9 | def readme_fixt(): 10 | server = http.StopableWSGIServer.create(debug_app) 11 | server.wait() 12 | path_to_html_file = os.path.join('tests', 'test.html') 13 | yield ( 14 | urlopen, 15 | server.application_url, 16 | path_to_html_file, 17 | ) 18 | server.shutdown() 19 | -------------------------------------------------------------------------------- /tests/test_browser.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pyquery.pyquery import PyQuery 4 | from .browser_base import TextExtractionMixin 5 | 6 | 7 | class TestInnerText(unittest.TestCase, TextExtractionMixin): 8 | def _prepare_dom(self, html): 9 | super()._prepare_dom(html) 10 | self.pq = PyQuery(self.last_html) 11 | 12 | def _simple_test(self, html, expected_sq, expected_nosq, **kwargs): 13 | self._prepare_dom(html) 14 | text_sq = self.pq.text(squash_space=True, **kwargs) 15 | text_nosq = self.pq.text(squash_space=False, **kwargs) 16 | self.assertEqual(text_sq, expected_sq) 17 | self.assertEqual(text_nosq, expected_nosq) 18 | -------------------------------------------------------------------------------- /docs/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import pytest 4 | from webtest import http 5 | from webtest.debugapp import debug_app 6 | 7 | 8 | @pytest.fixture 9 | def scrap_url(): 10 | sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) 11 | from tests.apps import input_app 12 | server = http.StopableWSGIServer.create(input_app) 13 | server.wait() 14 | yield server.application_url.rstrip('/') + '/html' 15 | server.shutdown() 16 | 17 | 18 | @pytest.fixture 19 | def tips_url(): 20 | server = http.StopableWSGIServer.create(debug_app) 21 | server.wait() 22 | yield server.application_url.rstrip('/') + '/form.html' 23 | server.shutdown() 24 | -------------------------------------------------------------------------------- /README_fixt.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webtest import http 3 | from webtest.debugapp import debug_app 4 | 5 | try: 6 | from urllib import urlopen 7 | except ImportError: 8 | from urllib.request import urlopen 9 | 10 | 11 | def setup_test(test): 12 | server = http.StopableWSGIServer.create(debug_app) 13 | server.wait() 14 | path_to_html_file = os.path.join('tests', 'test.html') 15 | test.globs.update( 16 | urlopen=urlopen, 17 | server=server, 18 | your_url=server.application_url, 19 | path_to_html_file=path_to_html_file, 20 | ) 21 | setup_test.__test__ = False 22 | 23 | 24 | def teardown_test(test): 25 | test.globs['server'].shutdown() 26 | teardown_test.__test__ = False 27 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist=py38,py39,py310,py311,py312 3 | 4 | [testenv] 5 | whitelist_externals= 6 | rm 7 | passenv= 8 | MOZ_HEADLESS 9 | commands = 10 | pytest [] 11 | deps = 12 | py38: selenium 13 | -e .[test] 14 | 15 | [testenv:lint] 16 | skipsdist=true 17 | skip_install=true 18 | basepython = python3.11 19 | commands = 20 | ruff check 21 | deps = 22 | ruff 23 | 24 | [testenv:docs] 25 | skip_install=false 26 | skipsdist=true 27 | basepython = python3.11 28 | changedir = docs 29 | deps = 30 | sphinx 31 | Pygments 32 | allowlist_externals = 33 | rm 34 | commands = 35 | rm -Rf {envtmpdir}/doctrees {envtmpdir}/html 36 | sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html 37 | 38 | # [testenv:selenium] 39 | # basepython = python3.5 40 | # deps = 41 | # selenium 42 | # commands = 43 | # {envbindir}/python -m unittest seleniumtests.offline 44 | # {envbindir}/python -m unittest seleniumtests.browser 45 | -------------------------------------------------------------------------------- /tests/doctests.rst: -------------------------------------------------------------------------------- 1 | Import:: 2 | 3 | >>> from pyquery import PyQuery as pq 4 | 5 | 6 | Assume spaces normalization:: 7 | 8 | >>> pq('
] 62 | 63 | And you can get back the modified html:: 64 | 65 | >>> print(d) 66 |
67 | 68 | You can generate html stuff:: 69 | 70 | >>> from pyquery import PyQuery as pq 71 | >>> print(pq('] 50 | >>> p = d("#hello") 51 | >>> print(p.html()) 52 | Hello world ! 53 | >>> p.html("you know Python rocks") 54 | [
] 55 | >>> print(p.html()) 56 | you know Python rocks 57 | >>> print(p.text()) 58 | you know Python rocks 59 | 60 | You can use some of the pseudo classes that are available in jQuery but that 61 | are not standard in css such as :first :last :even :odd :eq :lt :gt :checked 62 | :selected :file:: 63 | 64 | >>> d('p:first') 65 | [
] 66 | 67 | -------------------------------------------------------------------------------- /tests/browser_base.py: -------------------------------------------------------------------------------- 1 | class TextExtractionMixin(): 2 | def _prepare_dom(self, html): 3 | self.last_html = '
' + html + '' 4 | 5 | def _simple_test(self, html, expected_sq, expected_nosq, **kwargs): 6 | raise NotImplementedError 7 | 8 | def test_inline_tags(self): 9 | self._simple_test( 10 | 'Phasellus eget sem facilisis justo', 11 | 'Phasellus eget sem facilisis justo', 12 | 'Phasellus eget sem facilisis justo', 13 | ) 14 | self._simple_test( 15 | 'Phasellus eget sem facilisis\n justo', 16 | 'Phasellus eget sem facilisis justo', 17 | 'Phasellus eget sem facilisis\n justo', 18 | ) 19 | self._simple_test( 20 | ('Phasellus \n eget\n ' 21 | 'sem\n\tfacilisis justo'), 22 | 'Phasellus eget sem facilisis justo', 23 | 'Phasellus \n eget\n sem\n\tfacilisis justo' 24 | ) 25 | 26 | def test_block_tags(self): 27 | self._simple_test( 28 | 'Phasell
usIn sagittis
rutrum
condimentum
', 34 | 'In sagittis\nrutrum\ncondimentum', 35 | 'In sagittis\n \nrutrum\n\ncondimentum', 36 | ) 37 | self._simple_test( 38 | 'In\nultricies
\n erat et\n\n\nmaximus\n\n
mollis', 39 | 'In\nultricies\nerat et\nmaximus\nmollis', 40 | 'In \n\nultricies\n\n erat et \n\n\n\nmaximus\n\n\n mollis', 41 | ) 42 | self._simple_test( 43 | ('Integer content or set
22 | # by CSS rules)
23 | # apply this function on top of
24 | return WHITESPACE_RE.sub(' ', text)
25 |
26 |
27 | def _squash_artifical_nl(parts):
28 | output, last_nl = [], False
29 | for x in parts:
30 | if x is not None:
31 | output.append(x)
32 | last_nl = False
33 | elif not last_nl:
34 | output.append(None)
35 | last_nl = True
36 | return output
37 |
38 |
39 | def _strip_artifical_nl(parts):
40 | if not parts:
41 | return parts
42 | for start_idx, pt in enumerate(parts):
43 | if isinstance(pt, str):
44 | # 0, 1, 2, index of first string [start_idx:...
45 | break
46 | iterator = enumerate(parts[:start_idx - 1 if start_idx > 0 else None:-1])
47 | for end_idx, pt in iterator:
48 | if isinstance(pt, str): # 0=None, 1=-1, 2=-2, index of last string
49 | break
50 | return parts[start_idx:-end_idx if end_idx > 0 else None]
51 |
52 |
53 | def _merge_original_parts(parts):
54 | output, orp_buf = [], []
55 |
56 | def flush():
57 | if orp_buf:
58 | item = squash_html_whitespace(''.join(orp_buf)).strip()
59 | if item:
60 | output.append(item)
61 | orp_buf[:] = []
62 |
63 | for x in parts:
64 | if not isinstance(x, str):
65 | flush()
66 | output.append(x)
67 | else:
68 | orp_buf.append(x)
69 | flush()
70 | return output
71 |
72 |
73 | def extract_text_array(dom, squash_artifical_nl=True, strip_artifical_nl=True):
74 | if callable(dom.tag):
75 | return ''
76 | r = []
77 | if dom.tag in SEPARATORS:
78 | r.append(True) # equivalent of '\n' used to designate separators
79 | elif dom.tag not in INLINE_TAGS:
80 | # equivalent of '\n' used to designate artificially inserted newlines
81 | r.append(None)
82 | if dom.text is not None:
83 | r.append(dom.text)
84 | for child in dom.getchildren():
85 | r.extend(extract_text_array(child, squash_artifical_nl=False,
86 | strip_artifical_nl=False))
87 | if child.tail is not None:
88 | r.append(child.tail)
89 | if dom.tag not in INLINE_TAGS and dom.tag not in SEPARATORS:
90 | # equivalent of '\n' used to designate artificially inserted newlines
91 | r.append(None)
92 | if squash_artifical_nl:
93 | r = _squash_artifical_nl(r)
94 | if strip_artifical_nl:
95 | r = _strip_artifical_nl(r)
96 | return r
97 |
98 |
99 | def extract_text(dom, block_symbol='\n', sep_symbol='\n', squash_space=True):
100 | a = extract_text_array(dom, squash_artifical_nl=squash_space)
101 | if squash_space:
102 | a = _strip_artifical_nl(_squash_artifical_nl(_merge_original_parts(a)))
103 | result = ''.join(
104 | block_symbol if x is None else (
105 | sep_symbol if x is True else x
106 | )
107 | for x in a
108 | )
109 | if squash_space:
110 | result = result.strip()
111 | return result
112 |
--------------------------------------------------------------------------------
/tests/test_real_browser.py:
--------------------------------------------------------------------------------
1 | import os
2 | import unittest
3 | from threading import Thread
4 | from time import sleep
5 |
6 | from .browser_base import TextExtractionMixin
7 |
8 | SELENIUM = 'MOZ_HEADLESS' in os.environ
9 |
10 | try:
11 | from selenium import webdriver
12 | from selenium.webdriver.firefox.options import Options
13 | except ImportError:
14 | SELENIUM = False
15 |
16 | if SELENIUM:
17 | from urllib.parse import urlunsplit
18 | from http.server import HTTPServer, BaseHTTPRequestHandler
19 | from queue import Queue
20 |
21 | class BaseTestRequestHandler(BaseHTTPRequestHandler):
22 | _last_html = ''
23 |
24 | def _get_last_html(self):
25 | q = self.server.html_queue
26 | while not q.empty():
27 | self._last_html = q.get_nowait()
28 | return self._last_html
29 |
30 | def log_request(self, code='-', size='-'):
31 | pass
32 |
33 | def recv_from_testsuite(self, non_blocking=False):
34 | q = self.server.in_queue
35 | if non_blocking:
36 | return None if q.empty() else q.get_nowait()
37 | return q.get()
38 |
39 | def send_to_testsuite(self, value):
40 | self.server.out_queue.put(value)
41 |
42 | class HTMLSnippetSender(BaseTestRequestHandler):
43 | last_html = b''
44 |
45 | def get_last_html(self):
46 | while True:
47 | value = self.recv_from_testsuite(non_blocking=True)
48 | if value is None:
49 | break
50 | self.last_html = value
51 | return self.last_html
52 |
53 | def do_GET(self):
54 | if self.path == '/':
55 | self.send_response(200)
56 | self.send_header('Content-Type', 'text/html; charset=utf-8')
57 | self.end_headers()
58 | self.wfile.write(self.get_last_html().encode('utf-8'))
59 | else:
60 | self.send_response(404)
61 | self.end_headers()
62 |
63 | class BaseBrowserTest(unittest.TestCase):
64 | LOCAL_IP = '127.0.0.1'
65 | PORT = 28546
66 | # descendant of BaseBrowserTestRequestHandler
67 | REQUEST_HANDLER_CLASS = None
68 |
69 | @classmethod
70 | def setUpClass(cls):
71 | cls.to_server_queue = Queue()
72 | cls.from_server_queue = Queue()
73 | cls.server = HTTPServer((cls.LOCAL_IP, cls.PORT),
74 | cls.REQUEST_HANDLER_CLASS)
75 | cls.server.in_queue = cls.to_server_queue
76 | cls.server.out_queue = cls.from_server_queue
77 | cls.server_thread = Thread(target=cls.server.serve_forever)
78 | cls.server_thread.daemon = True
79 | cls.server_thread.start()
80 | options = Options()
81 | options.add_argument('-headless')
82 | cls.driver = webdriver.Firefox(options=options)
83 | sleep(1)
84 |
85 | @classmethod
86 | def tearDownClass(cls):
87 | cls.driver.quit()
88 | cls.server.shutdown()
89 | cls.server.server_close()
90 |
91 | def send_to_server(self, value):
92 | self.to_server_queue.put(value)
93 |
94 | def recv_from_server(self, non_blocking=False):
95 | q = self.from_server_queue
96 | if non_blocking:
97 | return None if q.empty() else q.get_nowait()
98 | return q.get()
99 |
100 | def open_url(self, path):
101 | self.driver.get(urlunsplit(
102 | ('http', '{}:{}'.format(
103 | self.LOCAL_IP, self.PORT), path, '', '')))
104 |
105 | class TestInnerText(BaseBrowserTest, TextExtractionMixin):
106 | REQUEST_HANDLER_CLASS = HTMLSnippetSender
107 |
108 | def _simple_test(self, html, expected_sq, expected_nosq, **kwargs):
109 | self.send_to_server(html)
110 | self.open_url('/')
111 |
112 | selenium_text = self.driver.find_element_by_tag_name('body').text
113 | self.assertEqual(selenium_text, expected_sq)
114 |
115 | # inner_text = self.driver.execute_script(
116 | # 'return document.body.innerText')
117 | # text_content = self.driver.execute_script(
118 | # 'return document.body.textContent')
119 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = ../bin/sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # Internal variables.
11 | PAPEROPT_a4 = -D latex_paper_size=a4
12 | PAPEROPT_letter = -D latex_paper_size=letter
13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14 | # the i18n builder cannot share the environment and doctrees with the others
15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16 |
17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18 |
19 | help:
20 | @echo "Please use \`make ' where is one of"
21 | @echo " html to make standalone HTML files"
22 | @echo " dirhtml to make HTML files named index.html in directories"
23 | @echo " singlehtml to make a single large HTML file"
24 | @echo " pickle to make pickle files"
25 | @echo " json to make JSON files"
26 | @echo " htmlhelp to make HTML files and a HTML help project"
27 | @echo " qthelp to make HTML files and a qthelp project"
28 | @echo " devhelp to make HTML files and a Devhelp project"
29 | @echo " epub to make an epub"
30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
32 | @echo " text to make text files"
33 | @echo " man to make manual pages"
34 | @echo " texinfo to make Texinfo files"
35 | @echo " info to make Texinfo files and run them through makeinfo"
36 | @echo " gettext to make PO message catalogs"
37 | @echo " changes to make an overview of all changed/added/deprecated items"
38 | @echo " linkcheck to check all external links for integrity"
39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40 |
41 | clean:
42 | -rm -rf $(BUILDDIR)/*
43 |
44 | html:
45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46 | @echo
47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48 |
49 | dirhtml:
50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51 | @echo
52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53 |
54 | singlehtml:
55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56 | @echo
57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58 |
59 | pickle:
60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61 | @echo
62 | @echo "Build finished; now you can process the pickle files."
63 |
64 | json:
65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66 | @echo
67 | @echo "Build finished; now you can process the JSON files."
68 |
69 | htmlhelp:
70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71 | @echo
72 | @echo "Build finished; now you can run HTML Help Workshop with the" \
73 | ".hhp project file in $(BUILDDIR)/htmlhelp."
74 |
75 | qthelp:
76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77 | @echo
78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/chut.qhcp"
81 | @echo "To view the help file:"
82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/chut.qhc"
83 |
84 | devhelp:
85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86 | @echo
87 | @echo "Build finished."
88 | @echo "To view the help file:"
89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/chut"
90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/chut"
91 | @echo "# devhelp"
92 |
93 | epub:
94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95 | @echo
96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97 |
98 | latex:
99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100 | @echo
101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
103 | "(use \`make latexpdf' here to do that automatically)."
104 |
105 | latexpdf:
106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107 | @echo "Running LaTeX files through pdflatex..."
108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110 |
111 | text:
112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113 | @echo
114 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
115 |
116 | man:
117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118 | @echo
119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120 |
121 | texinfo:
122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123 | @echo
124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125 | @echo "Run \`make' in that directory to run these through makeinfo" \
126 | "(use \`make info' here to do that automatically)."
127 |
128 | info:
129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130 | @echo "Running Texinfo files through makeinfo..."
131 | make -C $(BUILDDIR)/texinfo info
132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133 |
134 | gettext:
135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136 | @echo
137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138 |
139 | changes:
140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141 | @echo
142 | @echo "The overview file is in $(BUILDDIR)/changes."
143 |
144 | linkcheck:
145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146 | @echo
147 | @echo "Link check complete; look for any errors in the above output " \
148 | "or in $(BUILDDIR)/linkcheck/output.txt."
149 |
150 | doctest:
151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152 | @echo "Testing of doctests in the sources finished, look at the " \
153 | "results in $(BUILDDIR)/doctest/output.txt."
154 |
--------------------------------------------------------------------------------
/CHANGES.rst:
--------------------------------------------------------------------------------
1 | 2.0.2 (unreleased)
2 | ------------------
3 |
4 | - Nothing changed yet.
5 |
6 |
7 | 2.0.1 (2024-08-30)
8 | ------------------
9 |
10 | - Breaking change: its seems no longer possible to use the html parser with a xml file so its no longer tested
11 |
12 | - Drop support for python 3.7
13 |
14 | 2.0.0 (2022-12-28)
15 | ------------------
16 |
17 | - Breaking change: inputs starting with ``"http://"`` or ``"https://"`` like
18 | ``PyQuery("http://example.com")`` will no longer fetch the contents of the URL.
19 | Users desiring the old behavior should switch to ``PyQuery(url="http://example.com")``.
20 |
21 | - Add nextUntil method
22 |
23 | - ``.remove()`` no longer inserts a space in place of the removed element
24 |
25 | - Fix escaping of top-level element text in ``.html()`` output
26 |
27 | - Support (and require) cssselect 1.2+
28 |
29 | - Drop support for python 3.5/3.6
30 |
31 |
32 | 1.4.3 (2020-11-21)
33 | ------------------
34 |
35 | - No longer use a universal wheel
36 |
37 |
38 | 1.4.2 (2020-11-21)
39 | ------------------
40 |
41 | - Fix exception raised when calling `PyQuery("").text()`
42 |
43 | - python2 is no longer supported
44 |
45 | 1.4.1 (2019-10-26)
46 | ------------------
47 |
48 | - This is the latest release with py2 support
49 |
50 | - Remove py33, py34 support
51 |
52 | - web scraping improvements: default timeout and session support
53 |
54 | - Add API methods to serialize form-related elements according to spec
55 |
56 | - Include HTML markup when querying textarea text/value
57 |
58 |
59 | 1.4.0 (2018-01-11)
60 | ------------------
61 |
62 | - Refactoring of `.text()` to match firefox behavior.
63 |
64 |
65 | 1.3.0 (2017-10-21)
66 | ------------------
67 |
68 | - Remove some unmaintained modules: ``pyquery.ajax`` and ``pyquery.rules``
69 |
70 | - Code cleanup. No longer use ugly hacks required by python2.6/python3.2.
71 |
72 | - Run tests with python3.6 on CI
73 |
74 | - Add a ``method`` argument to ``.outer_html()``
75 |
76 |
77 | 1.2.17 (2016-10-14)
78 | -------------------
79 |
80 | - ``PyQuery('').val()`` is ``''``
81 | - ``PyQuery('').val()`` is ``''``
82 |
83 |
84 | 1.2.16 (2016-10-14)
85 | -------------------
86 |
87 | - ``.attr('value', '')`` no longer removes the ``value`` attribute
88 |
89 | - ```` without ``value="..."`` have a ``.val()`` of
90 | ``'on'``
91 |
92 | - ```` without ``value="..."`` have a ``.val()`` of
93 | ``'on'``
94 |
95 | - ``