f20080305d
Определение специфических рекомендаций (матрица профилей §8):
1. Ж/д слой (закрыт мёртвый railway ×2.5 у РАС):
- /api/v1/water/{case_id} отдаёт railway=rail как LineString
(без service/industrial/military веток), кэш общий v2;
- railway_warning «перекрыть/проверить немедленно» по профилям;
- SearchMap: Polyline слой ж/д (тёмно-красный), счётчики 💧/🚂.
2. cant_swim → профиль не_умеет_плавать (water ×3.0, без изменения
радиуса, critical_warning «обследовать водоёмы НЕМЕДЛЕННО»):
- раньше чекбокс влиял только на текст, в скоринге был пробел;
- derive в analyze._derive_profiles — работает и для closed_cases.
3. unmodeled_profiles: ДЦП/слабое зрение/слух — честная пометка
«вне поведенческой модели» с пояснением (vector_tasks B12:
профили без аналога не выдавать за учтённые); блок на фронте
в карточке здоровья.
Площадь воды: сферический эксцесс, проверен на квадрате 53° (744017 м²
vs 743272 точного). Тесты: 202 passed (новый test_cant_swim_profile).
235 lines
6.2 KiB
Python
235 lines
6.2 KiB
Python
#
|
|
# This file is part of pyasn1 software.
|
|
#
|
|
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
|
|
# License: https://pyasn1.readthedocs.io/en/latest/license.html
|
|
#
|
|
import io
|
|
import os
|
|
|
|
from pyasn1 import error
|
|
from pyasn1.type import univ
|
|
|
|
class CachingStreamWrapper(io.IOBase):
|
|
"""Wrapper around non-seekable streams.
|
|
|
|
Note that the implementation is tied to the decoder,
|
|
not checking for dangerous arguments for the sake
|
|
of performance.
|
|
|
|
The read bytes are kept in an internal cache until
|
|
setting _markedPosition which may reset the cache.
|
|
"""
|
|
def __init__(self, raw):
|
|
self._raw = raw
|
|
self._cache = io.BytesIO()
|
|
self._markedPosition = 0
|
|
|
|
def peek(self, n):
|
|
result = self.read(n)
|
|
self._cache.seek(-len(result), os.SEEK_CUR)
|
|
return result
|
|
|
|
def seekable(self):
|
|
return True
|
|
|
|
def seek(self, n=-1, whence=os.SEEK_SET):
|
|
# Note that this not safe for seeking forward.
|
|
return self._cache.seek(n, whence)
|
|
|
|
def read(self, n=-1):
|
|
read_from_cache = self._cache.read(n)
|
|
if n != -1:
|
|
n -= len(read_from_cache)
|
|
if not n: # 0 bytes left to read
|
|
return read_from_cache
|
|
|
|
read_from_raw = self._raw.read(n)
|
|
|
|
self._cache.write(read_from_raw)
|
|
|
|
return read_from_cache + read_from_raw
|
|
|
|
@property
|
|
def markedPosition(self):
|
|
"""Position where the currently processed element starts.
|
|
|
|
This is used for back-tracking in SingleItemDecoder.__call__
|
|
and (indefLen)ValueDecoder and should not be used for other purposes.
|
|
The client is not supposed to ever seek before this position.
|
|
"""
|
|
return self._markedPosition
|
|
|
|
@markedPosition.setter
|
|
def markedPosition(self, value):
|
|
# By setting the value, we ensure we won't seek back before it.
|
|
# `value` should be the same as the current position
|
|
# We don't check for this for performance reasons.
|
|
self._markedPosition = value
|
|
|
|
# Whenever we set _marked_position, we know for sure
|
|
# that we will not return back, and thus it is
|
|
# safe to drop all cached data.
|
|
if self._cache.tell() > io.DEFAULT_BUFFER_SIZE:
|
|
self._cache = io.BytesIO(self._cache.read())
|
|
self._markedPosition = 0
|
|
|
|
def tell(self):
|
|
return self._cache.tell()
|
|
|
|
|
|
def asSeekableStream(substrate):
|
|
"""Convert object to seekable byte-stream.
|
|
|
|
Parameters
|
|
----------
|
|
substrate: :py:class:`bytes` or :py:class:`io.IOBase` or :py:class:`univ.OctetString`
|
|
|
|
Returns
|
|
-------
|
|
: :py:class:`io.IOBase`
|
|
|
|
Raises
|
|
------
|
|
: :py:class:`~pyasn1.error.PyAsn1Error`
|
|
If the supplied substrate cannot be converted to a seekable stream.
|
|
"""
|
|
if isinstance(substrate, io.BytesIO):
|
|
return substrate
|
|
|
|
elif isinstance(substrate, bytes):
|
|
return io.BytesIO(substrate)
|
|
|
|
elif isinstance(substrate, univ.OctetString):
|
|
return io.BytesIO(substrate.asOctets())
|
|
|
|
try:
|
|
if substrate.seekable(): # Will fail for most invalid types
|
|
return substrate
|
|
else:
|
|
return CachingStreamWrapper(substrate)
|
|
|
|
except AttributeError:
|
|
raise error.UnsupportedSubstrateError(
|
|
"Cannot convert " + substrate.__class__.__name__ +
|
|
" to a seekable bit stream.")
|
|
|
|
|
|
def isEndOfStream(substrate):
|
|
"""Check whether we have reached the end of a stream.
|
|
|
|
Although it is more effective to read and catch exceptions, this
|
|
function
|
|
|
|
Parameters
|
|
----------
|
|
substrate: :py:class:`IOBase`
|
|
Stream to check
|
|
|
|
Returns
|
|
-------
|
|
: :py:class:`bool`
|
|
"""
|
|
if isinstance(substrate, io.BytesIO):
|
|
cp = substrate.tell()
|
|
substrate.seek(0, os.SEEK_END)
|
|
result = substrate.tell() == cp
|
|
substrate.seek(cp, os.SEEK_SET)
|
|
yield result
|
|
|
|
else:
|
|
received = substrate.read(1)
|
|
if received is None:
|
|
yield
|
|
|
|
if received:
|
|
substrate.seek(-1, os.SEEK_CUR)
|
|
|
|
yield not received
|
|
|
|
|
|
def peekIntoStream(substrate, size=-1):
|
|
"""Peek into stream.
|
|
|
|
Parameters
|
|
----------
|
|
substrate: :py:class:`IOBase`
|
|
Stream to read from.
|
|
|
|
size: :py:class:`int`
|
|
How many bytes to peek (-1 = all available)
|
|
|
|
Returns
|
|
-------
|
|
: :py:class:`bytes` or :py:class:`str`
|
|
The return type depends on Python major version
|
|
"""
|
|
if hasattr(substrate, "peek"):
|
|
received = substrate.peek(size)
|
|
if received is None:
|
|
yield
|
|
|
|
while len(received) < size:
|
|
yield
|
|
|
|
yield received
|
|
|
|
else:
|
|
current_position = substrate.tell()
|
|
try:
|
|
for chunk in readFromStream(substrate, size):
|
|
yield chunk
|
|
|
|
finally:
|
|
substrate.seek(current_position)
|
|
|
|
|
|
def readFromStream(substrate, size=-1, context=None):
|
|
"""Read from the stream.
|
|
|
|
Parameters
|
|
----------
|
|
substrate: :py:class:`IOBase`
|
|
Stream to read from.
|
|
|
|
Keyword parameters
|
|
------------------
|
|
size: :py:class:`int`
|
|
How many bytes to read (-1 = all available)
|
|
|
|
context: :py:class:`dict`
|
|
Opaque caller context will be attached to exception objects created
|
|
by this function.
|
|
|
|
Yields
|
|
------
|
|
: :py:class:`bytes` or :py:class:`str` or :py:class:`SubstrateUnderrunError`
|
|
Read data or :py:class:`~pyasn1.error.SubstrateUnderrunError`
|
|
object if no `size` bytes is readily available in the stream. The
|
|
data type depends on Python major version
|
|
|
|
Raises
|
|
------
|
|
: :py:class:`~pyasn1.error.EndOfStreamError`
|
|
Input stream is exhausted
|
|
"""
|
|
while True:
|
|
# this will block unless stream is non-blocking
|
|
received = substrate.read(size)
|
|
if received is None: # non-blocking stream can do this
|
|
yield error.SubstrateUnderrunError(context=context)
|
|
|
|
elif not received and size != 0: # end-of-stream
|
|
raise error.EndOfStreamError(context=context)
|
|
|
|
elif len(received) < size:
|
|
substrate.seek(-len(received), os.SEEK_CUR)
|
|
|
|
# behave like a non-blocking stream
|
|
yield error.SubstrateUnderrunError(context=context)
|
|
|
|
else:
|
|
break
|
|
|
|
yield received
|