login page

This commit is contained in:
Alicja Cięciwa
2020-10-27 12:57:58 +01:00
commit cb8886666c
8545 changed files with 1082463 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
__all__ = [
"DataView", "DataViewCollection", "DataViewMapping", "DataViewSequence",
"validate", "ValidationError",
"Hash", "Package", "Requires", "Source", "Script",
"Meta", "PackageCollection", "ScriptCollection", "SourceCollection",
]
from .base import (
DataView, DataViewCollection, DataViewMapping, DataViewSequence,
validate, ValidationError,
)
from .hashes import Hash
from .packages import Package
from .scripts import Script
from .sources import Source
from .sections import (
Meta, Requires, PackageCollection, ScriptCollection, SourceCollection,
)

View File

@@ -0,0 +1,162 @@
try:
import cerberus
except ImportError:
cerberus = None
class ValidationError(ValueError):
def __init__(self, value, validator):
super(ValidationError, self).__init__(value)
self.validator = validator
self.value = value
def __str__(self):
return '{}\n{}'.format(
self.value,
'\n'.join(
'{}: {}'.format(k, e)
for k, errors in self.validator.errors.items()
for e in errors
)
)
VALIDATORS = {}
def validate(cls, data):
if not cerberus: # Skip validation if Cerberus is not available.
return
schema = cls.__SCHEMA__
key = id(schema)
try:
v = VALIDATORS[key]
except KeyError:
v = VALIDATORS[key] = cerberus.Validator(schema, allow_unknown=True)
if v.validate(data, normalize=False):
return
raise ValidationError(data, v)
class DataView(object):
"""A "view" to a data.
Validates the input mapping on creation. A subclass is expected to
provide a `__SCHEMA__` class attribute specifying a validator schema.
"""
def __init__(self, data):
self.validate(data)
self._data = data
def __repr__(self):
return "{0}({1!r})".format(type(self).__name__, self._data)
def __eq__(self, other):
if not isinstance(other, type(self)):
raise TypeError(
"cannot compare {0!r} with {1!r}".format(
type(self).__name__, type(other).__name__
)
)
return self._data == other._data
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
@classmethod
def validate(cls, data):
return validate(cls, data)
class DataViewCollection(DataView):
"""A homogeneous collection of data views.
Subclasses are expected to assign a class attribute `item_class` to specify
the type of items it contains. This class will be used to coerce return
values when accessed. The item class should conform to the `DataView`
protocol.
You should not instantiate an instance from this class, but from one of its
subclasses instead.
"""
item_class = None
def __repr__(self):
return "{0}({1!r})".format(type(self).__name__, self._data)
def __len__(self):
return len(self._data)
def __getitem__(self, key):
return self.item_class(self._data[key])
def __setitem__(self, key, value):
if isinstance(value, DataView):
value = value._data
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
class DataViewMapping(DataViewCollection):
"""A mapping of data views.
The keys are primitive values, while values are instances of `item_class`.
"""
@classmethod
def validate(cls, data):
for d in data.values():
cls.item_class.validate(d)
def __iter__(self):
return iter(self._data)
def keys(self):
return self._data.keys()
def values(self):
return [self[k] for k in self._data]
def items(self):
return [(k, self[k]) for k in self._data]
class DataViewSequence(DataViewCollection):
"""A sequence of data views.
Each entry is an instance of `item_class`.
"""
@classmethod
def validate(cls, data):
for d in data:
cls.item_class.validate(d)
def __iter__(self):
return (self.item_class(d) for d in self._data)
def __getitem__(self, key):
if isinstance(key, slice):
return type(self)(self._data[key])
return super(DataViewSequence, self).__getitem__(key)
def append(self, value):
if isinstance(value, DataView):
value = value._data
self._data.append(value)

View File

@@ -0,0 +1,51 @@
from .base import DataView
class Hash(DataView):
"""A hash.
"""
__SCHEMA__ = {
"__hash__": {
"type": "list", "minlength": 1, "maxlength": 1,
"schema": {
"type": "list", "minlength": 2, "maxlength": 2,
"schema": {"type": "string"},
},
},
}
@classmethod
def validate(cls, data):
super(Hash, cls).validate({"__hash__": list(data.items())})
@classmethod
def from_hash(cls, ins):
"""Interpolation to the hash result of `hashlib`.
"""
return cls({ins.name: ins.hexdigest()})
@classmethod
def from_line(cls, value):
try:
name, value = value.split(":", 1)
except ValueError:
name = "sha256"
return cls({name: value})
def __eq__(self, other):
if not isinstance(other, Hash):
raise TypeError("cannot compare Hash with {0!r}".format(
type(other).__name__,
))
return self._data == other._data
@property
def name(self):
return next(iter(self._data.keys()))
@property
def value(self):
return next(iter(self._data.values()))
def as_line(self):
return "{0[0]}:{0[1]}".format(next(iter(self._data.items())))

View File

@@ -0,0 +1,45 @@
import six
from .base import DataView
class Package(DataView):
"""A package requirement specified in a Pipfile.
This is the base class of variants appearing in either `[packages]` or
`[dev-packages]` sections of a Pipfile.
"""
# The extra layer is intentional. Cerberus does not allow top-level keys
# to have oneof_schema (at least I can't do it), so we wrap this in a
# top-level key. The Requirement model class implements extra hacks to
# make this work.
__SCHEMA__ = {
"__package__": {
"oneof_type": ["string", "dict"],
},
}
@classmethod
def validate(cls, data):
# HACK: Make this validatable for Cerberus. See comments in validation
# side for more information.
return super(Package, cls).validate({"__package__": data})
def __getattr__(self, key):
if isinstance(self._data, six.string_types):
if key == "version":
return self._data
raise AttributeError(key)
try:
return self._data[key]
except KeyError:
pass
raise AttributeError(key)
def __setattr__(self, key, value):
if key == "_data":
super(Package, self).__setattr__(key, value)
elif key == "version" and isinstance(self._data, six.string_types):
self._data = value
else:
self._data[key] = value

View File

@@ -0,0 +1,79 @@
import re
import shlex
import six
from .base import DataView
class Script(DataView):
"""Parse a script line (in Pipfile's [scripts] section).
This always works in POSIX mode, even on Windows.
"""
# This extra layer is intentional. Cerberus does not allow validation of
# non-mapping inputs, so we wrap this in a top-level key. The Script model
# class implements extra hacks to make this work.
__SCHEMA__ = {
"__script__": {
"oneof_type": ["string", "list"], "required": True, "empty": False,
"schema": {"type": "string"},
},
}
def __init__(self, data):
super(Script, self).__init__(data)
if isinstance(data, six.string_types):
data = shlex.split(data)
self._parts = [data[0]]
self._parts.extend(data[1:])
@classmethod
def validate(cls, data):
# HACK: Make this validatable for Cerberus. See comments in validation
# side for more information.
return super(Script, cls).validate({"__script__": data})
def __repr__(self):
return "Script({0!r})".format(self._parts)
@property
def command(self):
return self._parts[0]
@property
def args(self):
return self._parts[1:]
def cmdify(self, extra_args=None):
"""Encode into a cmd-executable string.
This re-implements CreateProcess's quoting logic to turn a list of
arguments into one single string for the shell to interpret.
* All double quotes are escaped with a backslash.
* Existing backslashes before a quote are doubled, so they are all
escaped properly.
* Backslashes elsewhere are left as-is; cmd will interpret them
literally.
The result is then quoted into a pair of double quotes to be grouped.
An argument is intentionally not quoted if it does not contain
whitespaces. This is done to be compatible with Windows built-in
commands that don't work well with quotes, e.g. everything with `echo`,
and DOS-style (forward slash) switches.
The intended use of this function is to pre-process an argument list
before passing it into ``subprocess.Popen(..., shell=True)``.
See also: https://docs.python.org/3/library/subprocess.html
"""
parts = list(self._parts)
if extra_args:
parts.extend(extra_args)
return " ".join(
arg if not next(re.finditer(r'\s', arg), None)
else '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', arg))
for arg in parts
)

View File

@@ -0,0 +1,123 @@
from .base import DataView, DataViewMapping, DataViewSequence
from .hashes import Hash
from .packages import Package
from .scripts import Script
from .sources import Source
class PackageCollection(DataViewMapping):
item_class = Package
class ScriptCollection(DataViewMapping):
item_class = Script
class SourceCollection(DataViewSequence):
item_class = Source
class Requires(DataView):
"""Representation of the `[requires]` section in a Pipfile.
"""
__SCHEMA__ = {
"python_version": {
"type": "string",
"excludes": ["python_full_version"],
},
"python_full_version": {
"type": "string",
"excludes": ["python_version"],
},
}
@property
def python_version(self):
try:
return self._data["python_version"]
except KeyError:
raise AttributeError("python_version")
@property
def python_full_version(self):
try:
return self._data["python_full_version"]
except KeyError:
raise AttributeError("python_full_version")
META_SECTIONS = {
"hash": Hash,
"requires": Requires,
"sources": SourceCollection,
}
class Meta(DataView):
"""Representation of the `_meta` section in a Pipfile.lock.
"""
__SCHEMA__ = {
"hash": {"type": "dict", "required": True},
"pipfile-spec": {"type": "integer", "required": True, "min": 0},
"requires": {"type": "dict", "required": True},
"sources": {"type": "list", "required": True},
}
@classmethod
def validate(cls, data):
super(Meta, cls).validate(data)
for key, klass in META_SECTIONS.items():
klass.validate(data[key])
def __getitem__(self, key):
value = super(Meta, self).__getitem__(key)
try:
return META_SECTIONS[key](value)
except KeyError:
return value
def __setitem__(self, key, value):
if isinstance(value, DataView):
self._data[key] = value._data
else:
self._data[key] = value
@property
def hash_(self):
return self["hash"]
@hash_.setter
def hash_(self, value):
self["hash"] = value
@property
def hash(self):
return self["hash"]
@hash.setter
def hash(self, value):
self["hash"] = value
@property
def pipfile_spec(self):
return self["pipfile-spec"]
@pipfile_spec.setter
def pipfile_spec(self, value):
self["pipfile-spec"] = value
@property
def requires(self):
return self["requires"]
@requires.setter
def requires(self, value):
self["requires"] = value
@property
def sources(self):
return self["sources"]
@sources.setter
def sources(self, value):
self["sources"] = value

View File

@@ -0,0 +1,45 @@
import os
from .base import DataView
class Source(DataView):
"""Information on a "simple" Python package index.
This could be PyPI, or a self-hosted index server, etc. The server
specified by the `url` attribute is expected to provide the "simple"
package API.
"""
__SCHEMA__ = {
"name": {"type": "string", "required": True},
"url": {"type": "string", "required": True},
"verify_ssl": {"type": "boolean", "required": True},
}
@property
def name(self):
return self._data["name"]
@name.setter
def name(self, value):
self._data["name"] = value
@property
def url(self):
return self._data["url"]
@url.setter
def url(self, value):
self._data["url"] = value
@property
def verify_ssl(self):
return self._data["verify_ssl"]
@verify_ssl.setter
def verify_ssl(self, value):
self._data["verify_ssl"] = value
@property
def url_expanded(self):
return os.path.expandvars(self._data["url"])