backup the current project
"""convert code to markdown
"""
import datetime
import os
import platform
import re
import shutil
class CodeToMarkDown:
"""_summary_"""
__slots__ = ["path", "md_path", "code_file_path", "exclude_dirs", "exclude_files", "md_suffix_table", "include_exts", "key_work_filter_list"]
def __init__(self, path: str = None) -> None:
if path:
self.path = path
else:
self.path = os.getcwd()
# 需要排除的目录
self.exclude_dirs = [
"__pycache__",
"venv",
"build",
"dist",
"node_modules",
"public",
"LICENSE",
"assets",
"vendor",
"tmp",
"static",
"templates",
"bin",
"obj",
"Migrations",
"Properties",
"packages",
]
# 排除的文件的后缀
self.exclude_files = [
"_NOTE.md",
".d.ts",
".lock",
".png",
".woff2",
".ttf",
".woff",
".css",
"README.md",
".toml",
"swagger-ui-bundle.js",
"-lock.json",
"zz_code2md.py",
"zz.py",
"temp.md",
]
# 文件后缀名对应的 md code代码提示名
self.md_suffix_table = {"command": "sh", "csproj": "xml"}
# 需要包含的文件后缀名
self.include_exts = [
".py",
".vue",
".js",
".ts",
".html",
".go",
".mod",
".json",
".txt",
".sh",
".command",
".cs",
"csproj",
".jsx",
".sln",
".sh",
".bat",
]
# 需要过滤的文件名的后缀
self.key_work_filter_list = [""]
def generate_md(self):
self.__generate_md_file_path()
self.__collect_code_files()
self.__generate_md_file()
def __generate_md_file_path(self):
cur_time_str = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
md_name = f"Z_{cur_time_str}_NOTE.md"
self.md_path = os.path.join(self.path, md_name)
def __collect_code_files(self):
"""_summary_
Returns:
_type_: _description_
"""
self.code_file_path = []
for root, dirs, files in os.walk(self.path):
# 过滤不符合的文件夹------------------------------------------------------------------------
dirs[:] = [d for d in dirs if not d.startswith(".") and not any(ex in d for ex in self.exclude_dirs)]
# 过滤不符合的文件-----------------------------------------------------------------------------
files[:] = [f for f in files if not f.startswith(".") and not any(ex in f for ex in self.exclude_files)]
# 筛选所有符合后缀的文件------------------------------------------------------------------------
for file in files:
# 正向过滤含有(\.py|vue|js|ts)$ 结尾的文件
if any(file.endswith(ext) for ext in self.include_exts):
self.code_file_path.append(os.path.join(root, file))
def __generate_md_file(self):
for i, code_file_path in enumerate(self.code_file_path):
print(i + 1, "->", self.__get_md_title_level_one(code_file_path))
self.__readcode_writemd(code_file_path)
def __get_md_title_level_one(self, code_file_path):
"""获取每个代码文件的md标题,去掉项目之前的文件路径
Args:
code_file_path (_type_): 代码路径
project_path (_type_): 项目根路径
Returns:
_type_: 每个代码文件的md标题
"""
# Get the common prefix of the two paths
common_prefix = os.path.commonprefix([code_file_path, self.path])
# Get the different parts of the two paths
diff1 = code_file_path[len(common_prefix) + 1 :]
md_title = os.path.join(os.path.basename(self.path), diff1)
return md_title
def __readcode_writemd(self, code_file_path):
"""_summary_
Args:
code_file_path (_type_): _description_
"""
with open(code_file_path, "r", encoding="utf-8") as f: # 打开文件
try:
content = f.read()
except Exception as e:
print(f"{code_file_path}{e}文件编码读取错误")
content = ""
self.__write2md(content, code_file_path)
def __write2md(
self,
content,
code_file_path,
):
"""_summary_
Args:
content (_type_): _description_
suffix (_type_): _description_
code_file_path (_type_): _description_
"""
with open(self.md_path, "a", encoding="utf-8") as f: # 打开文件
md_title_level_one = self.__get_md_title_level_one(code_file_path)
code_label = self.__get_code_md_lable_by_suffix(code_file_path)
f.write("\n")
f.write(f"# `{md_title_level_one}`\n\n")
f.write(f"```{code_label}\n")
f.write(content)
f.write("\n")
f.write("```\n\n\n")
def __get_code_md_lable_by_suffix(self, code_file_path):
suffix = re.findall(r'\.[^.\\/:*?"<>|\r\n]+$', code_file_path)
if len(suffix):
suffix = suffix[0][1:]
if self.md_suffix_table.get(suffix) is not None:
return self.md_suffix_table.get(suffix)
return suffix
class MarkdownToCode:
"""_summary_
Returns:
_type_: _description_
"""
__slots__ = ["path", "base_dir"]
def __init__(self, path: str = None) -> None:
if path:
self.path = path
else:
self.path = self.__get_latest_md_file_path()
def __get_latest_md_file_path(self):
dst_md_files = []
for root, _, files in os.walk(os.getcwd()):
for file in files:
if file.endswith("_NOTE.md"):
dst_md_files.append(os.path.join(root, file))
return sorted(dst_md_files).pop()
def generate_code(self):
self.__set_base_dir()
self.__read_md_file()
def __read_md_file(self):
"""_summary_"""
with open(self.path, "r", encoding="utf-8") as f: # 打开文件
md_text = f.read()
# Match the first-level headings and code blocks
# \n{1,}# `(.+)`\n{1,}```\w{2,5}\n{1,}
pattern = r"^# `(.+)`\n{1,}```(?:\w{2,}\n)([\s\S]+?)\n{1,}```\n{1,}"
matches = re.findall(pattern, md_text, re.MULTILINE)
# Loop over the matches
for i, (file_path, code) in enumerate(matches):
print(f"{i}->", file_path)
self.__create_from_file_path(file_path, code)
def __set_base_dir(self):
self.base_dir = os.path.dirname(self.path)
def __create_from_file_path(self, file_path, content):
"""_summary_
Args:
file_path (_type_): _description_
content (_type_): _description_
"""
dir_path = os.path.join(self.base_dir, os.path.dirname(file_path))
os.makedirs(dir_path, exist_ok=True)
full_file_path = os.path.join(self.base_dir, file_path)
with open(full_file_path, "w", encoding="utf-8") as f:
f.write(content)
class CollectMarkdownNote:
"""_summary_"""
__slots__ = [
"path",
"md_path",
"cur_file_name",
"cur_file_new_name",
"md_files",
"dotnet_md_files",
"python_md_files",
"dotnet_line_number_start",
"dotnet_split_flag",
"dotnet_file_names",
"python_split_flag",
"current_new_md_file_name",
"save_md_file_heads",
"split_flag",
"other_split_flag",
"other_md_files",
]
def __init__(self, path: str = None) -> None:
if path:
self.path = path
else:
self.path = os.getcwd()
self.dotnet_line_number_start = []
self.dotnet_file_names = []
self.current_new_md_file_name = None
# 需要保留的markdown文件的开头
# self.save_md_file_heads = ["zz_dotnet", "zz_python", "zz_csharp", "zz_note", "zz_"]
self.save_md_file_heads = ["zz_"]
# 需要需要的markdown文件,zz_开头,不在zz_note里面的markdown文件
self.md_files = []
# 需要收集的关于dotent的md文件,zz_开头,不在zz_note里面
self.dotnet_md_files = []
# 需要收集的关于python的md文件,zz_开头,不在zz_note里面
self.python_md_files = []
# 需要收集的关于python的md文件,zz_开头,不在zz_note里面
self.other_md_files = []
# 即将生成的python文件的文件名,就是当前文件的文件夹,加上时间戳的后缀
self.cur_file_new_name = None
# 当前这个python脚本的文件名
self.cur_file_name = os.path.basename(__file__)
def collect_markdown(self):
"""收集当前项目中的markdown笔记"""
self.__get_new_python_file_name()
self.__get_cur_markdown_notes()
self.__read_cur_markdown_notes()
self.__generate_new_python_file()
def __write2md(self, line):
# 如我文件名不为空,代表可以写入,同时要过滤到python中的注释符号,防止python脚本出现错误
if (self.current_new_md_file_name is not None) and line != '"""\n' and line != '"""' and line != '\n"""':
nf = open(self.current_new_md_file_name, "a+", encoding="utf-8")
nf.write(line)
nf.close()
def un_collect_markdown(self):
"""doc"""
f = open(self.cur_file_name, "r", encoding="utf-8")
for i, line in enumerate(f):
self.__write2md(line)
res = re.findall(re.compile(r"^\"\"\"#==(.{1,10})=="), line)
if len(res) > 0:
self.current_new_md_file_name = self.__get_output_md_file_name_by_line(line)
print(i + 1, "->", self.current_new_md_file_name, "start")
if line.startswith('"""\n'):
print(i + 1, "->", self.current_new_md_file_name, "end")
self.current_new_md_file_name = None
def __get_output_md_file_name_by_line(self, line):
# 输出zz_note的子文件夹的名称,从"""==python==提取
dir_name = "other"
name = "other"
pattern = re.compile(r"^\"\"\"#==(.{1,10})==(.+).md")
res = pattern.match(line)
if res:
dir_name = res.groups()[0]
name = res.groups()[1]
# 生成markdown文件的后缀名,防止冲突
cur_time_str = str(datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))
# 生成的markdown文件的文件夹,zz_note/python,或者给zz_dotnet,取决于什么类型的文件
dir_path = os.path.join("zz_note", dir_name)
os.makedirs(dir_path, exist_ok=True)
return "zz_note/" + dir_name + "/" + name + "_" + cur_time_str + ".md"
def __read_cur_markdown_notes(self):
"""_summary_"""
for md_file in self.md_files:
if "dotnet" in md_file:
self.dotnet_md_files.append(md_file)
elif "python" in md_file:
self.python_md_files.append(md_file)
elif "other" in md_file:
self.other_md_files.append(md_file)
def __get_cur_markdown_notes(self):
"""_summary_"""
print("开始收集,所以以zz_开头的,不在zz_note文件夹中的markdown文件")
pattern = re.compile(r"zz_(\w+)_")
for root, dirs, files in os.walk(self.path):
dirs[:] = [d for d in dirs if "zz_note" not in d]
# 过滤符合的文件-----------------------------------------------------------------------------
files[:] = [f for f in files if not f.startswith(".") and any(ex in f for ex in [".md"])]
# 筛选所有符合后缀的文件------------------------------------------------------------------------
for i, file in enumerate(files):
print(i + 1, "->", file)
res = pattern.findall(file)
if len(res) > 0:
self.md_files.append(os.path.join(root, file))
def __get_new_python_file_name(self):
cur_time_str = str(datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))
file_names = self.cur_file_name.split("_")
if len(file_names) > 1:
self.cur_file_new_name = f"{os.path.splitext(file_names[0])[0]}_{cur_time_str}.py"
else:
self.cur_file_new_name = f"{os.path.splitext(self.cur_file_name)[0]}_{cur_time_str}.py"
def __get_cur_file_name(self, md_file_path):
return os.path.basename(md_file_path)
def __generate_new_python_file(self):
"""_summary_"""
f = open(self.cur_file_name, "r", encoding="utf-8")
for line in f:
nf = open(self.cur_file_new_name, "a+", encoding="utf-8")
nf.write(line)
for md_file in self.md_files:
split_flag = "other"
pattern = re.compile(r"zz_(\w+)_")
res = pattern.findall(md_file)
if len(res) > 0:
split_flag = res[0]
md_title = self.__get_cur_file_name(md_file)
content = self.__read_md_file(md_file)
nf.write(f'\n\n"""#=={split_flag}=={md_title}\n\n')
nf.write(self.__filter_python_comment(content))
nf.write('\n"""\n\n')
f.close()
nf.close()
# 备份新生成的python文件
self.__copy_current_python_file_to_dst_dir(self.cur_file_new_name)
def __copy_current_python_file_to_dst_dir(self, current_python_file_name):
"""备份新生成的python文件,到特定的文件夹
Args:
current_python_file_name (_type_): _description_
"""
system = platform.system()
if system == "Windows":
dir_path = r"D:/zz"
os.makedirs(dir_path, exist_ok=True)
shutil.copy(current_python_file_name, os.path.join(dir_path, current_python_file_name))
elif system == "Darwin":
dir_path = r"/Users/song/Code/zz_note"
os.makedirs(dir_path, exist_ok=True)
shutil.copy(current_python_file_name, os.path.join(dir_path, current_python_file_name))
else:
print("Unknown system")
def __filter_python_comment(self, content: str):
return content.replace('"""', "")
def __read_md_file(self, file):
with open(file, "r", encoding="utf-8") as f:
content = f.read()
return content
def backup_current_project():
"""_summary_"""
src_dir = os.path.dirname(__file__)
cur_time_str = str(datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
compress_filename = f"{os.path.basename(src_dir)}_{cur_time_str}"
dst_dir = os.path.join(
os.path.dirname(os.path.dirname(__file__)),
compress_filename,
)
shutil.copytree(src_dir, dst_dir)
if __name__ == "__main__":
print("===============================start===============================")
print("1. Project Convert to Markdown 2. Markdown Convert to Project")
print("3. Collect Markdown Notes 4. Uncollect Markdown Notes")
print("5. Backup the project ")
try:
option_number = int(input("Please input a number: "))
except Exception as e:
option_number = 0
print("您输入的整数是:", option_number)
if option_number == 1:
code2md = CodeToMarkDown()
code2md.generate_md()
elif option_number == 2:
md_path = input("请输入需要转换的markdown文件路径(默认使用当前路径最新的markdown文件) : ")
md2code = MarkdownToCode(md_path)
md2code.generate_code()
elif option_number == 3:
collect_md = CollectMarkdownNote()
collect_md.collect_markdown()
elif option_number == 4:
is_del = input("是否要删除现有的文件夹(Y/N):")
if is_del == "N" or is_del == "n":
pass
else:
try:
res = shutil.rmtree("zz_note")
print("zz_note文件夹,删除成功")
except FileNotFoundError as e:
print("no such directory,zz_note")
collect_md = CollectMarkdownNote()
collect_md.un_collect_markdown()
elif option_number == 5:
backup_current_project()
else:
print("unknown option")
print("===============================done===============================")
# ================================================================================================
"""#==python==zz_python_的vscode配置.md
# `.vscode/.Pylintrc`
```sh
# This Pylint rcfile contains a best-effort configuration to uphold the
# best-practices and style described in the Google Python style guide:
# https://google.github.io/styleguide/pyguide.html
#
# Its canonical open-source location is:
# https://google.github.io/styleguide/pylintrc
[MASTER]
# Files or directories to be skipped. They should be base names, not paths.
ignore=third_party
# Files or directories matching the regex patterns are skipped. The regex
# matches against base names, not paths.
ignore-patterns=
# Pickle collected data for later comparisons.
persistent=no
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Use multiple processes to speed up Pylint.
jobs=4
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=abstract-method,
broad-exception-caught,
missing-module-docstring,
apply-builtin,
arguments-differ,
attribute-defined-outside-init,
backtick,
bad-option-value,
basestring-builtin,
buffer-builtin,
c-extension-no-member,
consider-using-enumerate,
cmp-builtin,
cmp-method,
coerce-builtin,
coerce-method,
delslice-method,
div-method,
duplicate-code,
eq-without-hash,
execfile-builtin,
file-builtin,
filter-builtin-not-iterating,
fixme,
getslice-method,
global-statement,
hex-method,
idiv-method,
implicit-str-concat,
import-error,
import-self,
import-star-module-level,
inconsistent-return-statements,
input-builtin,
intern-builtin,
invalid-str-codec,
locally-disabled,
long-builtin,
long-suffix,
map-builtin-not-iterating,
misplaced-comparison-constant,
metaclass-assignment,
next-method-called,
next-method-defined,
no-absolute-import,
no-else-break,
no-else-continue,
no-else-raise,
no-else-return,
no-init, # added
no-member,
no-name-in-module,
no-self-use,
nonzero-method,
oct-method,
old-division,
old-ne-operator,
old-octal-literal,
old-raise-syntax,
parameter-unpacking,
print-statement,
raising-string,
range-builtin-not-iterating,
raw_input-builtin,
rdiv-method,
reduce-builtin,
relative-import,
reload-builtin,
round-builtin,
setslice-method,
signature-differs,
standarderror-builtin,
suppressed-message,
sys-max-int,
too-few-public-methods,
too-many-ancestors,
too-many-arguments,
too-many-boolean-expressions,
too-many-branches,
too-many-instance-attributes,
too-many-locals,
too-many-nested-blocks,
too-many-public-methods,
too-many-return-statements,
too-many-statements,
trailing-newlines,
unichr-builtin,
unicode-builtin,
unnecessary-pass,
unpacking-in-except,
useless-else-on-loop,
useless-object-inheritance,
useless-suppression,
using-cmp-argument,
wrong-import-order,
xrange-builtin,
zip-builtin-not-iterating,
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
[BASIC]
# Good variable names which should always be accepted, separated by a comma
good-names=main,_
# Bad variable names which should always be refused, separated by a comma
bad-names=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
# Regular expression matching correct function names
function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct constant names
const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression matching correct attribute names
attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
# Regular expression matching correct argument names
argument-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct class attribute names
class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression matching correct inline iteration names
inlinevar-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct class names
class-rgx=^_?[A-Z][a-zA-Z0-9]*$
# Regular expression matching correct module names
module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
# Regular expression matching correct method names
method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=10
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=150
# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
# lines made too long by directives to pytype.
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=(?x)(
^\s*(\#\ )?<?https?://\S+>?$|
^\s*(from\s+\S+\s+)?import\s+.+$)
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=yes
# Maximum number of lines in a module
max-module-lines=99999
# String used as indentation unit. The internal Google style guide mandates 2
# spaces. Google's externaly-published style guide says 4, consistent with
# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google
# projects (like TensorFlow).
indent-string=' '
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=TODO
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=yes
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging,absl.logging,tensorflow.io.logging
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,
TERMIOS,
Bastion,
rexec,
sets
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant, absl
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls,
class_
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=builtins.StandardError,
builtins.Exception,
builtins.BaseException
.vscode/settings.json
{
"python.analysis.autoImportCompletions": true,
// 若要为安装在非标准位置的包启用 IntelliSense,请将这些位置添加到 settings.json 文件中的 python.analysis.extraPaths 集合中(默认集合为空)。
// 例如,您可能已将 Google App Engine 安装在自定义位置,在本例中,请按如下方式指定这些位置:
// "python.analysis.extraPaths": [
// "C:/Program Files (x86)/Google/google_appengine",
// "C:/Program Files (x86)/Google/google_appengine/lib/flask-0.12"]
// "python.analysis.extraPaths": [],
"python.analysis.packageIndexDepths": [
{
"name": "fastapi",
"depth": 2
},
{
"name": "selenium",
"depth": 2,
"includeAllSymbols": false
}
],
// "pylint.path": ["${workspaceFolder}/.venv/bin", "-m", "pylint"],
// pylint的配置
"pylint.args": ["--rcfile=${workspaceFolder}/.vscode/.pylintrc"],
"[python]": {
"diffEditor.ignoreTrimWhitespace": false,
"editor.formatOnType": true,
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.wordBasedSuggestions": "off",
// "editor.defaultFormatter": "ms-python.pylint",
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"black-formatter.args": ["--line-length=150"],
"editor.tabSize": 2,
"isort.args": [
"--profile",
"black"
],
"dotnet.defaultSolution": "dotnet_agv_back.sln"
}
"""
"""#pythonzz_python_运行脚本bat_shell脚本.md
bat脚本传递文件路径给python脚本
简单版本
@echo off
:start
set filePath=
set /p filePath=Please input file path:
python main.py %filePath%
goto start
指定python的版本(Python虚拟环境)
@echo off
:start
set filePath=
set /p filePath=Please input file path:
D:\Python38\python E:\song\python_code2md\md2code\md2code.py %filePath%
goto start
shell脚本运行python(mac系统)
#! /bin/bash
# 激活虚拟环境,安装目前的情况,不需要虚拟环境,也可以实现
# source /home/song/venv/bin/activate
echo "请拖入一个代码项目根目录的文件或者文件夹:"
read file
python3 /Users/song/Code/script_python/code2md/md2code.py "$file"
# 等待五秒钟,然后自动关闭
sleep 3
osascript -e 'tell application "Terminal" to close first window' & exit
"""
"""#pythonzz_python_的gitignore文件.md
.gitignore
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
"""
"""#dotnetzz_dotnet_ef工具使用.md
EF Core
# 为模型的更改添加一个新的迁移
dotnet ef migrations add <NAME>
# 删除上一个迁移
dotnet ef migrations remove
# 列出所有的迁移
dotnet ef migrations list
# 生成一个SQL脚本,用于将数据库更新到指定的迁移
dotnet ef migrations script
# 将数据库更新到指定的迁移或最新的迁移
dotnet ef database update
# 删除数据库
dotnet ef database drop
# 从现有数据库生成模型
dotnet ef dbcontext scaffold <CONNECTION> <PROVIDER>
# 获取当前的DbContext的信息
dotnet ef dbcontext info
# 列出项目中的所有DbContext
dotnet ef dbcontext list
"""
"""#dotnetzz_dotnet_升级助手.md
.NET 升级助手
安装并运行升级助手
dotnet tool install -g upgrade-assistant
升级项目
upgrade-assistant upgrade <Path to Project>
"""
"""#dotnetzz_dotnet_的依赖注入.md
原先的模式
GamesEndpoints.cs
public static class GamesEndpoints
{
public static RouteGroupBuilder MapGamesEndpoints(this IEndpointRouteBuilder endpoints)
{
// 自动创建一个实例,然后使用
InMemGamesRepository repository = new();
var group = endpoints.MapGroup("/games").WithParameterValidation();
group.MapGet("/", () => repository.GetAll());
return group;
}
}
InMemGamesRepository.cs
using GameStore.Api.Entities;
namespace GameStore.Api.Repositoriesa;
public class InMemGamesRepository
{
private readonly List<Game> games = new()
{
new Game(){
Id = 1,
Name="Street Fighter II",
Genre ="Fighting",
Price = 19.99M,
ReleaseDate = new DateTime(1991,2,1),
ImgUri = "https://palcehold.co/100"
},
new Game(){
Id = 2,
Name="FIFA 23",
Genre ="Sports",
Price = 29.99M,
ReleaseDate = new DateTime(2022,2,1),
ImgUri = "https://palcehold.co/100"
},
};
public IEnumerable<Game> GetAll()
{
return games;
}
public Game? Get(int id)
{
return games.Find(game => game.Id == id);
}
public void Create(Game game)
{
game.Id = games.Max(game => game.Id) + 1;
games.Add(game);
}
public void Update(Game updatedGame)
{
var index = games.FindIndex(game => game.Id == updatedGame.Id);
games[index] = updatedGame;
}
public void Delete(int id)
{
var index = games.FindIndex(game => game.Id == id);
games.RemoveAt(index);
}
}
现在的模式
GamesEndpoints.cs
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using GameStore.Api.Entities;
using GameStore.Api.Repositoriesa;
namespace GameStore.Api.Endpoints;
public static class GamesEndpoints
{
const string GetGameEndpointName = "GetGame";
public static RouteGroupBuilder MapGamesEndpoints(this IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("/games").WithParameterValidation();
// 直接依赖注入
group.MapGet("/", (IGamesRepository repository) => repository.GetAll());
group.MapGet("/{id}", (IGamesRepository repository,int id) =>
{
Game? game = repository.Get(id);
if (game is null)
{
return Results.NotFound();
}
return Results.Ok(game);
}).WithName(GetGameEndpointName);
group.MapPut("/{id}", (IGamesRepository repository,int id, Game updatedGame) =>
{
Game? existingGame = repository.Get(id);
if (existingGame is null)
{
return Results.NotFound();
}
existingGame.Name = updatedGame.Name;
existingGame.Genre = updatedGame.Genre;
existingGame.Price = updatedGame.Price;
existingGame.ReleaseDate = updatedGame.ReleaseDate;
existingGame.ImgUri = updatedGame.ImgUri;
repository.Update(existingGame);
return Results.NoContent();
});
group.MapDelete("/{id}", (IGamesRepository repository,int id) =>
{
Game? game = repository.Get (id);
if (game is not null)
{
repository.Delete(id);
}
return Results.NoContent();
});
return group;
}
}
对比
手动实例化
InMemGamesRepository repository = new();
group.MapGet("/", () => repository.GetAll());
依赖注入
依赖注入:
group.MapGet("/", (IGamesRepository repository) => repository.GetAll());
注册服务:
只有在builder中注册了服务,上面的接口在访问的时候才会自动帮你实例化.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IGamesRepository, InMemGamesRepository>();
// builder.Services.AddScoped<IGamesRepository, InMemGamesRepository>();
"""
"""#dotnetzz_dotnet_接口的扩展方法.md
接口的扩展方法
定义
当我们在C#中定义接口时,有时候我们希望为接口添加一些额外的方法,但是我们又不想修改接口本身。这时,接口的扩展方法就派上用场了。
接口的扩展方法允许我们在不改变接口定义的情况下,为接口添加新的方法。这些方法可以像实例方法一样调用,但实际上它们是静态方法。
例子
假设我们有一个接口 IVehicle
,表示交通工具。我们想要为这个接口添加一个新的方法,计算交通工具行驶的英尺数。我们可以使用接口的扩展方法来实现这个功能。
public interface IVehicle
{
int MilesDriven { get; set; }
}
public static class Extensions
{
// 这是一个接口的扩展方法
public static int FeetDriven(this IVehicle vehicle)
{
// 假设1英里等于5028英尺
return vehicle.MilesDriven * 5028;
}
}
class Program
{
static void Main()
{
// 创建一个实现了 IVehicle 接口的类
var car = new Car { MilesDriven = 100 };
// 调用扩展方法
int feet = car.FeetDriven();
Console.WriteLine($"Car has driven {feet} feet.");
}
}
public class Car : IVehicle
{
public int MilesDriven { get; set; }
}
在上面的代码中,我们定义了一个接口 IVehicle
,表示交通工具。然后,我们创建了一个扩展方法 FeetDriven
,它可以在任何实现了 IVehicle
接口的类上调用。在 Main
方法中,我们创建了一个 Car
类的实例,并调用了扩展方法来计算行驶的英尺数。
总之,接口的扩展方法允许我们为接口添加新的方法,而无需修改接口本身。这对于在不破坏现有代码的情况下扩展接口功能非常有用。
this关键字
在C#中,this
关键字用于引用当前对象的实例。在接口的扩展方法中,this
关键字表示该方法是一个扩展方法,并且可以在实现了该接口的类的实例上调用。
让我详细解释一下:
- 当我们定义一个接口的扩展方法时,我们需要在静态类中创建一个静态方法。这个方法的第一个参数必须使用
this
关键字,指示我们要扩展的类型。 - 在调用这个扩展方法时,我们可以像调用实例方法一样使用它,但实际上它是一个静态方法。
this
关键字告诉编译器将当前实例作为第一个参数传递给这个方法。
例如,如果我们有一个接口 IVehicle
表示交通工具,我们可以为它添加一个扩展方法来计算行驶的英尺数。在这个方法中,this IVehicle vehicle
表示我们要在实现了 IVehicle
接口的类的实例上调用这个方法。
"""
"""#dotnetzz_dotnet_eftool指定文件夹.md
ef core 生成迁移文件时,如何指定文件夹
dotnet ef migrations add InitialCreate --output-dir Data/Migrations
dotnet ef database update
"""
"""#dotnetzz_dotnet_的依赖注入.md
原先的模式
GamesEndpoints.cs
public static class GamesEndpoints
{
public static RouteGroupBuilder MapGamesEndpoints(this IEndpointRouteBuilder endpoints)
{
// 自动创建一个实例,然后使用
InMemGamesRepository repository = new();
var group = endpoints.MapGroup("/games").WithParameterValidation();
group.MapGet("/", () => repository.GetAll());
return group;
}
}
InMemGamesRepository.cs
using GameStore.Api.Entities;
namespace GameStore.Api.Repositoriesa;
public class InMemGamesRepository
{
private readonly List<Game> games = new()
{
new Game(){
Id = 1,
Name="Street Fighter II",
Genre ="Fighting",
Price = 19.99M,
ReleaseDate = new DateTime(1991,2,1),
ImgUri = "https://palcehold.co/100"
},
new Game(){
Id = 2,
Name="FIFA 23",
Genre ="Sports",
Price = 29.99M,
ReleaseDate = new DateTime(2022,2,1),
ImgUri = "https://palcehold.co/100"
},
};
public IEnumerable<Game> GetAll()
{
return games;
}
public Game? Get(int id)
{
return games.Find(game => game.Id == id);
}
public void Create(Game game)
{
game.Id = games.Max(game => game.Id) + 1;
games.Add(game);
}
public void Update(Game updatedGame)
{
var index = games.FindIndex(game => game.Id == updatedGame.Id);
games[index] = updatedGame;
}
public void Delete(int id)
{
var index = games.FindIndex(game => game.Id == id);
games.RemoveAt(index);
}
}
现在的模式
GamesEndpoints.cs
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using GameStore.Api.Entities;
using GameStore.Api.Repositoriesa;
namespace GameStore.Api.Endpoints;
public static class GamesEndpoints
{
const string GetGameEndpointName = "GetGame";
public static RouteGroupBuilder MapGamesEndpoints(this IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("/games").WithParameterValidation();
// 直接依赖注入
group.MapGet("/", (IGamesRepository repository) => repository.GetAll());
group.MapGet("/{id}", (IGamesRepository repository,int id) =>
{
Game? game = repository.Get(id);
if (game is null)
{
return Results.NotFound();
}
return Results.Ok(game);
}).WithName(GetGameEndpointName);
group.MapPut("/{id}", (IGamesRepository repository,int id, Game updatedGame) =>
{
Game? existingGame = repository.Get(id);
if (existingGame is null)
{
return Results.NotFound();
}
existingGame.Name = updatedGame.Name;
existingGame.Genre = updatedGame.Genre;
existingGame.Price = updatedGame.Price;
existingGame.ReleaseDate = updatedGame.ReleaseDate;
existingGame.ImgUri = updatedGame.ImgUri;
repository.Update(existingGame);
return Results.NoContent();
});
group.MapDelete("/{id}", (IGamesRepository repository,int id) =>
{
Game? game = repository.Get (id);
if (game is not null)
{
repository.Delete(id);
}
return Results.NoContent();
});
return group;
}
}
对比
手动实例化
InMemGamesRepository repository = new();
group.MapGet("/", () => repository.GetAll());
依赖注入
依赖注入:
group.MapGet("/", (IGamesRepository repository) => repository.GetAll());
注册服务:
只有在builder中注册了服务,上面的接口在访问的时候才会自动帮你实例化.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IGamesRepository, InMemGamesRepository>();
// builder.Services.AddScoped<IGamesRepository, InMemGamesRepository>();
"""
"""#dotnetzz_dotnet_接口的扩展方法.md
接口的扩展方法
定义
当我们在C#中定义接口时,有时候我们希望为接口添加一些额外的方法,但是我们又不想修改接口本身。这时,接口的扩展方法就派上用场了。
接口的扩展方法允许我们在不改变接口定义的情况下,为接口添加新的方法。这些方法可以像实例方法一样调用,但实际上它们是静态方法。
例子
假设我们有一个接口 IVehicle
,表示交通工具。我们想要为这个接口添加一个新的方法,计算交通工具行驶的英尺数。我们可以使用接口的扩展方法来实现这个功能。
public interface IVehicle
{
int MilesDriven { get; set; }
}
public static class Extensions
{
// 这是一个接口的扩展方法
public static int FeetDriven(this IVehicle vehicle)
{
// 假设1英里等于5028英尺
return vehicle.MilesDriven * 5028;
}
}
class Program
{
static void Main()
{
// 创建一个实现了 IVehicle 接口的类
var car = new Car { MilesDriven = 100 };
// 调用扩展方法
int feet = car.FeetDriven();
Console.WriteLine($"Car has driven {feet} feet.");
}
}
public class Car : IVehicle
{
public int MilesDriven { get; set; }
}
在上面的代码中,我们定义了一个接口 IVehicle
,表示交通工具。然后,我们创建了一个扩展方法 FeetDriven
,它可以在任何实现了 IVehicle
接口的类上调用。在 Main
方法中,我们创建了一个 Car
类的实例,并调用了扩展方法来计算行驶的英尺数。
总之,接口的扩展方法允许我们为接口添加新的方法,而无需修改接口本身。这对于在不破坏现有代码的情况下扩展接口功能非常有用。
this关键字
在C#中,this
关键字用于引用当前对象的实例。在接口的扩展方法中,this
关键字表示该方法是一个扩展方法,并且可以在实现了该接口的类的实例上调用。
让我详细解释一下:
- 当我们定义一个接口的扩展方法时,我们需要在静态类中创建一个静态方法。这个方法的第一个参数必须使用
this
关键字,指示我们要扩展的类型。 - 在调用这个扩展方法时,我们可以像调用实例方法一样使用它,但实际上它是一个静态方法。
this
关键字告诉编译器将当前实例作为第一个参数传递给这个方法。
例如,如果我们有一个接口 IVehicle
表示交通工具,我们可以为它添加一个扩展方法来计算行驶的英尺数。在这个方法中,this IVehicle vehicle
表示我们要在实现了 IVehicle
接口的类的实例上调用这个方法。
"""
"""#dotnetzz_dotnet_eftool指定文件夹.md
ef core 生成迁移文件时,如何指定文件夹
dotnet ef migrations add InitialCreate --output-dir Data/Migrations
dotnet ef database update
"""
"""#otherzz_other_vscode插件restclient的使用.md
vscode插件中restclient插件的使用
1.讲下面的文件保存 xxx.http 的格式的文件
### get
GET http://localhost:5090/games HTTP/1.1
### get by id
GET http://localhost:5090/games/1 HTTP/1.1
### post
POST http://localhost:5090/games HTTP/1.1
content-type: application/json
{
"name": "Hun Dou Luo2222222",
"genre": "Fighting",
"price": 19.99,
"releaseDate": "1992-02-01T00:00:00",
"imageUri": "https://palcehold.co/100"
}
### post missing name
POST http://localhost:5090/games HTTP/1.1
content-type: application/json
{
"genre": "Fighting",
"price": 19.99,
"releaseDate": "1992-02-01T00:00:00",
"imageUri": "https://palcehold.co/100"
}
"""
"""#pythonzz_python_正则表达式.md
正则表达式在线测试网站
regexr
分组匹配
import re
name = "#==other==zz_other_vscode插件restclient的使用.md"
pattern = re.compile(r'#==(.{1,10})==(.+).md')
res =pattern.match(name)
if res:
print(res.groups()) # => ('other', 'zz_other_vscode插件restclient的使用')
print(res.groups()[0])# => other
print(res.groups()[1])# => zz_other_vscode插件restclient的使用
正则表达式中各个函数的区别
re.match
- re.match(pattern, string):这个函数用于检查字符串的开头是否匹配给定的模式,如果匹配,返回一个匹配对象,否则返回None。这个函数只在字符串的开头进行匹配,不会在字符串的其他位置查找模式。例如:
import re
result = re.match(r"hello", "hello world")
print(result) # <re.Match object; span=(0, 5), match='hello'>
result = re.match(r"world", "hello world")
print(result) # None
re.search
- re.search(pattern, string):这个函数用于在字符串中查找给定的模式的第一个匹配,如果找到,返回一个匹配对象,否则返回None。这个函数会在字符串的任何位置进行匹配,不仅仅是开头。例如:
import re
result = re.search(r"hello", "hello world")
print(result) # <re.Match object; span=(0, 5), match='hello'>
result = re.search(r"world", "hello world")
print(result) # <re.Match object; span=(6, 11), match='world'>
re.findall
- re.findall(pattern, string):这个函数用于在字符串中查找给定的模式的所有匹配,返回一个包含所有匹配的字符串的列表,如果没有找到匹配,返回一个空列表。这个函数会在字符串的任何位置进行匹配,不会停止在第一个匹配。例如:
import re
result = re.findall(r"hello", "hello world hello python")
print(result) # ['hello', 'hello']
result = re.findall(r"world", "hello world hello python")
print(result) # ['world']
re.finditer
- re.finditer(pattern, string):这个函数用于在字符串中查找给定的模式的所有匹配,返回一个包含所有匹配对象的迭代器,如果没有找到匹配,返回一个空的迭代器。这个函数会在字符串的任何位置进行匹配,不会停止在第一个匹配。这个函数与re.findall的区别是,它返回的是匹配对象,而不是字符串,这样可以获取更多的匹配信息,如位置,分组等。例如:
import re
result = re.finditer(r"hello", "hello world hello python")
for match in result:
print(match) # <re.Match object; span=(0, 5), match='hello'>
# <re.Match object; span=(12, 17), match='hello'>
result = re.finditer(r"world", "hello world hello python")
for match in result:
print(match) # <re.Match object; span=(6, 11), match='world'>
re.sub
- re.sub(pattern, repl, string):这个函数用于在字符串中替换给定的模式的所有匹配,返回一个新的字符串,其中所有的匹配都被repl替换,如果没有找到匹配,返回原始字符串。repl可以是一个字符串,也可以是一个函数,用于根据匹配对象生成替换的字符串。例如:
import re
result = re.sub(r"hello", "hi", "hello world hello python")
print(result) # hi world hi python
result = re.sub(r"(\w+) (\w+)", r"\2 \1", "hello world hello python")
print(result) # world hello python hello
re.split
- re.split(pattern, string):这个函数用于用给定的模式作为分隔符,将字符串分割成多个子字符串,返回一个包含所有子字符串的列表,如果没有找到匹配,返回一个只包含原始字符串的列表。例如:
import re
result = re.split(r"\s", "hello world hello python")
print(result) # ['hello', 'world', 'hello', 'python']
result = re.split(r"o", "hello world hello python")
print(result) # ['hell', ' w', 'rld hell', ' pyth', 'n']
"""
"""#dotnetzz_dotnet_的依赖注入.md
原先的模式
GamesEndpoints.cs
public static class GamesEndpoints
{
public static RouteGroupBuilder MapGamesEndpoints(this IEndpointRouteBuilder endpoints)
{
// 自动创建一个实例,然后使用
InMemGamesRepository repository = new();
var group = endpoints.MapGroup("/games").WithParameterValidation();
group.MapGet("/", () => repository.GetAll());
return group;
}
}
InMemGamesRepository.cs
using GameStore.Api.Entities;
namespace GameStore.Api.Repositoriesa;
public class InMemGamesRepository
{
private readonly List<Game> games = new()
{
new Game(){
Id = 1,
Name="Street Fighter II",
Genre ="Fighting",
Price = 19.99M,
ReleaseDate = new DateTime(1991,2,1),
ImgUri = "https://palcehold.co/100"
},
new Game(){
Id = 2,
Name="FIFA 23",
Genre ="Sports",
Price = 29.99M,
ReleaseDate = new DateTime(2022,2,1),
ImgUri = "https://palcehold.co/100"
},
};
public IEnumerable<Game> GetAll()
{
return games;
}
public Game? Get(int id)
{
return games.Find(game => game.Id == id);
}
public void Create(Game game)
{
game.Id = games.Max(game => game.Id) + 1;
games.Add(game);
}
public void Update(Game updatedGame)
{
var index = games.FindIndex(game => game.Id == updatedGame.Id);
games[index] = updatedGame;
}
public void Delete(int id)
{
var index = games.FindIndex(game => game.Id == id);
games.RemoveAt(index);
}
}
现在的模式
GamesEndpoints.cs
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using GameStore.Api.Entities;
using GameStore.Api.Repositoriesa;
namespace GameStore.Api.Endpoints;
public static class GamesEndpoints
{
const string GetGameEndpointName = "GetGame";
public static RouteGroupBuilder MapGamesEndpoints(this IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("/games").WithParameterValidation();
// 直接依赖注入
group.MapGet("/", (IGamesRepository repository) => repository.GetAll());
group.MapGet("/{id}", (IGamesRepository repository,int id) =>
{
Game? game = repository.Get(id);
if (game is null)
{
return Results.NotFound();
}
return Results.Ok(game);
}).WithName(GetGameEndpointName);
group.MapPut("/{id}", (IGamesRepository repository,int id, Game updatedGame) =>
{
Game? existingGame = repository.Get(id);
if (existingGame is null)
{
return Results.NotFound();
}
existingGame.Name = updatedGame.Name;
existingGame.Genre = updatedGame.Genre;
existingGame.Price = updatedGame.Price;
existingGame.ReleaseDate = updatedGame.ReleaseDate;
existingGame.ImgUri = updatedGame.ImgUri;
repository.Update(existingGame);
return Results.NoContent();
});
group.MapDelete("/{id}", (IGamesRepository repository,int id) =>
{
Game? game = repository.Get (id);
if (game is not null)
{
repository.Delete(id);
}
return Results.NoContent();
});
return group;
}
}
对比
手动实例化
InMemGamesRepository repository = new();
group.MapGet("/", () => repository.GetAll());
依赖注入
依赖注入:
group.MapGet("/", (IGamesRepository repository) => repository.GetAll());
注册服务:
只有在builder中注册了服务,上面的接口在访问的时候才会自动帮你实例化.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IGamesRepository, InMemGamesRepository>();
// builder.Services.AddScoped<IGamesRepository, InMemGamesRepository>();
"""
"""#dotnetzz_dotnet_接口的扩展方法.md
接口的扩展方法
定义
当我们在C#中定义接口时,有时候我们希望为接口添加一些额外的方法,但是我们又不想修改接口本身。这时,接口的扩展方法就派上用场了。
接口的扩展方法允许我们在不改变接口定义的情况下,为接口添加新的方法。这些方法可以像实例方法一样调用,但实际上它们是静态方法。
例子
假设我们有一个接口 IVehicle
,表示交通工具。我们想要为这个接口添加一个新的方法,计算交通工具行驶的英尺数。我们可以使用接口的扩展方法来实现这个功能。
public interface IVehicle
{
int MilesDriven { get; set; }
}
public static class Extensions
{
// 这是一个接口的扩展方法
public static int FeetDriven(this IVehicle vehicle)
{
// 假设1英里等于5028英尺
return vehicle.MilesDriven * 5028;
}
}
class Program
{
static void Main()
{
// 创建一个实现了 IVehicle 接口的类
var car = new Car { MilesDriven = 100 };
// 调用扩展方法
int feet = car.FeetDriven();
Console.WriteLine($"Car has driven {feet} feet.");
}
}
public class Car : IVehicle
{
public int MilesDriven { get; set; }
}
在上面的代码中,我们定义了一个接口 IVehicle
,表示交通工具。然后,我们创建了一个扩展方法 FeetDriven
,它可以在任何实现了 IVehicle
接口的类上调用。在 Main
方法中,我们创建了一个 Car
类的实例,并调用了扩展方法来计算行驶的英尺数。
总之,接口的扩展方法允许我们为接口添加新的方法,而无需修改接口本身。这对于在不破坏现有代码的情况下扩展接口功能非常有用。
this关键字
在C#中,this
关键字用于引用当前对象的实例。在接口的扩展方法中,this
关键字表示该方法是一个扩展方法,并且可以在实现了该接口的类的实例上调用。
让我详细解释一下:
- 当我们定义一个接口的扩展方法时,我们需要在静态类中创建一个静态方法。这个方法的第一个参数必须使用
this
关键字,指示我们要扩展的类型。 - 在调用这个扩展方法时,我们可以像调用实例方法一样使用它,但实际上它是一个静态方法。
this
关键字告诉编译器将当前实例作为第一个参数传递给这个方法。
例如,如果我们有一个接口 IVehicle
表示交通工具,我们可以为它添加一个扩展方法来计算行驶的英尺数。在这个方法中,this IVehicle vehicle
表示我们要在实现了 IVehicle
接口的类的实例上调用这个方法。
"""
"""#dotnetzz_dotnet_eftool指定文件夹.md
ef core 生成迁移文件时,如何指定文件夹
dotnet ef migrations add InitialCreate --output-dir Data/Migrations
dotnet ef database update
"""
"""#otherzz_other_vscode插件restclient的使用.md
vscode插件中restclient插件的使用
1.讲下面的文件保存 xxx.http 的格式的文件
### get
GET http://localhost:5090/games HTTP/1.1
### get by id
GET http://localhost:5090/games/1 HTTP/1.1
### post
POST http://localhost:5090/games HTTP/1.1
content-type: application/json
{
"name": "Hun Dou Luo2222222",
"genre": "Fighting",
"price": 19.99,
"releaseDate": "1992-02-01T00:00:00",
"imageUri": "https://palcehold.co/100"
}
### post missing name
POST http://localhost:5090/games HTTP/1.1
content-type: application/json
{
"genre": "Fighting",
"price": 19.99,
"releaseDate": "1992-02-01T00:00:00",
"imageUri": "https://palcehold.co/100"
}