Skip to content
Snippets Groups Projects
Commit f3762eafed66 authored by Matt Harbison's avatar Matt Harbison
Browse files

typing: add some type annotations to the `merge.mergeresult` class

The generated type annotations around `filemap()` and `files()` were slightly
modified by the pyupgrade series culminating in 70a75d379daf.  This module is
way more complicated than the other changes, but these weren't too bad to figure
out.

The typing caught a trivial issue in `sparse`- it was passing an empty data list
to `addfile()` for the `ACTION_REMOVE` case, instead of a tuple or None.
`merge.manifestmerge()` calls this function with None for the data, so 1) it has
to be typed as optional, and 2) is safe to pass None in the sparse code.
parent 10e7adbffa8c
No related branches found
No related tags found
2 merge requests!1292Draft: 7.0rc preparation,!1209Type annotations around the pyupgrade changes
......@@ -11,7 +11,7 @@
import os
import struct
import typing
from typing import Dict, Iterator, Optional, Tuple
from typing import Dict, Iterable, Iterator, Optional, Tuple
from .i18n import _
from .node import nullrev
......@@ -41,6 +41,18 @@
worker,
)
if typing.TYPE_CHECKING:
# TODO: figure out what exactly is in this tuple
MergeResultData = tuple
MergeResultAction = tuple[bytes, Optional[MergeResultData], bytes]
"""The filename, data about the merge, and message about the merge."""
FileMappingValue = tuple[
mergestatemod.MergeAction, Optional[MergeResultData], bytes
]
"""The merge action, data about the merge, and message about the merge, for
the keyed file."""
rust_update_mod = policy.importrust("update")
_pack = struct.pack
......@@ -132,7 +144,9 @@
return None
def _checkunknownfiles(repo, wctx, mctx, force, mresult, mergeforce):
def _checkunknownfiles(
repo, wctx, mctx, force, mresult: mergeresult, mergeforce
):
"""
Considers any actions that care about the presence of conflicting unknown
files. For some actions, the result is to abort; for others, it is to
......@@ -277,7 +291,7 @@
)
def _forgetremoved(wctx, mctx, branchmerge, mresult):
def _forgetremoved(wctx, mctx, branchmerge, mresult: mergeresult) -> None:
"""
Forget removed files
......@@ -310,7 +324,7 @@
)
def _checkcollision(repo, wmf, mresult):
def _checkcollision(repo, wmf, mresult: mergeresult | None) -> None:
"""
Check for case-folding collisions.
"""
......@@ -378,7 +392,7 @@
lastfull = f
def _filesindirs(repo, manifest, dirs):
def _filesindirs(repo, manifest, dirs) -> Iterator[tuple[bytes, bytes]]:
"""
Generator that yields pairs of all the files in the manifest that are found
inside the directories listed in dirs, and which directory they are found
......@@ -391,7 +405,7 @@
break
def checkpathconflicts(repo, wctx, mctx, mresult):
def checkpathconflicts(repo, wctx, mctx, mresult: mergeresult) -> None:
"""
Check if any actions introduce path conflicts in the repository, updating
actions to record or handle the path conflict accordingly.
......@@ -492,7 +506,13 @@
ctxname = bytes(mctx).rstrip(b'+')
for f, p in _filesindirs(repo, mf, remoteconflicts):
if f not in deletedfiles:
m, args, msg = mresult.getfile(p)
mapping_value = mresult.getfile(p)
# Help pytype- in theory, this could be None since no default
# value is passed to getfile() above.
assert mapping_value is not None
m, args, msg = mapping_value
pnew = util.safename(p, ctxname, wctx, set(mresult.files()))
if m in (
mergestatemod.ACTION_DELETED_CHANGED,
......@@ -526,7 +546,9 @@
)
def _filternarrowactions(narrowmatch, branchmerge, mresult):
def _filternarrowactions(
narrowmatch, branchmerge, mresult: mergeresult
) -> None:
"""
Filters out actions that can ignored because the repo is narrowed.
......@@ -567,7 +589,12 @@
It has information about what actions need to be performed on dirstate
mapping of divergent renames and other such cases."""
def __init__(self):
_filemapping: dict[bytes, FileMappingValue]
_actionmapping: dict[
mergestatemod.MergeAction, dict[bytes, tuple[MergeResultData, bytes]]
]
def __init__(self) -> None:
"""
filemapping: dict of filename as keys and action related info as values
diverge: mapping of source name -> list of dest name for
......@@ -589,7 +616,13 @@
self._diverge = diverge
self._renamedelete = renamedelete
def addfile(self, filename, action, data, message):
def addfile(
self,
filename: bytes,
action: mergestatemod.MergeAction,
data: MergeResultData | None,
message,
) -> None:
"""adds a new file to the mergeresult object
filename: file which we are adding
......@@ -606,7 +639,12 @@
self._filemapping[filename] = (action, data, message)
self._actionmapping[action][filename] = (data, message)
def mapaction(self, actionfrom, actionto, transform):
def mapaction(
self,
actionfrom: mergestatemod.MergeAction,
actionto: mergestatemod.MergeAction,
transform,
):
"""changes all occurrences of action `actionfrom` into `actionto`,
transforming its args with the function `transform`.
"""
......@@ -618,7 +656,9 @@
self._filemapping[f] = (actionto, data, msg)
dest[f] = (data, msg)
def getfile(self, filename, default_return=None):
def getfile(
self, filename: bytes, default_return: FileMappingValue | None = None
) -> FileMappingValue | None:
"""returns (action, args, msg) about this file
returns default_return if the file is not present"""
......@@ -626,7 +666,9 @@
return self._filemapping[filename]
return default_return
def files(self, actions=None):
def files(
self, actions: Iterable[mergestatemod.MergeAction] | None = None
) -> Iterator[bytes]:
"""returns files on which provided action needs to perfromed
If actions is None, all files are returned
......@@ -640,10 +682,10 @@
for a in actions:
yield from self._actionmapping[a]
def removefile(self, filename):
def removefile(self, filename: bytes) -> None:
"""removes a file from the mergeresult object as the file might
not merging anymore"""
action, data, message = self._filemapping[filename]
del self._filemapping[filename]
del self._actionmapping[action][filename]
......@@ -644,10 +686,12 @@
"""removes a file from the mergeresult object as the file might
not merging anymore"""
action, data, message = self._filemapping[filename]
del self._filemapping[filename]
del self._actionmapping[action][filename]
def getactions(self, actions, sort=False):
def getactions(
self, actions: Iterable[mergestatemod.MergeAction], sort: bool = False
) -> Iterator[MergeResultAction]:
"""get list of files which are marked with these actions
if sort is true, files for each action is sorted and then added
......@@ -662,7 +706,9 @@
for f, (args, msg) in self._actionmapping[a].items():
yield f, args, msg
def len(self, actions=None):
def len(
self, actions: Iterable[mergestatemod.MergeAction] | None = None
) -> int:
"""returns number of files which needs actions
if actions is passed, total of number of files in that action
......@@ -673,9 +719,11 @@
return sum(len(self._actionmapping[a]) for a in actions)
def filemap(self, sort=False) -> Iterator[tuple]: # TODO: fill out tuple
def filemap(
self, sort: bool = False
) -> Iterator[tuple[bytes, MergeResultData]]:
if sort:
yield from sorted(self._filemapping.items())
else:
yield from self._filemapping.items()
......@@ -677,9 +725,9 @@
if sort:
yield from sorted(self._filemapping.items())
else:
yield from self._filemapping.items()
def addcommitinfo(self, filename, key, value):
def addcommitinfo(self, filename: bytes, key, value) -> None:
"""adds key-value information about filename which will be required
while committing this merge"""
self._commitinfo[filename][key] = value
......@@ -697,7 +745,9 @@
return self._commitinfo
@property
def actionsdict(self):
def actionsdict(
self,
) -> dict[mergestatemod.MergeAction, list[MergeResultAction]]:
"""returns a dictionary of actions to be perfomed with action as key
and a list of files and related arguments as values"""
res = collections.defaultdict(list)
......@@ -706,9 +756,9 @@
res[a].append((f, args, msg))
return res
def setactions(self, actions):
def setactions(self, actions) -> None:
self._filemapping = actions
self._actionmapping = collections.defaultdict(dict)
for f, (act, data, msg) in self._filemapping.items():
self._actionmapping[act][f] = data, msg
......@@ -710,9 +760,9 @@
self._filemapping = actions
self._actionmapping = collections.defaultdict(dict)
for f, (act, data, msg) in self._filemapping.items():
self._actionmapping[act][f] = data, msg
def hasconflicts(self):
def hasconflicts(self) -> bool:
"""tells whether this merge resulted in some actions which can
result in conflicts or not"""
for a in self._actionmapping.keys():
......@@ -743,7 +793,7 @@
acceptremote,
followcopies,
forcefulldiff=False,
):
) -> mergeresult:
"""
Merge wctx and p2 with ancestor pa and generate merge action list
......@@ -1117,7 +1167,7 @@
return mresult
def _resolvetrivial(repo, wctx, mctx, ancestor, mresult):
def _resolvetrivial(repo, wctx, mctx, ancestor, mresult: mergeresult) -> None:
"""Resolves false conflicts where the nodeid changed but the content
remained the same."""
# We force a copy of actions.items() because we're going to mutate
......@@ -1146,7 +1196,7 @@
followcopies,
matcher=None,
mergeforce=False,
):
) -> mergeresult:
"""
Calculate the actions needed to merge mctx into wctx using ancestors
......@@ -1469,7 +1519,7 @@
yield True, filedata
def _prefetchfiles(repo, ctx, mresult):
def _prefetchfiles(repo, ctx, mresult: mergeresult) -> None:
"""Invoke ``scmutil.prefetchfiles()`` for the files relevant to the dict
of merge actions. ``ctx`` is the context being merged in."""
......@@ -1516,7 +1566,7 @@
def applyupdates(
repo,
mresult,
mresult: mergeresult,
wctx,
mctx,
overwrite,
......
......@@ -548,7 +548,7 @@
elif (old and not new) or (not old and not new and file in dirstate):
dropped.append(file)
if file not in pending:
mresult.addfile(file, mergestatemod.ACTION_REMOVE, [], b'')
mresult.addfile(file, mergestatemod.ACTION_REMOVE, None, b'')
# Verify there are no pending changes in newly included files
abort = False
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment