def test_limits(self): try: ProtocolBase().from_string(Integer, "1" * (Integer.__max_str_len__ + 1)) except: pass else: raise Exception("must fail.") ProtocolBase().from_string(UnsignedInteger, "-1") # This is not supposed to fail. try: UnsignedInteger.validate_native(-1) # This is supposed to fail. except: pass else: raise Exception("must fail.")
class HelloWorldService(ServiceBase): @rpc(Unicode(default='World'), UnsignedInteger(default=5), _returns=Iterable(Unicode)) def say_hello(ctx, name, times): # workaround for Python2's lacking of nonlocal times = [times] def _cb(push): # This callback is called immediately after the function returns. if times[0] > 0: times[0] -= 1 data = u'Hello, %s' % name print data # The object passed to the append() method is immediately # serialized to bytes and pushed to the response stream's # file-like object. push.append(data) # When a push-callback returns anything other than a deferred, # the response gets closed. return deferLater(reactor, 1, _cb, push) # This is Spyne's way of returning NOT_DONE_YET return Iterable.Push(_cb) @rpc(Unicode(default='World'), _returns=Iterable(Unicode)) def say_hello_forever(ctx, name): def _cb(push): push.append(u'Hello, %s' % name) return deferLater(reactor, 0.1, _cb, push) return Iterable.Push(_cb)
def test_limits(self): try: ProtocolBase().from_string(Integer, "1" * (Integer.__max_str_len__ + 1)) except: pass else: raise Exception("must fail.") ProtocolBase().from_string(UnsignedInteger, "-1") # This is not supposed to fail. try: UnsignedInteger.validate_native(-1) # This is supposed to fail. except: pass else: raise Exception("must fail.")
class Email(ComplexModel): _type_info = [ # # Metadata # ('id', JmapId( sub_name='id', doc="Id (immutable; server-set) The id of the Email object. Note " "that this is the JMAP object id, NOT the Message-ID header " "field value of the message [@!RFC5322].")), ('blob_id', JmapId(sub_name='blobId', doc="Id (immutable; server-set) The id representing the raw " "octets of the message [@!RFC5322] for this Email. This may " "be used to download the raw original message or to attach it " "directly to another Email, etc.")), ('thread_id', JmapId(sub_name='threadId', doc="(immutable; server-set) The id of the Thread to which " "this Email belongs.")), ( 'mailbox_ids', AnyDict( # this is supposed to be a JmapId: Boolean dict sub_name='mailboxIds', doc="The set of Mailbox ids this Email belongs to. An " "Email in the mail store MUST belong to one or more Mailboxes " "at all times (until it is destroyed). The set is represented " "as an object, with each key being a Mailbox id. The value " "for each key in the object MUST be true.")), ( 'keywords', AnyDict( # this is supposed to be a String: Boolean dict sub_name='keywords', doc="(default: {}) A set of keywords that apply " "to the Email. The set is represented as an object, with the " "keys being the keywords. The value for each key in the " "object MUST be true.")), ('size', UnsignedInteger( sub_name='size', doc="(immutable; server-set) The size, in octets, " "of the raw data for the message [@!RFC5322] (as referenced " "by the blobId, i.e., the number of octets in the file the " "user would download).")), ('received_at', UtcDate(sub_name='receivedAt', doc="(immutable; default: time of creation on server) The " "date the Email was received by the message store. This is " "the internal date in IMAP [@?RFC3501].")), ]
class DaemonConfig(ComplexModel): SECTION_NAME = 'basic' daemonize = Boolean(default=False) """Fork the process to the background.""" log_file = AbsolutePath """Log file.""" pid_file = AbsolutePath """File that will contain the pid of the daemon process.""" config_file = AbsolutePath """Alternative configuration file..""" uid = SystemUser """Daemon will drop privileges and switch to this uid when specified""" gid = SystemGroup """Daemon will drop privileges and switch to this gid when specified""" log_level = Unicode(values=['DEBUG', 'INFO'], default='DEBUG') """Logging level""" show_rpc = Boolean(default=False) """Log raw request and response data.""" secret = ByteArray(default_factory=lambda: [os.urandom(64)], no_cmdline=True) """Cookie encryption key. Keep secret.""" thread_min = UnsignedInteger(default=3) """Min number of threads in the thread pool""" thread_max = UnsignedInteger(default=10) """Max number of threads in the thread pool""" listeners = Array(ListenerConfig)
class ListenerConfig(ComplexModel): id = Unicode """Name of the listener resource.""" host = Unicode(default='127.0.0.1') """The host the server will listen to""" port = UnsignedInteger(default=5534) """The port the server will listen to""" thread_min = UnsignedInteger """Min number of threads in the thread pool""" thread_max = UnsignedInteger """Max number of threads in the thread pool"""
class CoreCapabilities(ComplexModel): _type_info = [ ('max_size_upload', UnsignedInteger( subname='maxSizeUpload', doc="The maximum file size, in octets, that the server will " "accept for a single file upload (for any purpose). Suggested " "minimum: 50,000,000.")), ('max_concurrent_upload', UnsignedInteger( subname='maxConcurrentUpload', doc="The maximum number of concurrent requests the server will " "accept to the upload endpoint. Suggested minimum: 4.")), ('max_size_request', UnsignedInteger( subname='maxSizeRequest', doc="The maximum size, in octets, that the server will accept for " "a single request to the API endpoint. Suggested minimum: 10," "000,000.")), ('max_concurrent_requests', UnsignedInteger( subname='maxConcurrentRequests', doc="The maximum number of concurrent requests the server will " "accept to the API endpoint. Suggested minimum: 4.")), ('max_calls_in_request', UnsignedInteger( subname='maxCallsInRequest', doc="The maximum number of method calls the server will accept in " "a single request to the API endpoint. Suggested minimum: 16.")), ('max_objects_in_get', UnsignedInteger( subname='maxObjectsInGet', doc="The maximum number of objects that the client may request in " "a single /get type method call. Suggested minimum: 500.")), ('max_objects_in_set', UnsignedInteger( subname='maxObjectsInSet', doc="The maximum number of objects the client may send to create, " "update, or destroy in a single /set type method call. This " "is the combined total, e.g., if the maximum is 10, you could " "not create 7 objects and destroy 6, as this would be 13 " "actions, which exceeds the limit. Suggested minimum: 500.")), ('collation_algorithms', Array(Unicode, subname='collationAlgorithms', doc="A list of identifiers for algorithms registered in the " "collation registry, as defined in [@!RFC4790], that the " "server supports for sorting when querying records.")), ]
class DatabaseConfig(ComplexModel): name = Unicode """Database name. Must be a valid python variable name.""" type = Unicode(values=['sqlalchemy']) """Connection type. Only 'sqlalchemy' is supported.""" conn_str = Unicode """Connection string. See SQLAlchemy docs for more info.""" pool_size = UnsignedInteger(default=10) """Max. number of connections in the the db conn pool.""" show_queries = Boolean(default=False) """Logs sql queries.""" show_results = Boolean(default=False) """Logs sql queries as well as their results."""
class MailCapabilities(ComplexModel): _type_info = [ ('max_mailboxes_per_email', UnsignedInteger( sub_name='maxMailboxesPerEmail', doc="The maximum number of Mailboxes (see " "Section 2) that can be can assigned to a single Email " "object (see Section 4). This MUST be an integer >= 1, " "or null for no limit (or rather, the limit is always the " "number of Mailboxes in the account).")), ('max_mailbox_depth', UnsignedInteger( sub_name='maxMailboxDepth', doc="The maximum depth of the Mailbox hierarchy " "(i.e., one more than the maximum number of ancestors a " "Mailbox may have), or null for no limit.")), ('max_size_mailbox_name', M( UnsignedInteger( sub_name='maxSizeMailboxName', doc="The maximum length, in (UTF-8) octets, allowed " "for the name of a Mailbox. This MUST be at least 100, " "although it is recommended servers allow more."))), ('max_size_attachments_per_email', M( UnsignedInteger( sub_name='maxSizeAttachmentsPerEmail', doc="The maximum total size of attachments, " "in octets, allowed for a single Email object. A server MAY " "still reject the import or creation of an Email with a " "lower attachment size total (for example, if the body " "includes several megabytes of text, causing the size of the " "encoded MIME structure to be over some server-defined " "limit).\n\n" "Note that this limit is for the sum of unencoded attachment " "sizes. Users are generally not knowledgeable about encoding " "overhead, etc., nor should they need to be, so marketing " "and help materials normally tell them the “max size " "attachments”. This is the unencoded size they see on their " "hard drive, so this capability matches that and allows the " "client to consistently enforce what the user understands as " "the limit.\n\n" "The server may separately have a limit for the total size " "of the message [@!RFC5322], created by combining the " "attachments (often base64 encoded) with the message headers " "and bodies. For example, suppose the server advertises " "maxSizeAttachmentsPerEmail: 50000000 (50 MB). The enforced " "server limit may be for a message size of 70000000 octets. " "Even with base64 encoding and a 2 MB HTML body, " "50 MB attachments would fit under this limit."))), ('email_query_sort_options', Array(Unicode, sub_name='emailQuerySortOptions', doc="A list of all the values the server supports for " "the “property” field of the Comparator object in an " "Email/query sort (see Section 4.4.2). This MAY include " "properties the client does not recognise (for example, " "custom properties specified in a vendor extension). Clients " "MUST ignore any unknown properties in the list.")), ('may_create_top_level_mailbox', Boolean(sub_name='mayCreateTopLevelMailbox', doc="If true, the user may create a Mailbox (see Section " "2) in this account with a null parentId. (Permission for " "creating a child of an existing Mailbox is given by the " "myRights property on that Mailbox.)")), ]
class EmailBodyPart(ComplexModel): _type_info = [ ('part_id', Unicode( sub_name='partId', doc="Identifies this part uniquely within the Email. This is " "scoped to the emailId and has no meaning outside of the " "JMAP Email object representation. This is null if, and only " "if, the part is of type multipart." )), ('blob_id', JmapId( sub_name='blobId', doc="Id|null The id representing the raw octets of the contents " "of the part, after decoding any known " "Content-Transfer-Encoding (as defined in [@!RFC2045]), or " "null if, and only if, the part is of type multipart. Note " "that two parts may be transfer-encoded differently but have " "the same blob id if their decoded octets are identical and " "the server is using a secure hash of the data for the blob " "id. If the transfer encoding is unknown, it is treated as " "though it had no transfer encoding." )), ('size', M(UnsignedInteger( sub_name='size', doc="UnsignedInt The size, in octets, of the raw data after " "content transfer decoding (as referenced by the blobId, " "i.e., the number of octets in the file the user would " "download)." ))), ('headers', Array(EmailHeader, sub_name='headers', doc="This is a list of all header fields in the " "part, in the order they appear in the message. The values " "are in Raw form." )), ('name', Unicode( sub_name='name', doc="This is the decoded filename parameter of the " "Content-Disposition header field per [@!RFC2231], or (for " "compatibility with existing systems) if not present, " "then it’s the decoded name parameter of the Content-Type " "header field per [@!RFC2047]." )), ('type', M(Unicode( sub_name='type', doc='String The value of the Content-Type header field of the ' 'part, if present; otherwise, the implicit type as per the ' 'MIME standard (text/plain or message/rfc822 if inside a ' 'multipart/digest). CFWS is removed and any parameters are ' 'stripped.' ))), ('charset', Unicode( sub_name='charset', doc="The value of the charset parameter of the Content-Type " "header field, if present, or null if the header field is " "present but not of type text. If there is no Content-Type " "header field, or it exists and is of type text but has no " "charset parameter, this is the implicit charset as per the " "MIME standard: us-ascii." )), ('disposition', Unicode( sub_name='disposition', doc="The value of the Content-Disposition header " "field of the part, if present; otherwise, it’s null. CFWS is " "removed and any parameters are stripped." )), ('cid', Unicode( sub_name='cid', doc="The value of the Content-Id header field of the " "part, if present; otherwise it’s null. CFWS and surrounding " "angle brackets (<>) are removed. This may be used to " "reference the content from within a text/html body part HTML " "using the cid: protocol, as defined in [@!RFC2392]." )), ('language', Array(Unicode, sub_name='language', doc="The list of language tags, as defined in [" "@!RFC3282], in the Content-Language header field of the " "part, if present." )), ('location', Unicode( sub_name='location', doc="The URI, as defined in [@!RFC2557], in the " "Content-Location header field of the part, if present." )), ('subParts', Array(SelfReference, sub_name='subParts', doc="If the type is multipart, this contains the body parts of " "each child." )), ]
class Email(ComplexModel): _type_info = [ # # Metadata # ('id', JmapId( sub_name='id', doc="(immutable; server-set) The id of the Email object. Note " "that this is the JMAP object id, NOT the Message-ID header " "field value of the message [@!RFC5322]." )), ('blob_id', JmapId( sub_name='blobId', doc="(immutable; server-set) The id representing the raw " "octets of the message [@!RFC5322] for this Email. This may " "be used to download the raw original message or to attach it " "directly to another Email, etc." )), ('thread_id', JmapId( sub_name='threadId', doc="(immutable; server-set) The id of the Thread to which " "this Email belongs." )), ('mailbox_ids', AnyDict( # this is supposed to be a JmapId: bool dict sub_name='mailboxIds', doc="The set of Mailbox ids this Email belongs to. An " "Email in the mail store MUST belong to one or more Mailboxes " "at all times (until it is destroyed). The set is represented " "as an object, with each key being a Mailbox id. The value " "for each key in the object MUST be true." )), ('keywords', AnyDict( # this is supposed to be a str: bool dict sub_name='keywords', doc="(default: {}) A set of keywords that apply " "to the Email. The set is represented as an object, with the " "keys being the keywords. The value for each key in the " "object MUST be true." )), ('size', UnsignedInteger( sub_name='size', doc="(immutable; server-set) The size, in octets, " "of the raw data for the message [@!RFC5322] (as referenced " "by the blobId, i.e., the number of octets in the file the " "user would download)." )), ('received_at', UtcDate( default_factory=lambda: datetime.utcnow().replace(tzinfo=pytz.utc) .isoformat(), sub_name='receivedAt', doc="(immutable; default: time of creation on server) The " "date the Email was received by the message store. This is " "the internal date in IMAP [@?RFC3501]." )), # # Header fields # ('message_id', Array(Unicode, sub_name='messageId', doc="(immutable) The value is identical to the " "value of header:Message-ID:asMessageIds. For messages " "conforming to RFC 5322 this will be an array with a single " "entry." )), ('in_reply_to', Array(Unicode, sub_name='inReplyTo', doc="(immutable) The value is identical to the " "value of header:In-Reply-To:asMessageIds." )), ('references', Array(Unicode, sub_name='references', doc="(immutable) The value is identical to the " "value of header:References:asMessageIds." )), ('sender', Array(EmailAddress, sub_name='sender', doc="(immutable) The value is identical to " "the value of header:Sender:asAddresses." )), ('from_', Array(Unicode, sub_name='from', doc="(immutable) The value is identical to " "the value of header:From:asAddresses." )), ('to', Array(Unicode, sub_name='to', doc="(immutable) The value is identical to " "the value of header:To:asAddresses." )), ('cc', Array(Unicode, sub_name='cc', doc="(immutable) The value is identical to " "the value of header:Cc:asAddresses." )), ('bcc', Array(Unicode, sub_name='bcc', doc="(immutable) The value is identical to " "the value of header:Bcc:asAddresses." )), ('reply_to', Unicode( sub_name='replyTo', doc="(immutable) The value is identical to " "the value of header:Reply-To:asAddresses." )), ('subject', Unicode( sub_name='subject', doc="(immutable) The value is identical to the value " "of header:Subject:asText." )), ('sent_at', DateTime( sub_name='sentAt', doc="(immutable; default on creation: current server " "time) The value is identical to the value of " "header:Date:asDate." )), # # Body Parts # ('body_structure', Array(EmailBodyPart, sub_name='bodyStructure', doc="(immutable) This is the full MIME structure of the message " "body, without recursing into message/rfc822 or message/global " "parts. Note that EmailBodyParts may have subParts if they " "are of type multipart." )), ('body_values', AnyDict( sub_name='bodyValues', doc="(immutable) This is a map of partId to an EmailBodyValue " "object for none, some, or all text parts. Which parts are " "included and whether the value is truncated is determined " "by various arguments to Email/get and Email/parse." )), ('text_body', Array(EmailBodyPart, sub_name='textBody', doc="(immutable) A list of text/plain, text/html, image, audio, " "and/or video parts to display (sequentially) as the message " "body, with a preference for text/plain when alternative " "versions are available." )), ('html_body', Array(EmailBodyPart, sub_name='htmlBody', doc="(immutable) A list of text/plain, text/html, image, audio, " "and/or video parts to display (sequentially) as the message " "body, with a preference for text/html when alternative " "versions are available." )), ('attachments', Array(EmailBodyPart, sub_name='attachments', doc="(immutable) A list, traversing depth-first, " "of all parts in bodyStructure that satisfy either of the " "following conditions:" )), ('has_attachment', M(Boolean( sub_name='hasAttachment', default=False, doc="(immutable; server-set) This is true if there are " "one or more parts in the message that a client UI should " "offer as downloadable. A server SHOULD set hasAttachment to " "true if the attachments list contains at least one item that " "does not have Content-Disposition: inline. The server MAY " "ignore parts in this list that are processed automatically " "in some way or are referenced as embedded images in one of " "the text/html parts of the message." ))), ('preview', Unicode(256, sub_name='preview', default=u'', doc="(immutable; server-set) A plaintext fragment of the " "message body. This is intended to be shown as a preview line " "when listing messages in the mail store and may be truncated " "when shown. The server may choose which part of the message " "to include in the preview; skipping quoted sections and " "salutations and collapsing white space can result in a more " "useful preview." )), ]