MXc @sddkZddkZddkZddklZlZddklZddkl Z ddk l Z ddk l Z lZeieZeZeZdZe ideZd Zd Zd Zd Zed ZdZdZedZe dZ!dZ"dZ#dZ$dZ%dZ&dZ'edZ(dZ)dZ*dZ+dZ,dddZ.dZ/d Z0d!Z1d"Z2d#Z3d$Z4dS(%iN(tRequestturlopen(tloads(t http_post(tetree(t binary_typet text_typettresolve_entitiescCstidtiS(s#Get the date, right now, in ISO8601s%Y-%m-%dT%H:%M:%SZ(ttimetstrftimet localtime(((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytget_today_and_now4scCs|djodSt|tio|idS|idjo.|idjo|idjo|idS|idSdS(s"Return a datetime value as ISO8601s%Y-%m-%dis%Y-%m-%dT%H:%M:%SZN(tNonet isinstancetdatetimetdateR thourtminutetsecond(tvalue((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytdatetime2iso86019s 0cCs&ttiti|dtiS(s!Convert ISO8601 to UNIX timestamps%Y-%m-%dT%H:%M:%SZ(tintR tmktimetstrptimettimezone(tisotime((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytget_time_iso2unixFscCs|d j o|id}t|djodSy6t|ddt|ddt|dSWqtj o}td t|qXndSd S( s-Get an integer of the OGC version value x.y.zt.iiii'iidis%sN(R tsplittlenRt Exceptiont RuntimeErrortstr(tversiontxyzterr((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytget_version_integerLs 6cCs,|dj o|o|S|iSndSdS(s>Test that the XML value exists, return value, else return NoneN(R ttext(tvaltattrib((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt find_exmlZs   cCs]g}xG|idD]6}|id\}}|id|||fqWdi|S(sReturn an etree friendly xpatht/t:s{%s}%s(Rtappendtjoin(txpathtnsmaptouttchunkst namespacetelement((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt nspath_evales cCs$y|iddSWn|SXdS(s1Return XML element bare tag name (without prefix)t}iN(R(ttag((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt xmltag_splitnscCsy|iddidd}g}|iD]$\}}||jo ||q4q4~}|d}|o d|dS|dSWndSXdS(s&Return XML namespace prefix of elementR5it{is%s:RN(Rtitems(R6t namespacestcolontnsurit_[1]tkeyRtnsprefix((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt xmltag_split2vs !   cCsYd}|iddjo|idd}nt|}|o |iiS|SdS(s0return Shapely geometry object based on WKT/EWKTtSRIDit;N(R tfindRRtenvelopetbounds(twktREtgeometry((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytwkt2geoms  c Csu|id}t|d}t|d}t|d}t|d}d||||||||||f S(s.Return OGC WKT Polygon of a simple bbox stringt,iiiis@POLYGON((%.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f))(Rtfloat(tbboxttmptminxtminytmaxxtmaxy((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytbbox2wktpolygonscCsG|djp |djodS|djo|djodS|iddjot|idd}n t|}t|}|djo|i|}n|djo|i|t|j}n_|djo|i|}n?|d jo|i|}n|d jo|i |}n|djo|i|t|j}n|d jo|i |}n|d jo|i|}n|d jo5|i|o|i | o t }q3t }nQ|djo|i |}n1|djo|i|}ntd||odSdSdS(sperform spatial querytfalsetbeyondtdwithinRAiRBRKtcontainstcrossestdisjointtequalst intersectstoverlapsttouchestwithins#Invalid spatial query predicate: %sttrueN(RSRT(R RCRRRYtdistanceRJRURVRWRXR[tTruetFalseR\R (t bbox_data_wkttbbox_input_wktt predicateR^tbbox1tbbox2tresult((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt query_spatialsH           !    cCs8y)|dj ott|iSdSWndSXdS(sDerive area of a given geometryt0N(R R!Rtarea(RG((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytget_geometry_areas  c Csqddkl}d}d}|d j oD|d j o7y t|}t|}|i}|i}td||gDotiddS|i|i} |djoF|djo9ti dt | || |t | || |Sti dt | ||| ||t | ||| ||SWqmt j o} tid| dSXndS( s{Derive spatial overlay rank for geospatial search as per Lanfear (2006) http://pubs.usgs.gov/of/2006/1279/2006-1279.pdfi(t BaseGeometryg?cssx|]}|djVqWdS(gN((t.0titem((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pys s sGeometry has no areaRhsSpatial Rank: %ss(Cannot derive spatial overlay ranking %sN( tshapely.geometry.baseRkR RRitanytLOGGERtwarnt intersectiontdebugR!R( ttarget_geometrytquery_geometryRktkttkqtq_geomtt_geomtQtTtXR$((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytget_spatial_overlay_ranks,     "*" c Csddkl}g}x!|D]}|it|qWyC||i}d|d|d|d|df}t|SWn+tj o}tdt|nXd S( s)Derive an aggregated bbox from n polygonsi(t MultiPolygons%.2f,%.2f,%.2f,%.2fiiiisCannot aggregate polygons: %sN( tshapely.geometryR~R,RRERQRR R!(tbboxsR~tpolystbbxtbstrR$((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytbbox_from_polygonss&cCst|tpt|toti|t}nt|}t|}yn|i|ddd|}t|djo:x7|D]+}|i |djo|d|_ qqWnWn0t j o$}|GHt dt |nXti |S(s Update XML document XPath valuestrpR.R:iRs ERROR: %s(RRRRt fromstringtPARSERtevalR.RR&RR R!ttostring(R/txmltrecproptnodestnode1R$((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt update_xpath s   cs|ox|iD]w|ijo^tfd|iD}||}h|<|d|d<|d|d%s R.tdbcolN(tkeystvaluestnextR9(t queryablesttypenametreverseRLR'((RsC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyttransform_mappings s "   cCst|to:dig}|D]}|o ||q!q!~iSt|tpt|toti|t}ndig}|i dD]}||iq~SdS(sp generate bag of text for free text searches accepts list of words, string of XML, or etree.Element t s//text()N( RtlistR-tstripRRRRRR.(tbagR=t_ft_[2]R((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt get_anytext0s : cCsAddk}td|iD}|i|dtd|S(s&Convert an lxml object to a dictionaryiNcss%x|]\}}||fVqWdS(N((RlRR((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pys Es tprocess_namespacesR:(t xmltodicttdictR9tparseR_(t xml_stringR:Rtnamespaces_reverse((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytxml2dict@s cCsyt||}t|doFtid|iddjotidt|S|St|tipt|tiotidt |S|SWndSXdS(sget value of an object, safelyt__call__sattribute is a functiontlinkisattribute is a linksattribute is a dateN( tgetattrthasattrRpRsRCt_linkifyRRRRR (tobjtnameR((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytgetqattrKs    cCs@g}x*|D]"}|idit|q Wdi|S(screate link formatRIt^(R,R-R(RR0R((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyR^s  icCsW|djot||d|St|}|iddt|d|iSdS(sPerform HTTP requesttPOSTttimeouts User-Agentspycsw (http://pycsw.org/)N(RRt add_headerRtread(tmethodturltrequestR((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt http_requestfs   cCs|iddjo d}n|iddjo-|idddjo d}qcd}n|iddjoJ|idddjo d}q|idddjo d}qnd||fS(s'binds an HTTP GET query string endpointt?it=t&Rs%s%s(RC(Rtbinder((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytbind_urlos    c Cstdig}|idD]}|dt|q~d}|id\}}tdig}|idD]}|dt|qx~d}ddt|>d@} || @|| @jS(s(decipher whether IP is within CIDR rangeRRs%02xiR*Ii (RR-R( tiptnetR=txtipaddrtnetstrtbitsRtnetaddrtmask((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytip_in_network_cidrs FFcCs||jotSxy|D]q}|iddjot||otSq|iddjo&|i|iddotSqqWtS(s decipher whether IP is in IP whitelist IP whitelist is a list supporting: - single IP address (e.g. 192.168.0.1) - IP range using CIDR (e.g. 192.168.0/22) - IP range using subnet wildcard (e.g. 192.168.0.*, 192.168.*) R*it*i(R_RCRt startswithRR`(t ipaddresst whitelisttwhite((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytipaddress_in_whitelists   cCsEd}|}|iddjo|id\}}n||gS(s6Checks whether repository.table is a schema namespacedRiN(R RCR(ttabletschema((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt sniff_tables cCst}dt|djo djnodt|djo djnoZdt|djo djno2dt|djo djno t}n|S( s" Helper function to validate 4326 gfigf@gVigV@ii(R`RJR_(t bbox_listtis_valid((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt validate_4326s(((( cCst||dS(s: Helper function to calculate elapsed time in millisecondsi(R(tbegintend((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pytget_elapsed_times(5R Rtloggingtsix.moves.urllib.requestRRt shapely.wktRt owslib.utilRtpycsw.core.etreeRtsixRRt getLoggert__name__RpR`tranking_enabledt ranking_passtranking_query_geometryt XMLParserRR RRR%R)R4R7R@R_RHRQRgRjR}RRRRRRRR RRRRRRR(((sC/local/public/lgc/web/api.rvdata.us/htdocs/pycsw/pycsw/core/util.pyt!sN          3