Qiling Framework is always a fast-evolving project thanks to the efforts of the whole community. Since more and more developers join us, it's also a big challenge to maintain the whole project clean and thus here comes the contribution guide.
Before creating your first pull request, please read this page carefully.
- Join our telegram group, most of our developers are active in this group.
- Follow our twitter @qiling_io to get latest news.
- Don't forget to give us a star on Github!
Check existing issue/PR
Before starting your first line, there are a bunch of reading materials for you to get start.
See here for a full list.
Based on dev and merge to dev
Once you fork our project and decide to write your awesome PR, one thing you should keep in mind is that: Always work on dev branch.
In Qiling Framework, dev branch means new features, new fixes and testing functions where new pull requests should be based on.
Since the refactor is going on, you may find some parts of current codebase are opposite to these conventions.
ql.log, which is a
When catching an exception, besides simply raising it,
ql.log.exception can be of great help.
try: 1/0 except ZeroDivisionError as e: #print(e) ql.log.exception("Divide by zero!")
Whenever you would like to add a class member, consider property instead.
class QlOsDumb: def __init__(self): #self.dumb = 1 self._dumb = 1 @property def dumb(self): return self._dumb def do_something(self): print(self.dumb)
Python property is more readable and helpful for code autocompletion.
Python type hinting is a kind of edit-time annotation which provides extra information for autocompletion.
def ql_is_multithread(ql: Qiling) -> bool: return ql.multithread
Due to the historical design problem, you may encounter cyclic import when adding type hints. See this link for a clean solution.
Whenever possible, add docstring for your method or property.
def ql_dumb_function(): """ This is a docstring """ pass
See codes below for naming convention.
# Class: PascalCase class QlOsDumb: pass # Function: snake_case def ql_dumb_function(): pass # Variable: snake_case mem_ptr = 0 # Constants: UPPERCASE # If the constant is from other place, e.g. Linux Kernel, follow their naming convention. ERROR = 0
If your PR consists of some new features, remember to add a new test.
See test_pathutils.py for an example.
Always prefer relative imports for qiling modules.
from .mapper import QlFsMapper
Built in modules should be imported either in one line or fully seperately.
# ok import logging, os, re # ok import logging import re import os # no import logging, re import os
Due to the historical design problem on project structure, you may have to use full import like
from qiling.os.utils import * sometimes.
You should leave comments for your code if it matches the following cases:
- This part of code is copied/rewritten/extracted from other location, e.g. Linux kernel, etc.
- This implementation follows some external documents, e.g. Linux manual.
- This code has some unexpected side effects.
Of course, the more, the better.
Finally, before merging your PR into dev branch, one last thing you have to do is to update Changelog.