Hi, Maxime, great!
if I come across any additional issues of a similar nature, I'll update this post.
Hi, Maxime, great!
if I come across any additional issues of a similar nature, I'll update this post.
@ferdinand said in A few items that should get fixed on the Python side:
Hey @mikegold10,
..., the word "of" does not in any way indicate ownership, [...]
It does, of is a possessive preposition, in is a relative preposition, specifically one that denotes a place. See here for an overview of the subject. I would not even challenge the fact that for you and your peers of might sound more natural (or maybe even all native speakers as you claim).
But language in general, and especially things like prepositions, pronouns, and flexions, is subject to language change which is often highly regional, so what people consider correct can vary regionally. As indicated in my first answer, prepositions are quite interchangeable, and if the text would have said of instead of in, I would not waste any time on changing that. But in the same notion, I cannot change the preposition on what you subjectively consider better. The grammatical situation from a Standard English point of view seems obvious here and personal preference cannot be grounds for a change. I am more than happy to change the preposition when you can demonstrate with a respectable English style guide like Oxford English that it would be more common to use here of. But that seems unlikely to me.
Cheers,
Ferdinand
As additional supportive evidence for my proposed change, I am providing a link to a respected source for the definitions of American English words, including many sample phrases that provide context for the often huge set of alternative definitions that are provided for commonly used words like "of" (and "in"):
Meriam-Webster Dictionary: of - Definition / preposition
Specifically, under the definitions of the word "of," when used as a preposition (i.e., Section 1 of 3 on the page, as linked above), please examine the following alternative definitions and examples of proper English usage that I believe are of relevance to my proposed change to the original Python comment:
Here is a copy of the original comment to provide context:
The index of the first and last selected elements in the given segment.
..., and the revised version that replaces the preposition in with of::
The index of the first and last selected elements of the given segment.
Of course the decision is yours to make. I am simply trying to "open your mind" to, as well as provide objective evidence for, an alternative phrasing which I perceive to be a better fit for the technical subject matter that is being documented, within the framework of modern American English usage patterns. I have to concede on the fact that this is ultimately subjective and may (or may not - not sure) be specific to the en_US
locale.
Michael
@ferdinand said in A few items that should get fixed on the Python side:
Hey @mikegold10,
thank you for reaching out to us and for taking the time to point these out; much appreciated. As a FYI, the line number and the
__file__
attribute a function/method/class carries are pretty much useless, as internally this data is stored in different files. Just name the class or function, you do not have to go through the effort of getting line numbers and file names, as I will not use them anyways.
- Matrix.__mul__ and the Matrix Manual: I have fixed that, it will be published with an upcoming release.
BaseSelect.GetRange
: Hm, I would say this is very much a question of taste, both the preposition in and of are commonly used in such context as this sentence. But the preposition in denotes a location while of denotes ownership. Since the function returns the location of the first and last selected index, I would say in is a more fitting and the grammatically correct choice here. I therefore left this as is.Regarding argument names shadowing built-in types and functions: We understand that this can be a bit annoying, but we strive for parity between C++ and Python and will therefore not change the names of arguments in Python. When you invoke functions/methods, this is not an issue as nothing will be shadowed. This is only a problem when you overwrite methods, and then you can rename them locally, as Cinema 4D will not call these methods with keywords, but always positionally.
import c4d class MyDialog (c4d.gui.GeDialog): def Command(self, id: int, msg: c4d.BaseContainer) -> bool: """The argument id shadows here the built-in function id(), not so nice. """ return super().Command(id, msg) def Command(self, cid: int, msg: c4d.BaseContainer) -> bool: """You can rename arguments as you please when overwriting methods. """ return super().Command(cid, msg)
For the same reason we will also not rename arguments for readability reasons. And there are also a lot of other PEP8 violations in the
c4d
andmaxon
modules due to our C++-first policy. This has been discussed multiple times internally, and we will not adopt PEP8 conformance for our APIs.Cheers,
Ferdinand
I think you missed one of my corrections for BaseSelect.GetRange()
to the second line of the Python comment that is neither grammatically correct nor informative:
34544: | If the segment has a length of one, the same
->if<- () will be set for the first and last entry in the tuple.
..., and my recommended correction that I feel is far more clear:
34544: | For segments with a length of one, the indices of both elements will be set to the same value.
With regard to the correction to the previous comment (i.e., the use of "in" vs "of" to start the subsequent preposition):
34543: | The index of the first and last selected elements
in of the given segment.
..., the word "of" does not in any way indicate ownership, it is used simply to refer to the specific segment being discussed. For an issue such as this, where the wording is not strictly incorrect in terms of grammar, but the choice of words (IMHO) violates common English language usage patterns for expressing what is stated, I would very strongly urge you to run the two word possibilities by some native (American) English speakers at Maxon. It would be a very good idea to hear the opinions of others, before coming to a firm decision on this matter.
Believe me, I would not bother pursuing this point any further, if I did not feel that the present wording is very non-conventional, if not outright poor. I will go so far as to say that, in its present form, it sounds like either a non-native English speaker or a mechanical translator translating from a different language (e.g., German) came up with the present wording.
Michael
Updated post with an additional item. I couldn't update the above post, because of the 3600 s timeout for editing.
C:\Program Files\Maxon Cinema 4D 2023\resource\modules\python\libs\python39\c4d_init_.py
Note: Code lines in the file are prefixed with their line numbers, for convenience.
Instead of: (Note that the second if
word in the statement on line 34544 is completely out of place)
34543: | The index of the first and last selected elements in the given segment.
34544: | If the segment has a length of one, the same if will be set for the first and last entry in the tuple.
34545: | **None** if the function failed.
..., much clearer would be:
34543: | The index of the first and last selected elements
in of the given segment.
34544: | For segments with a length of one, the indices of both elements will be set to the same value.
..., with line 34544 completely rewritten as shown in the above text (or something similar).
If I find any more I will either update this message or post a new reply.
A few issues I found in:
C:\Program Files\Maxon Cinema 4D 2023\resource\modules\python\libs\python39\c4d_init_.py
Line numbers are on the left
36819: >>> # Matrix multiplication is not communicative, i.e., executing the transforms in a
36820: >>> # different order will yield another matrix product.
36821: >>> Z * Y * X
36822: >>> Matrix(v1: (0.5, -0.5, -0.707); v2: (0.146, 0.854, -0.5); v3: (0.854, 0.146, 0.5); off: (0, 0, 0))
36819: >>> # Matrix multiplication is not
communicative commutative , i.e., executing the transforms in a
36820: >>> # different order
wil yield another may result in a completely different matrix product.
...
36822:
>>> Matrix(v1: (0.5, -0.5, -0.707); v2: (0.146, 0.854, -0.5); v3: (0.854, 0.146, 0.5); off: (0, 0, 0))
-------^ Remove erroneous >>> prefix from this line
Also, use of id
for a parameter name in this code (and perhaps other places) is highly discouraged, because such use shadows the built-in function id()
.
E.g.:
>>> help(id)
Help on built-in function id in module builtins:
id(obj, /)
Return the identity of an object.
This is guaranteed to be unique among simultaneously existing objects.
(CPython uses the object's memory address.)
A simple suffix in front of id
would be a good way to fix the issue and make the code more informative. E.g.:
ob_id: int
sub_cont_id: int
# Etc.
I realize that id
is used all over the code and this may not be a simple change, so just a suggested possibility for the next major set of refactoring changes.
Finally the use of l
as a variable name is highly discouraged (see: PEP 8: E741), because it can be easily mistaken for the digit 1
, as you can clearly even see within the context of this forum's formatting of the two code excerpts for l
and 1
! I see that the variable name v
is used for floating point values and the same name could be used for integral values, as well.
For example, change:
37717: def SetInt32(self, id: int, l: int) -> None:
..., to:
37717: def SetInt32(self, id: int, v: int) -> None:
# ---------------------------------^
Hi, Maxime, great!
if I come across any additional issues of a similar nature, I'll update this post.
The argument self should not appear in any of the following static method declarations that are part of the generated Python C4D API skeletal/placeholder code, since any good Python IDE will complain and/or flag correct user code that use these methods.
In the future, you guys can do something like the following in ...resource\modules\python\libs
:
# You can also add the -n flag to the first grep in the pipe chain below, to add line number info after the file name
grep -R -A2 -H "@staticmethod" * 2>&1 | grep -v "MAXON_" | grep -PB2 "def.*?self"
I am not sure if the above grep comprehensively captures every one of these issues, but 99-100% of them should have been caught:
python39/c4d/bitmaps/__init__.py: @staticmethod
python39/c4d/bitmaps/__init__.py- def AllocWrapper(self, bmp):
--
python39/c4d/modules/mograph/__init__.py: @staticmethod
python39/c4d/modules/mograph/__init__.py- def Create(self, flags, thread, doc, currentThreadIndex, threadCount, inputs, callers):
--
python39/c4d/utils/__init__.py: @staticmethod
python39/c4d/utils/__init__.py- def PickObject(self, bd, doc, x, y, rad, flags):
--
python39/c4d/__init__.py: @staticmethod
python39/c4d/__init__.py- def GetDistance(self, v1, v2):
--
python39/maxon/decorators.py: @staticmethod
python39/maxon/decorators.py- @wraps(fn)
python39/maxon/decorators.py- def Auto(self, *args):
--
python39/maxon/decorators.py: @staticmethod
python39/maxon/decorators.py- @wraps(fn)
python39/maxon/decorators.py- def ReferenceConvert(self, *args):
--
python39/maxon/decorators.py: @staticmethod
python39/maxon/decorators.py- @wraps(fn)
python39/maxon/decorators.py- def Wrap(self, *args):
--
python39/maxon/decorators.py: @staticmethod
python39/maxon/decorators.py- @wraps(fn)
python39/maxon/decorators.py- def NativeDataOrBuiltin(self, *args):
--
python39/maxon/decorators.py: @staticmethod
python39/maxon/decorators.py- @wraps(fn)
python39/maxon/decorators.py- def _MaxonConvertOrFail(self, *args):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def Free(self):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def GetLocal(self):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def AllocEmpty(self):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def AllocFromUuid(self, uuid):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def AllocFromString(self, uuidStr):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def DescribeIO(self):
--
python39/maxon/interface.py: @staticmethod
python39/maxon/interface.py- def CreateUuidString(self):
--
python39.win64.framework/lib/pathlib.py: @staticmethod
python39.win64.framework/lib/pathlib.py- def link_to(self, target):
Also, for all of the following, the @classmethod
attribute should be changed to @staticmethod
and the self
argument should be removed, just like for the above cases:
python39.win64.framework/lib/importlib/_bootstrap.py- @classmethod
python39.win64.framework/lib/importlib/_bootstrap.py: def create_module(self, spec):
--
python39.win64.framework/lib/importlib/_bootstrap.py- @classmethod
python39.win64.framework/lib/importlib/_bootstrap.py: def exec_module(self, module):
--
python39.win64.framework/lib/_collections_abc.py- @classmethod
python39.win64.framework/lib/_collections_abc.py: def _from_iterable(self, it):
--
python39.win64.framework/lib/_collections_abc.py- @classmethod
python39.win64.framework/lib/_collections_abc.py: def _from_iterable(self, it):
It seems like S24 is too sensitive when it comes to deciding whether a user intended to hold a key down for a period of time so as to temporarily toggle a state and revert back once the key is released or if the intent was to permanently change to that state.
For example, the lowercase L key can be used to:
Unfortunately, the actual length of time used for the decision by C4D as to the user's intent seems to be too short. I don't know where exactly the threshold lies, but it seems to be in the 100 ms ballpark. There should be a way to change the number of milliseconds that a key must be held before C4D assumes that the user's intent was to toggle (and not permanently enter a state/mode). I have not been able to find this setting if it exists it in the preferences. Or, is this value "hard coded" into the app and cannot be modified by the user?
This issue effects both mice and keyboards that allow for macros, since sometimes they can send the key down even followed by a key up event with some delay in between that cannot be modified via configuration and happens to be long enough to confuse C4D into thinking that the user's intent was to temporarily toggle. I should add that such interpretation can occur intermittently due to key down/key up delay jitter making things even more confusing.
On the other hand, even using a decent wired keyboard, if I press a key reasonably briefly, but not really fast, I sometimes get a temporary toggle instead of a permanent mode switch. This is true for those commands/modes that are toggleable. One almost has to put in a mental effort when pressing a key on the keyboard so as not to wind up holding it down for what C4D considers too long a time (where "too long a time" could be as little as somewhere in the 100-150 ms ballpark...). Often when I press a key, without concentrating on pressing it really quickly, C4D thinks my intent was to hold the key down so as to temporarily toggle, and reverts the setting back once I release the key.
There should be some way to control this delay and increase it in the software to make C4D wait longer before assuming that the user intended to temporarily toggle a command (say 250-500 ms would be a reasonable delay as compared to the unnecessarily brief delay it is presently set to by default (50-100 ms??).
I should note that this issue was present in R23 as well, but the delay was longer and could be lived with (although some users of Bluetooth keyboards and other forms of wireless keyboards as well as macro capable mice experienced the issue). As of S24, the delay has gotten so short, that it even affects users with common run-of-the-mill wired keyboards like myself, unless they can press/release keyboard keys really briefly (as an analogy for piano players out there, think of playing staccato notes vs tenuto notes).
Test setup:
OS: Windows 10
Hardware/PC: Very fast modern desktop
Keyboards attempted: Velocifire TKL02/wired, an old Dell wired keyboard, an old Logitech wired keyboard
Hi Maxime,
Thanks for confirming that I was not missing something in the docs and this is just not possible.
@zipit I am hopeful that @r_gigante will take a look at my reply to his post and address the question in Step 2 of said post:
How do you "Hand color information to Cinema 4D inside Draw() (or where else??), so that it can use it to correctly draw the object in a Viewport" ?
@zipit I tried this route and it doesn't work, at least not in the way I expected, because for this to work, it is critical that the ordering between Draw() and Output() functions across all object nodes and their respective tags in the node hierarchy, has to be in a certain well-defined and compatible (with this idea) way. Otherwise, the color you cache in Draw() based on the TextureTag received is not necessarily the correct color when Output() gets called (and if Output() gets called, because it almost never called unless you render, but Draw() gets called a lot).
The reason things don't work as expected using this method of caching color info in Draw(), to be used later in Output (if object info is not available), is because either the object changed or the "current" texture tag is different by the time Output() is called, but often Draw() has not yet been called to update the cached color info. Also, aside from rendering, as I mentioned previously, calls to output are far and few in between. For example, if you use the mouse to move or rotate objects in a view, only Draw() gets called (for each texture tag/object), with no subsequent call to Output() as far as I can tell.