From 57d0eeaf0f6c91fd9c683e23306369b2a1e93397 Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Fri, 24 May 2024 21:20:09 -0400 Subject: [PATCH] pylint (#8) Current score: Your code has been rated at 8.08/10 (previous run: 7.98/10, +0.09) Reviewed-on: https://gitea.balki.me/balki/mail4one/pulls/8 --- DEVNOTES.md | 38 ++++++++++++++++++++++++++++ mail4one/config.py | 5 ++-- mail4one/pop3.py | 60 +++++++++++++++++++++----------------------- mail4one/poputils.py | 2 -- mail4one/server.py | 10 +++----- mail4one/smtp.py | 10 +++++--- 6 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 DEVNOTES.md diff --git a/DEVNOTES.md b/DEVNOTES.md new file mode 100644 index 0000000..56099dd --- /dev/null +++ b/DEVNOTES.md @@ -0,0 +1,38 @@ +Notes for developers + +## Running just one test + +``` +python -m unittest tests.test_pop.TestPop3.test_CAPA +``` + +## Patch for enable logging in test + +Patch generated using below + +``` +git diff --patch -U1 tests >> ./DEVNOTES.md +``` + +Apply with below + +```bash +git apply - < None: + global MAILS_PATH +- logging.basicConfig(level=logging.CRITICAL) ++ logging.basicConfig(level=logging.DEBUG) + td = tempfile.TemporaryDirectory(prefix="m41.pop.") +PATCH +``` + +## pylint + +``` +pylint mail4one/*py > /tmp/errs +vim +"cfile /tmp/errs" +``` diff --git a/mail4one/config.py b/mail4one/config.py index eebe563..97ab9dd 100644 --- a/mail4one/config.py +++ b/mail4one/config.py @@ -96,11 +96,10 @@ def parse_checkers(cfg: Config) -> list[Checker]: raise Exception("Both addrs and addr_rexs is set") if m.addrs: return lambda malias: malias in m.addrs - elif m.addr_rexs: + if m.addr_rexs: compiled_res = [re.compile(reg) for reg in m.addr_rexs] return lambda malias: any(reg.match(malias) for reg in compiled_res) - else: - raise Exception("Neither addrs nor addr_rexs is set") + raise Exception("Neither addrs nor addr_rexs is set") matches = {m.name: make_match_fn(Match(m)) for m in cfg.matches or []} matches[DEFAULT_MATCH_ALL] = lambda _: True diff --git a/mail4one/pop3.py b/mail4one/pop3.py index 46bc316..9f56854 100644 --- a/mail4one/pop3.py +++ b/mail4one/pop3.py @@ -72,14 +72,14 @@ class PopLogger(logging.LoggerAdapter): def __init__(self): super().__init__(logging.getLogger("pop3"), None) - def process(self, msg, kwargs): - state: State = c_state.get(None) - if not state: - return super().process(msg, kwargs) + def process(self, log_msg, kwargs): + st: State = c_state.get(None) + if not st: + return super().process(log_msg, kwargs) user = "NA" - if state.username: - user = state.username - return super().process(f"{state.ip} {state.req_id} {user} {msg}", kwargs) + if st.username: + user = st.username + return super().process(f"{st.ip} {st.req_id} {user} {log_msg}", kwargs) logger = PopLogger() @@ -101,8 +101,7 @@ async def next_req() -> Request: if request.cmd == Command.QUIT: raise ClientQuit return request - else: - raise ClientError(f"Bad command {InvalidCommand.RETRIES} times") + raise ClientError(f"Bad command {InvalidCommand.RETRIES} times") async def expect_cmd(*commands: Command) -> Request: @@ -150,25 +149,23 @@ async def auth_stage() -> None: write(ok("Following are supported")) write(msg("USER")) write(end()) - else: - await handle_user_pass_auth(req) - if state().username in scfg().loggedin_users: - logger.warning( - f"User: {state().username} already has an active session" - ) - raise AuthError("Already logged in") - else: - scfg().loggedin_users.add(state().username) - write(ok("Login successful")) - return + continue + await handle_user_pass_auth(req) + if state().username in scfg().loggedin_users: + logger.warning( + f"User: {state().username} already has an active session" + ) + raise AuthError("Already logged in") + scfg().loggedin_users.add(state().username) + write(ok("Login successful")) + return except AuthError as ae: write(err(f"Auth Failed: {ae}")) - except ClientQuit as c: + except ClientQuit: write(ok("Bye")) logger.warning("Client has QUIT before auth succeeded") raise - else: - raise ClientError("Failed to authenticate") + raise ClientError("Failed to authenticate") def trans_command_capa(_, __) -> None: @@ -269,9 +266,8 @@ async def process_transactions(mails_list: list[MailEntry]) -> set[str]: except KeyError: write(err("Not implemented")) raise ClientError("We shouldn't reach here") - else: - func(mails, req) - await state().writer.drain() + func(mails, req) + await state().writer.drain() def get_deleted_items(deleted_items_path: Path) -> set[str]: @@ -302,7 +298,7 @@ async def transaction_stage() -> None: deleted_items_path, existing_deleted_items.union(new_deleted_items) ) - logger.info(f"Saved deleted items") + logger.info("Saved deleted items") async def start_session() -> None: @@ -339,13 +335,13 @@ def parse_users(users: list[User]) -> dict[str, tuple[PWInfo, str]]: def make_pop_server_callback(mails_path: Path, users: list[User], timeout_seconds: int): - scfg = SharedState(mails_path=mails_path, users=parse_users(users)) + s_state = SharedState(mails_path=mails_path, users=parse_users(users)) async def session_cb(reader: StreamReader, writer: StreamWriter): - c_shared_state.set(scfg) + c_shared_state.set(s_state) ip, _ = writer.get_extra_info("peername") - c_state.set(State(reader=reader, writer=writer, ip=ip, req_id=scfg.next_id())) - logger.info(f"Got pop server callback") + c_state.set(State(reader=reader, writer=writer, ip=ip, req_id=s_state.next_id())) + logger.info("Got pop server callback") try: try: return await asyncio.wait_for(start_session(), timeout_seconds) @@ -367,7 +363,7 @@ async def create_pop_server( timeout_seconds: int = 60, ) -> asyncio.Server: logging.info( - f"Starting POP3 server {host=}, {port=}, {mails_path=!s}, {len(users)=}, {ssl_context != None=}, {timeout_seconds=}" + f"Starting POP3 server {host=}, {port=}, {mails_path=!s}, {len(users)=}, {bool(ssl_context)=}, {timeout_seconds=}" ) return await asyncio.start_server( make_pop_server_callback(mails_path, users, timeout_seconds), diff --git a/mail4one/poputils.py b/mail4one/poputils.py index 451a1e2..d4a1218 100644 --- a/mail4one/poputils.py +++ b/mail4one/poputils.py @@ -20,12 +20,10 @@ class ClientDisconnected(ClientError): class InvalidCommand(ClientError): RETRIES = 3 """WIll allow NUM_BAD_COMMANDS times""" - pass class AuthError(ClientError): RETRIES = 3 - pass class Command(Enum): diff --git a/mail4one/server.py b/mail4one/server.py index f701e68..9188476 100644 --- a/mail4one/server.py +++ b/mail4one/server.py @@ -42,17 +42,15 @@ async def a_main(cfg: config.Config) -> None: def get_tls_context(tls: Union[config.TLSCfg, str]): if tls == "default": return default_tls_context - elif tls == "disable": + if tls == "disable": return None - else: - tls_cfg = config.TLSCfg(tls) - return create_tls_context(tls_cfg.certfile, tls_cfg.keyfile) + tls_cfg = config.TLSCfg(tls) + return create_tls_context(tls_cfg.certfile, tls_cfg.keyfile) def get_host(host): if host == "default": return cfg.default_host - else: - return host + return host mbox_finder = config.gen_addr_to_mboxes(cfg) servers: list[asyncio.Server] = [] diff --git a/mail4one/smtp.py b/mail4one/smtp.py index a01ae26..fa0a557 100644 --- a/mail4one/smtp.py +++ b/mail4one/smtp.py @@ -24,6 +24,8 @@ class MyHandler(AsyncMessage): super().__init__() self.mails_path = mails_path self.mbox_finder = mbox_finder + self.rcpt_tos = [] + self.peer = None async def handle_DATA( self, server: SMTP, session: SMTPSession, envelope: SMTPEnvelope @@ -32,7 +34,7 @@ class MyHandler(AsyncMessage): self.peer = session.peer return await super().handle_DATA(server, session, envelope) - async def handle_message(self, m: Message): # type: ignore[override] + async def handle_message(self, message: Message): # type: ignore[override] all_mboxes: set[str] = set() for addr in self.rcpt_tos: for mbox in self.mbox_finder(addr.lower()): @@ -49,7 +51,7 @@ class MyHandler(AsyncMessage): temp_email_path = Path(tmpdir) / filename with open(temp_email_path, "wb") as fp: gen = BytesGenerator(fp, policy=email.policy.SMTP) - gen.flatten(m) + gen.flatten(message) for mbox in all_mboxes: shutil.copy(temp_email_path, self.mails_path / mbox / "new") logger.info( @@ -102,7 +104,7 @@ async def create_smtp_server_starttls( smtputf8: bool, ) -> asyncio.Server: logging.info( - f"Starting SMTP STARTTLS server {host=}, {port=}, {mails_path=!s}, {ssl_context != None=}" + f"Starting SMTP STARTTLS server {host=}, {port=}, {mails_path=!s}, {bool(ssl_context)=}" ) loop = asyncio.get_event_loop() return await loop.create_server( @@ -129,7 +131,7 @@ async def create_smtp_server( smtputf8: bool, ) -> asyncio.Server: logging.info( - f"Starting SMTP server {host=}, {port=}, {mails_path=!s}, {ssl_context != None=}" + f"Starting SMTP server {host=}, {port=}, {mails_path=!s}, {bool(ssl_context)=}" ) loop = asyncio.get_event_loop() return await loop.create_server(