11import os
2- from datetime import datetime
2+ from abc import ABC
3+ from collections import deque
4+ from typing import Any , AnyStr , Dict , List , Mapping , Optional , Union
35
46from xmlsec .crypto import CertDict
57
68from .constants import NS
79from .logs import get_log
10+ from .resource import Resource , ResourceOpts
811from .utils import find_matching_files , parse_xml , root , unicode_stream , utc_now
912
1013__author__ = 'leifj'
@@ -22,10 +25,22 @@ def raise_wraped(self):
2225 raise self ._wraped
2326
2427
25- class PyffParser (object ):
28+ class PyffParser (ABC ):
2629 def to_json (self ):
2730 return str (self )
2831
32+ def magic (self , content : str ):
33+ """Return True if this parser is applicable to this content"""
34+ raise NotImplementedError ()
35+
36+ def parse (self , resource : Resource , content : str ) -> Mapping [str , Any ]:
37+ """Initialise/update a resource based on this content, returning information about it
38+ TODO: Determine what 'parse' actually means
39+
40+ TODO: Return something more structured than an arbitrary mapping
41+ """
42+ raise NotImplementedError ()
43+
2944
3045class NoParser (PyffParser ):
3146 def __init__ (self ):
@@ -34,10 +49,10 @@ def __init__(self):
3449 def __str__ (self ):
3550 return "Not a supported type"
3651
37- def magic (self , content ) :
52+ def magic (self , content : str ) -> bool :
3853 return True
3954
40- def parse (self , resource , content ) :
55+ def parse (self , resource : Resource , content : str ) -> Mapping [ str , Any ] :
4156 raise ParserException ("No matching parser found for %s" % resource .url )
4257
4358
@@ -48,17 +63,18 @@ def __init__(self, extensions):
4863 def __str__ (self ):
4964 return "Directory"
5065
51- def magic (self , content ) :
66+ def magic (self , content : str ) -> bool :
5267 return os .path .isdir (content )
5368
54- def parse (self , resource , content ) :
55- resource .children = []
69+ def parse (self , resource : Resource , content : str ) -> Mapping [ str , Any ] :
70+ resource .children = deque ()
5671 info = dict ()
5772 info ['Description' ] = 'Directory'
5873 info ['Expiration Time' ] = 'never expires'
5974 n = 0
6075 for fn in find_matching_files (content , self .extensions ):
61- resource .add_child ("file://" + fn )
76+ child_opts = resource .opts .copy (update = {'alias' : None })
77+ resource .add_child ("file://" + fn , child_opts )
6278 n += 1
6379
6480 if n == 0 :
@@ -78,10 +94,10 @@ def __init__(self):
7894 def __str__ (self ):
7995 return "XRD"
8096
81- def magic (self , content ) :
97+ def magic (self , content : str ) -> bool :
8298 return 'XRD' in content
8399
84- def parse (self , resource , content ) :
100+ def parse (self , resource : Resource , content : str ) -> Mapping [ str , Any ] :
85101 info = dict ()
86102 info ['Description' ] = "XRD links"
87103 info ['Expiration Time' ] = 'never expires'
@@ -97,22 +113,24 @@ def parse(self, resource, content):
97113 if len (fingerprints ) > 0 :
98114 fp = fingerprints [0 ]
99115 log .debug ("XRD: {} verified by {}" .format (link_href , fp ))
100- resource .add_child (link_href , verify = fp )
116+ child_opts = resource .opts .copy (update = {'alias' : None })
117+ resource .add_child (link_href , child_opts )
101118 resource .last_seen = utc_now ().replace (microsecond = 0 )
102119 resource .expire_time = None
103120 resource .never_expires = True
104121 return info
105122
106123
107- _parsers = [XRDParser (), DirectoryParser (['xml' ]), NoParser ()]
124+ _parsers : List [ PyffParser ] = [XRDParser (), DirectoryParser (['xml' ]), NoParser ()]
108125
109126
110127def add_parser (parser ):
111128 _parsers .insert (0 , parser )
112129
113130
114- def parse_resource (resource , content ) :
131+ def parse_resource (resource : Resource , content : str ) -> Optional [ Mapping [ str , Any ]] :
115132 for parser in _parsers :
116133 if parser .magic (content ):
117134 resource .last_parser = parser
118135 return parser .parse (resource , content )
136+ return None
0 commit comments