rococo 0.1.2__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rococo-0.1.6/PKG-INFO ADDED
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.1
2
+ Name: rococo
3
+ Version: 0.1.6
4
+ Summary: A Python library to help build things the way we want them built
5
+ Home-page: https://github.com/EcorRouge/rococo
6
+ Author: Jay Grieves
7
+ Author-email: jaygrieves@gmail.com
8
+ License: MIT
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: surrealdb==0.3.1
13
+ Requires-Dist: boto3==1.28.55
14
+ Requires-Dist: pika==1.3.2
15
+
16
+ # rococo
17
+ A Python library to help build things the way we want them built.
18
+
19
+
20
+ ## Basic Usage
21
+
22
+ ### Installation
23
+
24
+ Install using pip:
25
+
26
+ ```bash
27
+ pip install rococo
28
+ ```
29
+
30
+ ### Example
31
+
32
+ #### Models
33
+
34
+ ```python
35
+ from rococo.models import Person
36
+
37
+ # Initialize a Person object from rococo's built-in models.
38
+ someone = Person(first_name="John", last_name="Doe")
39
+
40
+ # Prepare to save the object in the database adding/updating attributes for the object.
41
+ someone.prepare_for_save(changed_by_id="jane_doe")
42
+
43
+ someone.as_dict()
44
+
45
+ {
46
+ 'active': True,
47
+ 'changed_by_id': 'jane_doe',
48
+ 'changed_on': datetime.datetime(2023, 9, 20, 19, 50, 23, 532875),
49
+ 'entity_id': 'e06876705b364640a20efc165f6ffb76',
50
+ 'first_name': 'John',
51
+ 'last_name': 'Doe',
52
+ 'previous_version': '7e63a5d0aa0f43b5aa9c8cc0634c41f2',
53
+ 'version': '08489d2bc5d74f78b7af0f2c1d9c5498'
54
+ }
55
+ ```
56
+
57
+ #### Messaging
58
+
59
+
60
+ ##### RabbitMQ
61
+ ```python
62
+ # Producer
63
+ from rococo.messaging import RabbitMqConnection
64
+
65
+ with RabbitMqConnection('host', 'port', 'username', 'password', 'virtual_host') as conn:
66
+ conn.send_message('queue_name', {'message': 'data'})
67
+
68
+
69
+ # Consumer
70
+ from rococo.messaging import RabbitMqConnection
71
+
72
+ def process_message(message_data: dict):
73
+ print(f"Processing message {message_data}...")
74
+
75
+ with RabbitMqConnection('host', 'port', 'username', 'password', 'virtual_host') as conn:
76
+ conn.consume_messages('queue_name', process_message)
77
+ ```
78
+
79
+ ##### SQS
80
+ ```python
81
+ # Producer
82
+ from rococo.messaging import SqsConnection
83
+
84
+ with SqsConnection(region_name='us-east-1') as conn:
85
+ conn.send_message('queue_name', {'message': 'data'})
86
+
87
+
88
+ # Consumer
89
+ from rococo.messaging import SqsConnection
90
+
91
+ def process_message(message_data: dict):
92
+ print(f"Processing message {message_data}...")
93
+
94
+ with SqsConnection(region_name='us-east-1') as conn:
95
+ conn.consume_messages('queue_name', process_message)
96
+
97
+ # Note: since cleanup is not required for SQS connections, you can also do:
98
+ conn = SqsConnection(region_name='us-east-1')
99
+ conn.send_message('queue_name', {'message': 'data'})
100
+ conn.consume_messages('queue_name', process_message)
101
+ ```
102
+
103
+ #### Data
104
+
105
+ ##### SurrealDB
106
+ ```python
107
+ from rococo.data import SurrealDbAdapter
108
+
109
+ def get_db_connection():
110
+ endpoint = "ws://localhost:8000/rpc"
111
+ username = "myuser"
112
+ password = "mypassword"
113
+ namespace = "test"
114
+ database = "test"
115
+
116
+ return SurrealDbAdapter(endpoint, username, password, namespace, database)
117
+
118
+
119
+ with get_db_connection() as db:
120
+ db.execute_query("""insert into person {
121
+ user: 'me',
122
+ pass: 'very_safe',
123
+ tags: ['python', 'documentation']
124
+ };""")
125
+ print(db.execute_query("SELECT * FROM person;", {}))
126
+ ```
rococo-0.1.6/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # rococo
2
+ A Python library to help build things the way we want them built.
3
+
4
+
5
+ ## Basic Usage
6
+
7
+ ### Installation
8
+
9
+ Install using pip:
10
+
11
+ ```bash
12
+ pip install rococo
13
+ ```
14
+
15
+ ### Example
16
+
17
+ #### Models
18
+
19
+ ```python
20
+ from rococo.models import Person
21
+
22
+ # Initialize a Person object from rococo's built-in models.
23
+ someone = Person(first_name="John", last_name="Doe")
24
+
25
+ # Prepare to save the object in the database adding/updating attributes for the object.
26
+ someone.prepare_for_save(changed_by_id="jane_doe")
27
+
28
+ someone.as_dict()
29
+
30
+ {
31
+ 'active': True,
32
+ 'changed_by_id': 'jane_doe',
33
+ 'changed_on': datetime.datetime(2023, 9, 20, 19, 50, 23, 532875),
34
+ 'entity_id': 'e06876705b364640a20efc165f6ffb76',
35
+ 'first_name': 'John',
36
+ 'last_name': 'Doe',
37
+ 'previous_version': '7e63a5d0aa0f43b5aa9c8cc0634c41f2',
38
+ 'version': '08489d2bc5d74f78b7af0f2c1d9c5498'
39
+ }
40
+ ```
41
+
42
+ #### Messaging
43
+
44
+
45
+ ##### RabbitMQ
46
+ ```python
47
+ # Producer
48
+ from rococo.messaging import RabbitMqConnection
49
+
50
+ with RabbitMqConnection('host', 'port', 'username', 'password', 'virtual_host') as conn:
51
+ conn.send_message('queue_name', {'message': 'data'})
52
+
53
+
54
+ # Consumer
55
+ from rococo.messaging import RabbitMqConnection
56
+
57
+ def process_message(message_data: dict):
58
+ print(f"Processing message {message_data}...")
59
+
60
+ with RabbitMqConnection('host', 'port', 'username', 'password', 'virtual_host') as conn:
61
+ conn.consume_messages('queue_name', process_message)
62
+ ```
63
+
64
+ ##### SQS
65
+ ```python
66
+ # Producer
67
+ from rococo.messaging import SqsConnection
68
+
69
+ with SqsConnection(region_name='us-east-1') as conn:
70
+ conn.send_message('queue_name', {'message': 'data'})
71
+
72
+
73
+ # Consumer
74
+ from rococo.messaging import SqsConnection
75
+
76
+ def process_message(message_data: dict):
77
+ print(f"Processing message {message_data}...")
78
+
79
+ with SqsConnection(region_name='us-east-1') as conn:
80
+ conn.consume_messages('queue_name', process_message)
81
+
82
+ # Note: since cleanup is not required for SQS connections, you can also do:
83
+ conn = SqsConnection(region_name='us-east-1')
84
+ conn.send_message('queue_name', {'message': 'data'})
85
+ conn.consume_messages('queue_name', process_message)
86
+ ```
87
+
88
+ #### Data
89
+
90
+ ##### SurrealDB
91
+ ```python
92
+ from rococo.data import SurrealDbAdapter
93
+
94
+ def get_db_connection():
95
+ endpoint = "ws://localhost:8000/rpc"
96
+ username = "myuser"
97
+ password = "mypassword"
98
+ namespace = "test"
99
+ database = "test"
100
+
101
+ return SurrealDbAdapter(endpoint, username, password, namespace, database)
102
+
103
+
104
+ with get_db_connection() as db:
105
+ db.execute_query("""insert into person {
106
+ user: 'me',
107
+ pass: 'very_safe',
108
+ tags: ['python', 'documentation']
109
+ };""")
110
+ print(db.execute_query("SELECT * FROM person;", {}))
111
+ ```
@@ -0,0 +1,3 @@
1
+ from .base import DbAdapter
2
+ from .surrealdb import SurrealDbAdapter
3
+
@@ -0,0 +1,13 @@
1
+ from abc import abstractmethod
2
+
3
+
4
+ class DbAdapter:
5
+
6
+ @abstractmethod
7
+ def execute_query(self, query: str):
8
+ """Abstract method for executing a query.
9
+
10
+ Args:
11
+ query (str): The query to execute.
12
+ """
13
+ pass
@@ -0,0 +1,46 @@
1
+ from surrealdb import Surreal
2
+ import asyncio
3
+
4
+
5
+ class SurrealDbAdapter():
6
+ """SurrealDB adapter for interacting with SurrealDB."""
7
+
8
+ def __init__(self, endpoint: str, username: str, password: str, namespace: str, db_name: str):
9
+ """Initializes a new SurrealDB adapter."""
10
+ self._endpoint = endpoint
11
+ self._username = username
12
+ self._password = password
13
+ self._namespace = namespace
14
+ self._db_name = db_name
15
+ self._db = None
16
+
17
+ def __enter__(self):
18
+ """Context manager entry point for preparing DB connection."""
19
+ self._event_loop = asyncio.new_event_loop()
20
+ self._db = self._event_loop.run_until_complete(self._prepare_db())
21
+ return self
22
+
23
+ def __exit__(self, exc_type, exc_value, traceback):
24
+ """Context manager exit point for closing DB connection."""
25
+ self._event_loop.run_until_complete(self._db.close())
26
+ self._event_loop.stop()
27
+ self._event_loop = None
28
+ self._db = None
29
+
30
+ async def _prepare_db(self):
31
+ """Prepares the DB connection."""
32
+ db = Surreal(self._endpoint)
33
+ await db.connect()
34
+ await db.signin({"user": self._username, "pass": self._password})
35
+ await db.use(self._namespace, self._db_name)
36
+ return db
37
+
38
+ def execute_query(self, sql, _vars=None):
39
+ """Executes a query against the DB."""
40
+ if _vars is None:
41
+ _vars = {}
42
+
43
+ if not self._db:
44
+ raise Exception("No connection to SurrealDB.")
45
+
46
+ return self._event_loop.run_until_complete(self._db.query(sql, _vars))
@@ -0,0 +1,3 @@
1
+ from .base import Connection
2
+ from .rabbitmq import RabbitMqConnection
3
+ from .sqs import SqsConnection
@@ -0,0 +1,40 @@
1
+ from abc import abstractmethod
2
+
3
+
4
+ # An abstract Connection class that enforces the implementation of the send_message and consume_messages methods.
5
+
6
+ class Connection:
7
+ """Abstract class for a connection to a message queue."""
8
+
9
+ @abstractmethod
10
+ def send_message(self, queue_name: str, message: dict):
11
+ """
12
+ Sends a message to the specified queue.
13
+
14
+ Args:
15
+ queue_name (str): The name of the queue to send the message to.
16
+ message (dict): The message to send.
17
+ """
18
+ pass
19
+
20
+ @abstractmethod
21
+ def consume_messages(self, queue_name: str, callback_function: callable):
22
+ """
23
+ Consumes messages from the specified queue.
24
+
25
+ Args:
26
+ queue_name (str): The name of the queue to consume messages from.
27
+ callback_function (callable): The function to call when a message is received.
28
+ """
29
+ pass
30
+
31
+
32
+ @abstractmethod
33
+ def __enter__(self):
34
+ """Performs any initialization required for the connection."""
35
+ pass
36
+
37
+ @abstractmethod
38
+ def __exit__(self, exc_type, exc_value, traceback):
39
+ """Performs any cleanup required for the connection."""
40
+ pass
@@ -0,0 +1,141 @@
1
+ import json
2
+ import pika
3
+ import functools
4
+ import threading
5
+ import logging
6
+ from typing import Callable
7
+
8
+ from . import Connection
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ class RabbitMqConnection(Connection):
13
+ """A connection to a RabbitMQ message queue that allows to send and receive messages."""
14
+
15
+
16
+ def __init__(self, host: str, port: int, username: str, password: str, virtual_host: str = ''):
17
+ """
18
+ Initializes a new RabbitMQ connection.
19
+
20
+ Args:
21
+ host (str): The host of the RabbitMQ server.
22
+ port (int): The port of the RabbitMQ server.
23
+ username (str): The username to use when connecting to the RabbitMQ server.
24
+ password (str): The password to use when connecting to the RabbitMQ server.
25
+ virtual_host (str): The virtual host to use when connecting to the RabbitMQ server.
26
+ """
27
+ self._host = host
28
+ self._port = port
29
+ self._username = username
30
+ self._password = password
31
+ self._virtual_host = virtual_host
32
+
33
+ self._connection = None
34
+ self._channel = None
35
+
36
+ def __enter__(self):
37
+ """
38
+ Opens a connection to the RabbitMQ server.
39
+
40
+ Returns:
41
+ RabbitMqConnection: The connection to the RabbitMQ server.
42
+ """
43
+ self._connection = pika.BlockingConnection(
44
+ pika.ConnectionParameters(host=self._host, port=self._port, credentials=pika.PlainCredentials(self._username, self._password),
45
+ virtual_host=self._virtual_host))
46
+ self._channel = self._connection.channel()
47
+
48
+ return self
49
+
50
+ def __exit__(self, exc_type, exc_value, traceback):
51
+ """
52
+ Closes the connection to the RabbitMQ server.
53
+ """
54
+ self._connection.close()
55
+ self._connection = None
56
+ self._channel = None
57
+
58
+
59
+ def send_message(self, queue_name: str, message: dict):
60
+ """
61
+ Sends a message to the specified queue.
62
+
63
+ Args:
64
+ queue_name (str): The name of the queue to send the message to.
65
+ message (dict): The message to send.
66
+ """
67
+ self._channel.basic_publish(exchange='', routing_key=queue_name, body=json.dumps(message))
68
+
69
+ def consume_messages(self, queue_name: str, callback_function: Callable[[dict], bool], num_threads: int = 1):
70
+ """
71
+ Consumes messages from the specified queue.
72
+
73
+ Args:
74
+ queue_name (str): The name of the queue to consume messages from.
75
+ callback_function (callable): The function to call when a message is received.
76
+ """
77
+
78
+ def _ack_message(ch, delivery_tag):
79
+ """Ack a message by its delivery tag if channel is open."""
80
+
81
+ if ch.is_open:
82
+ ch.basic_ack(delivery_tag)
83
+
84
+ def _do_work(ch, delivery_tag, body, callback):
85
+ """Callback function that processes the message."""
86
+
87
+ thread_id = threading.get_ident()
88
+ logger.info(
89
+ "Thread id: %s Delivery tag: %s Message body: %s",
90
+ thread_id,
91
+ delivery_tag,
92
+ body,
93
+ )
94
+ try:
95
+ success = callback(body)
96
+ except Exception:
97
+ logger.exception("Error processing message...")
98
+ success = False
99
+ logger.info(
100
+ "Thread id: %s Delivery tag: %s Message body: %s Processed...",
101
+ thread_id,
102
+ delivery_tag,
103
+ body,
104
+ )
105
+ cb = functools.partial(_ack_message, ch, delivery_tag)
106
+ logger.info(f"Sent ack for Delivery tag {delivery_tag}...")
107
+ self._connection.add_callback_threadsafe(cb)
108
+
109
+ def _on_message(ch, method_frame, _header_frame, body, args):
110
+ """Called when a message is received."""
111
+
112
+ body = json.loads(body.decode())
113
+ (callback,) = args
114
+ delivery_tag = method_frame.delivery_tag
115
+ t = threading.Thread(
116
+ target=_do_work, args=(ch, delivery_tag, body, callback)
117
+ )
118
+ t.start()
119
+ self._threads.append(t)
120
+
121
+ self._channel.queue_declare(queue=queue_name, durable=True)
122
+
123
+ self._threads = []
124
+ self._channel.basic_qos(prefetch_count=num_threads)
125
+
126
+ on_message_callback = functools.partial(_on_message, args=(callback_function,))
127
+ self._channel.basic_consume(
128
+ queue=queue_name, on_message_callback=on_message_callback
129
+ )
130
+
131
+ try:
132
+ logger.info(f"Listening to RabbitMQ queue {queue_name} on {self._host}:{self._port} with {num_threads} threads...")
133
+ self._channel.start_consuming()
134
+ except KeyboardInterrupt:
135
+ logger.info("Exiting gracefully...")
136
+ self._channel.stop_consuming()
137
+ finally:
138
+ # Wait for all to complete
139
+ for thread in self._threads:
140
+ thread.join()
141
+ self._connection.close()
@@ -0,0 +1,88 @@
1
+ import json
2
+ import boto3
3
+ import logging
4
+ import uuid
5
+
6
+ from . import Connection
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class SqsConnection(Connection):
11
+ """A connection to AWS SQS that allows sending and receiving messages to and from queues."""
12
+
13
+ def __init__(self, aws_access_key_id: str = None, aws_access_key_secret: str = None, region_name: str = None):
14
+ """Initializes a new SQS connection.
15
+
16
+ Args:
17
+ aws_access_key_id (str): The AWS access key ID.
18
+ aws_access_key_secret (str): The AWS access key secret.
19
+ region_name (str): The AWS region name.
20
+ """
21
+
22
+ self._aws_access_key_id = aws_access_key_id
23
+ self._aws_access_key_secret = aws_access_key_secret
24
+ self._region_name = region_name
25
+ self._sqs = boto3.resource('sqs', aws_access_key_id=self._aws_access_key_id, aws_secret_access_key=self._aws_access_key_secret, region_name=self._region_name)
26
+ self._queue_map = {}
27
+
28
+ def __enter__(self):
29
+ return self
30
+
31
+ def __exit__(self, exc_type, exc_value, traceback):
32
+ pass
33
+
34
+ def send_message(self, queue_name: str, message: dict):
35
+ """Sends a message to the specified SQS queue.
36
+
37
+ Args:
38
+ queue_name (str): The name of the queue to send the message to.
39
+ message (dict): The message to send.
40
+ """
41
+ if queue_name in self._queue_map:
42
+ queue = self._queue_map[queue_name]
43
+ else:
44
+ queue = self._sqs.get_queue_by_name(QueueName=queue_name)
45
+
46
+ queue.send_message(QueueUrl=queue_name, MessageBody=json.dumps(message))
47
+
48
+ def consume_messages(self, queue_name: str, callback_function: callable):
49
+ """Consumes messages from the specified SQS queue.
50
+
51
+ Args:
52
+ queue_name (str): The name of the queue to consume messages from.
53
+ callback_function (callable): The function to call when a message is received.
54
+ """
55
+
56
+ def _delete_queue_message(queue, handle):
57
+ logger.info("Deleting message.")
58
+ queue.delete_messages(
59
+ Entries=[
60
+ {
61
+ 'Id': str(uuid.uuid4()),
62
+ 'ReceiptHandle': handle
63
+ },
64
+ ]
65
+ )
66
+
67
+ logger.info(f"Connecting to SQS queue: {queue_name}...")
68
+ queue = self._sqs.get_queue_by_name(QueueName=queue_name)
69
+
70
+ while True:
71
+ logger.info(f"Fetching messages from SQS queue: {queue_name}...")
72
+ responses = queue.receive_messages(
73
+ AttributeNames=['All'],
74
+ MaxNumberOfMessages=1,
75
+ WaitTimeSeconds=20
76
+ )
77
+ if not responses:
78
+ logger.info("No messages left in queue.")
79
+ continue
80
+
81
+ response = {}
82
+ try:
83
+ response = responses[0]
84
+ body = json.loads(response.body)
85
+ callback_function(body)
86
+ except Exception as _:
87
+ logger.exception("Error processing message...")
88
+ _delete_queue_message(queue, response.receipt_handle)
@@ -0,0 +1,7 @@
1
+ from .versioned_model import VersionedModel
2
+
3
+ from .login_method import LoginMethod
4
+ from .organization import Organization
5
+ from .otp_method import OtpMethod
6
+ from .person import Person
7
+ from .person_organization_role import PersonOrganizationRole
@@ -0,0 +1,15 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from . import VersionedModel
5
+
6
+
7
+ @dataclass
8
+ class LoginMethod(VersionedModel):
9
+ """A login method model."""
10
+
11
+ person_id: str
12
+ method_type: str
13
+ method_data: Optional[dict]
14
+ email: Optional[str]
15
+ password: Optional[str]
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+
3
+ from . import VersionedModel
4
+
5
+
6
+ @dataclass
7
+ class Organization(VersionedModel):
8
+ """An organization model."""
9
+
10
+ name: str
@@ -0,0 +1,15 @@
1
+ from dataclasses import dataclass
2
+ from typing import List
3
+
4
+ from . import VersionedModel
5
+
6
+
7
+ @dataclass
8
+ class OtpMethod(VersionedModel):
9
+ """An OTP method model."""
10
+
11
+ person_id: str
12
+ secret: str
13
+ name: str
14
+ enabled: bool
15
+ recovery_codes: List[str]
@@ -0,0 +1,11 @@
1
+ from dataclasses import dataclass
2
+
3
+ from . import VersionedModel
4
+
5
+
6
+ @dataclass
7
+ class Person(VersionedModel):
8
+ """A person model."""
9
+
10
+ first_name: str
11
+ last_name: str
@@ -0,0 +1,12 @@
1
+ from dataclasses import dataclass
2
+
3
+ from . import VersionedModel
4
+
5
+
6
+ @dataclass
7
+ class PersonOrganizationRole(VersionedModel):
8
+ """A person organization role model."""
9
+
10
+ person_id: str
11
+ organization_id: str
12
+ role: str
@@ -0,0 +1,69 @@
1
+ from uuid import uuid4
2
+ from dataclasses import dataclass, field, fields
3
+ from datetime import datetime
4
+ from typing import Any, Dict, List
5
+
6
+
7
+ @dataclass(kw_only=True)
8
+ class VersionedModel:
9
+ """A base class for versioned models with common (Big 6) attributes."""
10
+
11
+ entity_id: str = uuid4().hex
12
+ version: str = uuid4().hex
13
+ previous_version: str = '00000000000000000000000000000000'
14
+ active: bool = True
15
+ changed_by_id: str = '00000000000000000000000000000000'
16
+ changed_on: datetime = field(default_factory=lambda: datetime.utcnow())
17
+
18
+ @classmethod
19
+ def fields(cls) -> List[str]:
20
+ """Get a list of field names for this model.
21
+
22
+ Returns:
23
+ List[str]: A list of field names.
24
+ """
25
+ return [f.name for f in fields(cls)]
26
+
27
+ def as_dict(self, convert_datetime_to_iso_string: bool = False) -> Dict[str, Any]:
28
+ """Convert this model to a dictionary.
29
+
30
+ Args:
31
+ convert_datetime_to_iso_string (bool, optional): Whether to convert datetime objects to ISO strings. Defaults to False.
32
+
33
+ Returns:
34
+ Dict[str, Any]: A dictionary representation of this model.
35
+ """
36
+ results = self.__dict__
37
+
38
+ if convert_datetime_to_iso_string:
39
+ for key, value in results.items():
40
+ if isinstance(value, datetime):
41
+ results[key] = value.isoformat()
42
+
43
+ return results
44
+
45
+ @classmethod
46
+ def from_dict(cls, model_dict: dict):
47
+ """Create a model from a dictionary.
48
+
49
+ Args:
50
+ model_dict (dict): A dictionary representation of a model.
51
+
52
+ Returns:
53
+ VersionedModel: A model object.
54
+ """
55
+ for key in model_dict:
56
+ if key in cls.__dict__:
57
+ cls.__dict__[key] = model_dict[key]
58
+
59
+ def prepare_for_save(self, changed_by_id: str):
60
+ """
61
+ Prepare this model for saving to the database.
62
+
63
+ Args:
64
+ changed_by_id (str): The ID of the user making the change.
65
+ """
66
+ self.previous_version = self.version
67
+ self.version = uuid4().hex
68
+ self.changed_on = datetime.utcnow()
69
+ self.changed_by_id = changed_by_id
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.1
2
+ Name: rococo
3
+ Version: 0.1.6
4
+ Summary: A Python library to help build things the way we want them built
5
+ Home-page: https://github.com/EcorRouge/rococo
6
+ Author: Jay Grieves
7
+ Author-email: jaygrieves@gmail.com
8
+ License: MIT
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: surrealdb==0.3.1
13
+ Requires-Dist: boto3==1.28.55
14
+ Requires-Dist: pika==1.3.2
15
+
16
+ # rococo
17
+ A Python library to help build things the way we want them built.
18
+
19
+
20
+ ## Basic Usage
21
+
22
+ ### Installation
23
+
24
+ Install using pip:
25
+
26
+ ```bash
27
+ pip install rococo
28
+ ```
29
+
30
+ ### Example
31
+
32
+ #### Models
33
+
34
+ ```python
35
+ from rococo.models import Person
36
+
37
+ # Initialize a Person object from rococo's built-in models.
38
+ someone = Person(first_name="John", last_name="Doe")
39
+
40
+ # Prepare to save the object in the database adding/updating attributes for the object.
41
+ someone.prepare_for_save(changed_by_id="jane_doe")
42
+
43
+ someone.as_dict()
44
+
45
+ {
46
+ 'active': True,
47
+ 'changed_by_id': 'jane_doe',
48
+ 'changed_on': datetime.datetime(2023, 9, 20, 19, 50, 23, 532875),
49
+ 'entity_id': 'e06876705b364640a20efc165f6ffb76',
50
+ 'first_name': 'John',
51
+ 'last_name': 'Doe',
52
+ 'previous_version': '7e63a5d0aa0f43b5aa9c8cc0634c41f2',
53
+ 'version': '08489d2bc5d74f78b7af0f2c1d9c5498'
54
+ }
55
+ ```
56
+
57
+ #### Messaging
58
+
59
+
60
+ ##### RabbitMQ
61
+ ```python
62
+ # Producer
63
+ from rococo.messaging import RabbitMqConnection
64
+
65
+ with RabbitMqConnection('host', 'port', 'username', 'password', 'virtual_host') as conn:
66
+ conn.send_message('queue_name', {'message': 'data'})
67
+
68
+
69
+ # Consumer
70
+ from rococo.messaging import RabbitMqConnection
71
+
72
+ def process_message(message_data: dict):
73
+ print(f"Processing message {message_data}...")
74
+
75
+ with RabbitMqConnection('host', 'port', 'username', 'password', 'virtual_host') as conn:
76
+ conn.consume_messages('queue_name', process_message)
77
+ ```
78
+
79
+ ##### SQS
80
+ ```python
81
+ # Producer
82
+ from rococo.messaging import SqsConnection
83
+
84
+ with SqsConnection(region_name='us-east-1') as conn:
85
+ conn.send_message('queue_name', {'message': 'data'})
86
+
87
+
88
+ # Consumer
89
+ from rococo.messaging import SqsConnection
90
+
91
+ def process_message(message_data: dict):
92
+ print(f"Processing message {message_data}...")
93
+
94
+ with SqsConnection(region_name='us-east-1') as conn:
95
+ conn.consume_messages('queue_name', process_message)
96
+
97
+ # Note: since cleanup is not required for SQS connections, you can also do:
98
+ conn = SqsConnection(region_name='us-east-1')
99
+ conn.send_message('queue_name', {'message': 'data'})
100
+ conn.consume_messages('queue_name', process_message)
101
+ ```
102
+
103
+ #### Data
104
+
105
+ ##### SurrealDB
106
+ ```python
107
+ from rococo.data import SurrealDbAdapter
108
+
109
+ def get_db_connection():
110
+ endpoint = "ws://localhost:8000/rpc"
111
+ username = "myuser"
112
+ password = "mypassword"
113
+ namespace = "test"
114
+ database = "test"
115
+
116
+ return SurrealDbAdapter(endpoint, username, password, namespace, database)
117
+
118
+
119
+ with get_db_connection() as db:
120
+ db.execute_query("""insert into person {
121
+ user: 'me',
122
+ pass: 'very_safe',
123
+ tags: ['python', 'documentation']
124
+ };""")
125
+ print(db.execute_query("SELECT * FROM person;", {}))
126
+ ```
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ rococo/__init__.py
5
+ rococo.egg-info/PKG-INFO
6
+ rococo.egg-info/SOURCES.txt
7
+ rococo.egg-info/dependency_links.txt
8
+ rococo.egg-info/requires.txt
9
+ rococo.egg-info/top_level.txt
10
+ rococo/data/__init__.py
11
+ rococo/data/base.py
12
+ rococo/data/surrealdb.py
13
+ rococo/messaging/__init__.py
14
+ rococo/messaging/base.py
15
+ rococo/messaging/rabbitmq.py
16
+ rococo/messaging/sqs.py
17
+ rococo/models/__init__.py
18
+ rococo/models/login_method.py
19
+ rococo/models/organization.py
20
+ rococo/models/otp_method.py
21
+ rococo/models/person.py
22
+ rococo/models/person_organization_role.py
23
+ rococo/models/versioned_model.py
@@ -0,0 +1,3 @@
1
+ surrealdb==0.3.1
2
+ boto3==1.28.55
3
+ pika==1.3.2
@@ -1,9 +1,9 @@
1
- from setuptools import setup
1
+ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='rococo',
5
- version='0.1.2',
6
- packages=['rococo'],
5
+ version='0.1.6',
6
+ packages=find_packages(),
7
7
  url='https://github.com/EcorRouge/rococo',
8
8
  license='MIT',
9
9
  author='Jay Grieves',
@@ -11,5 +11,10 @@ setup(
11
11
  description='A Python library to help build things the way we want them built',
12
12
  long_description=open('README.md').read(),
13
13
  long_description_content_type='text/markdown',
14
+ install_requires=[
15
+ 'surrealdb==0.3.1',
16
+ 'boto3==1.28.55',
17
+ 'pika==1.3.2'
18
+ ],
14
19
  python_requires=">=3.10"
15
20
  )
rococo-0.1.2/PKG-INFO DELETED
@@ -1,51 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: rococo
3
- Version: 0.1.2
4
- Summary: A Python library to help build things the way we want them built
5
- Home-page: https://github.com/EcorRouge/rococo
6
- Author: Jay Grieves
7
- Author-email: jaygrieves@gmail.com
8
- License: MIT
9
- Requires-Python: >=3.10
10
- Description-Content-Type: text/markdown
11
- License-File: LICENSE
12
-
13
- # rococo
14
- A Python library to help build things the way we want them built.
15
-
16
-
17
- ## Basic Usage
18
-
19
- ### Installation
20
-
21
- Install using pip:
22
-
23
- ```bash
24
- pip install rococo
25
- ```
26
-
27
- ### Example
28
-
29
- ```python
30
- from rococo.models import Person
31
-
32
- # Initialize a Person object from rococo's built-in models.
33
- someone = Person(first_name="John", last_name="Doe")
34
-
35
- # Prepare to save the object in the database adding/updating attributes for the object.
36
- someone.prepare_for_save(changed_by_id="jane_doe")
37
-
38
- someone.as_dict()
39
-
40
- {
41
- 'active': True,
42
- 'changed_by_id': 'jane_doe',
43
- 'changed_on': datetime.datetime(2023, 9, 20, 19, 50, 23, 532875),
44
- 'entity_id': 'e06876705b364640a20efc165f6ffb76',
45
- 'first_name': 'John',
46
- 'last_name': 'Doe',
47
- 'previous_version': '7e63a5d0aa0f43b5aa9c8cc0634c41f2',
48
- 'version': '08489d2bc5d74f78b7af0f2c1d9c5498'
49
- }
50
- ```
51
-
rococo-0.1.2/README.md DELETED
@@ -1,39 +0,0 @@
1
- # rococo
2
- A Python library to help build things the way we want them built.
3
-
4
-
5
- ## Basic Usage
6
-
7
- ### Installation
8
-
9
- Install using pip:
10
-
11
- ```bash
12
- pip install rococo
13
- ```
14
-
15
- ### Example
16
-
17
- ```python
18
- from rococo.models import Person
19
-
20
- # Initialize a Person object from rococo's built-in models.
21
- someone = Person(first_name="John", last_name="Doe")
22
-
23
- # Prepare to save the object in the database adding/updating attributes for the object.
24
- someone.prepare_for_save(changed_by_id="jane_doe")
25
-
26
- someone.as_dict()
27
-
28
- {
29
- 'active': True,
30
- 'changed_by_id': 'jane_doe',
31
- 'changed_on': datetime.datetime(2023, 9, 20, 19, 50, 23, 532875),
32
- 'entity_id': 'e06876705b364640a20efc165f6ffb76',
33
- 'first_name': 'John',
34
- 'last_name': 'Doe',
35
- 'previous_version': '7e63a5d0aa0f43b5aa9c8cc0634c41f2',
36
- 'version': '08489d2bc5d74f78b7af0f2c1d9c5498'
37
- }
38
- ```
39
-
@@ -1,51 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: rococo
3
- Version: 0.1.2
4
- Summary: A Python library to help build things the way we want them built
5
- Home-page: https://github.com/EcorRouge/rococo
6
- Author: Jay Grieves
7
- Author-email: jaygrieves@gmail.com
8
- License: MIT
9
- Requires-Python: >=3.10
10
- Description-Content-Type: text/markdown
11
- License-File: LICENSE
12
-
13
- # rococo
14
- A Python library to help build things the way we want them built.
15
-
16
-
17
- ## Basic Usage
18
-
19
- ### Installation
20
-
21
- Install using pip:
22
-
23
- ```bash
24
- pip install rococo
25
- ```
26
-
27
- ### Example
28
-
29
- ```python
30
- from rococo.models import Person
31
-
32
- # Initialize a Person object from rococo's built-in models.
33
- someone = Person(first_name="John", last_name="Doe")
34
-
35
- # Prepare to save the object in the database adding/updating attributes for the object.
36
- someone.prepare_for_save(changed_by_id="jane_doe")
37
-
38
- someone.as_dict()
39
-
40
- {
41
- 'active': True,
42
- 'changed_by_id': 'jane_doe',
43
- 'changed_on': datetime.datetime(2023, 9, 20, 19, 50, 23, 532875),
44
- 'entity_id': 'e06876705b364640a20efc165f6ffb76',
45
- 'first_name': 'John',
46
- 'last_name': 'Doe',
47
- 'previous_version': '7e63a5d0aa0f43b5aa9c8cc0634c41f2',
48
- 'version': '08489d2bc5d74f78b7af0f2c1d9c5498'
49
- }
50
- ```
51
-
@@ -1,8 +0,0 @@
1
- LICENSE
2
- README.md
3
- setup.py
4
- rococo/__init__.py
5
- rococo.egg-info/PKG-INFO
6
- rococo.egg-info/SOURCES.txt
7
- rococo.egg-info/dependency_links.txt
8
- rococo.egg-info/top_level.txt
File without changes
File without changes
File without changes