mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-10 01:17:42 +01:00
"mqtt added"
This commit is contained in:
parent
9c3a1f564b
commit
12857c73ef
50 changed files with 10834 additions and 113 deletions
|
@ -1 +1 @@
|
||||||
__version__ = "4.0.0.31"
|
__version__ = "4.0.0.32"
|
|
@ -60,7 +60,7 @@ class Actor:
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "name={} props={}, state={}, type={}".format(self.name, self.props, self.state, self.type)
|
return "name={} props={}, state={}, type={}".format(self.name, self.props, self.state, self.type)
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return dict(id=self.id, name=self.name, type=self.type, props=self.props.to_dict(), state=self.instance.get_state())
|
return dict(id=self.id, name=self.name, type=self.type, props=self.props.to_dict(), state2="HELLO WORLD", state=self.instance.get_state())
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -150,3 +150,12 @@ class NotificationAction:
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return dict(id=self.id, label=self.label)
|
return dict(id=self.id, label=self.label)
|
||||||
|
|
||||||
|
class NotificationType(Enum):
|
||||||
|
INFO="info"
|
||||||
|
WARNING="warning"
|
||||||
|
ERROR="error"
|
||||||
|
SUCCESS="success"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
|
@ -35,6 +35,7 @@ class CBPiSensor(CBPiBase, metaclass=ABCMeta):
|
||||||
def push_update(self, value):
|
def push_update(self, value):
|
||||||
try:
|
try:
|
||||||
self.cbpi.ws.send(dict(topic="sensorstate", id=self.id, value=value))
|
self.cbpi.ws.send(dict(topic="sensorstate", id=self.id, value=value))
|
||||||
|
self.cbpi.push_update("cbpi/sensor/{}/udpate".format(self.id), dict(id=self.id, value=value), retain=True)
|
||||||
except:
|
except:
|
||||||
logging.error("Faild to push sensor update")
|
logging.error("Faild to push sensor update")
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ index_url: /cbpi_ui/static/index.html
|
||||||
|
|
||||||
port: 8000
|
port: 8000
|
||||||
|
|
||||||
|
mqtt: false
|
||||||
|
mqtt_host: localhost
|
||||||
|
mqtt_port: 1883
|
||||||
|
mqtt_username: ""
|
||||||
|
mqtt_password: ""
|
||||||
|
|
||||||
username: cbpi
|
username: cbpi
|
||||||
password: 123
|
password: 123
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,14 @@ class ActorController(BasicController):
|
||||||
super(ActorController, self).__init__(cbpi, Actor,"actor.json")
|
super(ActorController, self).__init__(cbpi, Actor,"actor.json")
|
||||||
self.update_key = "actorupdate"
|
self.update_key = "actorupdate"
|
||||||
|
|
||||||
|
|
||||||
async def on(self, id):
|
async def on(self, id):
|
||||||
try:
|
try:
|
||||||
item = self.find_by_id(id)
|
item = self.find_by_id(id)
|
||||||
|
|
||||||
if item.instance.state is False:
|
if item.instance.state is False:
|
||||||
await item.instance.on()
|
await item.instance.on()
|
||||||
await self.push_udpate()
|
await self.push_udpate()
|
||||||
#await self.cbpi.satellite.publish("cbpi/actor/on", "ACTOR ON")
|
self.cbpi.push_update("cbpi/actor/"+id, item.to_dict(), True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
|
|
||||||
|
@ -26,14 +25,16 @@ class ActorController(BasicController):
|
||||||
if item.instance.state is True:
|
if item.instance.state is True:
|
||||||
await item.instance.off()
|
await item.instance.off()
|
||||||
await self.push_udpate()
|
await self.push_udpate()
|
||||||
|
self.cbpi.push_update("cbpi/actor/"+id, item.to_dict())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
logging.error("Faild to switch on Actor {} {}".format(id, e), True)
|
||||||
|
|
||||||
async def toogle(self, id):
|
async def toogle(self, id):
|
||||||
try:
|
try:
|
||||||
item = self.find_by_id(id)
|
item = self.find_by_id(id)
|
||||||
instance = item.get("instance")
|
instance = item.get("instance")
|
||||||
await instance.toggle()
|
await instance.toggle()
|
||||||
|
self.cbpi.push_update("cbpi/actor/update", item.to_dict())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
|
|
|
@ -30,7 +30,6 @@ class BasicController:
|
||||||
await self.load()
|
await self.load()
|
||||||
|
|
||||||
def create(self, data):
|
def create(self, data):
|
||||||
|
|
||||||
return self.resource(data.get("id"), data.get("name"), type=data.get("type"), props=Props(data.get("props", {})) )
|
return self.resource(data.get("id"), data.get("name"), type=data.get("type"), props=Props(data.get("props", {})) )
|
||||||
|
|
||||||
async def load(self):
|
async def load(self):
|
||||||
|
@ -56,6 +55,7 @@ class BasicController:
|
||||||
|
|
||||||
async def push_udpate(self):
|
async def push_udpate(self):
|
||||||
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
|
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
|
||||||
|
self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
|
||||||
|
|
||||||
def find_by_id(self, id):
|
def find_by_id(self, id):
|
||||||
return next((item for item in self.data if item.id == id), None)
|
return next((item for item in self.data if item.id == id), None)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from cbpi.api.dataclasses import NotificationType
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
@ -29,9 +30,10 @@ class DashboardController:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
async def add_content(self, dashboard_id, data):
|
async def add_content(self, dashboard_id, data):
|
||||||
|
print(data)
|
||||||
with open(self.path, 'w') as outfile:
|
with open(self.path, 'w') as outfile:
|
||||||
json.dump(data, outfile, indent=4, sort_keys=True)
|
json.dump(data, outfile, indent=4, sort_keys=True)
|
||||||
self.cbpi.notify(title="Dashboard", message="Saved Successfully", type="success")
|
self.cbpi.notify(title="Dashboard", message="Saved Successfully", type=NotificationType.SUCCESS)
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
|
||||||
async def delete_content(self, dashboard_id):
|
async def delete_content(self, dashboard_id):
|
||||||
|
|
|
@ -1,18 +1,36 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from cbpi.api.dataclasses import NotificationType
|
||||||
import logging
|
import logging
|
||||||
import shortuuid
|
import shortuuid
|
||||||
class NotificationController:
|
class NotificationController:
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
:param cbpi: craftbeerpi object
|
:param cbpi: craftbeerpi object
|
||||||
'''
|
'''
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
self.callback_cache = {}
|
self.callback_cache = {}
|
||||||
|
self.listener = {}
|
||||||
|
|
||||||
def notify(self, title, message: str, type: str = "info", action=[]) -> None:
|
def add_listener(self, method):
|
||||||
|
listener_id = shortuuid.uuid()
|
||||||
|
self.listener[listener_id] = method
|
||||||
|
return listener_id
|
||||||
|
|
||||||
|
def remove_listener(self, listener_id):
|
||||||
|
try:
|
||||||
|
del self.listener[listener_id]
|
||||||
|
except:
|
||||||
|
self.logger.error("Faild to remove listener {}".format(listener_id))
|
||||||
|
|
||||||
|
async def _call_listener(self, title, message, type, action):
|
||||||
|
for id, method in self.listener.items():
|
||||||
|
print(id, method)
|
||||||
|
asyncio.create_task(method(self.cbpi, title, message, type, action ))
|
||||||
|
|
||||||
|
|
||||||
|
def notify(self, title, message: str, type: NotificationType = NotificationType.INFO, action=[]) -> None:
|
||||||
'''
|
'''
|
||||||
This is a convinience method to send notification to the client
|
This is a convinience method to send notification to the client
|
||||||
|
|
||||||
|
@ -29,7 +47,11 @@ class NotificationController:
|
||||||
|
|
||||||
actions = list(map(lambda item: prepare_action(item), action))
|
actions = list(map(lambda item: prepare_action(item), action))
|
||||||
self.callback_cache[notifcation_id] = action
|
self.callback_cache[notifcation_id] = action
|
||||||
self.cbpi.ws.send(dict(id=notifcation_id, topic="notifiaction", type=type, title=title, message=message, action=actions))
|
self.cbpi.ws.send(dict(id=notifcation_id, topic="notifiaction", type=type.value, title=title, message=message, action=actions))
|
||||||
|
data = dict(type=type.value, title=title, message=message, action=actions)
|
||||||
|
self.cbpi.push_update(topic="cbpi/notification", data=data)
|
||||||
|
asyncio.create_task(self._call_listener(title, message, type, action))
|
||||||
|
|
||||||
|
|
||||||
def notify_callback(self, notification_id, action_id) -> None:
|
def notify_callback(self, notification_id, action_id) -> None:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,38 +1,82 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import json
|
||||||
from asyncio_mqtt import Client, MqttError, Will
|
from re import M
|
||||||
|
from asyncio_mqtt import Client, MqttError, Will, client
|
||||||
from contextlib import AsyncExitStack, asynccontextmanager
|
from contextlib import AsyncExitStack, asynccontextmanager
|
||||||
|
from cbpi import __version__
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class SatelliteController:
|
class SatelliteController:
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
self.host = cbpi.static_config.get("mqtt_host", "localhost")
|
||||||
|
self.port = cbpi.static_config.get("mqtt_port", 1883)
|
||||||
|
self.username = cbpi.static_config.get("mqtt_username", None)
|
||||||
|
self.password = cbpi.static_config.get("mqtt_password", None)
|
||||||
self.client = None
|
self.client = None
|
||||||
|
self.topic_filters = [
|
||||||
|
("cbpi/actor/+/on", self._actor_on),
|
||||||
|
("cbpi/actor/+/off", self._actor_off)
|
||||||
|
]
|
||||||
|
self.tasks = set()
|
||||||
|
|
||||||
async def init(self):
|
async def init(self):
|
||||||
asyncio.create_task(self.init_client(self.cbpi))
|
asyncio.create_task(self.init_client(self.cbpi))
|
||||||
|
|
||||||
async def publish(self, topic, message):
|
async def publish(self, topic, message, retain=False):
|
||||||
print("MQTT ON")
|
if self.client is not None and self.client._connected:
|
||||||
await self.client.publish(topic, message, qos=1)
|
try:
|
||||||
|
await self.client.publish(topic, message, qos=1, retain=retain)
|
||||||
|
except:
|
||||||
|
self.logger.warning("Faild to push data via mqtt")
|
||||||
|
|
||||||
async def handle_message(self, messages):
|
async def _actor_on(self, messages):
|
||||||
async for message in messages:
|
async for message in messages:
|
||||||
print("FILTERED", message.payload.decode())
|
try:
|
||||||
|
topic_key = message.topic.split("/")
|
||||||
|
await self.cbpi.actor.on(topic_key[2])
|
||||||
|
except:
|
||||||
|
self.logger.warning("Faild to process actor on via mqtt")
|
||||||
|
|
||||||
async def handle_unfilterd_message(self, messages):
|
async def _actor_off(self, messages):
|
||||||
async for message in messages:
|
async for message in messages:
|
||||||
print("UNFILTERED", message.payload.decode())
|
try:
|
||||||
|
topic_key = message.topic.split("/")
|
||||||
|
await self.cbpi.actor.off(topic_key[2])
|
||||||
|
except:
|
||||||
|
self.logger.warning("Faild to process actor off via mqtt")
|
||||||
|
|
||||||
|
def subcribe(self, topic, method):
|
||||||
|
task = asyncio.create_task(self._subcribe(topic, method))
|
||||||
|
return task
|
||||||
|
|
||||||
|
async def _subcribe(self, topic, method):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if self.client._connected.done():
|
||||||
|
async with self.client.filtered_messages(topic) as messages:
|
||||||
|
await self.client.subscribe(topic)
|
||||||
|
async for message in messages:
|
||||||
|
await method(message.payload.decode())
|
||||||
|
except asyncio.CancelledError as e:
|
||||||
|
# Cancel
|
||||||
|
self.logger.warning(
|
||||||
|
"Sub CancelledError Exception: {}".format(e))
|
||||||
|
return
|
||||||
|
except MqttError as e:
|
||||||
|
self.logger.error("Sub MQTT Exception: {}".format(e))
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error("Sub Exception: {}".format(e))
|
||||||
|
|
||||||
|
# wait before try to resubscribe
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
async def init_client(self, cbpi):
|
async def init_client(self, cbpi):
|
||||||
async def log_messages(messages, template):
|
|
||||||
|
|
||||||
async for message in messages:
|
|
||||||
print(template.format(message.payload.decode()))
|
|
||||||
|
|
||||||
async def cancel_tasks(tasks):
|
async def cancel_tasks(tasks):
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
|
@ -44,31 +88,32 @@ class SatelliteController:
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
async with AsyncExitStack() as stack:
|
async with AsyncExitStack() as stack:
|
||||||
|
self.tasks = set()
|
||||||
|
stack.push_async_callback(cancel_tasks, self.tasks)
|
||||||
|
self.client = Client(self.host, port=self.port, username=self.username, password=self.password, will=Will(topic="cbpi/diconnect", payload="CBPi Server Disconnected"))
|
||||||
|
|
||||||
tasks = set()
|
|
||||||
stack.push_async_callback(cancel_tasks, tasks)
|
|
||||||
|
|
||||||
self.client = Client("localhost", will=Will(topic="cbpi/diconnect", payload="CBPi Server Disconnected"))
|
|
||||||
await stack.enter_async_context(self.client)
|
await stack.enter_async_context(self.client)
|
||||||
|
|
||||||
topic_filters = (
|
for topic_filter in self.topic_filters:
|
||||||
"cbpi/sensor/#",
|
topic = topic_filter[0]
|
||||||
"cbpi/actor/#"
|
method = topic_filter[1]
|
||||||
)
|
manager = self.client.filtered_messages(topic)
|
||||||
for topic_filter in topic_filters:
|
|
||||||
# Log all messages that matches the filter
|
|
||||||
manager = self.client.filtered_messages(topic_filter)
|
|
||||||
messages = await stack.enter_async_context(manager)
|
messages = await stack.enter_async_context(manager)
|
||||||
task = asyncio.create_task(self.handle_message(messages))
|
task = asyncio.create_task(method(messages))
|
||||||
tasks.add(task)
|
self.tasks.add(task)
|
||||||
|
|
||||||
messages = await stack.enter_async_context(self.client.unfiltered_messages())
|
for topic_filter in self.topic_filters:
|
||||||
task = asyncio.create_task(self.handle_unfilterd_message(messages))
|
topic = topic_filter[0]
|
||||||
tasks.add(task)
|
await self.client.subscribe(topic)
|
||||||
|
|
||||||
await self.client.subscribe("cbpi/#")
|
self.logger.info("MQTT Connected to {}:{}".format(self.host, self.port))
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*self.tasks)
|
||||||
|
|
||||||
|
except MqttError as e:
|
||||||
|
self.logger.error("MQTT Exception: {}".format(e))
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error("MQTT General Exception: {}".format(e))
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
|
@ -78,7 +78,6 @@ class StepController:
|
||||||
try:
|
try:
|
||||||
type_cfg = self.types.get(item.type)
|
type_cfg = self.types.get(item.type)
|
||||||
clazz = type_cfg.get("class")
|
clazz = type_cfg.get("class")
|
||||||
print("CLASS", clazz)
|
|
||||||
item.instance = clazz(self.cbpi, item.id, item.name, item.props, self.done)
|
item.instance = clazz(self.cbpi, item.id, item.name, item.props, self.done)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning("Failed to create step instance %s - %s " % (id, e))
|
logging.warning("Failed to create step instance %s - %s " % (id, e))
|
||||||
|
@ -258,6 +257,8 @@ class StepController:
|
||||||
else:
|
else:
|
||||||
self.cbpi.ws.send(dict(topic="step_update", data=list(map(lambda item: item.to_dict(), self.profile))))
|
self.cbpi.ws.send(dict(topic="step_update", data=list(map(lambda item: item.to_dict(), self.profile))))
|
||||||
|
|
||||||
|
self.cbpi.push_update(topic="cbpi/stepupdate", data=list(map(lambda item: item.to_dict(), self.profile)))
|
||||||
|
|
||||||
async def start_step(self,step):
|
async def start_step(self,step):
|
||||||
try:
|
try:
|
||||||
logging.info("Try to start step %s" % step)
|
logging.info("Try to start step %s" % step)
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
from voluptuous.schema_builder import message
|
||||||
|
from cbpi.api.dataclasses import NotificationType
|
||||||
from cbpi.controller.notification_controller import NotificationController
|
from cbpi.controller.notification_controller import NotificationController
|
||||||
import logging
|
import logging
|
||||||
from os import urandom
|
from os import urandom
|
||||||
|
@ -22,6 +26,7 @@ from cbpi.controller.sensor_controller import SensorController
|
||||||
from cbpi.controller.step_controller import StepController
|
from cbpi.controller.step_controller import StepController
|
||||||
from cbpi.controller.recipe_controller import RecipeController
|
from cbpi.controller.recipe_controller import RecipeController
|
||||||
from cbpi.controller.system_controller import SystemController
|
from cbpi.controller.system_controller import SystemController
|
||||||
|
from cbpi.controller.satellite_controller import SatelliteController
|
||||||
|
|
||||||
from cbpi.controller.log_file_controller import LogController
|
from cbpi.controller.log_file_controller import LogController
|
||||||
|
|
||||||
|
@ -102,7 +107,10 @@ class CraftBeerPi:
|
||||||
self.step : StepController = StepController(self)
|
self.step : StepController = StepController(self)
|
||||||
self.recipe : RecipeController = RecipeController(self)
|
self.recipe : RecipeController = RecipeController(self)
|
||||||
self.notification : NotificationController = NotificationController(self)
|
self.notification : NotificationController = NotificationController(self)
|
||||||
#self.satellite: SatelliteController = SatelliteController(self)
|
self.satellite = None
|
||||||
|
if self.static_config.get("mqtt", False) is True:
|
||||||
|
self.satellite: SatelliteController = SatelliteController(self)
|
||||||
|
|
||||||
self.dashboard = DashboardController(self)
|
self.dashboard = DashboardController(self)
|
||||||
self.http_step = StepHttpEndpoints(self)
|
self.http_step = StepHttpEndpoints(self)
|
||||||
self.http_recipe = RecipeHttpEndpoints(self)
|
self.http_recipe = RecipeHttpEndpoints(self)
|
||||||
|
@ -212,9 +220,11 @@ class CraftBeerPi:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def notify(self, title: str, message: str, type: str = "info", action=[]) -> None:
|
def notify(self, title: str, message: str, type: NotificationType = NotificationType.INFO, action=[]) -> None:
|
||||||
self.notification.notify(title, message, type, action)
|
self.notification.notify(title, message, type, action)
|
||||||
|
|
||||||
|
def push_update(self, topic, data, retain=False) -> None:
|
||||||
|
asyncio.create_task(self.satellite.publish(topic=topic, message=json.dumps(data), retain=retain))
|
||||||
|
|
||||||
async def call_initializer(self, app):
|
async def call_initializer(self, app):
|
||||||
self.initializer = sorted(self.initializer, key=lambda k: k['order'])
|
self.initializer = sorted(self.initializer, key=lambda k: k['order'])
|
||||||
|
@ -249,6 +259,8 @@ class CraftBeerPi:
|
||||||
await self.job.init()
|
await self.job.init()
|
||||||
|
|
||||||
await self.config.init()
|
await self.config.init()
|
||||||
|
if self.satellite is not None:
|
||||||
|
await self.satellite.init()
|
||||||
self._setup_http_index()
|
self._setup_http_index()
|
||||||
self.plugin.load_plugins()
|
self.plugin.load_plugins()
|
||||||
self.plugin.load_plugins_from_evn()
|
self.plugin.load_plugins_from_evn()
|
||||||
|
@ -259,7 +271,8 @@ class CraftBeerPi:
|
||||||
await self.kettle.init()
|
await self.kettle.init()
|
||||||
await self.call_initializer(self.app)
|
await self.call_initializer(self.app)
|
||||||
await self.dashboard.init()
|
await self.dashboard.init()
|
||||||
#await self.satellite.init()
|
|
||||||
|
|
||||||
self._swagger_setup()
|
self._swagger_setup()
|
||||||
|
|
||||||
return self.app
|
return self.app
|
||||||
|
|
|
@ -2,7 +2,7 @@ from socket import timeout
|
||||||
from typing import KeysView
|
from typing import KeysView
|
||||||
|
|
||||||
from voluptuous.schema_builder import message
|
from voluptuous.schema_builder import message
|
||||||
from cbpi.api.dataclasses import NotificationAction
|
from cbpi.api.dataclasses import NotificationAction, NotificationType
|
||||||
import logging
|
import logging
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
@ -17,10 +17,9 @@ class DummyActor(CBPiActor):
|
||||||
def __init__(self, cbpi, id, props):
|
def __init__(self, cbpi, id, props):
|
||||||
super().__init__(cbpi, id, props)
|
super().__init__(cbpi, id, props)
|
||||||
|
|
||||||
async def yes(self, **kwargs):
|
@action("SAY HELLO", {})
|
||||||
print("YES!")
|
async def helloWorld(self, **kwargs):
|
||||||
await self.cbpi.step.next()
|
self.cbpi.notify("HELLO", "WOOHO", NotificationType.ERROR)
|
||||||
|
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
await super().start()
|
await super().start()
|
||||||
|
|
|
@ -38,7 +38,7 @@ class MashStep(CBPiStep):
|
||||||
self.timer = Timer(int(self.props.Timer) *60 ,on_update=self.on_timer_update, on_done=self.on_timer_done)
|
self.timer = Timer(int(self.props.Timer) *60 ,on_update=self.on_timer_update, on_done=self.on_timer_done)
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
while self.running == True:
|
while True:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
sensor_value = self.get_sensor_value(self.props.Sensor)
|
sensor_value = self.get_sensor_value(self.props.Sensor)
|
||||||
if sensor_value.get("value") >= int(self.props.Temp) and self.timer.is_running is not True:
|
if sensor_value.get("value") >= int(self.props.Temp) and self.timer.is_running is not True:
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
import json
|
|
||||||
|
|
||||||
from cbpi.utils.encoder import ComplexEncoder
|
|
||||||
from hbmqtt.mqtt.constants import QOS_0
|
|
||||||
from hbmqtt.client import MQTTClient
|
|
||||||
from hbmqtt.mqtt.constants import QOS_1, QOS_2
|
|
||||||
from asyncio_mqtt import Client, MqttError, Will
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
class CBPiMqttClient:
|
|
||||||
def __init__(self, cbpi):
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self.cbpi.bus.register("#", self.listen)
|
|
||||||
self.client = None
|
|
||||||
self._loop = asyncio.get_event_loop()
|
|
||||||
self._loop.create_task(self.init_client(self.cbpi))
|
|
||||||
|
|
||||||
async def init_client(self, cbpi):
|
|
||||||
|
|
||||||
async with Client("localhost", will=Will(topic="cbpi/diconnect", payload="MY CLIENT"))as client:
|
|
||||||
async with client.filtered_messages("cbpi/#") as messages:
|
|
||||||
await client.subscribe("cbpi/#")
|
|
||||||
async for message in messages:
|
|
||||||
await self.cbpi.actor.on("YwGzXvWMpmbLb6XobesL8n")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def listen(self, topic, **kwargs):
|
|
||||||
if self.client is not None:
|
|
||||||
await self.client.publish(topic, str.encode(json.dumps(kwargs, cls=ComplexEncoder)), QOS_0)
|
|
||||||
|
|
||||||
def setup(cbpi):
|
|
||||||
'''
|
|
||||||
This method is called by the server during startup
|
|
||||||
Here you need to register your plugins at the server
|
|
||||||
|
|
||||||
:param cbpi: the cbpi core
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
|
|
||||||
client = CBPiMqttClient(cbpi)
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
name: MQTT
|
|
||||||
version: 4
|
|
||||||
active: false
|
|
49
cbpi/extension/mqtt_sensor/__init__.py
Normal file
49
cbpi/extension/mqtt_sensor/__init__.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import asyncio
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
from aiohttp import web
|
||||||
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
|
@parameters([Property.Text(label="Topic", configurable=True)])
|
||||||
|
class MQTTSensor(CBPiSensor):
|
||||||
|
|
||||||
|
async def on_message(self, message):
|
||||||
|
try:
|
||||||
|
self.value = message
|
||||||
|
self.log_data(self.value)
|
||||||
|
self.push_update(message)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, props):
|
||||||
|
super(MQTTSensor, self).__init__(cbpi, id, props)
|
||||||
|
self.mqtt_task = self.cbpi.satellite.subcribe(self.props.Topic, self.on_message)
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
while self.running == True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return dict(value=self.value)
|
||||||
|
|
||||||
|
async def on_stop(self):
|
||||||
|
if self.mqtt_task.done() is False:
|
||||||
|
self.mqtt_task.cancel()
|
||||||
|
try:
|
||||||
|
await self.mqtt_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setup(cbpi):
|
||||||
|
|
||||||
|
'''
|
||||||
|
This method is called by the server during startup
|
||||||
|
Here you need to register your plugins at the server
|
||||||
|
|
||||||
|
:param cbpi: the cbpi core
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
if cbpi.static_config.get("mqtt", False) is True:
|
||||||
|
cbpi.plugin.register("MQTTSensor", MQTTSensor)
|
3
cbpi/extension/mqtt_sensor/config.yaml
Normal file
3
cbpi/extension/mqtt_sensor/config.yaml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
name: DummySensor
|
||||||
|
version: 4
|
||||||
|
active: true
|
|
@ -69,6 +69,7 @@ class DashBoardHttpEndpoints:
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
dashboard_id = int(request.match_info['id'])
|
dashboard_id = int(request.match_info['id'])
|
||||||
await self.cbpi.dashboard.add_content(dashboard_id, data)
|
await self.cbpi.dashboard.add_content(dashboard_id, data)
|
||||||
|
print("##### SAVE")
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/content", method="DELETE", auth_required=False)
|
@request_mapping(path="/{id:\d+}/content", method="DELETE", auth_required=False)
|
||||||
|
|
11
venv3/bin/autopep8
Executable file
11
venv3/bin/autopep8
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/Users/manuelfritsch/Documents/git/cbpi4/venv3/bin/python3
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from autopep8 import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||||
|
sys.exit(main())
|
11
venv3/bin/pycodestyle
Executable file
11
venv3/bin/pycodestyle
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/Users/manuelfritsch/Documents/git/cbpi4/venv3/bin/python3
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pycodestyle import _main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||||
|
sys.exit(_main())
|
|
@ -0,0 +1,48 @@
|
||||||
|
Main contributors
|
||||||
|
-----------------
|
||||||
|
- Hideo Hattori (https://github.com/hhatto)
|
||||||
|
- Steven Myint (https://github.com/myint)
|
||||||
|
- Bill Wendling (https://github.com/gwelymernans)
|
||||||
|
|
||||||
|
Patches
|
||||||
|
-------
|
||||||
|
- Fraser Tweedale (https://github.com/frasertweedale)
|
||||||
|
- clach04 (https://github.com/clach04)
|
||||||
|
- Marc Abramowitz (https://github.com/msabramo)
|
||||||
|
- dellis23 (https://github.com/dellis23)
|
||||||
|
- Sam Vilain (https://github.com/samv)
|
||||||
|
- Florent Xicluna (https://github.com/florentx)
|
||||||
|
- Andras Tim (https://github.com/andras-tim)
|
||||||
|
- tomscytale (https://github.com/tomscytale)
|
||||||
|
- Filip Noetzel (https://github.com/peritus)
|
||||||
|
- Erik Bray (https://github.com/iguananaut)
|
||||||
|
- Christopher Medrela (https://github.com/chrismedrela)
|
||||||
|
- 小明 (https://github.com/dongweiming)
|
||||||
|
- Andy Hayden (https://github.com/hayd)
|
||||||
|
- Fabio Zadrozny (https://github.com/fabioz)
|
||||||
|
- Alex Chernetz (https://github.com/achernet)
|
||||||
|
- Marc Schlaich (https://github.com/schlamar)
|
||||||
|
- E. M. Bray (https://github.com/embray)
|
||||||
|
- Thomas Hisch (https://github.com/thisch)
|
||||||
|
- Florian Best (https://github.com/spaceone)
|
||||||
|
- Ian Clark (https://github.com/evenicoulddoit)
|
||||||
|
- Khairi Hafsham (https://github.com/khairihafsham)
|
||||||
|
- Neil Halelamien (https://github.com/neilsh)
|
||||||
|
- Hashem Nasarat (https://github.com/Hnasar)
|
||||||
|
- Hugo van Kemenade (https://github.com/hugovk)
|
||||||
|
- gmbnomis (https://github.com/gmbnomis)
|
||||||
|
- Samuel Lelièvre (https://github.com/slel)
|
||||||
|
- bigredengineer (https://github.com/bigredengineer)
|
||||||
|
- Kai Chen (https://github.com/kx-chen)
|
||||||
|
- Anthony Sottile (https://github.com/asottile)
|
||||||
|
- 秋葉 (https://github.com/Hanaasagi)
|
||||||
|
- Christian Clauss (https://github.com/cclauss)
|
||||||
|
- tobixx (https://github.com/tobixx)
|
||||||
|
- bigredengineer (https://github.com/bigredengineer)
|
||||||
|
- Bastien Gérard (https://github.com/bagerard)
|
||||||
|
- nicolasbonifas (https://github.com/nicolasbonifas)
|
||||||
|
- Andrii Yurchuk (https://github.com/Ch00k)
|
||||||
|
- José M. Guisado (https://github.com/pvxe)
|
||||||
|
- Dai Truong (https://github.com/NovaDev94)
|
||||||
|
- jnozsc (https://github.com/jnozsc)
|
||||||
|
- Edwin Shepherd (https://github.com/shardros)
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,23 @@
|
||||||
|
Copyright (C) 2010-2011 Hideo Hattori
|
||||||
|
Copyright (C) 2011-2013 Hideo Hattori, Steven Myint
|
||||||
|
Copyright (C) 2013-2016 Hideo Hattori, Steven Myint, Bill Wendling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,453 @@
|
||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: autopep8
|
||||||
|
Version: 1.5.5
|
||||||
|
Summary: A tool that automatically formats Python code to conform to the PEP 8 style guide
|
||||||
|
Home-page: https://github.com/hhatto/autopep8
|
||||||
|
Author: Hideo Hattori
|
||||||
|
Author-email: hhatto.jp@gmail.com
|
||||||
|
License: Expat License
|
||||||
|
Keywords: automation,pep8,format,pycodestyle
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Environment :: Console
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: MIT License
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: 3.8
|
||||||
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||||
|
Classifier: Topic :: Software Development :: Quality Assurance
|
||||||
|
Requires-Dist: pycodestyle (>=2.6.0)
|
||||||
|
Requires-Dist: toml
|
||||||
|
|
||||||
|
========
|
||||||
|
autopep8
|
||||||
|
========
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/autopep8.svg
|
||||||
|
:target: https://pypi.org/project/autopep8/
|
||||||
|
:alt: PyPI Version
|
||||||
|
|
||||||
|
.. image:: https://github.com/hhatto/autopep8/workflows/Python%20package/badge.svg
|
||||||
|
:target: https://github.com/hhatto/autopep8/actions
|
||||||
|
:alt: Build status
|
||||||
|
|
||||||
|
.. image:: https://codecov.io/gh/hhatto/autopep8/branch/master/graph/badge.svg
|
||||||
|
:target: https://codecov.io/gh/hhatto/autopep8
|
||||||
|
:alt: Code Coverage
|
||||||
|
|
||||||
|
autopep8 automatically formats Python code to conform to the `PEP 8`_ style
|
||||||
|
guide. It uses the pycodestyle_ utility to determine what parts of the code
|
||||||
|
needs to be formatted. autopep8 is capable of fixing most of the formatting
|
||||||
|
issues_ that can be reported by pycodestyle.
|
||||||
|
|
||||||
|
.. _PEP 8: https://www.python.org/dev/peps/pep-0008/
|
||||||
|
.. _issues: https://pycodestyle.readthedocs.org/en/latest/intro.html#error-codes
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
From pip::
|
||||||
|
|
||||||
|
$ pip install --upgrade autopep8
|
||||||
|
|
||||||
|
Consider using the ``--user`` option_.
|
||||||
|
|
||||||
|
.. _option: https://pip.pypa.io/en/latest/user_guide/#user-installs
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
============
|
||||||
|
|
||||||
|
autopep8 requires pycodestyle_.
|
||||||
|
|
||||||
|
.. _pycodestyle: https://github.com/PyCQA/pycodestyle
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
To modify a file in place (with aggressive level 2)::
|
||||||
|
|
||||||
|
$ autopep8 --in-place --aggressive --aggressive <filename>
|
||||||
|
|
||||||
|
Before running autopep8.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import math, sys;
|
||||||
|
|
||||||
|
def example1():
|
||||||
|
####This is a long comment. This should be wrapped to fit within 72 characters.
|
||||||
|
some_tuple=( 1,2, 3,'a' );
|
||||||
|
some_variable={'long':'Long code lines should be wrapped within 79 characters.',
|
||||||
|
'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
|
||||||
|
'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
|
||||||
|
20,300,40000,500000000,60000000000000000]}}
|
||||||
|
return (some_tuple, some_variable)
|
||||||
|
def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
|
||||||
|
class Example3( object ):
|
||||||
|
def __init__ ( self, bar ):
|
||||||
|
#Comments should have a space after the hash.
|
||||||
|
if bar : bar+=1; bar=bar* bar ; return bar
|
||||||
|
else:
|
||||||
|
some_string = """
|
||||||
|
Indentation in multiline strings should not be touched.
|
||||||
|
Only actual code should be reindented.
|
||||||
|
"""
|
||||||
|
return (sys.path, some_string)
|
||||||
|
|
||||||
|
After running autopep8.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import math
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def example1():
|
||||||
|
# This is a long comment. This should be wrapped to fit within 72
|
||||||
|
# characters.
|
||||||
|
some_tuple = (1, 2, 3, 'a')
|
||||||
|
some_variable = {
|
||||||
|
'long': 'Long code lines should be wrapped within 79 characters.',
|
||||||
|
'other': [
|
||||||
|
math.pi,
|
||||||
|
100,
|
||||||
|
200,
|
||||||
|
300,
|
||||||
|
9876543210,
|
||||||
|
'This is a long string that goes on'],
|
||||||
|
'more': {
|
||||||
|
'inner': 'This whole logical line should be wrapped.',
|
||||||
|
some_tuple: [
|
||||||
|
1,
|
||||||
|
20,
|
||||||
|
300,
|
||||||
|
40000,
|
||||||
|
500000000,
|
||||||
|
60000000000000000]}}
|
||||||
|
return (some_tuple, some_variable)
|
||||||
|
|
||||||
|
|
||||||
|
def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}
|
||||||
|
|
||||||
|
|
||||||
|
class Example3(object):
|
||||||
|
def __init__(self, bar):
|
||||||
|
# Comments should have a space after the hash.
|
||||||
|
if bar:
|
||||||
|
bar += 1
|
||||||
|
bar = bar * bar
|
||||||
|
return bar
|
||||||
|
else:
|
||||||
|
some_string = """
|
||||||
|
Indentation in multiline strings should not be touched.
|
||||||
|
Only actual code should be reindented.
|
||||||
|
"""
|
||||||
|
return (sys.path, some_string)
|
||||||
|
|
||||||
|
Options::
|
||||||
|
|
||||||
|
usage: autopep8 [-h] [--version] [-v] [-d] [-i] [--global-config filename]
|
||||||
|
[--ignore-local-config] [-r] [-j n] [-p n] [-a]
|
||||||
|
[--experimental] [--exclude globs] [--list-fixes]
|
||||||
|
[--ignore errors] [--select errors] [--max-line-length n]
|
||||||
|
[--line-range line line] [--hang-closing] [--exit-code]
|
||||||
|
[files [files ...]]
|
||||||
|
|
||||||
|
Automatically formats Python code to conform to the PEP 8 style guide.
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
files files to format or '-' for standard in
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
--version show program's version number and exit
|
||||||
|
-v, --verbose print verbose messages; multiple -v result in more
|
||||||
|
verbose messages
|
||||||
|
-d, --diff print the diff for the fixed source
|
||||||
|
-i, --in-place make changes to files in place
|
||||||
|
--global-config filename
|
||||||
|
path to a global pep8 config file; if this file does
|
||||||
|
not exist then this is ignored (default:
|
||||||
|
~/.config/pep8)
|
||||||
|
--ignore-local-config
|
||||||
|
don't look for and apply local config files; if not
|
||||||
|
passed, defaults are updated with any config files in
|
||||||
|
the project's root directory
|
||||||
|
-r, --recursive run recursively over directories; must be used with
|
||||||
|
--in-place or --diff
|
||||||
|
-j n, --jobs n number of parallel jobs; match CPU count if value is
|
||||||
|
less than 1
|
||||||
|
-p n, --pep8-passes n
|
||||||
|
maximum number of additional pep8 passes (default:
|
||||||
|
infinite)
|
||||||
|
-a, --aggressive enable non-whitespace changes; multiple -a result in
|
||||||
|
more aggressive changes
|
||||||
|
--experimental enable experimental fixes
|
||||||
|
--exclude globs exclude file/directory names that match these comma-
|
||||||
|
separated globs
|
||||||
|
--list-fixes list codes for fixes; used by --ignore and --select
|
||||||
|
--ignore errors do not fix these errors/warnings (default:
|
||||||
|
E226,E24,W50,W690)
|
||||||
|
--select errors fix only these errors/warnings (e.g. E4,W)
|
||||||
|
--max-line-length n set maximum allowed line length (default: 79)
|
||||||
|
--line-range line line, --range line line
|
||||||
|
only fix errors found within this inclusive range of
|
||||||
|
line numbers (e.g. 1 99); line numbers are indexed at
|
||||||
|
1
|
||||||
|
--hang-closing hang-closing option passed to pycodestyle
|
||||||
|
--exit-code change to behavior of exit code. default behavior of
|
||||||
|
return value, 0 is no differences, 1 is error exit.
|
||||||
|
return 2 when add this option. 2 is exists
|
||||||
|
differences.
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
========
|
||||||
|
|
||||||
|
autopep8 fixes the following issues_ reported by pycodestyle_::
|
||||||
|
|
||||||
|
E101 - Reindent all lines.
|
||||||
|
E11 - Fix indentation.
|
||||||
|
E121 - Fix indentation to be a multiple of four.
|
||||||
|
E122 - Add absent indentation for hanging indentation.
|
||||||
|
E123 - Align closing bracket to match opening bracket.
|
||||||
|
E124 - Align closing bracket to match visual indentation.
|
||||||
|
E125 - Indent to distinguish line from next logical line.
|
||||||
|
E126 - Fix over-indented hanging indentation.
|
||||||
|
E127 - Fix visual indentation.
|
||||||
|
E128 - Fix visual indentation.
|
||||||
|
E129 - Fix visual indentation.
|
||||||
|
E131 - Fix hanging indent for unaligned continuation line.
|
||||||
|
E133 - Fix missing indentation for closing bracket.
|
||||||
|
E20 - Remove extraneous whitespace.
|
||||||
|
E211 - Remove extraneous whitespace.
|
||||||
|
E22 - Fix extraneous whitespace around keywords.
|
||||||
|
E224 - Remove extraneous whitespace around operator.
|
||||||
|
E225 - Fix missing whitespace around operator.
|
||||||
|
E226 - Fix missing whitespace around arithmetic operator.
|
||||||
|
E227 - Fix missing whitespace around bitwise/shift operator.
|
||||||
|
E228 - Fix missing whitespace around modulo operator.
|
||||||
|
E231 - Add missing whitespace.
|
||||||
|
E241 - Fix extraneous whitespace around keywords.
|
||||||
|
E242 - Remove extraneous whitespace around operator.
|
||||||
|
E251 - Remove whitespace around parameter '=' sign.
|
||||||
|
E252 - Missing whitespace around parameter equals.
|
||||||
|
E26 - Fix spacing after comment hash for inline comments.
|
||||||
|
E265 - Fix spacing after comment hash for block comments.
|
||||||
|
E266 - Fix too many leading '#' for block comments.
|
||||||
|
E27 - Fix extraneous whitespace around keywords.
|
||||||
|
E301 - Add missing blank line.
|
||||||
|
E302 - Add missing 2 blank lines.
|
||||||
|
E303 - Remove extra blank lines.
|
||||||
|
E304 - Remove blank line following function decorator.
|
||||||
|
E305 - Expected 2 blank lines after end of function or class.
|
||||||
|
E306 - Expected 1 blank line before a nested definition.
|
||||||
|
E401 - Put imports on separate lines.
|
||||||
|
E402 - Fix module level import not at top of file
|
||||||
|
E501 - Try to make lines fit within --max-line-length characters.
|
||||||
|
E502 - Remove extraneous escape of newline.
|
||||||
|
E701 - Put colon-separated compound statement on separate lines.
|
||||||
|
E70 - Put semicolon-separated compound statement on separate lines.
|
||||||
|
E711 - Fix comparison with None.
|
||||||
|
E712 - Fix comparison with boolean.
|
||||||
|
E713 - Use 'not in' for test for membership.
|
||||||
|
E714 - Use 'is not' test for object identity.
|
||||||
|
E721 - Use "isinstance()" instead of comparing types directly.
|
||||||
|
E722 - Fix bare except.
|
||||||
|
E731 - Use a def when use do not assign a lambda expression.
|
||||||
|
W291 - Remove trailing whitespace.
|
||||||
|
W292 - Add a single newline at the end of the file.
|
||||||
|
W293 - Remove trailing whitespace on blank line.
|
||||||
|
W391 - Remove trailing blank lines.
|
||||||
|
W503 - Fix line break before binary operator.
|
||||||
|
W504 - Fix line break after binary operator.
|
||||||
|
W601 - Use "in" rather than "has_key()".
|
||||||
|
W602 - Fix deprecated form of raising exception.
|
||||||
|
W603 - Use "!=" instead of "<>"
|
||||||
|
W604 - Use "repr()" instead of backticks.
|
||||||
|
W605 - Fix invalid escape sequence 'x'.
|
||||||
|
W690 - Fix various deprecated code (via lib2to3).
|
||||||
|
|
||||||
|
autopep8 also fixes some issues not found by pycodestyle_.
|
||||||
|
|
||||||
|
- Correct deprecated or non-idiomatic Python code (via ``lib2to3``). Use this
|
||||||
|
for making Python 2.7 code more compatible with Python 3. (This is triggered
|
||||||
|
if ``W690`` is enabled.)
|
||||||
|
- Normalize files with mixed line endings.
|
||||||
|
- Put a blank line between a class docstring and its first method
|
||||||
|
declaration. (Enabled with ``E301``.)
|
||||||
|
- Remove blank lines between a function declaration and its docstring. (Enabled
|
||||||
|
with ``E303``.)
|
||||||
|
|
||||||
|
autopep8 avoids fixing some issues found by pycodestyle_.
|
||||||
|
|
||||||
|
- ``E112``/``E113`` for non comments are reports of bad indentation that break
|
||||||
|
syntax rules. These should not be modified at all.
|
||||||
|
- ``E265``, which refers to spacing after comment hash, is ignored if the
|
||||||
|
comment looks like code. autopep8 avoids modifying these since they are not
|
||||||
|
real comments. If you really want to get rid of the pycodestyle_ warning,
|
||||||
|
consider just removing the commented-out code. (This can be automated via
|
||||||
|
eradicate_.)
|
||||||
|
|
||||||
|
.. _eradicate: https://github.com/myint/eradicate
|
||||||
|
|
||||||
|
|
||||||
|
More advanced usage
|
||||||
|
===================
|
||||||
|
|
||||||
|
By default autopep8 only makes whitespace changes. Thus, by default, it does
|
||||||
|
not fix ``E711`` and ``E712``. (Changing ``x == None`` to ``x is None`` may
|
||||||
|
change the meaning of the program if ``x`` has its ``__eq__`` method
|
||||||
|
overridden.) Nor does it correct deprecated code ``W6``. To enable these
|
||||||
|
more aggressive fixes, use the ``--aggressive`` option::
|
||||||
|
|
||||||
|
$ autopep8 --aggressive <filename>
|
||||||
|
|
||||||
|
Use multiple ``--aggressive`` to increase the aggressiveness level. For
|
||||||
|
example, ``E712`` requires aggressiveness level 2 (since ``x == True`` could be
|
||||||
|
changed to either ``x`` or ``x is True``, but autopep8 chooses the former).
|
||||||
|
|
||||||
|
``--aggressive`` will also shorten lines more aggressively. It will also remove
|
||||||
|
trailing whitespace more aggressively. (Usually, we don't touch trailing
|
||||||
|
whitespace in docstrings and other multiline strings. And to do even more
|
||||||
|
aggressive changes to docstrings, use docformatter_.)
|
||||||
|
|
||||||
|
.. _docformatter: https://github.com/myint/docformatter
|
||||||
|
|
||||||
|
To enable only a subset of the fixes, use the ``--select`` option. For example,
|
||||||
|
to fix various types of indentation issues::
|
||||||
|
|
||||||
|
$ autopep8 --select=E1,W1 <filename>
|
||||||
|
|
||||||
|
Similarly, to just fix deprecated code::
|
||||||
|
|
||||||
|
$ autopep8 --aggressive --select=W6 <filename>
|
||||||
|
|
||||||
|
The above is useful when trying to port a single code base to work with both
|
||||||
|
Python 2 and Python 3 at the same time.
|
||||||
|
|
||||||
|
If the file being fixed is large, you may want to enable verbose progress
|
||||||
|
messages::
|
||||||
|
|
||||||
|
$ autopep8 -v <filename>
|
||||||
|
|
||||||
|
Passing in ``--experimental`` enables the following functionality:
|
||||||
|
|
||||||
|
- Shortens code lines by taking its length into account
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
$ autopep8 --experimental <filename>
|
||||||
|
|
||||||
|
Use as a module
|
||||||
|
===============
|
||||||
|
|
||||||
|
The simplest way of using autopep8 as a module is via the ``fix_code()``
|
||||||
|
function:
|
||||||
|
|
||||||
|
>>> import autopep8
|
||||||
|
>>> autopep8.fix_code('x= 123\n')
|
||||||
|
'x = 123\n'
|
||||||
|
|
||||||
|
Or with options:
|
||||||
|
|
||||||
|
>>> import autopep8
|
||||||
|
>>> autopep8.fix_code('x.has_key(y)\n',
|
||||||
|
... options={'aggressive': 1})
|
||||||
|
'y in x\n'
|
||||||
|
>>> autopep8.fix_code('print( 123 )\n',
|
||||||
|
... options={'ignore': ['E']})
|
||||||
|
'print( 123 )\n'
|
||||||
|
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
By default, if ``$HOME/.config/pycodestyle`` (``~\.pycodestyle`` in Windows
|
||||||
|
environment) exists, it will be used as global configuration file.
|
||||||
|
Alternatively, you can specify the global configuration file with the
|
||||||
|
``--global-config`` option.
|
||||||
|
|
||||||
|
Also, if ``setup.cfg``, ``tox.ini``, ``.pep8`` and ``.flake8`` files exist
|
||||||
|
in the directory where the target file exists, it will be used as the
|
||||||
|
configuration file.
|
||||||
|
|
||||||
|
``pep8``, ``pycodestyle``, and ``flake8`` can be used as a section.
|
||||||
|
|
||||||
|
configuration file example::
|
||||||
|
|
||||||
|
[pycodestyle]
|
||||||
|
max_line_length = 120
|
||||||
|
ignore = E501
|
||||||
|
|
||||||
|
pyproject.toml
|
||||||
|
--------------
|
||||||
|
|
||||||
|
autopep8 can also use ``pyproject.toml``.
|
||||||
|
section must use ``[tool.autopep8]``, and ``pyproject.toml`` takes precedence
|
||||||
|
over any other configuration files.
|
||||||
|
|
||||||
|
configuration file example::
|
||||||
|
|
||||||
|
[tool.autopep8]
|
||||||
|
max_line_length = 120
|
||||||
|
ignore = "E501,W6" # or ["E501", "W6"]
|
||||||
|
|
||||||
|
|
||||||
|
Testing
|
||||||
|
=======
|
||||||
|
|
||||||
|
Test cases are in ``test/test_autopep8.py``. They can be run directly via
|
||||||
|
``python test/test_autopep8.py`` or via tox_. The latter is useful for
|
||||||
|
testing against multiple Python interpreters. (We currently test against
|
||||||
|
CPython versions 2.7, 3.6 3.7 and 3.8. We also test against PyPy.)
|
||||||
|
|
||||||
|
.. _`tox`: https://pypi.org/project/tox/
|
||||||
|
|
||||||
|
Broad spectrum testing is available via ``test/acid.py``. This script runs
|
||||||
|
autopep8 against Python code and checks for correctness and completeness of the
|
||||||
|
code fixes. It can check that the bytecode remains identical.
|
||||||
|
``test/acid_pypi.py`` makes use of ``acid.py`` to test against the latest
|
||||||
|
released packages on PyPI.
|
||||||
|
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
===============
|
||||||
|
|
||||||
|
``pkg_resources.DistributionNotFound``
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
If you are using an ancient version of ``setuptools``, you might encounter
|
||||||
|
``pkg_resources.DistributionNotFound`` when trying to run ``autopep8``. Try
|
||||||
|
upgrading ``setuptools`` to workaround this ``setuptools`` problem::
|
||||||
|
|
||||||
|
$ pip install --upgrade setuptools
|
||||||
|
|
||||||
|
Use ``sudo`` if you are installing to the system.
|
||||||
|
|
||||||
|
|
||||||
|
Links
|
||||||
|
=====
|
||||||
|
|
||||||
|
* PyPI_
|
||||||
|
* GitHub_
|
||||||
|
* `Travis CI`_
|
||||||
|
* Coveralls_
|
||||||
|
|
||||||
|
.. _PyPI: https://pypi.org/project/autopep8/
|
||||||
|
.. _GitHub: https://github.com/hhatto/autopep8
|
||||||
|
.. _`Travis CI`: https://travis-ci.org/hhatto/autopep8
|
||||||
|
.. _`Coveralls`: https://coveralls.io/r/hhatto/autopep8
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
autopep8.py,sha256=xHkIfzd5IPgtTeyNq19o2SLHF28bregdzXEcx3G7ucQ,151970
|
||||||
|
autopep8-1.5.5.dist-info/AUTHORS.rst,sha256=tiTPsbzGl9dtXCMEWXbWSV1zan1M-BoWtiixs46GIWk,2003
|
||||||
|
autopep8-1.5.5.dist-info/LICENSE,sha256=jR0COOSFQ0QZFMqwdB1N4-Bwobg2f3h69fIJr7YLCWo,1181
|
||||||
|
autopep8-1.5.5.dist-info/METADATA,sha256=3IbGpS9FlKP4rzVE6EXbN-0O4D2AZoZcgaXEyYpAq3c,16661
|
||||||
|
autopep8-1.5.5.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
|
||||||
|
autopep8-1.5.5.dist-info/entry_points.txt,sha256=iHNa5_cSXw2ablVbRmfiFGMG1CNrpEPRCEjn3nspaJ8,44
|
||||||
|
autopep8-1.5.5.dist-info/top_level.txt,sha256=s2x-di3QBwGxr7kd5xErt2pom8dsFRdINbmwsOEgLfU,9
|
||||||
|
autopep8-1.5.5.dist-info/RECORD,,
|
||||||
|
../../../bin/autopep8,sha256=nvzzNDnv7luxQekE2qaJPtL_f3kgvxUAJNKivQVar48,253
|
||||||
|
autopep8-1.5.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
__pycache__/autopep8.cpython-37.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.34.2)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[console_scripts]
|
||||||
|
autopep8 = autopep8:main
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
autopep8
|
4469
venv3/lib/python3.7/site-packages/autopep8.py
Normal file
4469
venv3/lib/python3.7/site-packages/autopep8.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
|
||||||
|
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
|
||||||
|
Copyright © 2014-2020 Ian Lee <IanLee1521@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the terms of the Expat License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation files
|
||||||
|
(the "Software"), to deal in the Software without restriction,
|
||||||
|
including without limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
||||||
|
pycodestyle.py,sha256=xYcAkNSMHMAlz6cmdkfhwK7QC5RsRwK2pfG2_uPI2xM,103376
|
||||||
|
pycodestyle-2.6.0.dist-info/LICENSE,sha256=93IpXoGvNHjTTojlLQdiACMOx91qOeEjvFyzWqZqva4,1254
|
||||||
|
pycodestyle-2.6.0.dist-info/METADATA,sha256=WI4-bMnR66kT7MKGLVFW7xqmuotPGP0uLJProv7nhD4,30287
|
||||||
|
pycodestyle-2.6.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
|
||||||
|
pycodestyle-2.6.0.dist-info/entry_points.txt,sha256=6JU_7SAppC93MBSQi1_QxDwEQUyg6cgK71ab9q_Hxco,51
|
||||||
|
pycodestyle-2.6.0.dist-info/namespace_packages.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
||||||
|
pycodestyle-2.6.0.dist-info/top_level.txt,sha256=rHbIEiXmvsJ016mFcLVcF_d-dKgP3VdfOB6CWbivZug,12
|
||||||
|
pycodestyle-2.6.0.dist-info/RECORD,,
|
||||||
|
../../../bin/pycodestyle,sha256=pIp6u2iVgkZ61DS1jKVvK_T_RtnyEky3j3Hlf_fhhN8,258
|
||||||
|
pycodestyle-2.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
__pycache__/pycodestyle.cpython-37.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.34.2)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[console_scripts]
|
||||||
|
pycodestyle = pycodestyle:_main
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pycodestyle
|
2763
venv3/lib/python3.7/site-packages/pycodestyle.py
Normal file
2763
venv3/lib/python3.7/site-packages/pycodestyle.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,27 @@
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright 2013-2019 William Pearson
|
||||||
|
Copyright 2015-2016 Julien Enselme
|
||||||
|
Copyright 2016 Google Inc.
|
||||||
|
Copyright 2017 Samuel Vasko
|
||||||
|
Copyright 2017 Nate Prewitt
|
||||||
|
Copyright 2017 Jack Evans
|
||||||
|
Copyright 2019 Filippo Broggini
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
255
venv3/lib/python3.7/site-packages/toml-0.10.2.dist-info/METADATA
Normal file
255
venv3/lib/python3.7/site-packages/toml-0.10.2.dist-info/METADATA
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: toml
|
||||||
|
Version: 0.10.2
|
||||||
|
Summary: Python Library for Tom's Obvious, Minimal Language
|
||||||
|
Home-page: https://github.com/uiri/toml
|
||||||
|
Author: William Pearson
|
||||||
|
Author-email: uiri@xqz.ca
|
||||||
|
License: MIT
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: MIT License
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.6
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.3
|
||||||
|
Classifier: Programming Language :: Python :: 3.4
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: 3.8
|
||||||
|
Classifier: Programming Language :: Python :: 3.9
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
|
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
|
||||||
|
|
||||||
|
****
|
||||||
|
TOML
|
||||||
|
****
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/toml
|
||||||
|
:target: https://pypi.org/project/toml/
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/uiri/toml.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/uiri/toml
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/pyversions/toml.svg
|
||||||
|
:target: https://pypi.org/project/toml/
|
||||||
|
|
||||||
|
|
||||||
|
A Python library for parsing and creating `TOML <https://en.wikipedia.org/wiki/TOML>`_.
|
||||||
|
|
||||||
|
The module passes `the TOML test suite <https://github.com/BurntSushi/toml-test>`_.
|
||||||
|
|
||||||
|
See also:
|
||||||
|
|
||||||
|
* `The TOML Standard <https://github.com/toml-lang/toml>`_
|
||||||
|
* `The currently supported TOML specification <https://github.com/toml-lang/toml/blob/v0.5.0/README.md>`_
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
To install the latest release on `PyPI <https://pypi.org/project/toml/>`_,
|
||||||
|
simply run:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install toml
|
||||||
|
|
||||||
|
Or to install the latest development version, run:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
git clone https://github.com/uiri/toml.git
|
||||||
|
cd toml
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
Quick Tutorial
|
||||||
|
==============
|
||||||
|
|
||||||
|
*toml.loads* takes in a string containing standard TOML-formatted data and
|
||||||
|
returns a dictionary containing the parsed data.
|
||||||
|
|
||||||
|
.. code:: pycon
|
||||||
|
|
||||||
|
>>> import toml
|
||||||
|
>>> toml_string = """
|
||||||
|
... # This is a TOML document.
|
||||||
|
...
|
||||||
|
... title = "TOML Example"
|
||||||
|
...
|
||||||
|
... [owner]
|
||||||
|
... name = "Tom Preston-Werner"
|
||||||
|
... dob = 1979-05-27T07:32:00-08:00 # First class dates
|
||||||
|
...
|
||||||
|
... [database]
|
||||||
|
... server = "192.168.1.1"
|
||||||
|
... ports = [ 8001, 8001, 8002 ]
|
||||||
|
... connection_max = 5000
|
||||||
|
... enabled = true
|
||||||
|
...
|
||||||
|
... [servers]
|
||||||
|
...
|
||||||
|
... # Indentation (tabs and/or spaces) is allowed but not required
|
||||||
|
... [servers.alpha]
|
||||||
|
... ip = "10.0.0.1"
|
||||||
|
... dc = "eqdc10"
|
||||||
|
...
|
||||||
|
... [servers.beta]
|
||||||
|
... ip = "10.0.0.2"
|
||||||
|
... dc = "eqdc10"
|
||||||
|
...
|
||||||
|
... [clients]
|
||||||
|
... data = [ ["gamma", "delta"], [1, 2] ]
|
||||||
|
...
|
||||||
|
... # Line breaks are OK when inside arrays
|
||||||
|
... hosts = [
|
||||||
|
... "alpha",
|
||||||
|
... "omega"
|
||||||
|
... ]
|
||||||
|
... """
|
||||||
|
>>> parsed_toml = toml.loads(toml_string)
|
||||||
|
|
||||||
|
|
||||||
|
*toml.dumps* takes a dictionary and returns a string containing the
|
||||||
|
corresponding TOML-formatted data.
|
||||||
|
|
||||||
|
.. code:: pycon
|
||||||
|
|
||||||
|
>>> new_toml_string = toml.dumps(parsed_toml)
|
||||||
|
>>> print(new_toml_string)
|
||||||
|
title = "TOML Example"
|
||||||
|
[owner]
|
||||||
|
name = "Tom Preston-Werner"
|
||||||
|
dob = 1979-05-27T07:32:00Z
|
||||||
|
[database]
|
||||||
|
server = "192.168.1.1"
|
||||||
|
ports = [ 8001, 8001, 8002,]
|
||||||
|
connection_max = 5000
|
||||||
|
enabled = true
|
||||||
|
[clients]
|
||||||
|
data = [ [ "gamma", "delta",], [ 1, 2,],]
|
||||||
|
hosts = [ "alpha", "omega",]
|
||||||
|
[servers.alpha]
|
||||||
|
ip = "10.0.0.1"
|
||||||
|
dc = "eqdc10"
|
||||||
|
[servers.beta]
|
||||||
|
ip = "10.0.0.2"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
*toml.dump* takes a dictionary and a file descriptor and returns a string containing the
|
||||||
|
corresponding TOML-formatted data.
|
||||||
|
|
||||||
|
.. code:: pycon
|
||||||
|
|
||||||
|
>>> with open('new_toml_file.toml', 'w') as f:
|
||||||
|
... new_toml_string = toml.dump(parsed_toml, f)
|
||||||
|
>>> print(new_toml_string)
|
||||||
|
title = "TOML Example"
|
||||||
|
[owner]
|
||||||
|
name = "Tom Preston-Werner"
|
||||||
|
dob = 1979-05-27T07:32:00Z
|
||||||
|
[database]
|
||||||
|
server = "192.168.1.1"
|
||||||
|
ports = [ 8001, 8001, 8002,]
|
||||||
|
connection_max = 5000
|
||||||
|
enabled = true
|
||||||
|
[clients]
|
||||||
|
data = [ [ "gamma", "delta",], [ 1, 2,],]
|
||||||
|
hosts = [ "alpha", "omega",]
|
||||||
|
[servers.alpha]
|
||||||
|
ip = "10.0.0.1"
|
||||||
|
dc = "eqdc10"
|
||||||
|
[servers.beta]
|
||||||
|
ip = "10.0.0.2"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
For more functions, view the API Reference below.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
|
||||||
|
For Numpy users, by default the data types ``np.floatX`` will not be translated to floats by toml, but will instead be encoded as strings. To get around this, specify the ``TomlNumpyEncoder`` when saving your data.
|
||||||
|
|
||||||
|
.. code:: pycon
|
||||||
|
|
||||||
|
>>> import toml
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> a = np.arange(0, 10, dtype=np.double)
|
||||||
|
>>> output = {'a': a}
|
||||||
|
>>> toml.dumps(output)
|
||||||
|
'a = [ "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0",]\n'
|
||||||
|
>>> toml.dumps(output, encoder=toml.TomlNumpyEncoder())
|
||||||
|
'a = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,]\n'
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
``toml.load(f, _dict=dict)``
|
||||||
|
Parse a file or a list of files as TOML and return a dictionary.
|
||||||
|
|
||||||
|
:Args:
|
||||||
|
* ``f``: A path to a file, list of filepaths (to be read into single
|
||||||
|
object) or a file descriptor
|
||||||
|
* ``_dict``: The class of the dictionary object to be returned
|
||||||
|
|
||||||
|
:Returns:
|
||||||
|
A dictionary (or object ``_dict``) containing parsed TOML data
|
||||||
|
|
||||||
|
:Raises:
|
||||||
|
* ``TypeError``: When ``f`` is an invalid type or is a list containing
|
||||||
|
invalid types
|
||||||
|
* ``TomlDecodeError``: When an error occurs while decoding the file(s)
|
||||||
|
|
||||||
|
``toml.loads(s, _dict=dict)``
|
||||||
|
Parse a TOML-formatted string to a dictionary.
|
||||||
|
|
||||||
|
:Args:
|
||||||
|
* ``s``: The TOML-formatted string to be parsed
|
||||||
|
* ``_dict``: Specifies the class of the returned toml dictionary
|
||||||
|
|
||||||
|
:Returns:
|
||||||
|
A dictionary (or object ``_dict``) containing parsed TOML data
|
||||||
|
|
||||||
|
:Raises:
|
||||||
|
* ``TypeError``: When a non-string object is passed
|
||||||
|
* ``TomlDecodeError``: When an error occurs while decoding the
|
||||||
|
TOML-formatted string
|
||||||
|
|
||||||
|
``toml.dump(o, f, encoder=None)``
|
||||||
|
Write a dictionary to a file containing TOML-formatted data
|
||||||
|
|
||||||
|
:Args:
|
||||||
|
* ``o``: An object to be converted into TOML
|
||||||
|
* ``f``: A File descriptor where the TOML-formatted output should be stored
|
||||||
|
* ``encoder``: An instance of ``TomlEncoder`` (or subclass) for encoding the object. If ``None``, will default to ``TomlEncoder``
|
||||||
|
|
||||||
|
:Returns:
|
||||||
|
A string containing the TOML-formatted data corresponding to object ``o``
|
||||||
|
|
||||||
|
:Raises:
|
||||||
|
* ``TypeError``: When anything other than file descriptor is passed
|
||||||
|
|
||||||
|
``toml.dumps(o, encoder=None)``
|
||||||
|
Create a TOML-formatted string from an input object
|
||||||
|
|
||||||
|
:Args:
|
||||||
|
* ``o``: An object to be converted into TOML
|
||||||
|
* ``encoder``: An instance of ``TomlEncoder`` (or subclass) for encoding the object. If ``None``, will default to ``TomlEncoder``
|
||||||
|
|
||||||
|
:Returns:
|
||||||
|
A string containing the TOML-formatted data corresponding to object ``o``
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Licensing
|
||||||
|
=========
|
||||||
|
|
||||||
|
This project is released under the terms of the MIT Open Source License. View
|
||||||
|
*LICENSE.txt* for more information.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
toml/__init__.py,sha256=Au3kqCwKD0cjbf4yJGOpUFwpsY0WHsC1ZRGvWgIKmpc,723
|
||||||
|
toml/decoder.py,sha256=hSGTLf-2WBDZ_ddoCHWFy6N647XyMSh1o3rN2o4dEFg,38942
|
||||||
|
toml/encoder.py,sha256=XjBc8ayvvlsLyd_qDA4tMWDNmMFRS4DpwtuDSWBq7zo,9940
|
||||||
|
toml/ordered.py,sha256=mz03lZmV0bmc9lsYRIUOuj7Dsu5Ptwq-UtGVq5FdVZ4,354
|
||||||
|
toml/tz.py,sha256=-5vg8wkg_atnVi2TnEveexIVE7T_FxBVr_-2WVfO1oA,701
|
||||||
|
toml-0.10.2.dist-info/LICENSE,sha256=LZKUgj32yJNXyL5JJ_znk2HWVh5e51MtWSbmOTmqpTY,1252
|
||||||
|
toml-0.10.2.dist-info/METADATA,sha256=n_YkspvEihd_QXLIZZ50WVSFz3rZ_k7jQP-OU1WUpWY,7142
|
||||||
|
toml-0.10.2.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
|
||||||
|
toml-0.10.2.dist-info/top_level.txt,sha256=2BO8ZRNnvJWgXyiQv66LBb_v87qBzcoUtEBefA75Ouk,5
|
||||||
|
toml-0.10.2.dist-info/RECORD,,
|
||||||
|
toml-0.10.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
toml/__pycache__/ordered.cpython-37.pyc,,
|
||||||
|
toml/__pycache__/tz.cpython-37.pyc,,
|
||||||
|
toml/__pycache__/decoder.cpython-37.pyc,,
|
||||||
|
toml/__pycache__/encoder.cpython-37.pyc,,
|
||||||
|
toml/__pycache__/__init__.cpython-37.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.35.1)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
toml
|
25
venv3/lib/python3.7/site-packages/toml/__init__.py
Normal file
25
venv3/lib/python3.7/site-packages/toml/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
"""Python module which parses and emits TOML.
|
||||||
|
|
||||||
|
Released under the MIT license.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from toml import encoder
|
||||||
|
from toml import decoder
|
||||||
|
|
||||||
|
__version__ = "0.10.2"
|
||||||
|
_spec_ = "0.5.0"
|
||||||
|
|
||||||
|
load = decoder.load
|
||||||
|
loads = decoder.loads
|
||||||
|
TomlDecoder = decoder.TomlDecoder
|
||||||
|
TomlDecodeError = decoder.TomlDecodeError
|
||||||
|
TomlPreserveCommentDecoder = decoder.TomlPreserveCommentDecoder
|
||||||
|
|
||||||
|
dump = encoder.dump
|
||||||
|
dumps = encoder.dumps
|
||||||
|
TomlEncoder = encoder.TomlEncoder
|
||||||
|
TomlArraySeparatorEncoder = encoder.TomlArraySeparatorEncoder
|
||||||
|
TomlPreserveInlineDictEncoder = encoder.TomlPreserveInlineDictEncoder
|
||||||
|
TomlNumpyEncoder = encoder.TomlNumpyEncoder
|
||||||
|
TomlPreserveCommentEncoder = encoder.TomlPreserveCommentEncoder
|
||||||
|
TomlPathlibEncoder = encoder.TomlPathlibEncoder
|
1057
venv3/lib/python3.7/site-packages/toml/decoder.py
Normal file
1057
venv3/lib/python3.7/site-packages/toml/decoder.py
Normal file
File diff suppressed because it is too large
Load diff
304
venv3/lib/python3.7/site-packages/toml/encoder.py
Normal file
304
venv3/lib/python3.7/site-packages/toml/encoder.py
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from toml.decoder import InlineTableDict
|
||||||
|
|
||||||
|
if sys.version_info >= (3,):
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
|
||||||
|
def dump(o, f, encoder=None):
|
||||||
|
"""Writes out dict as toml to a file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
o: Object to dump into toml
|
||||||
|
f: File descriptor where the toml should be stored
|
||||||
|
encoder: The ``TomlEncoder`` to use for constructing the output string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String containing the toml corresponding to dictionary
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TypeError: When anything other than file descriptor is passed
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not f.write:
|
||||||
|
raise TypeError("You can only dump an object to a file descriptor")
|
||||||
|
d = dumps(o, encoder=encoder)
|
||||||
|
f.write(d)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def dumps(o, encoder=None):
|
||||||
|
"""Stringifies input dict as toml
|
||||||
|
|
||||||
|
Args:
|
||||||
|
o: Object to dump into toml
|
||||||
|
encoder: The ``TomlEncoder`` to use for constructing the output string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String containing the toml corresponding to dict
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```python
|
||||||
|
>>> import toml
|
||||||
|
>>> output = {
|
||||||
|
... 'a': "I'm a string",
|
||||||
|
... 'b': ["I'm", "a", "list"],
|
||||||
|
... 'c': 2400
|
||||||
|
... }
|
||||||
|
>>> toml.dumps(output)
|
||||||
|
'a = "I\'m a string"\nb = [ "I\'m", "a", "list",]\nc = 2400\n'
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
retval = ""
|
||||||
|
if encoder is None:
|
||||||
|
encoder = TomlEncoder(o.__class__)
|
||||||
|
addtoretval, sections = encoder.dump_sections(o, "")
|
||||||
|
retval += addtoretval
|
||||||
|
outer_objs = [id(o)]
|
||||||
|
while sections:
|
||||||
|
section_ids = [id(section) for section in sections.values()]
|
||||||
|
for outer_obj in outer_objs:
|
||||||
|
if outer_obj in section_ids:
|
||||||
|
raise ValueError("Circular reference detected")
|
||||||
|
outer_objs += section_ids
|
||||||
|
newsections = encoder.get_empty_table()
|
||||||
|
for section in sections:
|
||||||
|
addtoretval, addtosections = encoder.dump_sections(
|
||||||
|
sections[section], section)
|
||||||
|
|
||||||
|
if addtoretval or (not addtoretval and not addtosections):
|
||||||
|
if retval and retval[-2:] != "\n\n":
|
||||||
|
retval += "\n"
|
||||||
|
retval += "[" + section + "]\n"
|
||||||
|
if addtoretval:
|
||||||
|
retval += addtoretval
|
||||||
|
for s in addtosections:
|
||||||
|
newsections[section + "." + s] = addtosections[s]
|
||||||
|
sections = newsections
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
def _dump_str(v):
|
||||||
|
if sys.version_info < (3,) and hasattr(v, 'decode') and isinstance(v, str):
|
||||||
|
v = v.decode('utf-8')
|
||||||
|
v = "%r" % v
|
||||||
|
if v[0] == 'u':
|
||||||
|
v = v[1:]
|
||||||
|
singlequote = v.startswith("'")
|
||||||
|
if singlequote or v.startswith('"'):
|
||||||
|
v = v[1:-1]
|
||||||
|
if singlequote:
|
||||||
|
v = v.replace("\\'", "'")
|
||||||
|
v = v.replace('"', '\\"')
|
||||||
|
v = v.split("\\x")
|
||||||
|
while len(v) > 1:
|
||||||
|
i = -1
|
||||||
|
if not v[0]:
|
||||||
|
v = v[1:]
|
||||||
|
v[0] = v[0].replace("\\\\", "\\")
|
||||||
|
# No, I don't know why != works and == breaks
|
||||||
|
joinx = v[0][i] != "\\"
|
||||||
|
while v[0][:i] and v[0][i] == "\\":
|
||||||
|
joinx = not joinx
|
||||||
|
i -= 1
|
||||||
|
if joinx:
|
||||||
|
joiner = "x"
|
||||||
|
else:
|
||||||
|
joiner = "u00"
|
||||||
|
v = [v[0] + joiner + v[1]] + v[2:]
|
||||||
|
return unicode('"' + v[0] + '"')
|
||||||
|
|
||||||
|
|
||||||
|
def _dump_float(v):
|
||||||
|
return "{}".format(v).replace("e+0", "e+").replace("e-0", "e-")
|
||||||
|
|
||||||
|
|
||||||
|
def _dump_time(v):
|
||||||
|
utcoffset = v.utcoffset()
|
||||||
|
if utcoffset is None:
|
||||||
|
return v.isoformat()
|
||||||
|
# The TOML norm specifies that it's local time thus we drop the offset
|
||||||
|
return v.isoformat()[:-6]
|
||||||
|
|
||||||
|
|
||||||
|
class TomlEncoder(object):
|
||||||
|
|
||||||
|
def __init__(self, _dict=dict, preserve=False):
|
||||||
|
self._dict = _dict
|
||||||
|
self.preserve = preserve
|
||||||
|
self.dump_funcs = {
|
||||||
|
str: _dump_str,
|
||||||
|
unicode: _dump_str,
|
||||||
|
list: self.dump_list,
|
||||||
|
bool: lambda v: unicode(v).lower(),
|
||||||
|
int: lambda v: v,
|
||||||
|
float: _dump_float,
|
||||||
|
Decimal: _dump_float,
|
||||||
|
datetime.datetime: lambda v: v.isoformat().replace('+00:00', 'Z'),
|
||||||
|
datetime.time: _dump_time,
|
||||||
|
datetime.date: lambda v: v.isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_empty_table(self):
|
||||||
|
return self._dict()
|
||||||
|
|
||||||
|
def dump_list(self, v):
|
||||||
|
retval = "["
|
||||||
|
for u in v:
|
||||||
|
retval += " " + unicode(self.dump_value(u)) + ","
|
||||||
|
retval += "]"
|
||||||
|
return retval
|
||||||
|
|
||||||
|
def dump_inline_table(self, section):
|
||||||
|
"""Preserve inline table in its compact syntax instead of expanding
|
||||||
|
into subsection.
|
||||||
|
|
||||||
|
https://github.com/toml-lang/toml#user-content-inline-table
|
||||||
|
"""
|
||||||
|
retval = ""
|
||||||
|
if isinstance(section, dict):
|
||||||
|
val_list = []
|
||||||
|
for k, v in section.items():
|
||||||
|
val = self.dump_inline_table(v)
|
||||||
|
val_list.append(k + " = " + val)
|
||||||
|
retval += "{ " + ", ".join(val_list) + " }\n"
|
||||||
|
return retval
|
||||||
|
else:
|
||||||
|
return unicode(self.dump_value(section))
|
||||||
|
|
||||||
|
def dump_value(self, v):
|
||||||
|
# Lookup function corresponding to v's type
|
||||||
|
dump_fn = self.dump_funcs.get(type(v))
|
||||||
|
if dump_fn is None and hasattr(v, '__iter__'):
|
||||||
|
dump_fn = self.dump_funcs[list]
|
||||||
|
# Evaluate function (if it exists) else return v
|
||||||
|
return dump_fn(v) if dump_fn is not None else self.dump_funcs[str](v)
|
||||||
|
|
||||||
|
def dump_sections(self, o, sup):
|
||||||
|
retstr = ""
|
||||||
|
if sup != "" and sup[-1] != ".":
|
||||||
|
sup += '.'
|
||||||
|
retdict = self._dict()
|
||||||
|
arraystr = ""
|
||||||
|
for section in o:
|
||||||
|
section = unicode(section)
|
||||||
|
qsection = section
|
||||||
|
if not re.match(r'^[A-Za-z0-9_-]+$', section):
|
||||||
|
qsection = _dump_str(section)
|
||||||
|
if not isinstance(o[section], dict):
|
||||||
|
arrayoftables = False
|
||||||
|
if isinstance(o[section], list):
|
||||||
|
for a in o[section]:
|
||||||
|
if isinstance(a, dict):
|
||||||
|
arrayoftables = True
|
||||||
|
if arrayoftables:
|
||||||
|
for a in o[section]:
|
||||||
|
arraytabstr = "\n"
|
||||||
|
arraystr += "[[" + sup + qsection + "]]\n"
|
||||||
|
s, d = self.dump_sections(a, sup + qsection)
|
||||||
|
if s:
|
||||||
|
if s[0] == "[":
|
||||||
|
arraytabstr += s
|
||||||
|
else:
|
||||||
|
arraystr += s
|
||||||
|
while d:
|
||||||
|
newd = self._dict()
|
||||||
|
for dsec in d:
|
||||||
|
s1, d1 = self.dump_sections(d[dsec], sup +
|
||||||
|
qsection + "." +
|
||||||
|
dsec)
|
||||||
|
if s1:
|
||||||
|
arraytabstr += ("[" + sup + qsection +
|
||||||
|
"." + dsec + "]\n")
|
||||||
|
arraytabstr += s1
|
||||||
|
for s1 in d1:
|
||||||
|
newd[dsec + "." + s1] = d1[s1]
|
||||||
|
d = newd
|
||||||
|
arraystr += arraytabstr
|
||||||
|
else:
|
||||||
|
if o[section] is not None:
|
||||||
|
retstr += (qsection + " = " +
|
||||||
|
unicode(self.dump_value(o[section])) + '\n')
|
||||||
|
elif self.preserve and isinstance(o[section], InlineTableDict):
|
||||||
|
retstr += (qsection + " = " +
|
||||||
|
self.dump_inline_table(o[section]))
|
||||||
|
else:
|
||||||
|
retdict[qsection] = o[section]
|
||||||
|
retstr += arraystr
|
||||||
|
return (retstr, retdict)
|
||||||
|
|
||||||
|
|
||||||
|
class TomlPreserveInlineDictEncoder(TomlEncoder):
|
||||||
|
|
||||||
|
def __init__(self, _dict=dict):
|
||||||
|
super(TomlPreserveInlineDictEncoder, self).__init__(_dict, True)
|
||||||
|
|
||||||
|
|
||||||
|
class TomlArraySeparatorEncoder(TomlEncoder):
|
||||||
|
|
||||||
|
def __init__(self, _dict=dict, preserve=False, separator=","):
|
||||||
|
super(TomlArraySeparatorEncoder, self).__init__(_dict, preserve)
|
||||||
|
if separator.strip() == "":
|
||||||
|
separator = "," + separator
|
||||||
|
elif separator.strip(' \t\n\r,'):
|
||||||
|
raise ValueError("Invalid separator for arrays")
|
||||||
|
self.separator = separator
|
||||||
|
|
||||||
|
def dump_list(self, v):
|
||||||
|
t = []
|
||||||
|
retval = "["
|
||||||
|
for u in v:
|
||||||
|
t.append(self.dump_value(u))
|
||||||
|
while t != []:
|
||||||
|
s = []
|
||||||
|
for u in t:
|
||||||
|
if isinstance(u, list):
|
||||||
|
for r in u:
|
||||||
|
s.append(r)
|
||||||
|
else:
|
||||||
|
retval += " " + unicode(u) + self.separator
|
||||||
|
t = s
|
||||||
|
retval += "]"
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
class TomlNumpyEncoder(TomlEncoder):
|
||||||
|
|
||||||
|
def __init__(self, _dict=dict, preserve=False):
|
||||||
|
import numpy as np
|
||||||
|
super(TomlNumpyEncoder, self).__init__(_dict, preserve)
|
||||||
|
self.dump_funcs[np.float16] = _dump_float
|
||||||
|
self.dump_funcs[np.float32] = _dump_float
|
||||||
|
self.dump_funcs[np.float64] = _dump_float
|
||||||
|
self.dump_funcs[np.int16] = self._dump_int
|
||||||
|
self.dump_funcs[np.int32] = self._dump_int
|
||||||
|
self.dump_funcs[np.int64] = self._dump_int
|
||||||
|
|
||||||
|
def _dump_int(self, v):
|
||||||
|
return "{}".format(int(v))
|
||||||
|
|
||||||
|
|
||||||
|
class TomlPreserveCommentEncoder(TomlEncoder):
|
||||||
|
|
||||||
|
def __init__(self, _dict=dict, preserve=False):
|
||||||
|
from toml.decoder import CommentValue
|
||||||
|
super(TomlPreserveCommentEncoder, self).__init__(_dict, preserve)
|
||||||
|
self.dump_funcs[CommentValue] = lambda v: v.dump(self.dump_value)
|
||||||
|
|
||||||
|
|
||||||
|
class TomlPathlibEncoder(TomlEncoder):
|
||||||
|
|
||||||
|
def _dump_pathlib_path(self, v):
|
||||||
|
return _dump_str(str(v))
|
||||||
|
|
||||||
|
def dump_value(self, v):
|
||||||
|
if (3, 4) <= sys.version_info:
|
||||||
|
import pathlib
|
||||||
|
if isinstance(v, pathlib.PurePath):
|
||||||
|
v = str(v)
|
||||||
|
return super(TomlPathlibEncoder, self).dump_value(v)
|
15
venv3/lib/python3.7/site-packages/toml/ordered.py
Normal file
15
venv3/lib/python3.7/site-packages/toml/ordered.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
from toml import TomlEncoder
|
||||||
|
from toml import TomlDecoder
|
||||||
|
|
||||||
|
|
||||||
|
class TomlOrderedDecoder(TomlDecoder):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(self.__class__, self).__init__(_dict=OrderedDict)
|
||||||
|
|
||||||
|
|
||||||
|
class TomlOrderedEncoder(TomlEncoder):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(self.__class__, self).__init__(_dict=OrderedDict)
|
24
venv3/lib/python3.7/site-packages/toml/tz.py
Normal file
24
venv3/lib/python3.7/site-packages/toml/tz.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
from datetime import tzinfo, timedelta
|
||||||
|
|
||||||
|
|
||||||
|
class TomlTz(tzinfo):
|
||||||
|
def __init__(self, toml_offset):
|
||||||
|
if toml_offset == "Z":
|
||||||
|
self._raw_offset = "+00:00"
|
||||||
|
else:
|
||||||
|
self._raw_offset = toml_offset
|
||||||
|
self._sign = -1 if self._raw_offset[0] == '-' else 1
|
||||||
|
self._hours = int(self._raw_offset[1:3])
|
||||||
|
self._minutes = int(self._raw_offset[4:6])
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
return self.__class__(self._raw_offset)
|
||||||
|
|
||||||
|
def tzname(self, dt):
|
||||||
|
return "UTC" + self._raw_offset
|
||||||
|
|
||||||
|
def utcoffset(self, dt):
|
||||||
|
return self._sign * timedelta(hours=self._hours, minutes=self._minutes)
|
||||||
|
|
||||||
|
def dst(self, dt):
|
||||||
|
return timedelta(0)
|
|
@ -1 +1 @@
|
||||||
{"last_check":"2021-03-03T22:25:46Z","pypi_version":"21.0.1"}
|
{"last_check":"2021-03-14T08:43:16Z","pypi_version":"21.0.1"}
|
Loading…
Reference in a new issue