Skip to content

Commit

Permalink
Merge pull request #100 from galaxyproject/fix_#98
Browse files Browse the repository at this point in the history
Improve document root detection method
  • Loading branch information
davelopez authored Jan 23, 2021
2 parents 6c1996e + 32ad709 commit f4489e5
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 16 deletions.
4 changes: 3 additions & 1 deletion server/galaxyls/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
)
from pygls.workspace import Document

from galaxyls.services.validation import DocumentValidator

from .config import CompletionMode, GalaxyToolsConfiguration
from .features import AUTO_CLOSE_TAGS, CMD_GENERATE_COMMAND, CMD_GENERATE_TEST
from .services.language import GalaxyToolLanguageService
Expand Down Expand Up @@ -182,4 +184,4 @@ def _get_xml_document(document: Document) -> XmlDocument:

def _is_document_supported(document: Document) -> bool:
"""Returns True if the given document is supported by the server."""
return XmlDocument.has_valid_root(document)
return DocumentValidator().has_valid_root(document)
33 changes: 33 additions & 0 deletions server/galaxyls/services/validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import re

from typing import Optional
from pygls.workspace import Document

from galaxyls.services.xml.types import DocumentType

MAX_PEEK_CONTENT = 100
TAG_GROUP_NAME = "tag"
TAG_REGEX = rf"[\n\s]*?.*?[\n\s]*?<(?!\?)(?P<{TAG_GROUP_NAME}>[\w]*)"


class DocumentValidator:
"""Provides some utilities to quickly check documents without completely parse them beforehand."""

def has_valid_root(self, document: Document) -> bool:
"""Checks if the document's root element matches one of the supported types."""
root = self._get_document_root_tag(document)
if root is not None:
root_tag = root.upper()
supported = [e.name for e in DocumentType if e != DocumentType.UNKNOWN]
return root_tag in supported
return False

def _get_document_root_tag(self, document: Document) -> Optional[str]:
"""Checks the first MAX_PEEK_CONTENT characters of the document for a root tag and
returns the name of the tag if found."""
content_peek = document.source[:MAX_PEEK_CONTENT]
match = re.match(TAG_REGEX, content_peek)
if match:
group = match.group(TAG_GROUP_NAME)
return group
return None
15 changes: 0 additions & 15 deletions server/galaxyls/services/xml/document.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Dict, Optional

from anytree.search import findall
from lxml import etree
from pygls.types import Position, Range
from pygls.workspace import Document

Expand Down Expand Up @@ -118,17 +117,3 @@ def get_position_after(self, element: XmlElement) -> Position:
if element.is_self_closed:
return convert_document_offset_to_position(self.document, element.end)
return convert_document_offset_to_position(self.document, element.end_offset)

@staticmethod
def has_valid_root(document: Document) -> bool:
"""Checks if the document's root element matches one of the supported types."""
try:
xml = etree.parse(str(document.path))
root = xml.getroot()
if root is not None and root.tag:
root_tag = root.tag.upper()
supported = [e.name for e in DocumentType if e != DocumentType.UNKNOWN]
return root_tag in supported
return False
except BaseException:
return False
33 changes: 33 additions & 0 deletions server/galaxyls/tests/unit/test_validation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest
from lxml import etree

from galaxyls.services.validation import DocumentValidator

from ...services.xsd.constants import TOOL_XSD_FILE
from ...services.xsd.validation import GalaxyToolValidationService
from .sample_data import (
Expand Down Expand Up @@ -62,3 +64,34 @@ def test_validate_macro_file_returns_diagnostics_when_syntax_error(self, xsd_sch
actual = service.validate_document(xml_document)

assert len(actual) == 1


class TestDocumentValidatorClass:
@pytest.mark.parametrize(
"source, expected",
[
("<tool>", True),
(" <tool>", True),
("\n<tool>", True),
("\n <tool>", True),
(" \n <tool>", True),
("unexpected <tool>", True),
(" unexpected <tool>", True),
("\nunexpected\n <tool>", True),
('<?xml version="1.0" encoding="UTF-8"?><tool>', True),
('<?xml version="1.0" encoding="UTF-8"?>\n<tool>', True),
("<macros>", True),
('<?xml version="1.0" encoding="UTF-8"?>\n<macros>', True),
("", False),
(" ", False),
("test", False),
("<test>", False),
],
)
def test_has_valid_root_returns_expected(self, source: str, expected: bool) -> None:
document = TestUtils.to_document(source)
validator = DocumentValidator()

actual = validator.has_valid_root(document)

assert actual == expected

0 comments on commit f4489e5

Please sign in to comment.