From 3c0e7308ab93c95fde5de48f2b47e817502d57bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 26 May 2021 11:26:38 +0900 Subject: [PATCH 01/47] Implement `DOMString` --- python/dom/DOMString.py | 14 ++++++++++++++ python/dom/NotImplemented/DOMString.py | 2 -- python/dom/NotImplemented/__init__.py | 1 - python/dom/__init__.py | 2 ++ python/dom/type_checking.py | 1 + 5 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 python/dom/DOMString.py delete mode 100644 python/dom/NotImplemented/DOMString.py diff --git a/python/dom/DOMString.py b/python/dom/DOMString.py new file mode 100644 index 0000000..b719855 --- /dev/null +++ b/python/dom/DOMString.py @@ -0,0 +1,14 @@ +class DOMString(str): + """The `DOMString` type + + To ensure interoperability, the DOM specifies the `DOMString` type as follows: + + * A `DOMString` is a sequence of 16-bit quantities. This may be expressed in IDL terms as: + + `typedef sequence DOMString;` + + * Applications must encode `DOMString` using UTF-16 (defined in Appendix C.3 of [UNICODE] and Amendment 1 of [ISO-10646]).The UTF-16 encoding was chosen because of its widespread industry practice. Please note that for both HTML and XML, the document character set (and therefore the notation of numeric character references) is based on UCS-4. A single numeric character reference in a source document may therefore in some cases correspond to two array positions in a `DOMString` (a high surrogate and a low surrogate). Note: Even though the DOM defines the name of the string type to be `DOMString`, bindings may used different names. For, example for Java, `DOMString` is bound to the String type because it also uses UTF-16 as its encoding. + + > Note: As of August 1998, the OMG IDL specification included a wstring type. However, that definition did not meet the interoperability criteria of the DOM API since it relied on encoding negotiation to decide the width of a character. + """ + pass diff --git a/python/dom/NotImplemented/DOMString.py b/python/dom/NotImplemented/DOMString.py deleted file mode 100644 index e24a09b..0000000 --- a/python/dom/NotImplemented/DOMString.py +++ /dev/null @@ -1,2 +0,0 @@ -class DOMString: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/__init__.py b/python/dom/NotImplemented/__init__.py index 63df183..26f7fd8 100644 --- a/python/dom/NotImplemented/__init__.py +++ b/python/dom/NotImplemented/__init__.py @@ -9,7 +9,6 @@ from python.dom.NotImplemented.DocumentType import DocumentType from python.dom.NotImplemented.DOMException import DOMException from python.dom.NotImplemented.DOMImplementation import DOMImplementation -from python.dom.NotImplemented.DOMString import DOMString from python.dom.NotImplemented.Element import Element from python.dom.NotImplemented.Entity import Entity from python.dom.NotImplemented.EntityReference import EntityReference diff --git a/python/dom/__init__.py b/python/dom/__init__.py index c396168..68179c3 100644 --- a/python/dom/__init__.py +++ b/python/dom/__init__.py @@ -1 +1,3 @@ from __future__ import absolute_import + +from python.dom.DOMString import DOMString diff --git a/python/dom/type_checking.py b/python/dom/type_checking.py index b2e24a5..7663de7 100644 --- a/python/dom/type_checking.py +++ b/python/dom/type_checking.py @@ -4,6 +4,7 @@ if TYPE_CHECKING: from python.dom.NotImplemented import * + from python.dom.DOMString import DOMString AnyNode = Union[ Node, From cc0beb3665850b538b856193e04890e63b9f9e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 26 May 2021 11:45:33 +0900 Subject: [PATCH 02/47] Implement `DOMException` --- python/dom/DOMException.py | 39 +++++++++++++++++++++++ python/dom/NotImplemented/DOMException.py | 2 -- python/dom/NotImplemented/__init__.py | 1 - python/dom/__init__.py | 1 + python/dom/type_checking.py | 1 + 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 python/dom/DOMException.py delete mode 100644 python/dom/NotImplemented/DOMException.py diff --git a/python/dom/DOMException.py b/python/dom/DOMException.py new file mode 100644 index 0000000..a8550ea --- /dev/null +++ b/python/dom/DOMException.py @@ -0,0 +1,39 @@ +import enum + + +class ExceptionCode(enum.IntEnum): + """Definition group `ExceptionCode` + + An integer indicating the type of error generated. + """ + INDEX_SIZE_ERR = 1 # If index or size is negative, or greater than the allowed value + DOMSTRING_SIZE_ERR = 2 # If the specified range of text does not fit into a DOMString + HIERARCHY_REQUEST_ERR = 3 # If any node is inserted somewhere it doesn't belong + WRONG_DOCUMENT_ERR = 4 # If a node is used in a different document than the one that created it (that doesn't support it) + INVALID_CHARACTER_ERR = 5 # If an invalid character is specified, such as in a name. + NO_DATA_ALLOWED_ERR = 6 # If data is specified for a node which does not support data + NO_MODIFICATION_ALLOWED_ERR = 7 # If an attempt is made to modify an object where modifications are not allowed + NOT_FOUND_ERR = 8 # If an attempt was made to reference a node in a context where it does not exist + NOT_SUPPORTED_ERR = 9 # If the implementation does not support the type of object requested + INUSE_ATTRIBUTE_ERR = 10 # If an attempt is made to add an attribute that is already inuse elsewhere + + +class DOMException(Exception): + """Exception `DOMException` + + DOM operations only raise exceptions in "exceptional" circumstances, i.e., when an operation is impossible to perform (either for logical reasons, because data is lost, or because the implementation has become unstable). In general, DOM methods return specific error values in ordinary processing situation, such as out-of-bound errors when using `NodeList`. + + Implementations may raise other exceptions under other circumstances. For example, implementations may raise an implementation-dependent exception if a null argument is passed. + + Some languages and object systems do not support the concept of exceptions. For such systems, error conditions may be indicated using native error reporting mechanisms. For some bindings, for example, methods may return error codes similar to those listed in the corresponding method descriptions. + """ + INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR + DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR + HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR + WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR + INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR + NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR + NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR + NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR + NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR + INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR diff --git a/python/dom/NotImplemented/DOMException.py b/python/dom/NotImplemented/DOMException.py deleted file mode 100644 index 2d49d6a..0000000 --- a/python/dom/NotImplemented/DOMException.py +++ /dev/null @@ -1,2 +0,0 @@ -class DOMException: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/__init__.py b/python/dom/NotImplemented/__init__.py index 26f7fd8..eba7af7 100644 --- a/python/dom/NotImplemented/__init__.py +++ b/python/dom/NotImplemented/__init__.py @@ -7,7 +7,6 @@ from python.dom.NotImplemented.Document import Document from python.dom.NotImplemented.DocumentFragment import DocumentFragment from python.dom.NotImplemented.DocumentType import DocumentType -from python.dom.NotImplemented.DOMException import DOMException from python.dom.NotImplemented.DOMImplementation import DOMImplementation from python.dom.NotImplemented.Element import Element from python.dom.NotImplemented.Entity import Entity diff --git a/python/dom/__init__.py b/python/dom/__init__.py index 68179c3..63f0114 100644 --- a/python/dom/__init__.py +++ b/python/dom/__init__.py @@ -1,3 +1,4 @@ from __future__ import absolute_import +from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString diff --git a/python/dom/type_checking.py b/python/dom/type_checking.py index 7663de7..c46815c 100644 --- a/python/dom/type_checking.py +++ b/python/dom/type_checking.py @@ -4,6 +4,7 @@ if TYPE_CHECKING: from python.dom.NotImplemented import * + from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString AnyNode = Union[ From 8367ba7cea97c7b0667612578d58bfb5a0089f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Thu, 27 May 2021 15:06:02 +0900 Subject: [PATCH 03/47] Implement properties of interface Node (#3) * Start Implementing `Node` * Add definition group `NodeType` * Create class constructor * Add readonly attribute `node_type` * Add readonly attribute `node_name` (abstract) * Add protected boolean attribute `_read_only` * Add attribute `node_value` (abstract) * Add readonly attribute `parent_node` also create a method * `_set_parent_node()` * Add readonly attribute `child_nodes` * Add readonly attributes `first_child`, `last_child` * Add readonly attributes `previous_sibling`, `next_sibling` * Add readonly attribute `attributes` (abstract) * Add readonly attribute `owner_document` --- python/dom/Node.py | 167 ++++++++++++++++++++++++++ python/dom/NotImplemented/Node.py | 2 - python/dom/NotImplemented/__init__.py | 1 - python/dom/__init__.py | 1 + python/dom/type_checking.py | 1 + 5 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 python/dom/Node.py delete mode 100644 python/dom/NotImplemented/Node.py diff --git a/python/dom/Node.py b/python/dom/Node.py new file mode 100644 index 0000000..5f6fdc4 --- /dev/null +++ b/python/dom/Node.py @@ -0,0 +1,167 @@ +import enum +import warnings +from typing import AnyStr, Optional + +from python.dom.NotImplemented.Document import Document +from python.dom.DOMException import DOMException +from python.dom.DOMString import DOMString +from python.dom.NotImplemented.NamedNodeMap import NamedNodeMap +from python.dom.NotImplemented.NodeList import NodeList +from python.dom.type_checking import AnyNode + + +class NodeType(enum.IntEnum): + """Definition group `NodeType` + + An integer indicating which type of node this is. + """ + ELEMENT_NODE = 1 # The node is a `Element`. + ATTRIBUTE_NODE = 2 # The node is an `Attr`. + TEXT_NODE = 3 # The node is a `Text` node. + CDATA_SECTION_NODE = 4 # The node is a `CDATASection`. + ENTITY_REFERENCE_NODE = 5 # The node is an `EntityReference`. + ENTITY_NODE = 6 # The node is an `Entity`. + PROCESSING_INSTRUCTION_NODE = 7 # The node is a `ProcessingInstruction`. + COMMENT_NODE = 8 # The node is a `Comment`. + DOCUMENT_NODE = 9 # The node is a `Document`. + DOCUMENT_TYPE_NODE = 10 # The node is a `DocumentType`. + DOCUMENT_FRAGMENT_NODE = 11 # The node is a `DocumentFragment`. + NOTATION_NODE = 12 # The node is a `Notation`. + + +class Node: + """Interface `Node` + + The `Node` interface is the primary datatype for the entire Document Object Model. It represents a single node in the document tree. While all objects implementing the `Node` interface expose methods for dealing with children, not all objects implementing the `Node` interface may have children. For example, `Text` nodes may not have children, and adding children to such nodes results in a `DOMException` being raised. + + The attributes `node_name`, `node_value` and attributes are included as a mechanism to get at node information without casting down to the specific derived interface. In cases where there is no obvious mapping of these attributes for a specific `node_type` (e.g., `node_value` for an Element or `attributes` for a Comment), this returns `None`. Note that the specialized interfaces may contain additional and more convenient mechanisms to get and set the relevant information. + """ + ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE + TEXT_NODE = NodeType.TEXT_NODE + ELEMENT_NODE = NodeType.ELEMENT_NODE + CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE + ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE + ENTITY_NODE = NodeType.ENTITY_NODE + PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE + COMMENT_NODE = NodeType.COMMENT_NODE + DOCUMENT_NODE = NodeType.DOCUMENT_NODE + DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE + DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE + NOTATION_NODE = NodeType.NOTATION_NODE + + def __init__(self, + owner_document: Document, + node_type: NodeType, + parent_node: Optional[AnyNode] = None, + read_only: bool = False) -> None: + self._set_parent_node(parent_node, node_type) + self._node_type: NodeType = node_type + self._read_only: bool = read_only + self._parent_node: Optional[AnyNode] # parent node should be set with `_set_parent_node` method. + self._child_nodes: NodeList = NodeList() + self._previous_sibling: Optional[AnyNode] = None + self._next_sibling: Optional[AnyNode] = None + self._owner_document: Document = owner_document + + + @property + def node_name(self) -> DOMString: + """The name of this node, depending on its type. + """ + raise NotImplementedError + + @property + def node_value(self) -> DOMString: + """The value of this node, depending on its type. + + Raises: + DOMException: + - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. (on setting) + - `DOMSTRING_SIZE_ERR`: Raised when it would return more characters than fit in a `DOMString` variable on the implementation platform. (on retrieval) + """ + raise NotImplementedError + + @node_value.setter + def node_value(self, value: AnyStr) -> None: + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) + raise NotImplementedError + + @property + def node_type(self) -> NodeType: + """A code representing the type of the underlying object. + """ + return self._node_type + + @property + def parent_node(self) -> Optional[AnyNode]: + """The parent of this node. All nodes, except `Document`, `DocumentFragment`, and `Attr` may have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is null. + """ + return self._parent_node + + def _set_parent_node(self, + parent_node: Optional[AnyNode], + node_type: Optional[NodeType] = None) -> None: + """Sets parent node of this node. If given `parent_node` is a node that cannot have its parent, this method will raise a warning. + + Args: + parent_node: A node which is the parent of this node. + node_type: Optional; Value to be assumed as the type of this node. If `node_type` is not given, it will be replaced with the type of this node. + """ + if node_type is None: + node_type = self.node_type + if parent_node is not None: + if self.node_type in [Node.DOCUMENT_NODE, + Node.DOCUMENT_FRAGMENT_NODE, + Node.ATTRIBUTE_NODE]: + warnings.warn('Document, DocumentFragment, ' + 'and Attr may not have a parent.') + self._parent_node = parent_node + + @property + def child_nodes(self) -> NodeList: + """A `NodeList` that contains all children of this node. If there are no children, this is a `NodeList` containing no nodes. The content of the returned `NodeList` is "live" in the sense that, for instance, changes to the children of the node object that it was created from are immediately reflected in the nodes returned by the `NodeList` accessors; it is not a static snapshot of the content of the node. This is true for every `NodeList`, including the ones returned by the `getElementsByTagName` method. + """ + return self._child_nodes + + @property + def first_child(self) -> Optional[AnyNode]: + """The first child of this node. If there is no such node, this returns `None`. + """ + if self.child_nodes.length == 0: + return None + else: + return self.child_nodes.item(0) + + @property + def last_child(self) -> Optional[AnyNode]: + """The last child of this node. If there is no such node, this returns `None`. + """ + if self.child_nodes.length == 0: + return None + else: + return self.child_nodes.item(self.child_nodes.length-1) + + @property + def previous_sibling(self) -> Optional[AnyNode]: + """The node immediately preceding this node. If there is no such node, this returns `None`. + """ + return self._previous_sibling + + @property + def next_sibling(self) -> Optional[AnyNode]: + """The node immediately following this node. If there is no such node, this returns `None`. + """ + return self._next_sibling + + @property + def attributes(self) -> Optional[NamedNodeMap]: + """A `NamedNodeMap` containing the attributes of this node (if it is an `Element`) or `None` otherwise. + """ + raise NotImplementedError + + @property + def owner_document(self) -> Optional[Document]: + """The `Document` object associated with this node. This is also the `Document` object used to create new nodes. When this node is a `Document` this is `None`. + """ + return self._owner_document diff --git a/python/dom/NotImplemented/Node.py b/python/dom/NotImplemented/Node.py deleted file mode 100644 index e5d5f12..0000000 --- a/python/dom/NotImplemented/Node.py +++ /dev/null @@ -1,2 +0,0 @@ -class Node: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/__init__.py b/python/dom/NotImplemented/__init__.py index eba7af7..0e362b7 100644 --- a/python/dom/NotImplemented/__init__.py +++ b/python/dom/NotImplemented/__init__.py @@ -12,7 +12,6 @@ from python.dom.NotImplemented.Entity import Entity from python.dom.NotImplemented.EntityReference import EntityReference from python.dom.NotImplemented.NamedNodeMap import NamedNodeMap -from python.dom.NotImplemented.Node import Node from python.dom.NotImplemented.NodeList import NodeList from python.dom.NotImplemented.Notation import Notation from python.dom.NotImplemented.ProcessingInstruction import ProcessingInstruction diff --git a/python/dom/__init__.py b/python/dom/__init__.py index 63f0114..4afc3ec 100644 --- a/python/dom/__init__.py +++ b/python/dom/__init__.py @@ -2,3 +2,4 @@ from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString +from python.dom.Node import Node diff --git a/python/dom/type_checking.py b/python/dom/type_checking.py index c46815c..be5b87a 100644 --- a/python/dom/type_checking.py +++ b/python/dom/type_checking.py @@ -6,6 +6,7 @@ from python.dom.NotImplemented import * from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString + from python.dom.Node import Node AnyNode = Union[ Node, From f87d4d20ee348d1d162c33178c82468ea5d06965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Thu, 27 May 2021 23:34:39 +0900 Subject: [PATCH 04/47] Implement interface NodeList (#6) * Start implementing NodeList * Make class `NodeList` more list-like by inheriting `list` * Add readonly attribute `length` * Add method `item` --- python/dom/Node.py | 2 +- python/dom/NodeList.py | 34 +++++++++++++++++++++++++++ python/dom/NotImplemented/NodeList.py | 2 -- python/dom/NotImplemented/__init__.py | 1 - python/dom/__init__.py | 1 + python/dom/type_checking.py | 1 + 6 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 python/dom/NodeList.py delete mode 100644 python/dom/NotImplemented/NodeList.py diff --git a/python/dom/Node.py b/python/dom/Node.py index 5f6fdc4..c3ec01a 100644 --- a/python/dom/Node.py +++ b/python/dom/Node.py @@ -6,7 +6,7 @@ from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString from python.dom.NotImplemented.NamedNodeMap import NamedNodeMap -from python.dom.NotImplemented.NodeList import NodeList +from python.dom.NodeList import NodeList from python.dom.type_checking import AnyNode diff --git a/python/dom/NodeList.py b/python/dom/NodeList.py new file mode 100644 index 0000000..7e23ea4 --- /dev/null +++ b/python/dom/NodeList.py @@ -0,0 +1,34 @@ +from __future__ import absolute_import + +from typing import Optional + +from python.dom.type_checking import AnyNode + + +class NodeList(list): + """Interface NodeList + + The `NodeList` interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. + + The items in the `NodeList` are accessible via an integral index, starting from 0. + """ + + @property + def length(self) -> int: + """The number of nodes in the list. The range of valid child node indices is 0 to `length`-1 inclusive. + """ + return len(self) + + def item(self, index: int) -> Optional[AnyNode]: + """Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns `None`. + + Args: + index: Index into the collection. + + Returns: + The node at the `index`th position in the NodeList, or `None` if that is not a valid index. + """ + if 0 <= index < self.length: + return self[index] + else: + return None diff --git a/python/dom/NotImplemented/NodeList.py b/python/dom/NotImplemented/NodeList.py deleted file mode 100644 index ff5b1cd..0000000 --- a/python/dom/NotImplemented/NodeList.py +++ /dev/null @@ -1,2 +0,0 @@ -class NodeList: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/__init__.py b/python/dom/NotImplemented/__init__.py index 0e362b7..fe65252 100644 --- a/python/dom/NotImplemented/__init__.py +++ b/python/dom/NotImplemented/__init__.py @@ -12,7 +12,6 @@ from python.dom.NotImplemented.Entity import Entity from python.dom.NotImplemented.EntityReference import EntityReference from python.dom.NotImplemented.NamedNodeMap import NamedNodeMap -from python.dom.NotImplemented.NodeList import NodeList from python.dom.NotImplemented.Notation import Notation from python.dom.NotImplemented.ProcessingInstruction import ProcessingInstruction from python.dom.NotImplemented.Text import Text diff --git a/python/dom/__init__.py b/python/dom/__init__.py index 4afc3ec..b5c2a8c 100644 --- a/python/dom/__init__.py +++ b/python/dom/__init__.py @@ -3,3 +3,4 @@ from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString from python.dom.Node import Node +from python.dom.NodeList import NodeList diff --git a/python/dom/type_checking.py b/python/dom/type_checking.py index be5b87a..456f736 100644 --- a/python/dom/type_checking.py +++ b/python/dom/type_checking.py @@ -7,6 +7,7 @@ from python.dom.DOMException import DOMException from python.dom.DOMString import DOMString from python.dom.Node import Node + from python.dom.NodeList import NodeList AnyNode = Union[ Node, From ee746b1a48df3d1103371a70fa482987d0cdb639 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 17:09:08 +0900 Subject: [PATCH 05/47] Remove `python.*` module. --- python/__init__.py | 0 python/dom/DOMException.py | 39 ---- python/dom/DOMString.py | 14 -- python/dom/Node.py | 167 ------------------ python/dom/NodeList.py | 34 ---- python/dom/NotImplemented/Attr.py | 2 - python/dom/NotImplemented/CDATASection.py | 2 - python/dom/NotImplemented/CharacterData.py | 2 - python/dom/NotImplemented/Comment.py | 2 - .../dom/NotImplemented/DOMImplementation.py | 2 - python/dom/NotImplemented/Document.py | 2 - python/dom/NotImplemented/DocumentFragment.py | 2 - python/dom/NotImplemented/DocumentType.py | 2 - python/dom/NotImplemented/Element.py | 2 - python/dom/NotImplemented/Entity.py | 2 - python/dom/NotImplemented/EntityReference.py | 2 - python/dom/NotImplemented/NamedNodeMap.py | 2 - python/dom/NotImplemented/Notation.py | 2 - .../NotImplemented/ProcessingInstruction.py | 2 - python/dom/NotImplemented/Text.py | 2 - python/dom/NotImplemented/__init__.py | 17 -- python/dom/__init__.py | 6 - python/dom/type_checking.py | 27 --- python/parser/__init__.py | 0 24 files changed, 334 deletions(-) delete mode 100644 python/__init__.py delete mode 100644 python/dom/DOMException.py delete mode 100644 python/dom/DOMString.py delete mode 100644 python/dom/Node.py delete mode 100644 python/dom/NodeList.py delete mode 100644 python/dom/NotImplemented/Attr.py delete mode 100644 python/dom/NotImplemented/CDATASection.py delete mode 100644 python/dom/NotImplemented/CharacterData.py delete mode 100644 python/dom/NotImplemented/Comment.py delete mode 100644 python/dom/NotImplemented/DOMImplementation.py delete mode 100644 python/dom/NotImplemented/Document.py delete mode 100644 python/dom/NotImplemented/DocumentFragment.py delete mode 100644 python/dom/NotImplemented/DocumentType.py delete mode 100644 python/dom/NotImplemented/Element.py delete mode 100644 python/dom/NotImplemented/Entity.py delete mode 100644 python/dom/NotImplemented/EntityReference.py delete mode 100644 python/dom/NotImplemented/NamedNodeMap.py delete mode 100644 python/dom/NotImplemented/Notation.py delete mode 100644 python/dom/NotImplemented/ProcessingInstruction.py delete mode 100644 python/dom/NotImplemented/Text.py delete mode 100644 python/dom/NotImplemented/__init__.py delete mode 100644 python/dom/__init__.py delete mode 100644 python/dom/type_checking.py delete mode 100644 python/parser/__init__.py diff --git a/python/__init__.py b/python/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/python/dom/DOMException.py b/python/dom/DOMException.py deleted file mode 100644 index a8550ea..0000000 --- a/python/dom/DOMException.py +++ /dev/null @@ -1,39 +0,0 @@ -import enum - - -class ExceptionCode(enum.IntEnum): - """Definition group `ExceptionCode` - - An integer indicating the type of error generated. - """ - INDEX_SIZE_ERR = 1 # If index or size is negative, or greater than the allowed value - DOMSTRING_SIZE_ERR = 2 # If the specified range of text does not fit into a DOMString - HIERARCHY_REQUEST_ERR = 3 # If any node is inserted somewhere it doesn't belong - WRONG_DOCUMENT_ERR = 4 # If a node is used in a different document than the one that created it (that doesn't support it) - INVALID_CHARACTER_ERR = 5 # If an invalid character is specified, such as in a name. - NO_DATA_ALLOWED_ERR = 6 # If data is specified for a node which does not support data - NO_MODIFICATION_ALLOWED_ERR = 7 # If an attempt is made to modify an object where modifications are not allowed - NOT_FOUND_ERR = 8 # If an attempt was made to reference a node in a context where it does not exist - NOT_SUPPORTED_ERR = 9 # If the implementation does not support the type of object requested - INUSE_ATTRIBUTE_ERR = 10 # If an attempt is made to add an attribute that is already inuse elsewhere - - -class DOMException(Exception): - """Exception `DOMException` - - DOM operations only raise exceptions in "exceptional" circumstances, i.e., when an operation is impossible to perform (either for logical reasons, because data is lost, or because the implementation has become unstable). In general, DOM methods return specific error values in ordinary processing situation, such as out-of-bound errors when using `NodeList`. - - Implementations may raise other exceptions under other circumstances. For example, implementations may raise an implementation-dependent exception if a null argument is passed. - - Some languages and object systems do not support the concept of exceptions. For such systems, error conditions may be indicated using native error reporting mechanisms. For some bindings, for example, methods may return error codes similar to those listed in the corresponding method descriptions. - """ - INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR - DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR - HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR - WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR - INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR - NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR - NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR - NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR - NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR - INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR diff --git a/python/dom/DOMString.py b/python/dom/DOMString.py deleted file mode 100644 index b719855..0000000 --- a/python/dom/DOMString.py +++ /dev/null @@ -1,14 +0,0 @@ -class DOMString(str): - """The `DOMString` type - - To ensure interoperability, the DOM specifies the `DOMString` type as follows: - - * A `DOMString` is a sequence of 16-bit quantities. This may be expressed in IDL terms as: - - `typedef sequence DOMString;` - - * Applications must encode `DOMString` using UTF-16 (defined in Appendix C.3 of [UNICODE] and Amendment 1 of [ISO-10646]).The UTF-16 encoding was chosen because of its widespread industry practice. Please note that for both HTML and XML, the document character set (and therefore the notation of numeric character references) is based on UCS-4. A single numeric character reference in a source document may therefore in some cases correspond to two array positions in a `DOMString` (a high surrogate and a low surrogate). Note: Even though the DOM defines the name of the string type to be `DOMString`, bindings may used different names. For, example for Java, `DOMString` is bound to the String type because it also uses UTF-16 as its encoding. - - > Note: As of August 1998, the OMG IDL specification included a wstring type. However, that definition did not meet the interoperability criteria of the DOM API since it relied on encoding negotiation to decide the width of a character. - """ - pass diff --git a/python/dom/Node.py b/python/dom/Node.py deleted file mode 100644 index c3ec01a..0000000 --- a/python/dom/Node.py +++ /dev/null @@ -1,167 +0,0 @@ -import enum -import warnings -from typing import AnyStr, Optional - -from python.dom.NotImplemented.Document import Document -from python.dom.DOMException import DOMException -from python.dom.DOMString import DOMString -from python.dom.NotImplemented.NamedNodeMap import NamedNodeMap -from python.dom.NodeList import NodeList -from python.dom.type_checking import AnyNode - - -class NodeType(enum.IntEnum): - """Definition group `NodeType` - - An integer indicating which type of node this is. - """ - ELEMENT_NODE = 1 # The node is a `Element`. - ATTRIBUTE_NODE = 2 # The node is an `Attr`. - TEXT_NODE = 3 # The node is a `Text` node. - CDATA_SECTION_NODE = 4 # The node is a `CDATASection`. - ENTITY_REFERENCE_NODE = 5 # The node is an `EntityReference`. - ENTITY_NODE = 6 # The node is an `Entity`. - PROCESSING_INSTRUCTION_NODE = 7 # The node is a `ProcessingInstruction`. - COMMENT_NODE = 8 # The node is a `Comment`. - DOCUMENT_NODE = 9 # The node is a `Document`. - DOCUMENT_TYPE_NODE = 10 # The node is a `DocumentType`. - DOCUMENT_FRAGMENT_NODE = 11 # The node is a `DocumentFragment`. - NOTATION_NODE = 12 # The node is a `Notation`. - - -class Node: - """Interface `Node` - - The `Node` interface is the primary datatype for the entire Document Object Model. It represents a single node in the document tree. While all objects implementing the `Node` interface expose methods for dealing with children, not all objects implementing the `Node` interface may have children. For example, `Text` nodes may not have children, and adding children to such nodes results in a `DOMException` being raised. - - The attributes `node_name`, `node_value` and attributes are included as a mechanism to get at node information without casting down to the specific derived interface. In cases where there is no obvious mapping of these attributes for a specific `node_type` (e.g., `node_value` for an Element or `attributes` for a Comment), this returns `None`. Note that the specialized interfaces may contain additional and more convenient mechanisms to get and set the relevant information. - """ - ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE - TEXT_NODE = NodeType.TEXT_NODE - ELEMENT_NODE = NodeType.ELEMENT_NODE - CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE - ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE - ENTITY_NODE = NodeType.ENTITY_NODE - PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE - COMMENT_NODE = NodeType.COMMENT_NODE - DOCUMENT_NODE = NodeType.DOCUMENT_NODE - DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE - DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE - NOTATION_NODE = NodeType.NOTATION_NODE - - def __init__(self, - owner_document: Document, - node_type: NodeType, - parent_node: Optional[AnyNode] = None, - read_only: bool = False) -> None: - self._set_parent_node(parent_node, node_type) - self._node_type: NodeType = node_type - self._read_only: bool = read_only - self._parent_node: Optional[AnyNode] # parent node should be set with `_set_parent_node` method. - self._child_nodes: NodeList = NodeList() - self._previous_sibling: Optional[AnyNode] = None - self._next_sibling: Optional[AnyNode] = None - self._owner_document: Document = owner_document - - - @property - def node_name(self) -> DOMString: - """The name of this node, depending on its type. - """ - raise NotImplementedError - - @property - def node_value(self) -> DOMString: - """The value of this node, depending on its type. - - Raises: - DOMException: - - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. (on setting) - - `DOMSTRING_SIZE_ERR`: Raised when it would return more characters than fit in a `DOMString` variable on the implementation platform. (on retrieval) - """ - raise NotImplementedError - - @node_value.setter - def node_value(self, value: AnyStr) -> None: - if self._read_only: - raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) - raise NotImplementedError - - @property - def node_type(self) -> NodeType: - """A code representing the type of the underlying object. - """ - return self._node_type - - @property - def parent_node(self) -> Optional[AnyNode]: - """The parent of this node. All nodes, except `Document`, `DocumentFragment`, and `Attr` may have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is null. - """ - return self._parent_node - - def _set_parent_node(self, - parent_node: Optional[AnyNode], - node_type: Optional[NodeType] = None) -> None: - """Sets parent node of this node. If given `parent_node` is a node that cannot have its parent, this method will raise a warning. - - Args: - parent_node: A node which is the parent of this node. - node_type: Optional; Value to be assumed as the type of this node. If `node_type` is not given, it will be replaced with the type of this node. - """ - if node_type is None: - node_type = self.node_type - if parent_node is not None: - if self.node_type in [Node.DOCUMENT_NODE, - Node.DOCUMENT_FRAGMENT_NODE, - Node.ATTRIBUTE_NODE]: - warnings.warn('Document, DocumentFragment, ' - 'and Attr may not have a parent.') - self._parent_node = parent_node - - @property - def child_nodes(self) -> NodeList: - """A `NodeList` that contains all children of this node. If there are no children, this is a `NodeList` containing no nodes. The content of the returned `NodeList` is "live" in the sense that, for instance, changes to the children of the node object that it was created from are immediately reflected in the nodes returned by the `NodeList` accessors; it is not a static snapshot of the content of the node. This is true for every `NodeList`, including the ones returned by the `getElementsByTagName` method. - """ - return self._child_nodes - - @property - def first_child(self) -> Optional[AnyNode]: - """The first child of this node. If there is no such node, this returns `None`. - """ - if self.child_nodes.length == 0: - return None - else: - return self.child_nodes.item(0) - - @property - def last_child(self) -> Optional[AnyNode]: - """The last child of this node. If there is no such node, this returns `None`. - """ - if self.child_nodes.length == 0: - return None - else: - return self.child_nodes.item(self.child_nodes.length-1) - - @property - def previous_sibling(self) -> Optional[AnyNode]: - """The node immediately preceding this node. If there is no such node, this returns `None`. - """ - return self._previous_sibling - - @property - def next_sibling(self) -> Optional[AnyNode]: - """The node immediately following this node. If there is no such node, this returns `None`. - """ - return self._next_sibling - - @property - def attributes(self) -> Optional[NamedNodeMap]: - """A `NamedNodeMap` containing the attributes of this node (if it is an `Element`) or `None` otherwise. - """ - raise NotImplementedError - - @property - def owner_document(self) -> Optional[Document]: - """The `Document` object associated with this node. This is also the `Document` object used to create new nodes. When this node is a `Document` this is `None`. - """ - return self._owner_document diff --git a/python/dom/NodeList.py b/python/dom/NodeList.py deleted file mode 100644 index 7e23ea4..0000000 --- a/python/dom/NodeList.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import absolute_import - -from typing import Optional - -from python.dom.type_checking import AnyNode - - -class NodeList(list): - """Interface NodeList - - The `NodeList` interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. - - The items in the `NodeList` are accessible via an integral index, starting from 0. - """ - - @property - def length(self) -> int: - """The number of nodes in the list. The range of valid child node indices is 0 to `length`-1 inclusive. - """ - return len(self) - - def item(self, index: int) -> Optional[AnyNode]: - """Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns `None`. - - Args: - index: Index into the collection. - - Returns: - The node at the `index`th position in the NodeList, or `None` if that is not a valid index. - """ - if 0 <= index < self.length: - return self[index] - else: - return None diff --git a/python/dom/NotImplemented/Attr.py b/python/dom/NotImplemented/Attr.py deleted file mode 100644 index e9d9b08..0000000 --- a/python/dom/NotImplemented/Attr.py +++ /dev/null @@ -1,2 +0,0 @@ -class Attr: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/CDATASection.py b/python/dom/NotImplemented/CDATASection.py deleted file mode 100644 index b9e6035..0000000 --- a/python/dom/NotImplemented/CDATASection.py +++ /dev/null @@ -1,2 +0,0 @@ -class CDATASection: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/CharacterData.py b/python/dom/NotImplemented/CharacterData.py deleted file mode 100644 index 7d8dbeb..0000000 --- a/python/dom/NotImplemented/CharacterData.py +++ /dev/null @@ -1,2 +0,0 @@ -class CharacterData: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/Comment.py b/python/dom/NotImplemented/Comment.py deleted file mode 100644 index 65d2c49..0000000 --- a/python/dom/NotImplemented/Comment.py +++ /dev/null @@ -1,2 +0,0 @@ -class Comment: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/DOMImplementation.py b/python/dom/NotImplemented/DOMImplementation.py deleted file mode 100644 index 9b49ccd..0000000 --- a/python/dom/NotImplemented/DOMImplementation.py +++ /dev/null @@ -1,2 +0,0 @@ -class DOMImplementation: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/Document.py b/python/dom/NotImplemented/Document.py deleted file mode 100644 index ed2c476..0000000 --- a/python/dom/NotImplemented/Document.py +++ /dev/null @@ -1,2 +0,0 @@ -class Document: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/DocumentFragment.py b/python/dom/NotImplemented/DocumentFragment.py deleted file mode 100644 index be955b6..0000000 --- a/python/dom/NotImplemented/DocumentFragment.py +++ /dev/null @@ -1,2 +0,0 @@ -class DocumentFragment: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/DocumentType.py b/python/dom/NotImplemented/DocumentType.py deleted file mode 100644 index 881d240..0000000 --- a/python/dom/NotImplemented/DocumentType.py +++ /dev/null @@ -1,2 +0,0 @@ -class DocumentType: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/Element.py b/python/dom/NotImplemented/Element.py deleted file mode 100644 index f88fa1a..0000000 --- a/python/dom/NotImplemented/Element.py +++ /dev/null @@ -1,2 +0,0 @@ -class Element: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/Entity.py b/python/dom/NotImplemented/Entity.py deleted file mode 100644 index c39e2ed..0000000 --- a/python/dom/NotImplemented/Entity.py +++ /dev/null @@ -1,2 +0,0 @@ -class Entity: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/EntityReference.py b/python/dom/NotImplemented/EntityReference.py deleted file mode 100644 index 4324696..0000000 --- a/python/dom/NotImplemented/EntityReference.py +++ /dev/null @@ -1,2 +0,0 @@ -class EntityReference: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/NamedNodeMap.py b/python/dom/NotImplemented/NamedNodeMap.py deleted file mode 100644 index a846d98..0000000 --- a/python/dom/NotImplemented/NamedNodeMap.py +++ /dev/null @@ -1,2 +0,0 @@ -class NamedNodeMap: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/Notation.py b/python/dom/NotImplemented/Notation.py deleted file mode 100644 index fbf275f..0000000 --- a/python/dom/NotImplemented/Notation.py +++ /dev/null @@ -1,2 +0,0 @@ -class Notation: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/ProcessingInstruction.py b/python/dom/NotImplemented/ProcessingInstruction.py deleted file mode 100644 index 77a39c2..0000000 --- a/python/dom/NotImplemented/ProcessingInstruction.py +++ /dev/null @@ -1,2 +0,0 @@ -class ProcessingInstruction: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/Text.py b/python/dom/NotImplemented/Text.py deleted file mode 100644 index 26d222c..0000000 --- a/python/dom/NotImplemented/Text.py +++ /dev/null @@ -1,2 +0,0 @@ -class Text: - pass \ No newline at end of file diff --git a/python/dom/NotImplemented/__init__.py b/python/dom/NotImplemented/__init__.py deleted file mode 100644 index fe65252..0000000 --- a/python/dom/NotImplemented/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import absolute_import - -from python.dom.NotImplemented.Attr import Attr -from python.dom.NotImplemented.CDATASection import CDATASection -from python.dom.NotImplemented.CharacterData import CharacterData -from python.dom.NotImplemented.Comment import Comment -from python.dom.NotImplemented.Document import Document -from python.dom.NotImplemented.DocumentFragment import DocumentFragment -from python.dom.NotImplemented.DocumentType import DocumentType -from python.dom.NotImplemented.DOMImplementation import DOMImplementation -from python.dom.NotImplemented.Element import Element -from python.dom.NotImplemented.Entity import Entity -from python.dom.NotImplemented.EntityReference import EntityReference -from python.dom.NotImplemented.NamedNodeMap import NamedNodeMap -from python.dom.NotImplemented.Notation import Notation -from python.dom.NotImplemented.ProcessingInstruction import ProcessingInstruction -from python.dom.NotImplemented.Text import Text diff --git a/python/dom/__init__.py b/python/dom/__init__.py deleted file mode 100644 index b5c2a8c..0000000 --- a/python/dom/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import absolute_import - -from python.dom.DOMException import DOMException -from python.dom.DOMString import DOMString -from python.dom.Node import Node -from python.dom.NodeList import NodeList diff --git a/python/dom/type_checking.py b/python/dom/type_checking.py deleted file mode 100644 index 456f736..0000000 --- a/python/dom/type_checking.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import absolute_import - -from typing import Union, TYPE_CHECKING - -if TYPE_CHECKING: - from python.dom.NotImplemented import * - from python.dom.DOMException import DOMException - from python.dom.DOMString import DOMString - from python.dom.Node import Node - from python.dom.NodeList import NodeList - - AnyNode = Union[ - Node, - # Ordered by NodeType - Element, - Attr, - Text, - CDATASection, - EntityReference, - Entity, - ProcessingInstruction, - Comment, - Document, - DocumentType, - DocumentFragment, - Notation, - ] diff --git a/python/parser/__init__.py b/python/parser/__init__.py deleted file mode 100644 index e69de29..0000000 From 54c5d09ade9e9cc117e146e4633a07ca6dd6d024 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 18:18:29 +0900 Subject: [PATCH 06/47] Add .pylintrc To prevent pylint(import-error) `pylint --generate-rcfile > .pylintrc` --- .pylintrc | Bin 0 -> 39418 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000000000000000000000000000000000..5600ccc2268c8b6f0e246c237e82da22978193ec GIT binary patch literal 39418 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 Date: Mon, 31 May 2021 18:19:14 +0900 Subject: [PATCH 07/47] Design the basic structure of the module --- w3/python/core/__init__.py | 2 ++ w3/python/dom.py | 2 ++ w3/python/parser.py | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 w3/python/core/__init__.py create mode 100644 w3/python/dom.py create mode 100644 w3/python/parser.py diff --git a/w3/python/core/__init__.py b/w3/python/core/__init__.py new file mode 100644 index 0000000..8c19b16 --- /dev/null +++ b/w3/python/core/__init__.py @@ -0,0 +1,2 @@ +"""Module that contains classes of interfaces and ect. +""" \ No newline at end of file diff --git a/w3/python/dom.py b/w3/python/dom.py new file mode 100644 index 0000000..d49aa20 --- /dev/null +++ b/w3/python/dom.py @@ -0,0 +1,2 @@ +"""API Module of DOM - Level 1 +""" diff --git a/w3/python/parser.py b/w3/python/parser.py new file mode 100644 index 0000000..4a1b2d3 --- /dev/null +++ b/w3/python/parser.py @@ -0,0 +1,2 @@ +"""A Parser module for building Document Object Model Structure parsed from text/html. +""" From 547801e0300c0b58f91472ef6bb796c1d7702530 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 18:19:31 +0900 Subject: [PATCH 08/47] Create `DOMString` and `AnyNode` types --- w3/python/core/type.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 w3/python/core/type.py diff --git a/w3/python/core/type.py b/w3/python/core/type.py new file mode 100644 index 0000000..3ddc7e1 --- /dev/null +++ b/w3/python/core/type.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +from typing import TypeVar + + +DOMString = TypeVar('DOMString', str, bytes) + +AnyNode = TypeVar('AnyNode') From 3199b5d55aeb4dd1a4e80fb82816f6667f40160f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Mon, 31 May 2021 19:43:14 +0900 Subject: [PATCH 09/47] Implement of Interface DOMException (#11) * Create fundamental_interface.py * Create DOMException.py * Create definition group `ExceptionCode` * Create `DOMException` which inherits from `ExceptionCode` and `Exception` * Bind `DOMException` to `w3.python.core.fundamental_interfaces` * Fix TypeError: "cannot extend enumerations" * Bind `DOMException` to `w3.python.dom` and `w3.python.core` * Create unittest for `DOMException` * Rename dir "fundamental_interfaces" -> "fundamental_interface' of "w3/python/core/" --- w3/python/core/__init__.py | 4 ++- .../fundamental_interface/DOMException.py | 36 +++++++++++++++++++ .../DOMException_test.py | 18 ++++++++++ .../core/fundamental_interface/__init__.py | 8 +++++ w3/python/dom.py | 3 ++ 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 w3/python/core/fundamental_interface/DOMException.py create mode 100644 w3/python/core/fundamental_interface/DOMException_test.py create mode 100644 w3/python/core/fundamental_interface/__init__.py diff --git a/w3/python/core/__init__.py b/w3/python/core/__init__.py index 8c19b16..4a270a5 100644 --- a/w3/python/core/__init__.py +++ b/w3/python/core/__init__.py @@ -1,2 +1,4 @@ """Module that contains classes of interfaces and ect. -""" \ No newline at end of file +""" + +from w3.python.core.fundamental_interface import DOMException diff --git a/w3/python/core/fundamental_interface/DOMException.py b/w3/python/core/fundamental_interface/DOMException.py new file mode 100644 index 0000000..cbc83c1 --- /dev/null +++ b/w3/python/core/fundamental_interface/DOMException.py @@ -0,0 +1,36 @@ +import enum + + +class ExceptionCode(enum.IntEnum): + """Definition group `ExceptionCode` + An integer indicating the type of error generated. + """ + INDEX_SIZE_ERR = 1 + DOMSTRING_SIZE_ERR = 2 + HIERARCHY_REQUEST_ERR = 3 + WRONG_DOCUMENT_ERR = 4 + INVALID_CHARACTER_ERR = 5 + NO_DATA_ALLOWED_ERR = 6 + NO_MODIFICATION_ALLOWED_ERR = 7 + NOT_FOUND_ERR = 8 + NOT_SUPPORTED_ERR = 9 + INUSE_ATTRIBUTE_ERR = 10 + + +class DOMException(Exception): + """Exception DOMException + + DOM operations only raise exceptions in "exceptional" circumstances, i.e., when an operation is impossible to perform (either for logical reasons, because data is lost, or because the implementation has become unstable). In general, DOM methods return specific error values in ordinary processing situation, such as out-of-bound errors when using `NodeList`. + Implementations may raise other exceptions under other circumstances. For example, implementations may raise an implementation-dependent exception if a null argument is passed. + Some languages and object systems do not support the concept of exceptions. For such systems, error conditions may be indicated using native error reporting mechanisms. For some bindings, for example, methods may return error codes similar to those listed in the corresponding method descriptions. + """ + INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR + DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR + HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR + WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR + INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR + NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR + NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR + NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR + NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR + INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR diff --git a/w3/python/core/fundamental_interface/DOMException_test.py b/w3/python/core/fundamental_interface/DOMException_test.py new file mode 100644 index 0000000..99ad7c2 --- /dev/null +++ b/w3/python/core/fundamental_interface/DOMException_test.py @@ -0,0 +1,18 @@ +import unittest + +from w3.python.core.fundamental_interface.DOMException import DOMException + + +class Test_DOMException(unittest.TestCase): + def test_raise_INDEX_SIZE_ERR(self): + try: + raise DOMException(DOMException.INDEX_SIZE_ERR) + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.INDEX_SIZE_ERR) + else: + self.fail() + + +if __name__ == '__main__': + unittest.main() diff --git a/w3/python/core/fundamental_interface/__init__.py b/w3/python/core/fundamental_interface/__init__.py new file mode 100644 index 0000000..d5bb492 --- /dev/null +++ b/w3/python/core/fundamental_interface/__init__.py @@ -0,0 +1,8 @@ +"""Fundamental Interfaces + +The interfaces within this section are considered fundamental, and must be fully implemented by all conforming implementations of the DOM, including all HTML DOM implementations. +""" + +from __future__ import absolute_import + +from w3.python.core.fundamental_interface.DOMException import DOMException diff --git a/w3/python/dom.py b/w3/python/dom.py index d49aa20..1d5ec41 100644 --- a/w3/python/dom.py +++ b/w3/python/dom.py @@ -1,2 +1,5 @@ """API Module of DOM - Level 1 """ + +# Bring in subpackages. +from w3.python.core import DOMException From ea7745667c4a5e79426894ab95db8c23adc78175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Mon, 31 May 2021 19:52:34 +0900 Subject: [PATCH 10/47] Implement of interface DOMImplementation (#12) * Create DOMImplementation.py * Create interface `DOMImplementation` * Create `has_feature` method but not fully implemented * Bind `DOMImplementation` to `w3.python.dom` --- w3/python/core/__init__.py | 1 + .../DOMImplementation.py | 30 +++++++++++++++++++ .../core/fundamental_interface/__init__.py | 1 + w3/python/dom.py | 1 + 4 files changed, 33 insertions(+) create mode 100644 w3/python/core/fundamental_interface/DOMImplementation.py diff --git a/w3/python/core/__init__.py b/w3/python/core/__init__.py index 4a270a5..acb568b 100644 --- a/w3/python/core/__init__.py +++ b/w3/python/core/__init__.py @@ -2,3 +2,4 @@ """ from w3.python.core.fundamental_interface import DOMException +from w3.python.core.fundamental_interface import DOMImplementation diff --git a/w3/python/core/fundamental_interface/DOMImplementation.py b/w3/python/core/fundamental_interface/DOMImplementation.py new file mode 100644 index 0000000..906763c --- /dev/null +++ b/w3/python/core/fundamental_interface/DOMImplementation.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import + +from w3.python.core.type import DOMString + + +class DOMImplementation: + """Interface DOMImplementation + + The `DOMImplementation` interface provides a number of methods for performing operations that are independent of any particular instance of the document object model. + + The DOM Level 1 does not specify a way of creating a document instance, and hence document creation is an operation specific to an implementation. Future Levels of the DOM specification are expected to provide methods for creating documents directly. + """ + + # TODO + def has_feature(self, + feature: DOMString, + version: DOMString) -> bool: + """ + Test if the DOM implementation implements a specific feature. + + Args: + feature: The package name of the feature to test. In Level 1, the legal values are "HTML" and "XML" (case-insensitive). + version: This is the version number of the package name to test. In Level 1, this is the string "1.0". If the version is not specified, supporting any version of the feature will cause the method to return true. + + Returns: + `True` if the feature is implemented in the specified version, `False` otherwise. + + This method raises no exceptions. + """ + raise NotImplementedError diff --git a/w3/python/core/fundamental_interface/__init__.py b/w3/python/core/fundamental_interface/__init__.py index d5bb492..9d1c31c 100644 --- a/w3/python/core/fundamental_interface/__init__.py +++ b/w3/python/core/fundamental_interface/__init__.py @@ -6,3 +6,4 @@ from __future__ import absolute_import from w3.python.core.fundamental_interface.DOMException import DOMException +from w3.python.core.fundamental_interface.DOMImplementation import DOMImplementation diff --git a/w3/python/dom.py b/w3/python/dom.py index 1d5ec41..30e48f5 100644 --- a/w3/python/dom.py +++ b/w3/python/dom.py @@ -3,3 +3,4 @@ # Bring in subpackages. from w3.python.core import DOMException +from w3.python.core import DOMImplementation From 55118b0028a154f1bf0ccf3f81bedf5e95a042d3 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 19:53:28 +0900 Subject: [PATCH 11/47] Add some details for "w3/__init__.py" --- w3/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 w3/__init__.py diff --git a/w3/__init__.py b/w3/__init__.py new file mode 100644 index 0000000..d57af52 --- /dev/null +++ b/w3/__init__.py @@ -0,0 +1,14 @@ +"""A Python HTML Parser + +This is a personal project owned by Hepheir. + +https://github.com/Hepheir/Python-HTML-Parser/ +""" + +from w3.python import dom +from w3.python import parser + + +__version__ = '0.0.0' + +__author__ = 'hepheir@gmail.com' From ec81151f1cf29d2b50cf1370fc20d97615d6fec6 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 20:19:10 +0900 Subject: [PATCH 12/47] Create Node.py --- w3/python/core/fundamental_interface/Node.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 w3/python/core/fundamental_interface/Node.py diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py new file mode 100644 index 0000000..e69de29 From b9e72f98bb4c27743f12d4b760e72bdfc9d053aa Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 20:24:12 +0900 Subject: [PATCH 13/47] Create definition group `NodeType` --- w3/python/core/fundamental_interface/Node.py | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index e69de29..9c07150 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -0,0 +1,34 @@ +import enum + + +class NodeType(enum.IntEnum): + """Definition group `NodeType` + + An integer indicating which type of node this is. + + Attributes: + ELEMENT_NODE: The node is a `Element`. + ATTRIBUTE_NODE: The node is an `Attr`. + TEXT_NODE: The node is a `Text` node. + CDATA_SECTION_NODE: The node is a `CDATASection`. + ENTITY_REFERENCE_NODE: The node is an `EntityReference`. + ENTITY_NODE: The node is an `Entity`. + PROCESSING_INSTRUCTION_NODE: The node is a `ProcessingInstruction`. + COMMENT_NODE: The node is a `Comment`. + DOCUMENT_NODE: The node is a `Document`. + DOCUMENT_TYPE_NODE: The node is a `DocumentType`. + DOCUMENT_FRAGMENT_NODE: The node is a `DocumentFragment`. + NOTATION_NODE: The node is a `Notation`. + """ + ELEMENT_NODE = 1 + ATTRIBUTE_NODE = 2 + TEXT_NODE = 3 + CDATA_SECTION_NODE = 4 + ENTITY_REFERENCE_NODE = 5 + ENTITY_NODE = 6 + PROCESSING_INSTRUCTION_NODE = 7 + COMMENT_NODE = 8 + DOCUMENT_NODE = 9 + DOCUMENT_TYPE_NODE = 10 + DOCUMENT_FRAGMENT_NODE = 11 + NOTATION_NODE = 12 \ No newline at end of file From f56d30ba6390f3a87f39add9cedbdfae9b084a85 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 20:31:02 +0900 Subject: [PATCH 14/47] Create interface `Node` --- w3/python/core/fundamental_interface/Node.py | 24 +++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 9c07150..7e06532 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -31,4 +31,26 @@ class NodeType(enum.IntEnum): DOCUMENT_NODE = 9 DOCUMENT_TYPE_NODE = 10 DOCUMENT_FRAGMENT_NODE = 11 - NOTATION_NODE = 12 \ No newline at end of file + NOTATION_NODE = 12 + + +class Node: + """Interface `Node` + + The `Node` interface is the primary datatype for the entire Document Object Model. It represents a single node in the document tree. While all objects implementing the `Node` interface expose methods for dealing with children, not all objects implementing the `Node` interface may have children. For example, `Text` nodes may not have children, and adding children to such nodes results in a `DOMException` being raised. + The attributes `node_name`, `node_value` and attributes are included as a mechanism to get at node information without casting down to the specific derived interface. In cases where there is no obvious mapping of these attributes for a specific `node_type` (e.g., `node_value` for an Element or `attributes` for a Comment), this returns `None`. Note that the specialized interfaces may contain additional and more convenient mechanisms to get and set the relevant information. + + Attributes: + node_name: The name of this node, depending on its type. + node_value: The value of this node, depending on its type. + node_type: A code representing the type of the underlying object. + parent_node: The parent of this node. + child_nodes: A `NodeList` that contains all children of this node. + first_child: The first child of this node. + last_child: The last child of this node. + previous_sibling: The node immediately preceding this node. + next_sibling: The node immediately following this node. + attributes: A `NamedNodeMap` containing the attributes of this node. + owner_document: The `Document` object associated with this node. + """ + pass From c908e5ed95fc91f094ebc9f0dc83c600d8e8eceb Mon Sep 17 00:00:00 2001 From: Hepheir Date: Mon, 31 May 2021 20:48:17 +0900 Subject: [PATCH 15/47] Change the type of `DOMString` from `TypeVar` into `str` (cherry picked from commit 0903a8c0f986abc68d1a5ef06148f3740b996379) --- w3/python/core/type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3/python/core/type.py b/w3/python/core/type.py index 3ddc7e1..40ad1d9 100644 --- a/w3/python/core/type.py +++ b/w3/python/core/type.py @@ -3,6 +3,6 @@ from typing import TypeVar -DOMString = TypeVar('DOMString', str, bytes) +DOMString = str AnyNode = TypeVar('AnyNode') From b8221c3bb259388dff6cb27327e66dd90d4dd96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 11:40:03 +0900 Subject: [PATCH 16/47] Create read-only attribute `node_name` --- w3/python/core/fundamental_interface/Node.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 7e06532..171bd53 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,5 +1,7 @@ import enum +from w3.python.core.type import DOMString + class NodeType(enum.IntEnum): """Definition group `NodeType` @@ -53,4 +55,20 @@ class Node: attributes: A `NamedNodeMap` containing the attributes of this node. owner_document: The `Document` object associated with this node. """ - pass + + def __init__(self, + node_name: DOMString) -> None: + self._set_node_name(node_name) + # Attributes + self._node_name: DOMString + + @property + def node_name(self) -> DOMString: + """Read only; The name of this node, depending on its type. + """ + return self._node_name + + def _set_node_name(self, name: DOMString) -> None: + """Indirect accessor to set the 'node_name' property. + """ + self._node_name = DOMString(name) From 5a056b3ebdae35d49d333ec7b1a4d923f6790526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 11:58:43 +0900 Subject: [PATCH 17/47] Create accessor attribute `_read_only` and method `_check_modifiable()` --- w3/python/core/fundamental_interface/Node.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 171bd53..5f16063 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,5 +1,6 @@ import enum +from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.type import DOMString @@ -57,10 +58,23 @@ class Node: """ def __init__(self, - node_name: DOMString) -> None: + node_name: DOMString, + read_only: bool = False) -> None: self._set_node_name(node_name) + self._read_only = bool(read_only) # Attributes self._node_name: DOMString + self._read_only: bool + + def _check_modifiable(self) -> None: + """Checks if this node is modifiable. + + Raises: + DOMException: + - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. + """ + if self._read_only: + raise DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR) @property def node_name(self) -> DOMString: From b960da790f9f6dbc36fb54e073ddd259a9f345ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 12:01:43 +0900 Subject: [PATCH 18/47] Create attribute `node_value` with its accessor method `_set_node_value()` --- w3/python/core/fundamental_interface/Node.py | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 5f16063..935708a 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,4 +1,5 @@ import enum +from typing import Optional from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.type import DOMString @@ -59,11 +60,16 @@ class Node: def __init__(self, node_name: DOMString, + node_value: Optional[DOMString] = None, read_only: bool = False) -> None: + if node_value is None: + node_value = '' self._set_node_name(node_name) + self._set_node_value(node_value) self._read_only = bool(read_only) # Attributes self._node_name: DOMString + self._node_value: DOMString self._read_only: bool def _check_modifiable(self) -> None: @@ -86,3 +92,28 @@ def _set_node_name(self, name: DOMString) -> None: """Indirect accessor to set the 'node_name' property. """ self._node_name = DOMString(name) + + @property + def node_value(self) -> DOMString: + """The value of this node, depending on its type. + + Raises: + DOMException: + - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. (on setting) + - `DOMSTRING_SIZE_ERR`: Raised when it would return more characters than fit in a `DOMString` variable on the implementation platform. (on retrieval) + """ + return self._node_value + + @node_value.setter + def node_value(self, value: DOMString) -> None: + self._set_node_value(value) + + def _set_node_value(self, value: DOMString) -> None: + """Indirect accessor to set the 'node_value' property. + + Raises: + DOMException: + - `NO_MODIFICATION_ALLOWED_ERR`: Raised when the node is readonly. + """ + self._check_modifiable() + self._node_value = DOMString(value) From 8e7cc5247e777fdc9b2d2bd0fdd5e1be04b4ce58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 15:45:41 +0900 Subject: [PATCH 19/47] Create readonly attribute `node_type` with its accessor method `_set_node_type()` --- w3/python/core/fundamental_interface/Node.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 935708a..cd2e113 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -59,11 +59,13 @@ class Node: """ def __init__(self, + node_type: NodeType, node_name: DOMString, node_value: Optional[DOMString] = None, read_only: bool = False) -> None: if node_value is None: node_value = '' + self._set_node_type(node_type) self._set_node_name(node_name) self._set_node_value(node_value) self._read_only = bool(read_only) @@ -117,3 +119,17 @@ def _set_node_value(self, value: DOMString) -> None: """ self._check_modifiable() self._node_value = DOMString(value) + + @property + def node_type(self) -> NodeType: + """Read only; A code representing the type of the underlying object, as defined in `NodeType`. + """ + return self._node_type + + def _set_node_type(self, node_type: NodeType) -> None: + """Indirect accessor to set the 'node_type' property. + """ + if node_type not in NodeType: + raise ValueError(f'{node_type} is not a valid code ' + 'for a node type.') + self._node_type = node_type From 1720ff3bedb5a5807b541c373574f39f9afe5662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 15:46:26 +0900 Subject: [PATCH 20/47] Create unittest for `w3.python.core.fundamental_interface.Node` --- .../core/fundamental_interface/Node_test.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 w3/python/core/fundamental_interface/Node_test.py diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py new file mode 100644 index 0000000..a84ead8 --- /dev/null +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -0,0 +1,36 @@ +import unittest + +from w3.python.core.fundamental_interface.Node import Node +from w3.python.core.fundamental_interface.Node import NodeType + + +class Test_Node(unittest.TestCase): + def test_init(self): + node = Node(node_type=NodeType.DOCUMENT_NODE, + node_name='#document', + read_only=False) + self.assertEqual(node.node_type, NodeType.DOCUMENT_NODE) + self.assertEqual(node.node_name, '#document') + self.assertEqual(node.node_value, '') + + def testNodeType_get(self): + for node_type in NodeType: + node = Node(node_type=node_type, + node_name='') + self.assertEqual(node.node_type, node_type) + + def testNodeType_setCorrectTypes(self): + for node_type in NodeType: + node = Node(node_type=node_type, + node_name='') + self.assertEqual(node._node_type, node_type) + + def testNodeType_setWrongTypes(self): + for node_type in [-1, None, 'hi', Node]: + with self.assertRaises(TypeError): + Node(node_type=node_type, + node_name='') + + +if __name__ == '__main__': + unittest.main() From 71a8109d29a073f23171e0d8d80d9642b3b9152b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 15:48:03 +0900 Subject: [PATCH 21/47] Fix AttributeError: 'Node' object has no attribute '_read_only' found by unittest --- w3/python/core/fundamental_interface/Node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index cd2e113..01bf5b0 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -65,10 +65,10 @@ def __init__(self, read_only: bool = False) -> None: if node_value is None: node_value = '' + self._read_only = bool(read_only) self._set_node_type(node_type) self._set_node_name(node_name) self._set_node_value(node_value) - self._read_only = bool(read_only) # Attributes self._node_name: DOMString self._node_value: DOMString From af2290418807caecd4dbeb72915e47a3c1d64170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 16:02:03 +0900 Subject: [PATCH 22/47] Deprecate direct access to protected attribute when `node` is an instance of `Node()` Yes: `node.node_value` No: `node._node_value` --- w3/python/core/fundamental_interface/Node_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index a84ead8..2ed068f 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -23,7 +23,7 @@ def testNodeType_setCorrectTypes(self): for node_type in NodeType: node = Node(node_type=node_type, node_name='') - self.assertEqual(node._node_type, node_type) + self.assertEqual(node.node_type, node_type) def testNodeType_setWrongTypes(self): for node_type in [-1, None, 'hi', Node]: From c70a5365d18b30ea0bd6728ffc186a8d6f696042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 16:06:27 +0900 Subject: [PATCH 23/47] Add more 'wrong node type' cases --- w3/python/core/fundamental_interface/Node_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 2ed068f..49c7ce3 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -26,7 +26,7 @@ def testNodeType_setCorrectTypes(self): self.assertEqual(node.node_type, node_type) def testNodeType_setWrongTypes(self): - for node_type in [-1, None, 'hi', Node]: + for node_type in [-1, None, 'hi', Node, True, NodeType, 'DOCUMENT_NODE']: with self.assertRaises(TypeError): Node(node_type=node_type, node_name='') From 294913059e006894c84a2aad46fbe0b77ee8630e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 16:06:45 +0900 Subject: [PATCH 24/47] Create test for `node_value` --- .../core/fundamental_interface/Node_test.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 49c7ce3..e4c8f7e 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -1,5 +1,6 @@ import unittest +from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.fundamental_interface.Node import Node from w3.python.core.fundamental_interface.Node import NodeType @@ -13,6 +14,38 @@ def test_init(self): self.assertEqual(node.node_name, '#document') self.assertEqual(node.node_value, '') + def testNodeValue_get(self): + node = Node(node_type=NodeType.TEXT_NODE, + node_name='#text', + node_value='lorem ipsum') + self.assertEqual(node.node_value, 'lorem ipsum') + + def testNodeValue_set(self): + # set value from constructor + node = Node(node_type=NodeType.TEXT_NODE, + node_name='#text', + node_value='foo', + read_only=False) + self.assertEqual(node.node_value, 'foo') + # set using setter + node.node_value = 'bar' + self.assertEqual(node.node_value, 'bar') + + def testNodeValue_setReadOnly(self): + node = Node(node_type=NodeType.TEXT_NODE, + node_name='#text', + node_value='foo', + read_only=True) + try: + node.node_value = 'bar' + except DOMException as e: + code = e.args[0] + self.assertEqual(code, DOMException.NO_MODIFICATION_ALLOWED_ERR) + else: + self.fail() + # `node_value` should not be modified. + self.assertEqual(node.node_value, 'foo') + def testNodeType_get(self): for node_type in NodeType: node = Node(node_type=node_type, From 3c9748fe28edd6a40d3ee14eba6fff25d765402a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Tue, 1 Jun 2021 16:08:52 +0900 Subject: [PATCH 25/47] Fix `DOMException` while initiation of `Node` `NO_MODIFICATION_ALLOWED_ERR` --- w3/python/core/fundamental_interface/Node.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 01bf5b0..e2a41ff 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -65,10 +65,11 @@ def __init__(self, read_only: bool = False) -> None: if node_value is None: node_value = '' - self._read_only = bool(read_only) + self._read_only = False # Allow to modify only while initiating. self._set_node_type(node_type) self._set_node_name(node_name) self._set_node_value(node_value) + self._read_only = bool(read_only) # Attributes self._node_name: DOMString self._node_value: DOMString From a5d91f3bc552e1db4e5e6d0bcaad84d7e5c4a0cd Mon Sep 17 00:00:00 2001 From: Hepheir Date: Wed, 2 Jun 2021 01:28:08 +0900 Subject: [PATCH 26/47] Create "w3/python/__init__.py" ...to make Python extension of VSCode to discover unittests. (cherry picked from commit c147e3f94f7d0159ce89466f8f5b0976995cc7f1) --- w3/python/__init__.py | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 w3/python/__init__.py diff --git a/w3/python/__init__.py b/w3/python/__init__.py new file mode 100644 index 0000000..ffc4cd7 --- /dev/null +++ b/w3/python/__init__.py @@ -0,0 +1,2 @@ +from w3.python import dom +from w3.python import parser From 6c92e17d97b550d24730112c942f8705718ee210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 14:00:12 +0900 Subject: [PATCH 27/47] Add typing hint for `_node_type` --- w3/python/core/fundamental_interface/Node.py | 1 + 1 file changed, 1 insertion(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index e2a41ff..d88d342 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -71,6 +71,7 @@ def __init__(self, self._set_node_value(node_value) self._read_only = bool(read_only) # Attributes + self._node_type: NodeType self._node_name: DOMString self._node_value: DOMString self._read_only: bool From c6a040f5c079c81e668a1181aed5e5c2225062a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 14:01:17 +0900 Subject: [PATCH 28/47] Create `_AnyNode` for typing --- w3/python/core/fundamental_interface/Node.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index d88d342..3aeaf8f 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,5 +1,7 @@ +from __future__ import annotations + import enum -from typing import Optional +from typing import Optional, TypeVar from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.type import DOMString @@ -135,3 +137,6 @@ def _set_node_type(self, node_type: NodeType) -> None: raise ValueError(f'{node_type} is not a valid code ' 'for a node type.') self._node_type = node_type + + +_AnyNode = TypeVar('_AnyNode', Node) From 8a6f0aba4ea70448adf7ee5052723fa617940c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 14:03:07 +0900 Subject: [PATCH 29/47] Create readonly attribute `parent_node` --- w3/python/core/fundamental_interface/Node.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 3aeaf8f..e470399 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -64,6 +64,7 @@ def __init__(self, node_type: NodeType, node_name: DOMString, node_value: Optional[DOMString] = None, + parent_node: Optional[_AnyNode] = None, read_only: bool = False) -> None: if node_value is None: node_value = '' @@ -71,11 +72,13 @@ def __init__(self, self._set_node_type(node_type) self._set_node_name(node_name) self._set_node_value(node_value) + self._set_parent_node(parent_node) self._read_only = bool(read_only) # Attributes self._node_type: NodeType self._node_name: DOMString self._node_value: DOMString + self._parent_node: _AnyNode self._read_only: bool def _check_modifiable(self) -> None: @@ -138,5 +141,20 @@ def _set_node_type(self, node_type: NodeType) -> None: 'for a node type.') self._node_type = node_type + @property + def parent_node(self) -> Optional[_AnyNode]: + """The parent of this node. All nodes, except `Document`, `DocumentFragment`, and `Attr` may have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is `None`. + """ + return self._parent_node + + def _set_parent_node(self, + parent_node: Optional[_AnyNode]) -> None: + """Indirect accessor to set the 'node_type' property. + """ + if not parent_node: + self._parent_node = None + else: + self._parent_node = parent_node + _AnyNode = TypeVar('_AnyNode', Node) From 7ae58d7d0a05c98c02801793eab7470c5989c2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 14:08:53 +0900 Subject: [PATCH 30/47] Fix TypeError (`_AnyNode`): A single constraint is not allowed --- w3/python/core/fundamental_interface/Node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index e470399..e451c38 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -157,4 +157,4 @@ def _set_parent_node(self, self._parent_node = parent_node -_AnyNode = TypeVar('_AnyNode', Node) +_AnyNode = Node From a8970242be4d997d32a0a7aba5c19696da8d4ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 14:09:49 +0900 Subject: [PATCH 31/47] Create unittest for `Node.parent_node` --- w3/python/core/fundamental_interface/Node_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index e4c8f7e..3ac4926 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -64,6 +64,14 @@ def testNodeType_setWrongTypes(self): Node(node_type=node_type, node_name='') + def testParentNode_get(self): + parent_node = Node(node_type=NodeType.DOCUMENT_FRAGMENT_NODE, + node_name='#document-fragment') + node = Node(node_type=NodeType.ELEMENT_NODE, + node_name='tagName', + parent_node=parent_node) + self.assertEqual(node.parent_node, parent_node) + if __name__ == '__main__': unittest.main() From 26bd792a3a58eb7f32e36e7234067de72c922860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 14:17:21 +0900 Subject: [PATCH 32/47] Unimport unused var `TypeVar` --- w3/python/core/fundamental_interface/Node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index e451c38..8e97f33 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,7 +1,7 @@ from __future__ import annotations import enum -from typing import Optional, TypeVar +from typing import Optional from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.type import DOMString From 641ba8fc165ba2dc8be723141d7d17d981255f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 15:21:31 +0900 Subject: [PATCH 33/47] Implement of interface NodeList (#14) * Create NodeList.py * Implement `NodeList` based on `list` type * Create unittest for `NodeList` --- .../core/fundamental_interface/NodeList.py | 36 ++++++++++ .../fundamental_interface/NodeList_test.py | 69 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 w3/python/core/fundamental_interface/NodeList.py create mode 100644 w3/python/core/fundamental_interface/NodeList_test.py diff --git a/w3/python/core/fundamental_interface/NodeList.py b/w3/python/core/fundamental_interface/NodeList.py new file mode 100644 index 0000000..4df6941 --- /dev/null +++ b/w3/python/core/fundamental_interface/NodeList.py @@ -0,0 +1,36 @@ +from typing import Optional + +from w3.python.core.fundamental_interface.Node import Node + + +_AnyNode = Node + +class NodeList(list): + """Interface NodeList + + The `NodeList` interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. + The items in the `NodeList` are accessible via an integral index, starting from 0. + """ + + @property + def length(self) -> int: + """The number of nodes in the list. The range of valid child node indices is 0 to `length`-1 inclusive. + """ + return len(self) + + + def item(self, index: int) -> Optional[_AnyNode]: + """Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null. + + Args: + index: Index into the collection. + + Returns: + The node at the `index`th position in the `NodeList`, or `None` if that is not a valid index. + + This method raises no exceptions. + """ + if isinstance(index, int): + if 0 <= index < self.length: + return self[index] + return None diff --git a/w3/python/core/fundamental_interface/NodeList_test.py b/w3/python/core/fundamental_interface/NodeList_test.py new file mode 100644 index 0000000..d19801e --- /dev/null +++ b/w3/python/core/fundamental_interface/NodeList_test.py @@ -0,0 +1,69 @@ +from typing import Iterator +import unittest + +from w3.python.core.fundamental_interface.DOMException import DOMException +from w3.python.core.fundamental_interface.Node import Node +from w3.python.core.fundamental_interface.Node import NodeType +from w3.python.core.fundamental_interface.NodeList import NodeList + + +def _make_nodes(n: int) -> Iterator[Node]: + """Accessor to create `n` random nodes immediatly. + + Args: + n: number of nodes to generate. + + Yields: + A randomly generated node. + """ + for _ in range(n): + yield Node(NodeType.TEXT_NODE, '#text') + + +class Test_NodeList(unittest.TestCase): + def testInit(self): + NodeList() + # Initiate with a node + node = next(_make_nodes(1)) + NodeList([node]) + # Initiate with multiple nodes. + NodeList(_make_nodes(4)) + + def testIter(self): + nodes = [*_make_nodes(4)] + node_list = NodeList(nodes) + # Create an iterator for checking + node_iter = iter(nodes) + for list_elem in node_list: + self.assertEqual(list_elem, next(node_iter)) + + def testItem_inSize(self): + nodes = [*_make_nodes(5)] + node_list = NodeList(nodes) + for i in range(5): + self.assertEqual(node_list.item(i), nodes[i]) + + def testItem_greaterOrEqualThanSize(self): + node_list = NodeList(_make_nodes(5)) + for i in range(5, 8): + self.assertIsNone(node_list.item(i)) + + def testItem_notValid(self): + node_list = NodeList(_make_nodes(5)) + for idx in [-1, -9999, 'hi', '1', None, Node, NodeList, b'0']: + self.assertIsNone(node_list.item(idx)) + + def testLength(self): + # Empty NodeList + node_list = NodeList() + self.assertEqual(node_list.length, 0) + # NodeList with a node. + node_list = NodeList(_make_nodes(1)) + self.assertEqual(node_list.length, 1) + # NodeList with some items. + node_list = NodeList(_make_nodes(5)) + self.assertEqual(node_list.length, 5) + + +if __name__ == '__main__': + unittest.main() From 9c924ec34f02adb9fc9783a31d2a2f5a9adb76ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 16:05:59 +0900 Subject: [PATCH 34/47] Fix Circular import issue in `NodeList` (#15) * Create NodeList.py * Implement `NodeList` based on `list` type * Create unittest for `NodeList` * Unimport unused interface `DOMException` * Fix circular import issue by unimporting `Node` and replacing `_AnyNode = Node` with `_AnyNode = Any` --- w3/python/core/fundamental_interface/NodeList.py | 6 ++---- w3/python/core/fundamental_interface/NodeList_test.py | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/w3/python/core/fundamental_interface/NodeList.py b/w3/python/core/fundamental_interface/NodeList.py index 4df6941..6af09ab 100644 --- a/w3/python/core/fundamental_interface/NodeList.py +++ b/w3/python/core/fundamental_interface/NodeList.py @@ -1,9 +1,7 @@ -from typing import Optional +from typing import Any, Optional -from w3.python.core.fundamental_interface.Node import Node - -_AnyNode = Node +_AnyNode = Any class NodeList(list): """Interface NodeList diff --git a/w3/python/core/fundamental_interface/NodeList_test.py b/w3/python/core/fundamental_interface/NodeList_test.py index d19801e..4b63fa2 100644 --- a/w3/python/core/fundamental_interface/NodeList_test.py +++ b/w3/python/core/fundamental_interface/NodeList_test.py @@ -1,7 +1,6 @@ from typing import Iterator import unittest -from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.fundamental_interface.Node import Node from w3.python.core.fundamental_interface.Node import NodeType from w3.python.core.fundamental_interface.NodeList import NodeList From 4a1e3213c34281745eb97680f2f54c8d0436a3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 16:10:41 +0900 Subject: [PATCH 35/47] Create readonly attribute `child_nodes` and its accessor method `_init_child_nodes()` --- w3/python/core/fundamental_interface/Node.py | 21 +++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 8e97f33..bbddd11 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,9 +1,10 @@ from __future__ import annotations import enum -from typing import Optional +from typing import Iterable, Optional from w3.python.core.fundamental_interface.DOMException import DOMException +from w3.python.core.fundamental_interface.NodeList import NodeList from w3.python.core.type import DOMString @@ -65,6 +66,7 @@ def __init__(self, node_name: DOMString, node_value: Optional[DOMString] = None, parent_node: Optional[_AnyNode] = None, + child_nodes: Optional[Iterable[_AnyNode]] = None, read_only: bool = False) -> None: if node_value is None: node_value = '' @@ -73,12 +75,14 @@ def __init__(self, self._set_node_name(node_name) self._set_node_value(node_value) self._set_parent_node(parent_node) + self._init_child_nodes(child_nodes) self._read_only = bool(read_only) # Attributes self._node_type: NodeType self._node_name: DOMString self._node_value: DOMString self._parent_node: _AnyNode + self._child_nodes: NodeList self._read_only: bool def _check_modifiable(self) -> None: @@ -156,5 +160,20 @@ def _set_parent_node(self, else: self._parent_node = parent_node + @property + def child_nodes(self) -> NodeList: + """A `NodeList` that contains all children of this node. If there are no children, this is a `NodeList` containing no nodes. The content of the returned `NodeList` is "live" in the sense that, for instance, changes to the children of the node object that it was created from are immediately reflected in the nodes returned by the `NodeList` accessors; it is not a static snapshot of the content of the node. This is true for every `NodeList`, including the ones returned by the `getElementsByTagName` method. + """ + return self._child_nodes + + def _init_child_nodes(self, + child_nodes: Optional[Iterable[_AnyNode]] = None) -> None: + """Accessor to set the 'child_nodes' property. + """ + if child_nodes is None: + self._child_nodes = NodeList() + else: + self._child_nodes = NodeList(iter(child_nodes)) + _AnyNode = Node From fc6fe0a306246d24f4723d60824217454ba62a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 16:13:13 +0900 Subject: [PATCH 36/47] Bind `Node` and `NodeList` to `w3.python.dom` --- w3/python/core/__init__.py | 3 +++ w3/python/core/fundamental_interface/__init__.py | 5 +++-- w3/python/dom.py | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/w3/python/core/__init__.py b/w3/python/core/__init__.py index acb568b..f3de5c6 100644 --- a/w3/python/core/__init__.py +++ b/w3/python/core/__init__.py @@ -3,3 +3,6 @@ from w3.python.core.fundamental_interface import DOMException from w3.python.core.fundamental_interface import DOMImplementation +from w3.python.core.fundamental_interface import Node +from w3.python.core.fundamental_interface import NodeType +from w3.python.core.fundamental_interface import NodeList diff --git a/w3/python/core/fundamental_interface/__init__.py b/w3/python/core/fundamental_interface/__init__.py index 9d1c31c..fd1e595 100644 --- a/w3/python/core/fundamental_interface/__init__.py +++ b/w3/python/core/fundamental_interface/__init__.py @@ -3,7 +3,8 @@ The interfaces within this section are considered fundamental, and must be fully implemented by all conforming implementations of the DOM, including all HTML DOM implementations. """ -from __future__ import absolute_import - from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.fundamental_interface.DOMImplementation import DOMImplementation +from w3.python.core.fundamental_interface.Node import Node +from w3.python.core.fundamental_interface.Node import NodeType +from w3.python.core.fundamental_interface.NodeList import NodeList diff --git a/w3/python/dom.py b/w3/python/dom.py index 30e48f5..9dd9162 100644 --- a/w3/python/dom.py +++ b/w3/python/dom.py @@ -4,3 +4,6 @@ # Bring in subpackages. from w3.python.core import DOMException from w3.python.core import DOMImplementation +from w3.python.core import Node +from w3.python.core import NodeType +from w3.python.core import NodeList From dd0a41a0bd4c93cc091dd6ff13f4026695797670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 16:18:55 +0900 Subject: [PATCH 37/47] Relocate `dom` and `parser` direct under the `w3` --- w3/__init__.py | 4 ++-- w3/{python => }/dom.py | 0 w3/{python => }/parser.py | 0 w3/python/__init__.py | 3 +-- 4 files changed, 3 insertions(+), 4 deletions(-) rename w3/{python => }/dom.py (100%) rename w3/{python => }/parser.py (100%) diff --git a/w3/__init__.py b/w3/__init__.py index d57af52..ae0a0e5 100644 --- a/w3/__init__.py +++ b/w3/__init__.py @@ -5,8 +5,8 @@ https://github.com/Hepheir/Python-HTML-Parser/ """ -from w3.python import dom -from w3.python import parser +from w3 import dom +from w3 import parser __version__ = '0.0.0' diff --git a/w3/python/dom.py b/w3/dom.py similarity index 100% rename from w3/python/dom.py rename to w3/dom.py diff --git a/w3/python/parser.py b/w3/parser.py similarity index 100% rename from w3/python/parser.py rename to w3/parser.py diff --git a/w3/python/__init__.py b/w3/python/__init__.py index ffc4cd7..89ed0c7 100644 --- a/w3/python/__init__.py +++ b/w3/python/__init__.py @@ -1,2 +1 @@ -from w3.python import dom -from w3.python import parser +from w3.python import core From 77cb7ca33a55bf85a72bd2e976e9610d1e8b3c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Wed, 2 Jun 2021 16:20:28 +0900 Subject: [PATCH 38/47] Update import paths of all unittests --- w3/python/core/fundamental_interface/DOMException_test.py | 2 +- w3/python/core/fundamental_interface/NodeList_test.py | 6 +++--- w3/python/core/fundamental_interface/Node_test.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/w3/python/core/fundamental_interface/DOMException_test.py b/w3/python/core/fundamental_interface/DOMException_test.py index 99ad7c2..46f7f90 100644 --- a/w3/python/core/fundamental_interface/DOMException_test.py +++ b/w3/python/core/fundamental_interface/DOMException_test.py @@ -1,6 +1,6 @@ import unittest -from w3.python.core.fundamental_interface.DOMException import DOMException +from w3.dom import DOMException class Test_DOMException(unittest.TestCase): diff --git a/w3/python/core/fundamental_interface/NodeList_test.py b/w3/python/core/fundamental_interface/NodeList_test.py index 4b63fa2..d73ed22 100644 --- a/w3/python/core/fundamental_interface/NodeList_test.py +++ b/w3/python/core/fundamental_interface/NodeList_test.py @@ -1,9 +1,9 @@ from typing import Iterator import unittest -from w3.python.core.fundamental_interface.Node import Node -from w3.python.core.fundamental_interface.Node import NodeType -from w3.python.core.fundamental_interface.NodeList import NodeList +from w3.dom import Node +from w3.dom import NodeType +from w3.dom import NodeList def _make_nodes(n: int) -> Iterator[Node]: diff --git a/w3/python/core/fundamental_interface/Node_test.py b/w3/python/core/fundamental_interface/Node_test.py index 3ac4926..556039c 100644 --- a/w3/python/core/fundamental_interface/Node_test.py +++ b/w3/python/core/fundamental_interface/Node_test.py @@ -1,8 +1,8 @@ import unittest -from w3.python.core.fundamental_interface.DOMException import DOMException -from w3.python.core.fundamental_interface.Node import Node -from w3.python.core.fundamental_interface.Node import NodeType +from w3.dom import DOMException +from w3.dom import Node +from w3.dom import NodeType class Test_Node(unittest.TestCase): From 65e2872d8832f103f50aa17b2a4e1b74f4a9499d Mon Sep 17 00:00:00 2001 From: Hepheir Date: Wed, 2 Jun 2021 23:09:00 +0900 Subject: [PATCH 39/47] Create readonly attributes `first_child`, `last_child` --- w3/python/core/fundamental_interface/Node.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index bbddd11..68230d5 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -175,5 +175,19 @@ def _init_child_nodes(self, else: self._child_nodes = NodeList(iter(child_nodes)) + def first_child(self) -> Optional[_AnyNode]: + """The first child of this node. If there is no such node, this returns `None`. + """ + if not self.child_nodes: + return None + return self.child_nodes.item(0) + + def last_child(self) -> Optional[_AnyNode]: + """The last child of this node. If there is no such node, this returns `None`. + """ + if not self.child_nodes: + return None + return self.child_nodes.item(self.child_nodes.length-1) + _AnyNode = Node From 3859665df25510ccb1cfbbefd9a4412fd54f25d2 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Thu, 3 Jun 2021 00:56:41 +0900 Subject: [PATCH 40/47] Add unittests to test `NodeList`'s `list`-like behaviors Related issue: Implement of interface NodeList #17 --- .../fundamental_interface/NodeList_test.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/w3/python/core/fundamental_interface/NodeList_test.py b/w3/python/core/fundamental_interface/NodeList_test.py index d73ed22..b66e4c8 100644 --- a/w3/python/core/fundamental_interface/NodeList_test.py +++ b/w3/python/core/fundamental_interface/NodeList_test.py @@ -36,6 +36,27 @@ def testIter(self): for list_elem in node_list: self.assertEqual(list_elem, next(node_iter)) + def testBool(self): + # Empty `NodeList` should equal False. + node_list = NodeList() + self.assertFalse(node_list) + # `NodeList` with items should equal True. + node_list = NodeList(_make_nodes(2)) + self.assertTrue(node_list) + + def testGetItem(self): + nodes = [*_make_nodes(4)] + node_list = NodeList(nodes) + for i in range(4): + self.assertEqual(node_list[i], nodes[i]) + + def testSetItem(self): + node = Node(NodeType.TEXT_NODE, + '#text') + node_list = NodeList(_make_nodes(4)) + node_list[2] = node + self.assertEqual(node_list[2], node) + def testItem_inSize(self): nodes = [*_make_nodes(5)] node_list = NodeList(nodes) From cb87f92c7dfc4d12bd3699a260c601e73bb33c33 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Thu, 3 Jun 2021 01:20:52 +0900 Subject: [PATCH 41/47] Squashed commit of the following: commit 7307b2decc763e0e3040701e9568daa3d16edca8 Author: Hepheir Date: Wed Jun 2 01:19:42 2021 +0900 Remove all except `DOMString` commit e9134ff97813aa5518ff98e3a9f4e2ef15af7ea9 Author: Hepheir Date: Mon May 31 20:48:17 2021 +0900 Change the type of `DOMString` from `TypeVar` into `str` Related issues: - Implement of `DOMString` type #18 --- w3/python/core/type.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/w3/python/core/type.py b/w3/python/core/type.py index 40ad1d9..6a576d5 100644 --- a/w3/python/core/type.py +++ b/w3/python/core/type.py @@ -1,8 +1 @@ -from __future__ import absolute_import - -from typing import TypeVar - - DOMString = str - -AnyNode = TypeVar('AnyNode') From 4d554cd85f4f0f909c32de7c89a2bc9f87ab2d29 Mon Sep 17 00:00:00 2001 From: Hepheir Date: Thu, 3 Jun 2021 01:27:05 +0900 Subject: [PATCH 42/47] Add missing decorater; `property` 65e2872d8832f103f50aa17b2a4e1b74f4a9499d --- w3/python/core/fundamental_interface/Node.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 68230d5..2f4f8bb 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -175,6 +175,7 @@ def _init_child_nodes(self, else: self._child_nodes = NodeList(iter(child_nodes)) + @property def first_child(self) -> Optional[_AnyNode]: """The first child of this node. If there is no such node, this returns `None`. """ @@ -182,6 +183,7 @@ def first_child(self) -> Optional[_AnyNode]: return None return self.child_nodes.item(0) + @property def last_child(self) -> Optional[_AnyNode]: """The last child of this node. If there is no such node, this returns `None`. """ From e7e7f94a149f1c79f9e1167552445674876db6db Mon Sep 17 00:00:00 2001 From: Hepheir Date: Thu, 3 Jun 2021 01:51:40 +0900 Subject: [PATCH 43/47] Create readonly attributes `previous_sibling`, `next_sibling` also create accessor method `_nth_child_of_parent()` #16 --- w3/python/core/fundamental_interface/Node.py | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 2f4f8bb..3fc3a0b 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -191,5 +191,34 @@ def last_child(self) -> Optional[_AnyNode]: return None return self.child_nodes.item(self.child_nodes.length-1) + @property + def previous_sibling(self) -> Optional[_AnyNode]: + """The node immediately preceding this node. If there is no such node, this returns `None`. + """ + if self.parent_node is None: + return None + if self.parent_node.first_child is self: + return None + nth_child = self._nth_child_of_parent() + return self.parent_node.child_nodes.item(nth_child-1) + + @property + def next_sibling(self) -> Optional[_AnyNode]: + """The node immediately following this node. If there is no such node, this returns `None`. + """ + if self.parent_node is None: + return None + if self.parent_node.last_child is self: + return None + nth_child = self._nth_child_of_parent() + return self.parent_node.child_nodes.item(nth_child+1) + + def _nth_child_of_parent(self) -> Optional[int]: + """Accessor that indicates how many siblings are there preceding this node. if there is no such parent node, this returns `None`. + """ + if self.parent_node is None: + return None + return self.parent_node.child_nodes.index(self) + _AnyNode = Node From 6edfd99bfd01763470d9bc4c8a0c743fa4f897c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Thu, 3 Jun 2021 10:43:32 +0900 Subject: [PATCH 44/47] Create readonly attribute `attributes` #16 TODO: Implement interface `NamedNodeMap` #19 --- w3/python/core/fundamental_interface/Node.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 3fc3a0b..0dae4b6 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -1,7 +1,7 @@ from __future__ import annotations import enum -from typing import Iterable, Optional +from typing import Dict, Iterable, Optional from w3.python.core.fundamental_interface.DOMException import DOMException from w3.python.core.fundamental_interface.NodeList import NodeList @@ -67,6 +67,7 @@ def __init__(self, node_value: Optional[DOMString] = None, parent_node: Optional[_AnyNode] = None, child_nodes: Optional[Iterable[_AnyNode]] = None, + attributes: Optional[Iterable[_AnyNode]] = None, read_only: bool = False) -> None: if node_value is None: node_value = '' @@ -76,6 +77,7 @@ def __init__(self, self._set_node_value(node_value) self._set_parent_node(parent_node) self._init_child_nodes(child_nodes) + self._init_attributes(attributes) self._read_only = bool(read_only) # Attributes self._node_type: NodeType @@ -83,6 +85,7 @@ def __init__(self, self._node_value: DOMString self._parent_node: _AnyNode self._child_nodes: NodeList + self._attributes: _NamedNodeMap self._read_only: bool def _check_modifiable(self) -> None: @@ -220,5 +223,20 @@ def _nth_child_of_parent(self) -> Optional[int]: return None return self.parent_node.child_nodes.index(self) + @property + def attributes(self) -> _NamedNodeMap: + """A `NamedNodeMap` containing the attributes of this node (if it is an `Element`) or `None` otherwise. + """ + return self._attributes + + def _init_attributes(self, + attributes: Optional[Iterable[_AnyNode]] = None) -> None: + self._attributes: _NamedNodeMap = {} # TODO: Replace with real NamedNodeMap #19 + if attributes is None: + return + for attr in iter(attributes): + self._attributes.set_named_item(attr) + _AnyNode = Node +_NamedNodeMap = Dict[str, _AnyNode] # TODO: Implement NamedNodeMap #19 From 9c18ce3c6448cd2d05820437f72e75eee76117b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Thu, 3 Jun 2021 10:56:05 +0900 Subject: [PATCH 45/47] Create readonly attribute `owner_document` (#16) with its accessor `_set_owner_document()` and declared `_Document` for typing temporarily (TODO, #20) --- w3/python/core/fundamental_interface/Node.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 0dae4b6..373d0f5 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -68,6 +68,7 @@ def __init__(self, parent_node: Optional[_AnyNode] = None, child_nodes: Optional[Iterable[_AnyNode]] = None, attributes: Optional[Iterable[_AnyNode]] = None, + owner_document: Optional[_Document] = None, read_only: bool = False) -> None: if node_value is None: node_value = '' @@ -78,6 +79,7 @@ def __init__(self, self._set_parent_node(parent_node) self._init_child_nodes(child_nodes) self._init_attributes(attributes) + self._set_owner_document(owner_document) self._read_only = bool(read_only) # Attributes self._node_type: NodeType @@ -86,6 +88,7 @@ def __init__(self, self._parent_node: _AnyNode self._child_nodes: NodeList self._attributes: _NamedNodeMap + self._owner_document: _Document self._read_only: bool def _check_modifiable(self) -> None: @@ -237,6 +240,21 @@ def _init_attributes(self, for attr in iter(attributes): self._attributes.set_named_item(attr) + @property + def owner_document(self) -> Optional[_Document]: + """The `Document` object associated with this node. This is also the `Document` object used to create new nodes. When this node is a `Document` this is `None`. + """ + if self.node_type == NodeType.DOCUMENT_NODE: + return None + return self._owner_document + + def _set_owner_document(self, + owner_document: Optional[_Document] = None) -> None: + """Indirect accessor to set the 'owner_document' property. + """ + self._owner_document = owner_document + _AnyNode = Node _NamedNodeMap = Dict[str, _AnyNode] # TODO: Implement NamedNodeMap #19 +_Document = Node # TODO: Implement Document #20 From 32c2801845f36cffd7c35db713fa427d9f596a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Thu, 3 Jun 2021 10:56:46 +0900 Subject: [PATCH 46/47] Apply autopep8 & minor comment changes --- w3/python/core/fundamental_interface/Node.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 373d0f5..149202b 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -234,7 +234,7 @@ def attributes(self) -> _NamedNodeMap: def _init_attributes(self, attributes: Optional[Iterable[_AnyNode]] = None) -> None: - self._attributes: _NamedNodeMap = {} # TODO: Replace with real NamedNodeMap #19 + self._attributes: _NamedNodeMap = {} # TODO: Replace with real NamedNodeMap #19 if attributes is None: return for attr in iter(attributes): @@ -256,5 +256,5 @@ def _set_owner_document(self, _AnyNode = Node -_NamedNodeMap = Dict[str, _AnyNode] # TODO: Implement NamedNodeMap #19 -_Document = Node # TODO: Implement Document #20 +_NamedNodeMap = Dict[str, _AnyNode] # TODO: Implement NamedNodeMap (#19) +_Document = Node # TODO: Implement Document (#20) From b590a07b6b0d1cec5daf6f2a381c67e773bce30c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=EC=A3=BC?= Date: Thu, 3 Jun 2021 11:35:27 +0900 Subject: [PATCH 47/47] Fix doc-strings. --- w3/__init__.py | 1 - w3/dom.py | 4 +- w3/parser.py | 3 +- w3/python/__init__.py | 5 ++ w3/python/core/__init__.py | 3 +- .../DOMImplementation.py | 1 - w3/python/core/fundamental_interface/Node.py | 60 +++++++++++-------- .../core/fundamental_interface/NodeList.py | 8 ++- 8 files changed, 51 insertions(+), 34 deletions(-) diff --git a/w3/__init__.py b/w3/__init__.py index ae0a0e5..f5b457c 100644 --- a/w3/__init__.py +++ b/w3/__init__.py @@ -1,5 +1,4 @@ """A Python HTML Parser - This is a personal project owned by Hepheir. https://github.com/Hepheir/Python-HTML-Parser/ diff --git a/w3/dom.py b/w3/dom.py index 9dd9162..34da2ff 100644 --- a/w3/dom.py +++ b/w3/dom.py @@ -1,5 +1,5 @@ -"""API Module of DOM - Level 1 -""" +"""API Module of DOM - Level 1""" + # Bring in subpackages. from w3.python.core import DOMException diff --git a/w3/parser.py b/w3/parser.py index 4a1b2d3..43b70bf 100644 --- a/w3/parser.py +++ b/w3/parser.py @@ -1,2 +1 @@ -"""A Parser module for building Document Object Model Structure parsed from text/html. -""" +"""A Parser module for building Document Object Model Structure parsed from text/html.""" diff --git a/w3/python/__init__.py b/w3/python/__init__.py index 89ed0c7..b687bb7 100644 --- a/w3/python/__init__.py +++ b/w3/python/__init__.py @@ -1 +1,6 @@ +"""Imports core names of w3. + +Interfaces are implemented under "./core/" +""" + from w3.python import core diff --git a/w3/python/core/__init__.py b/w3/python/core/__init__.py index f3de5c6..07f7bd1 100644 --- a/w3/python/core/__init__.py +++ b/w3/python/core/__init__.py @@ -1,5 +1,4 @@ -"""Module that contains classes of interfaces and ect. -""" +"""Module that contains classes of interfaces and ect.""" from w3.python.core.fundamental_interface import DOMException from w3.python.core.fundamental_interface import DOMImplementation diff --git a/w3/python/core/fundamental_interface/DOMImplementation.py b/w3/python/core/fundamental_interface/DOMImplementation.py index 906763c..b3778d1 100644 --- a/w3/python/core/fundamental_interface/DOMImplementation.py +++ b/w3/python/core/fundamental_interface/DOMImplementation.py @@ -7,7 +7,6 @@ class DOMImplementation: """Interface DOMImplementation The `DOMImplementation` interface provides a number of methods for performing operations that are independent of any particular instance of the document object model. - The DOM Level 1 does not specify a way of creating a document instance, and hence document creation is an operation specific to an implementation. Future Levels of the DOM specification are expected to provide methods for creating documents directly. """ diff --git a/w3/python/core/fundamental_interface/Node.py b/w3/python/core/fundamental_interface/Node.py index 149202b..ae27bb3 100644 --- a/w3/python/core/fundamental_interface/Node.py +++ b/w3/python/core/fundamental_interface/Node.py @@ -103,13 +103,11 @@ def _check_modifiable(self) -> None: @property def node_name(self) -> DOMString: - """Read only; The name of this node, depending on its type. - """ + """Read only; The name of this node, depending on its type.""" return self._node_name def _set_node_name(self, name: DOMString) -> None: - """Indirect accessor to set the 'node_name' property. - """ + """Indirect accessor to set the 'node_name' property.""" self._node_name = DOMString(name) @property @@ -139,13 +137,11 @@ def _set_node_value(self, value: DOMString) -> None: @property def node_type(self) -> NodeType: - """Read only; A code representing the type of the underlying object, as defined in `NodeType`. - """ + """Read only; A code representing the type of the underlying object, as defined in `NodeType`.""" return self._node_type def _set_node_type(self, node_type: NodeType) -> None: - """Indirect accessor to set the 'node_type' property. - """ + """Indirect accessor to set the 'node_type' property.""" if node_type not in NodeType: raise ValueError(f'{node_type} is not a valid code ' 'for a node type.') @@ -153,14 +149,16 @@ def _set_node_type(self, node_type: NodeType) -> None: @property def parent_node(self) -> Optional[_AnyNode]: - """The parent of this node. All nodes, except `Document`, `DocumentFragment`, and `Attr` may have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is `None`. + """The parent of this node. + + All nodes, except `Document`, `DocumentFragment`, and `Attr` may have a parent. + However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is `None`. """ return self._parent_node def _set_parent_node(self, parent_node: Optional[_AnyNode]) -> None: - """Indirect accessor to set the 'node_type' property. - """ + """Indirect accessor to set the 'node_type' property.""" if not parent_node: self._parent_node = None else: @@ -168,14 +166,17 @@ def _set_parent_node(self, @property def child_nodes(self) -> NodeList: - """A `NodeList` that contains all children of this node. If there are no children, this is a `NodeList` containing no nodes. The content of the returned `NodeList` is "live" in the sense that, for instance, changes to the children of the node object that it was created from are immediately reflected in the nodes returned by the `NodeList` accessors; it is not a static snapshot of the content of the node. This is true for every `NodeList`, including the ones returned by the `getElementsByTagName` method. + """A `NodeList` that contains all children of this node. + + If there are no children, this is a `NodeList` containing no nodes. + The content of the returned `NodeList` is "live" in the sense that, for instance, changes to the children of the node object that it was created from are immediately reflected in the nodes returned by the `NodeList` accessors; it is not a static snapshot of the content of the node. + This is true for every `NodeList`, including the ones returned by the `getElementsByTagName` method. """ return self._child_nodes def _init_child_nodes(self, child_nodes: Optional[Iterable[_AnyNode]] = None) -> None: - """Accessor to set the 'child_nodes' property. - """ + """Accessor to set the 'child_nodes' property.""" if child_nodes is None: self._child_nodes = NodeList() else: @@ -183,7 +184,9 @@ def _init_child_nodes(self, @property def first_child(self) -> Optional[_AnyNode]: - """The first child of this node. If there is no such node, this returns `None`. + """The first child of this node. + + If there is no such node, this returns `None`. """ if not self.child_nodes: return None @@ -191,7 +194,9 @@ def first_child(self) -> Optional[_AnyNode]: @property def last_child(self) -> Optional[_AnyNode]: - """The last child of this node. If there is no such node, this returns `None`. + """The last child of this node. + + If there is no such node, this returns `None`. """ if not self.child_nodes: return None @@ -199,7 +204,9 @@ def last_child(self) -> Optional[_AnyNode]: @property def previous_sibling(self) -> Optional[_AnyNode]: - """The node immediately preceding this node. If there is no such node, this returns `None`. + """The node immediately preceding this node. + + If there is no such node, this returns `None`. """ if self.parent_node is None: return None @@ -210,7 +217,9 @@ def previous_sibling(self) -> Optional[_AnyNode]: @property def next_sibling(self) -> Optional[_AnyNode]: - """The node immediately following this node. If there is no such node, this returns `None`. + """The node immediately following this node. + + If there is no such node, this returns `None`. """ if self.parent_node is None: return None @@ -220,7 +229,9 @@ def next_sibling(self) -> Optional[_AnyNode]: return self.parent_node.child_nodes.item(nth_child+1) def _nth_child_of_parent(self) -> Optional[int]: - """Accessor that indicates how many siblings are there preceding this node. if there is no such parent node, this returns `None`. + """Accessor that indicates how many siblings are there preceding this node. + + If there is no such parent node, this returns `None`. """ if self.parent_node is None: return None @@ -228,8 +239,7 @@ def _nth_child_of_parent(self) -> Optional[int]: @property def attributes(self) -> _NamedNodeMap: - """A `NamedNodeMap` containing the attributes of this node (if it is an `Element`) or `None` otherwise. - """ + """A `NamedNodeMap` containing the attributes of this node (if it is an `Element`) or `None` otherwise.""" return self._attributes def _init_attributes(self, @@ -242,7 +252,10 @@ def _init_attributes(self, @property def owner_document(self) -> Optional[_Document]: - """The `Document` object associated with this node. This is also the `Document` object used to create new nodes. When this node is a `Document` this is `None`. + """The `Document` object associated with this node. + + This is also the `Document` object used to create new nodes. + When this node is a `Document` this is `None`. """ if self.node_type == NodeType.DOCUMENT_NODE: return None @@ -250,8 +263,7 @@ def owner_document(self) -> Optional[_Document]: def _set_owner_document(self, owner_document: Optional[_Document] = None) -> None: - """Indirect accessor to set the 'owner_document' property. - """ + """Indirect accessor to set the 'owner_document' property.""" self._owner_document = owner_document diff --git a/w3/python/core/fundamental_interface/NodeList.py b/w3/python/core/fundamental_interface/NodeList.py index 6af09ab..df63691 100644 --- a/w3/python/core/fundamental_interface/NodeList.py +++ b/w3/python/core/fundamental_interface/NodeList.py @@ -12,13 +12,17 @@ class NodeList(list): @property def length(self) -> int: - """The number of nodes in the list. The range of valid child node indices is 0 to `length`-1 inclusive. + """The number of nodes in the list. + + The range of valid child node indices is 0 to `length`-1 inclusive. """ return len(self) def item(self, index: int) -> Optional[_AnyNode]: - """Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null. + """Returns the indexth item in the collection. + + If index is greater than or equal to the number of nodes in the list, this returns null. Args: index: Index into the collection.