Fixing a bunch of bad stuff using an actual linter

This commit is contained in:
Luke Robles 2024-04-04 22:00:08 -07:00
parent a38370e3eb
commit 1062c9707b
18 changed files with 89 additions and 419 deletions

View File

@ -23,7 +23,7 @@ Currently the CI/CD pipeline has workers running as Kubernetes pods and dispatch
* You can see a diagram of how it all works by running the following command from the root of the repo: * You can see a diagram of how it all works by running the following command from the root of the repo:
```bash ```bash
docker run --rm -v $(pwd):/tmp/python python sh -c "apt-get update && apt-get install -y graphviz; pip install diagrams --user; cd /tmp/python; python dalebot-overview.py" docker run --rm -v $(pwd):/tmp/python python sh -c "apt-get update && apt-get install -y graphviz; pip install diagrams; cd /tmp/python; python /tmp/python/dalebot-overview.py"
``` ```
### What is this repository for? ### ### What is this repository for? ###

View File

@ -1,8 +1,8 @@
#!/usr/local/bin/python #!/usr/local/bin/python
from discord.ext import commands from discord.ext import commands
import core_utils
import discord import discord
import os import os
import requests_cache
intents = discord.Intents.default() intents = discord.Intents.default()
intents.message_content = True intents.message_content = True
@ -19,7 +19,6 @@ cogfiles = [
for cogfile in cogfiles: for cogfile in cogfiles:
bot.load_extension(cogfile) bot.load_extension(cogfile)
import requests_cache
requests_cache.install_cache(expire_after=300) requests_cache.install_cache(expire_after=300)
@ -112,7 +111,7 @@ async def convert_heic_to_jpg(ctx):
jpg_file = "/tmp/%s.jpg" % time.time() jpg_file = "/tmp/%s.jpg" % time.time()
await attachment.save(fp=file_path) await attachment.save(fp=file_path)
img = cmagick.convert(file_path, jpg_file) cmagick.convert(file_path, jpg_file)
try: try:
await ctx.delete() await ctx.delete()
@ -133,8 +132,8 @@ async def fix_social_media_links(ctx):
"https://www.x.com": "vxtwitter", "https://www.x.com": "vxtwitter",
"https://twitter.com": "vxtwitter", "https://twitter.com": "vxtwitter",
"https://www.twitter.com": "vxtwitter", "https://www.twitter.com": "vxtwitter",
# "https://tiktok.com": "vxtiktok", "https://tiktok.com": "vxtiktok",
# "https://www.tiktok.com": "vxtiktok", "https://www.tiktok.com": "vxtiktok",
} }
if ctx.author.id == bot.user.id: if ctx.author.id == bot.user.id:
return return

View File

@ -2,7 +2,6 @@ from discord.ext import commands
from discord import option from discord import option
import discord import discord
import os import os
import core_utils
class ActualUtils(commands.Cog): class ActualUtils(commands.Cog):
@ -54,26 +53,6 @@ class ActualUtils(commands.Cog):
await ctx.defer() await ctx.defer()
await ctx.followup.send(result) await ctx.followup.send(result)
@commands.slash_command(
guild_ids=core_utils.my_guilds,
name="issue",
description="Files an issue on gitlab",
)
@option(name="title", requried=True, description="The title of the issue")
@option(name="description", require=True, description="The body of the issue")
async def issue(self, ctx: commands.Context):
post_args = {"title": title, "description": description}
headers = {"PRIVATE-TOKEN": os.getenv("gitlab_token")}
r = requests.post(
"https://git.luker.fr/api/v4/projects/3/issues",
data=post_args,
headers=headers,
)
await ctx.respond(r.json()["web_url"])
@commands.slash_command( @commands.slash_command(
guild_ids=None, guild_ids=None,
name="define", name="define",

View File

@ -7,26 +7,6 @@ class AnimeGirls(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot: commands.Bot = bot self.bot: commands.Bot = bot
# @commands.slash_command(guild_ids=None, name="wink", description="Posts a gif of an anime girl winking")
# async def wink(self, ctx: commands.Context):
# await ctx.respond(
# embed=core_utils.generate_embed(
# embed_url=requests.get("https://some-random-api.ml/animu/wink").json()[
# "link"
# ]
# )
# )
@commands.slash_command(
guild_ids=None, name="pout", description="Posts a gif of an anime girl pouting"
)
async def pout(self, ctx: commands.Context):
await ctx.respond(
embed=core_utils.generate_embed(
embed_url=core_utils.waifu_pics(endpoint="blush")
)
)
@commands.slash_command( @commands.slash_command(
guild_ids=None, name="yeet", description="Posts a gif of an anime girl yeeting" guild_ids=None, name="yeet", description="Posts a gif of an anime girl yeeting"
) )

View File

@ -30,9 +30,6 @@ class Games(commands.Cog):
response = requests.get(url) response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser") soup = BeautifulSoup(response.text, "html.parser")
# Find all elements with class "world-list__world_name"
world_name_elements = soup.find_all(class_="world-list__world_name")
# Loop through each element and extract its contents # Loop through each element and extract its contents
worlds = [ worlds = [
element.get_text(strip=True) element.get_text(strip=True)

View File

@ -1,51 +0,0 @@
import openai
import os
from discord import option
from discord.ext import commands
import discord
import requests
class Gpt(commands.Cog):
def __init__(self, bot):
self.bot: commands.Bot = bot
@commands.slash_command(
guld_ids=None,
name="gpt",
description="Talk to an LLM",
)
@option(name="question", description="The question to ask", required=True)
async def gpt(
self,
ctx,
question: str,
):
openai.api_key = os.getenv("OPENAI_API_KEY")
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"},
],
)
embed = discord.Embed(
description=completion.choices[0].message,
color=discord.Color.green(),
type="rich",
)
embed.set_
embed.set_author(
name="You asked me: %s" % question,
icon_url="https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/ChatGPT_logo.svg/2048px-ChatGPT_logo.svg.png",
)
await ctx.followup.send(embed=embed)
def setup(bot):
bot.add_cog(Gpt(bot))

View File

@ -27,7 +27,7 @@ class Markov(commands.Cog):
# Make the model # Make the model
user_model = markovify.Text(". ".join(authors_mesages)) user_model = markovify.Text(". ".join(authors_mesages))
model_json = user_model.to_json() user_model.to_json()
dummy = [] dummy = []
for i in range(random.randint(3, 9)): for i in range(random.randint(3, 9)):

View File

@ -1,197 +0,0 @@
from discord import option
from discord.ext import commands, tasks
import discord
import requests
from bs4 import BeautifulSoup
import re
import os
class PalWorld(commands.Cog):
def __init__(self, bot):
self.bot: commands.Bot = bot
# self.poll_server_population.start()
palworld = discord.SlashCommandGroup("palworld", "Palworld related commands")
async def get_all_pals(ctx: discord.AutocompleteContext):
"""
returns a list of all pals in the game, which can then be passed to the /ship command for auto complete
"""
import requests
from bs4 import BeautifulSoup
all_pals = []
url = "https://paldex.io/palworld/pals/"
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
x = soup.find_all(
"p",
class_="text-base lg:text-lg group-hover:underline underline-offset-4 text-center",
)
for pal in x:
all_pals.append(pal.text)
return sorted(set(all_pals))
@palworld.command(
guild_ids=None,
name="paldeck",
description="Looks up data about a pal",
)
async def pal_lookup(
self,
ctx: commands.Context,
pal: discord.Option(
str,
autocomplete=discord.utils.basic_autocomplete(get_all_pals),
description="Pal to look up",
),
):
pal_url = "https://paldex.io/palworld/pals/%s/" % pal.lower().replace(" ", "-")
response = requests.get(pal_url)
soup = BeautifulSoup(response.text, "html.parser")
elements = {}
pal_elements = soup.find("div", class_="flex flex-row flex-wrap gap-3")
for div in pal_elements:
pal_element_badge = div.find("img", class_="rounded-full w-12 px-2 py-2")
element_type = pal_element_badge.find_next("p").text
element_icon = "https://paldex.io" + pal_element_badge["src"]
elements[element_type] = element_icon
primary_element = list(elements.keys())[0]
# https://discordpy.readthedocs.io/en/latest/api.html?highlight=colour#discord.Colour
color_lookup = {
"Dark": discord.Color.dark_purple(),
"Dragon": discord.Color.purple(),
"Earth": discord.Color.greyple(),
"Electricity": discord.Color.yellow(),
"Fire": discord.Color.red(),
"Leaf": discord.Color.green(),
"Ice": discord.Color.blue(),
"Normal": discord.Color.lighter_grey(),
"Water": discord.Color.dark_blue(),
}
embed = discord.Embed(
description="-------",
color=color_lookup[primary_element],
type="rich",
title=pal.capitalize(),
)
embed.set_author(
name=", ".join(elements.keys()),
icon_url=elements[primary_element],
url=pal_url,
)
embed.set_thumbnail(
url=soup.find(
"img",
class_="rounded-full w-32 sm:w-auto border-2 border-amber-500 aspect-square",
)["src"]
)
# embed.add_field(name="Work Skills", value="-----", inline=False)
# work skills
skills_emojis = {
"Cooling": "❄️",
"Farming": "🚜",
"Gathering": "🍃",
"Generating Electricity": "⚡️",
"Handwork": "🤚",
"Kindling": "🔥",
"Lumbering": "🪵",
"Medicine Production": "💉",
"Mining": "⛏️",
"Planting": "🌱",
"Transporting": "📦",
"Watering": "💦",
}
skill_table = soup.find("div", class_="flex flex-col gap-2")
for div in skill_table.find_all(
"div", class_=re.compile(".*border-amber-300\s+break-all")
):
skill_name = div.find("p", class_="text-base sm:text-lg").text
skill_level = div.find(
"p", class_="text-base sm:text-lg mr-2 md:mr-4"
).text.split("Lv")[-1]
embed.add_field(
name=skills_emojis[skill_name] + " " + skill_name,
value="%s" % (int(skill_level) * "⭐️"),
inline=True,
)
# Partner Skill
embed.add_field(name="Partner Skill", value="-----", inline=False)
skill_name = soup.find("h2", string="Partner Skill").find_next(
"p", class_=re.compile(".*text-xl.*")
)
skill_description = skill_name.find_next("p", class_="text-lg mr-4").text
embed.add_field(
name=skill_name.text,
value=skill_description,
inline=False,
)
# Drops
embed.add_field(name="Drops", value="-----", inline=False)
for div in soup.find_all(
"div",
class_="inline-flex flex-col gap-1 items-center bg-black-300 border border-amber-300 break-all p-2",
):
item = div.text
item_name = item.split("Quantity")[0].split("Drop Chance")
amount = item.split("Quantity")[-1].split("Drop Chance")
embed.add_field(
name=" ".join(item_name),
value="",
inline=False,
)
await ctx.defer()
await ctx.send_followup(embed=embed)
@palworld.command(
guild_ids=None,
name="elements",
description="Posts an infographic about which Pal elements are weak/strong against which",
)
async def post_medpen_guide(self, ctx: commands.Context):
await ctx.respond(
"https://img.game8.co/3822502/5ae8382d16bd390dd19f343e87680d51.png/show"
)
# @tasks.loop(seconds=60)
# async def poll_server_population(self):
# # Wait until the bot is ready before we actually start executing code
# await self.bot.wait_until_ready()
# from source_rcon import SourceRcon
# from loguru import logger
# logger.disable("source_rcon")
# rcon = SourceRcon("192.168.1.200", 25575, os.getenv("pal_rcon_pass"))
# num_players = len(rcon.send_command("ShowPlayers").split("\n")[1:-1])
# # channel = self.bot.get_channel(1201389692759842816) # test server
# channel = self.bot.get_channel(1199397770746925239)
# if str(num_players) in channel.name.split("/")[0]:
# return
# await channel.edit(name="Palworlders (%s/16 online)" % num_players)
def setup(bot):
bot.add_cog(PalWorld(bot))

View File

@ -21,7 +21,7 @@ class ServerUtils(commands.Cog):
type=bool, type=bool,
default=False, default=False,
) )
async def invite(self, ctx: commands.Context, temp): async def invite(self, ctx: commands.Context, temp: bool):
# Default to creating the invite to the channel the message was sent in # Default to creating the invite to the channel the message was sent in
# if the user is in a voice channel, create the invite there # if the user is in a voice channel, create the invite there
invite_channel = ctx.channel invite_channel = ctx.channel
@ -32,13 +32,13 @@ class ServerUtils(commands.Cog):
except AttributeError: except AttributeError:
pass pass
if temporary_invite: if temp:
await ctx.author.send("Here is your temporary invite") await ctx.author.send("Here is your temporary invite")
invite = await invite_channel.create_invite( invite = await invite_channel.create_invite(
max_uses=1, max_uses=1,
max_age=3600, max_age=3600,
temporary=temporary_invite, temporary=temp,
) )
await ctx.respond("Check your DMs") await ctx.respond("Check your DMs")
await ctx.author.send(invite) await ctx.author.send(invite)
@ -98,7 +98,7 @@ class ServerUtils(commands.Cog):
for role in ctx.guild.roles: for role in ctx.guild.roles:
try: try:
if role.name != "@everyone": if role.name != "@everyone":
await bot.add_roles(ctx.author, role) await self.bot.add_roles(ctx.author, role)
except Exception: except Exception:
pass pass
@ -247,10 +247,10 @@ class ServerUtils(commands.Cog):
), ),
} }
voice_channel = await ctx.guild.create_voice_channel( await ctx.guild.create_voice_channel(
name=channel_role_name, bitrate=96000, overwrites=overwrites name=channel_role_name, bitrate=96000, overwrites=overwrites
) )
text_channel = await ctx.guild.create_text_channel( await ctx.guild.create_text_channel(
name=channel_role_name, overwrites=overwrites name=channel_role_name, overwrites=overwrites
) )

View File

@ -64,7 +64,7 @@ class StableDiffusion(commands.Cog):
s.settimeout(1) s.settimeout(1)
try: try:
s.connect((ip, int(port))) s.connect((ip, int(port)))
except: except Exception:
ip = "192.168.1.52" ip = "192.168.1.52"
try: try:
await ctx.defer() await ctx.defer()

46
app/cogs/trackdays.py Executable file
View File

@ -0,0 +1,46 @@
from discord.ext import commands
import discord
import requests
from bs4 import BeautifulSoup
class TrackDays(commands.Cog):
def __init__(self, bot):
self.bot: commands.Bot = bot
async def get_all_tracks(ctx: discord.AutocompleteContext):
"""
returns a list of all the cali tracks for use in auto-complete
"""
url = "https://www.trackpinata.com/"
response = requests.get(url).text
soup = BeautifulSoup(response, "html.parser")
return [x.text for x in soup.find_all("h2", class_="thumbnail-header")]
@commands.slash_command(
guild_ids=None,
name="trackdays",
description="Look up upcoming trackdays",
)
async def trackdays_lookup(
self,
ctx: commands.Context,
track: discord.Option(
str,
autocomplete=discord.utils.basic_autocomplete(get_all_tracks),
description="Track to look up days for",
),
):
track = track.replace(" ", "-").lower()
base_url = f"https://www.trackpinata.com/tracks/{track}"
response = requests.get(base_url)
soup = BeautifulSoup(response.text, "html.parser")
soup.find_all("a", class_="list-item w-inline-block")
def setup(bot):
bot.add_cog(TrackDays(bot))

View File

@ -44,7 +44,7 @@ def make_request(name, server):
free_company = player_blob["FreeCompany"] free_company = player_blob["FreeCompany"]
fc_member_count = free_company["ActiveMemberCount"] fc_member_count = free_company["ActiveMemberCount"]
fc_name = free_company["Name"] fc_name = free_company["Name"]
fc_slogan = free_company["Slogan"] # fc_slogan = free_company["Slogan"]
fc_tag = free_company["Tag"] fc_tag = free_company["Tag"]
fc_rank = free_company["Rank"] fc_rank = free_company["Rank"]
fc_estate = free_company["Estate"] fc_estate = free_company["Estate"]

View File

@ -12,7 +12,7 @@ def get_river_stats(river_id):
soup = BeautifulSoup(url.content, "lxml") soup = BeautifulSoup(url.content, "lxml")
river_name = " ".join(soup.find("h2").text.split()[2:]) river_name = " ".join(soup.find("h2").text.split()[2:])
table = soup.find("table", border=1, align="left") table = soup.find("table", border=1, align="left")
title = table.find("caption").text.strip().split("--")[0].strip() # title = table.find("caption").text.strip().split("--")[0].strip()
for rows in table.findAll("tr"): for rows in table.findAll("tr"):
flow_value = rows.findAll("td", {"class": "highlight2"}) flow_value = rows.findAll("td", {"class": "highlight2"})

View File

@ -1,4 +1,3 @@
from bs4 import BeautifulSoup
import base64 import base64
import httpx import httpx
import tempfile import tempfile

View File

@ -66,11 +66,11 @@ async def rsi_find(player):
if "avatar_default_big" not in profile_photo: if "avatar_default_big" not in profile_photo:
profile_photo = base_url + profile_photo profile_photo = base_url + profile_photo
handle = ( # handle = (
soup.find("span", class_="label", string="Handle name") # soup.find("span", class_="label", string="Handle name")
.findNext("strong", class_="value") # .findNext("strong", class_="value")
.text # .text
) # )
citizen_number = ( citizen_number = (
soup.find("span", class_="label", string="UEE Citizen Record") soup.find("span", class_="label", string="UEE Citizen Record")
@ -222,14 +222,14 @@ async def get_ship(ship_name):
item_uuid = "N/A" item_uuid = "N/A"
embed.set_footer(text="item UUID: %s" % item_uuid) embed.set_footer(text="item UUID: %s" % item_uuid)
try: # try:
description = ( # description = (
soup.find("section", {"class": "citizen-section-collapsible"}) # soup.find("section", {"class": "citizen-section-collapsible"})
.findNext("p") # .findNext("p")
.text # .text
) # )
except Exception: # except Exception:
description = "N/A" # description = "N/A"
# embed.add_field(name="**Description**", #value=description, inline=False) # embed.add_field(name="**Description**", #value=description, inline=False)
ship_image = (soup.find("a", {"class": "mw-file-description"})).img["src"] ship_image = (soup.find("a", {"class": "mw-file-description"})).img["src"]
@ -242,7 +242,7 @@ async def get_ship(ship_name):
.findNext("a") .findNext("a")
.text .text
) )
except: except Exception:
manufacturer = "" manufacturer = ""
embed.set_thumbnail( embed.set_thumbnail(
@ -260,7 +260,7 @@ async def get_ship(ship_name):
.findNext("div") .findNext("div")
.text .text
) )
except: except Exception:
ship_role = "" ship_role = ""
embed.add_field(name="**Role**", value=ship_role) embed.add_field(name="**Role**", value=ship_role)
@ -289,7 +289,7 @@ async def get_ship(ship_name):
if "Not available" in ingame_price: if "Not available" in ingame_price:
price = "N/A" price = "N/A"
except: except Exception:
price = "N/A" price = "N/A"
embed.add_field( embed.add_field(

View File

@ -1,5 +1,4 @@
import discord import discord
import requests
import yfinance as yf import yfinance as yf
import os import os
@ -10,7 +9,7 @@ def parse_message(symbols, verbose):
for s in symbols.split(): for s in symbols.split():
try: try:
embeds.append(get_stock(s, verbose=verbose)) embeds.append(get_stock(s, verbose=verbose))
except Exception as e: except Exception:
bad_tickers.append(s) bad_tickers.append(s)
if bad_tickers: if bad_tickers:
embeds.append(_make_error_embed(bad_tickers)) embeds.append(_make_error_embed(bad_tickers))
@ -90,17 +89,9 @@ def get_stock(share_name, verbose=False, fast=False):
try: try:
os.mkdir("/root/.cache/py-yfinance") os.mkdir("/root/.cache/py-yfinance")
except OSError as error: except OSError:
pass pass
change_symbol = "+"
embed_color = 2067276
meme_url = "https://i.ytimg.com/vi/if-2M3K1tqk/hqdefault.jpg"
embed = discord.Embed(description="-------", color=embed_color, type="rich")
embed.set_thumbnail(url=meme_url)
embed.set_author(name=share_name)
try: try:
if fast: if fast:
request = yf.Ticker(share_name).fast_info request = yf.Ticker(share_name).fast_info
@ -110,16 +101,22 @@ def get_stock(share_name, verbose=False, fast=False):
request = yf.Ticker(share_name).info request = yf.Ticker(share_name).info
current_change = request["currentPrice"] - request["open"] current_change = request["currentPrice"] - request["open"]
current_price = request["currentPrice"] current_price = request["currentPrice"]
except Exception as e: except Exception:
raise ValueError("Invalid symbol %s: empty response from Yahoo" % share_name) raise ValueError("Invalid symbol %s: empty response from Yahoo" % share_name)
# If stock price has gone down since open, use red and a sad stonk meme
# current_change = request["lastPrice"] - request["open"] # If stock price has gone down since open, use red and a sad stonk meme
# change_symbol = "+"
embed_color = 2067276
meme_url = "https://i.ytimg.com/vi/if-2M3K1tqk/hqdefault.jpg"
if current_change < 0: if current_change < 0:
change_symbol = "-" # change_symbol = "-"
embed_color = 15158332 embed_color = 15158332
meme_url = "https://i.kym-cdn.com/photos/images/facebook/002/021/567/635.png" meme_url = "https://i.kym-cdn.com/photos/images/facebook/002/021/567/635.png"
embed = discord.Embed(description="-------", color=embed_color, type="rich")
embed.set_thumbnail(url=meme_url)
embed.set_author(name=share_name)
embed.add_field( embed.add_field(
name="Current price", name="Current price",
value="$" + format(current_price, ",.2f"), value="$" + format(current_price, ",.2f"),

View File

@ -1,78 +0,0 @@
from datetime import datetime
import json
import httpx
import xmltodict
async def get_msreg(track):
base_url = "https://api.motorsportreg.com/rest/calendars/organization"
orgs = {
"turn8": "F3469266-BEFF-E329-4FD6C4B189ACE2A8",
"speedventures": "DF7453ED-BF33-DC17-2C9BFD84C1F05E86",
"speedsf": "072A885E-AD68-6F64-E88C19E4D0D21DFB",
"speeddistrict": "2E22740B-E8C9-9FB9-21406A496429A28B",
"socaldriversclub": "B4FC0113-C903-E9D3-68562D6765806945",
"ongrid": "06277C99-00C9-23EB-FD08FE5275BCC0C5",
"nextlevel": "CC23AEA4-AAB1-D087-4A10818D229DAFD2",
"lightspeed": "BC6417B8-0ED9-DD48-28BA1463C2C14322",
"fast_toys": "F2829F4E-91A1-30B9-919956FB1BE3CFB4",
"drive_tracktime": "F8940175-D299-85F5-4BFFE1243A2D0B88",
"trackedllc": "22332933-D95D-7DD2-A81CE491A98854D5",
}
events = {}
client = httpx.AsyncClient()
if track == "Both":
tracks_we_care_about = ["buttonwillow", "thunderhill"]
else:
tracks_we_care_about = [track.lower()]
for org_name, org_id in orgs.items():
xml_blob = await client.get(
"%s/%s?exclude_cancelled=true&postalcode=94549&radius=500"
% (base_url, org_id)
)
awaited_xml_blob = xml_blob.text
json_blob = json.loads(
json.dumps(xmltodict.parse(awaited_xml_blob)["response"]["events"])
)
# prints for debug
import pprint
pp = pprint.PrettyPrinter(indent=4)
# If an organizer only has one upcoming event on MSReg, it is a dict, otherwise its a list of dicts
# My code assumes list of dicts, so wrap the event dict in a list of 1 item
if json_blob and isinstance(json_blob["event"], dict):
json_blob["event"] = [json_blob["event"]]
try:
for event in json_blob["event"]:
if any(
x in event["venue"]["name"].lower() for x in tracks_we_care_about
):
event_object = {
"event_organizer": event["organization"]["name"],
"event_name": event["name"],
"event_url": event["detailuri"].split("?utm")[0],
"event_date": event["start"],
}
track = event["venue"]["name"]
if track not in events:
events[track] = []
events[track].append(event_object)
for track, track_events in events.items():
events[track] = sorted(
track_events,
key=lambda event: datetime.fromisoformat(
event["event_date"]
),
)
except Exception as e:
print("Errored on %s" % org_name)
print(e)
pass
return events

View File

@ -6,7 +6,6 @@ from diagrams.generic.os import LinuxGeneral
from diagrams.k8s.compute import Pod from diagrams.k8s.compute import Pod
from diagrams.onprem.container import Docker from diagrams.onprem.container import Docker
from diagrams.onprem.compute import Server from diagrams.onprem.compute import Server
from diagrams.k8s.compute import Pod
from diagrams.k8s.podconfig import Secret from diagrams.k8s.podconfig import Secret