Skip to content

Commit 12cdddb

Browse files
author
Johannes Hentschel
authored
Next release (#110)
2 parents 1e6b0e3 + 4689897 commit 12cdddb

File tree

5 files changed

+231
-125
lines changed

5 files changed

+231
-125
lines changed

CONTRIBUTING.rst

+75-12
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ This means that the docs are kept in the same repository as the project code, an
4848
that any documentation update is done in the same way was a code contribution.
4949
The documentation is written in reStructuredText_ and includes the myst-nb_ extension.
5050

51+
Documentation pages are written in reStructuredText_ (as are the docstrings that are automatically compiled to the
52+
API docs).
53+
54+
.. tip::
55+
Please notice that the `GitHub web interface`_ provides a quick way of
56+
propose changes in ``ms3``'s files. While this mechanism can
57+
be tricky for normal code contributions, it works perfectly fine for
58+
contributing to the docs, and can be quite handy.
59+
60+
If you are interested in trying this method out, please navigate to
61+
the ``docs`` folder in the source repository_, find which file you
62+
would like to propose changes and click in the little pencil icon at the
63+
top, to open `GitHub's code editor`_. Once you finish editing the file,
64+
please write a message in the form at the bottom of the page describing
65+
which changes have you made and what are the motivations behind them and
66+
submit your proposal.
5167

5268

5369
When working on documentation changes in your local machine, you can
@@ -64,11 +80,15 @@ and use Python's built-in web server for a preview in your web browser
6480
Code Contributions
6581
==================
6682

67-
.. todo:: Please include a reference or explanation about the internals of the project.
83+
.. admonition:: TL;DR
84+
85+
* Fork the repository.
86+
* (Create a virtual environment, :ref:`see below <virtenv>`).
87+
* Head into the local clone of your fork and hit ``pip install -e ".[dev]"`` (where ``.`` is the current directory).
88+
* Install the precommit hooks via ``pre-commit install``.
89+
* Implement the changes and create a Pull Request against the ``development`` branch.
90+
* Thank you!
6891

69-
An architecture description, design principles or at least a summary of the
70-
main concepts will make it easy for potential contributors to get started
71-
quickly.
7292

7393
Submit an issue
7494
---------------
@@ -100,7 +120,7 @@ Clone the repository
100120
page. This creates a copy of the code under your account on |the repository service|.
101121
#. Clone this copy to your local disk::
102122

103-
git clone [email protected]:johentsch/ms3.git
123+
git clone [email protected]:YourLogin/ms3.git
104124

105125
#. You should run::
106126

@@ -132,6 +152,10 @@ Implement your changes
132152

133153
to record your changes in git_.
134154

155+
Please make sure to see the validation messages from |pre-commit|_ and fix
156+
any eventual issues.
157+
This should automatically use flake8_/black_ to check/fix the code style
158+
in a way that is compatible with the project.
135159

136160
.. important:: Don't forget to add unit tests and documentation in case your
137161
contribution adds an additional feature and is not just a bugfix.
@@ -162,13 +186,52 @@ Submit your contribution
162186
#. Go to the web page of your fork and click |contribute button|
163187
to send your changes for review.
164188

165-
.. todo:: if you are using GitHub, you can uncomment the following paragraph
166-
167-
Find more detailed information in `creating a PR`_. You might also want to open
168-
the PR as a draft first and mark it as ready for review after the feedbacks
169-
from the continuous integration (CI) system or any required fixes.
170-
171-
189+
Find more detailed information in `creating a PR`_. You might also want to open
190+
the PR as a draft first and mark it as ready for review after the feedbacks
191+
from the continuous integration (CI) system or any required fixes.
192+
193+
194+
Coding Conventions
195+
------------------
196+
197+
Please make sure to run ``pre-commit install`` in your local clone of the repository. This way, many coding
198+
conventions are automatically applied before each commit!
199+
200+
Commit messages
201+
~~~~~~~~~~~~~~~
202+
203+
``ms3`` uses `Conventional Commits <https://www.conventionalcommits.org/>`__ to determine the next SemVer version number. Please make sure to prefix each
204+
message with one of:
205+
206+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
207+
| Commit Type | Title | Description | SemVer |
208+
+===============+==========================+=============================================================================================================+========+
209+
| ``feat`` | Features | A new feature | MINOR |
210+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
211+
| ``fix`` | Bug Fixes | A bug Fix | PATCH |
212+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
213+
| ``docs`` | Documentation | Documentation only changes | PATCH |
214+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
215+
| ``style`` | Styles | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) | PATCH |
216+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
217+
| ``refactor`` | Code Refactoring | A code change that neither fixes a bug nor adds a feature | PATCH |
218+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
219+
| ``perf`` | Performance Improvements | A code change that improves performance | PATCH |
220+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
221+
| ``test`` | Tests | Adding missing tests or correcting existing tests | PATCH |
222+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
223+
| ``build`` | Builds | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) | PATCH |
224+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
225+
| ``ci`` | Continuous Integrations | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) | PATCH |
226+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
227+
| ``chore`` | Chores | Other changes that don't modify src or test files | PATCH |
228+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
229+
| ``revert`` | Reverts | Reverts a previous commit | PATCH |
230+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
231+
232+
In the case of breaking changes, which result in a new major version, please add a ``!`` after the type, e.g., ``refactor!:``.
233+
This type of commit message needs to come with a body, starting with ``BREAKING CHANGE:``, which explains in great detail everything
234+
that will not be working anymore.
172235
Troubleshooting
173236
---------------
174237

src/ms3/bs4_parser.py

+25-108
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
sort_note_list,
130130
unfold_measures_table,
131131
unfold_repeats,
132+
write_score_to_handler,
132133
)
133134
from .utils.constants import DCML_DOUBLE_REGEX, FORM_DETECTION_REGEX
134135

@@ -2492,7 +2493,7 @@ def rl(self, recompute: bool = False) -> pd.DataFrame:
24922493
self.make_standard_restlist()
24932494
return self._rl
24942495

2495-
def parse_soup(self):
2496+
def parse_soup(self) -> None:
24962497
"""First step of parsing the MuseScore source. Involves discovering the <staff> tags and storing the
24972498
<Measure> tags of each in the :attr:`measure_nodes` dictionary. Also stores the drum_map for each Drumset
24982499
staff.
@@ -2504,12 +2505,31 @@ def parse_soup(self):
25042505
f"Use 'ms3 convert' command or pass parameter 'ms' to Score to temporally convert."
25052506
)
25062507

2508+
root_tag = self.soup.find("museScore")
2509+
if root_tag is None:
2510+
self.logger.error(
2511+
"This does not seem to be a MuseScore file because it lacks the <museScore> tag that "
2512+
"would normally be the root of the XML tree."
2513+
)
2514+
return
2515+
2516+
score_tags = root_tag.find_all("Score")
2517+
if len(score_tags) == 0:
2518+
score_tag = root_tag
2519+
else:
2520+
score_tag = score_tags[0]
2521+
if len(score_tags) > 1:
2522+
self.logger.warning(
2523+
"The file seems to include separately encoded parts, encoded with their own "
2524+
"<Score> tags. Only the first one will be considered."
2525+
)
2526+
25072527
# Check if any of the <Part> tags contains a pitch -> drumset instrument map
25082528
# all_part_tags = self.soup.find_all('Part')
25092529
# if len(all_part_tags) == 0:
25102530
# self.logger.error(f"Looks like an empty score to me.")
25112531
part_tag = None
2512-
for part_tag in self.soup.find_all("Part"):
2532+
for part_tag in score_tag.find_all("Part", recursive=False):
25132533
drum_tags = part_tag.find_all("Drum")
25142534
staff_tag = part_tag.find("Staff")
25152535
if len(drum_tags) == 0 or staff_tag is None:
@@ -2527,11 +2547,11 @@ def parse_soup(self):
25272547
# Populate measure_nodes with one {mc: <Measure>} dictionary per staff.
25282548
# The <Staff> nodes containing the music are siblings of <Part>
25292549
if part_tag is None:
2530-
iterator = self.soup.find_all("Staff")
2550+
staff_iterator = score_tag.find_all("Staff")
25312551
else:
2532-
iterator = part_tag.find_next_siblings("Staff")
2552+
staff_iterator = part_tag.find_next_siblings("Staff")
25332553
staff = None
2534-
for staff in iterator:
2554+
for staff in staff_iterator:
25352555
staff_id = int(staff["id"])
25362556
self.measure_nodes[staff_id] = {}
25372557
for mc, measure in enumerate(
@@ -4687,109 +4707,6 @@ def decode_harmony_tag(tag):
46874707
return label
46884708

46894709

4690-
# region Functions for writing BeautifulSoup to MSCX file
4691-
4692-
4693-
def escape_string(s):
4694-
return (
4695-
str(s)
4696-
.replace("&", "&amp;")
4697-
.replace('"', "&quot;")
4698-
.replace("<", "&lt;")
4699-
.replace(">", "&gt;")
4700-
)
4701-
4702-
4703-
def opening_tag(node, closed=False):
4704-
result = f"<{node.name}"
4705-
attributes = node.attrs
4706-
if len(attributes) > 0:
4707-
result += " " + " ".join(
4708-
f'{attr}="{escape_string(value)}"' for attr, value in attributes.items()
4709-
)
4710-
closing = "/" if closed else ""
4711-
return f"{result}{closing}>"
4712-
4713-
4714-
def closing_tag(node_name):
4715-
return f"</{node_name}>"
4716-
4717-
4718-
def make_oneliner(node):
4719-
"""Pass a tag of which the layout does not spread over several lines."""
4720-
result = opening_tag(node)
4721-
for c in node.children:
4722-
if isinstance(c, bs4.element.Tag):
4723-
result += make_oneliner(c)
4724-
else:
4725-
result += escape_string(c)
4726-
result += closing_tag(node.name)
4727-
return result
4728-
4729-
4730-
def format_node(node, indent):
4731-
"""Recursively format Beautifulsoup tag as in an MSCX file."""
4732-
nxt_indent = indent + 2
4733-
space = indent * " "
4734-
node_name = node.name
4735-
# The following tags are exceptionally not abbreviated when empty,
4736-
# so for instance you get <metaTag></metaTag> and not <metaTag/>
4737-
if node_name in [
4738-
"continueAt",
4739-
"continueText",
4740-
"endText",
4741-
"LayerTag",
4742-
"metaTag",
4743-
"name",
4744-
"programRevision",
4745-
"text",
4746-
"trackName",
4747-
]:
4748-
return f"{space}{make_oneliner(node)}\n"
4749-
children = node.find_all(recursive=False)
4750-
if len(children) > 0:
4751-
result = f"{space}{opening_tag(node)}\n"
4752-
result += "".join(format_node(child, nxt_indent) for child in children)
4753-
result += f"{nxt_indent * ' '}{closing_tag(node_name)}\n"
4754-
return result
4755-
if node.string == "\n":
4756-
return (
4757-
f"{space}{opening_tag(node)}\n{nxt_indent * ' '}{closing_tag(node_name)}\n"
4758-
)
4759-
if node.string is None:
4760-
return f"{space}{opening_tag(node, closed=True)}\n"
4761-
return f"{space}{make_oneliner(node)}\n"
4762-
4763-
4764-
def bs4_to_mscx(soup: bs4.BeautifulSoup):
4765-
"""Turn the BeautifulSoup into a string representing an MSCX file"""
4766-
assert soup is not None, "BeautifulSoup XML structure is None"
4767-
initial_tag = """<?xml version="1.0" encoding="UTF-8"?>\n"""
4768-
first_tag = soup.find()
4769-
return initial_tag + format_node(first_tag, indent=0)
4770-
4771-
4772-
def write_score_to_handler(
4773-
soup: bs4.BeautifulSoup,
4774-
file_handler: IO,
4775-
logger=None,
4776-
) -> bool:
4777-
if logger is None:
4778-
logger = module_logger
4779-
elif isinstance(logger, str):
4780-
logger = get_logger(logger)
4781-
try:
4782-
mscx_string = bs4_to_mscx(soup)
4783-
except Exception as e:
4784-
logger.error(f"Couldn't output score because of the following error:\n{e}")
4785-
return False
4786-
file_handler.write(mscx_string)
4787-
return True
4788-
4789-
4790-
# endregion Functions for writing BeautifulSoup to MSCX file
4791-
4792-
47934710
def text_tag2str(tag: bs4.Tag) -> str:
47944711
"""Transforms a <text> tag into a string that potentially includes written-out HTML tags."""
47954712
components = []

0 commit comments

Comments
 (0)