How does vs code get intellisense hints from python comments? - python

I am seeing that VS Code is getting intellisense hints from the comments I put in my class functions:
def GyroDriveOnHeading(self, desiredHeading, desiredDistance):
"""
Drives the robot very straight on a given heading for a \
given distance, using the acceleration and the gyro. \
Accelerates to prevent wheel slipping. \
Gyro keeps the robot pointing on the desired heading.
Minimum distance that this will work for is about 16cm.
If you need to go a very short distance, use move_tank.
Parameters
-------------
desiredHeading: On what heading should the robot drive (float)
type: float
values: any. Best if the desired heading is close to the current heading. Unpredictable robot movement may occur for large heading differences.
default: no default value
desiredDistance: How far the robot should go in cm (float)
type: float
values: any value above 16.0. You can enter smaller numbers, but the robot will still go 16cm
default: no default value
Example
-------------
import base_robot
br = base_robot.BaseRobot()
br.GyroDriveOnHeading(90, 40) #drive on heading 90 for 40 cm
"""
Which gives me a really nice popup when I use that function:
As you can see here, since I am about to enter the first parameter, desiredHeading, the intellisense was smart enough to know that the line in the comments under "Parameters" that starts with the variable name should be the first thing displayed in the hint. And indeed, once I type the first parameter and a comma, the first line of the intellisense popup changes to show the information about desiredDistance.
But I would like to know more about how the comments should be written. I read about the numpy style guide as being close to a standard most widely adopted, but when I change the parameter documentation format to match numpy (and somethihng called Sphinx has something to do with this too, I think), the popups were not the same. Really, I just want to see the documentation on how to document (yikes!) my python code so it renders correct intellisense. For example, how can I bold a word in the middle of a sentence? Are there other formatting options available?
This is just for a middle-school robotics club, nothing like production code for real programmers. Nothing is broken, I just want to learn more about how this works.

That's it for docstrings in python, about it's introduction:
https://docs.python.org/3.10/tutorial/controlflow.html#documentation-strings
https://peps.python.org/pep-0287/
In addition, you can use the type stub of the parameter in this way.
def open(url: str, new: int = ..., autoraise: bool = ...) -> bool: ...

Related

How to insert a random element on a Anki card?

On Anki, the front of a card have "X+Y?" and the back shows "Z". For example, front "4+7?" and back "11" But I want next time that I see this card the numbers be different, randomizing the X, Y and Z elements. This could be possible picking the values from a pool previously defined by me, I guess.
Searching it on here, I found this code:
import random
foo = ['a', 'b', 'c', 'd', 'e']
print(random.choice(foo))
How can I put it to work on Anki? Because I just tried to copy it and paste in card model editor, but nothing happened. Sorry, I'm not a programmer, so I'd be grateful to know anything that can help me functionalize this random display. Thanks for your time.
Even though it is possible (but convoluted to make it happen), it is usually (very heavily) discouraged to make use of random content on Anki. The reason is the following: if some content has a change of being displayed at the front of a card, then it means you want to memorize it. But then, it means that you are bloating several things that you want to learn into a single card. For several reasons (among which: Anki is optimized to work with the assumption that each card corresponds to a single, atomic thing you want to learn. Breaking that assumption can only make it work worse, which in the end makes you spend more time trying to learn that stuff), it's better to just have a card for each possible thing you want to learn.
Edit having read my words of warning, I'll leave you judge of whether it's really a good decision to do what you want.
The first thing to understand is that even though Anki is mainly written in Rust and Python (which are two programming languages), and even though it supports add-ons written in Python, it's not Python (nor Rust) that should be used for this purpose. I say this because the snippet of code you provided is written in Python.
The reason behind this is that Anki uses webviews to render cards, which means that when you see a card, it's just like if you were seeing a website. Therefore, if you only want execute code when you are reviewing the cards (and not, say, automatically generate cards), the language you have to use is JavaScript. Unfortunately, I am not a JavaScript programmer, so my answer may suck. Fortunately, JavaScript is a rather simple programming language, very well documented, and your request is simple enough for me not to have much room to screw the code (meaning this answer should not suck too much). This being said, let's make it work:
Add a field to your notes that will hold the possible values that will be shown. To make it simple, let's assume none of these values will contain commas, so that we can simply write the values comma-separated. Let's say you called this field Values (rename it as you like). By default, it's going to pick the first of these values if it cannot pick at random. More on this at the end.
Now open the template edit window for this note. If you are in the browser, it should be the Cards... button.
Select Front Template (it should be selected by default). At the top of the template, add the following, which is code that will allow the randomly chosen value to be kept also when you reveal the answer (because by default it would just re-evaluate the whole script, picking at random again).
<script>
// v1.0.0 - https://github.com/SimonLammer/anki-persistence/blob/cd2ca88e019dc3b8f32dad623932c1eabdba7e21/script.js
if(void 0===window.Persistence){var _persistenceKey="github.com/SimonLammer/anki-persistence/",_defaultKey="_default";if(window.Persistence_sessionStorage=function(){var e=!1;try{"object"==typeof window.sessionStorage&&(e=!0,this.clear=function(){for(var e=0;e<sessionStorage.length;e++){var t=sessionStorage.key(e);0==t.indexOf(_persistenceKey)&&(sessionStorage.removeItem(t),e--)}},this.setItem=function(e,t){null==t&&(t=e,e=_defaultKey),sessionStorage.setItem(_persistenceKey+e,JSON.stringify(t))},this.getItem=function(e){return null==e&&(e=_defaultKey),JSON.parse(sessionStorage.getItem(_persistenceKey+e))},this.removeItem=function(e){null==e&&(e=_defaultKey),sessionStorage.removeItem(_persistenceKey+e)})}catch(e){}this.isAvailable=function(){return e}},window.Persistence_windowKey=function(e){var t=window[e],n=!1;"object"==typeof t&&(n=!0,this.clear=function(){t[_persistenceKey]={}},this.setItem=function(e,n){null==n&&(n=e,e=_defaultKey),t[_persistenceKey][e]=n},this.getItem=function(e){return null==e&&(e=_defaultKey),null==t[_persistenceKey][e]?null:t[_persistenceKey][e]},this.removeItem=function(e){null==e&&(e=_defaultKey),delete t[_persistenceKey][e]},null==t[_persistenceKey]&&this.clear()),this.isAvailable=function(){return n}},window.Persistence=new Persistence_sessionStorage,Persistence.isAvailable()||(window.Persistence=new Persistence_windowKey("py")),!Persistence.isAvailable()){var titleStartIndex=window.location.toString().indexOf("title"),titleContentIndex=window.location.toString().indexOf("main",titleStartIndex);titleStartIndex>0&&titleContentIndex>0&&titleContentIndex-titleStartIndex<10&&(window.Persistence=new Persistence_windowKey("qt"))}}
</script>
This code comes from anki persistance. Also, when editing templates, please do not write values above the snippet, always under (it won't change how it renders, but it will ensure all this code is loaded before you do anything else).
Select the Back Template, and add the following snippet at the top of the template (it's the same thing as before):
<script>
// v1.0.0 - https://github.com/SimonLammer/anki-persistence/blob/cd2ca88e019dc3b8f32dad623932c1eabdba7e21/script.js
if(void 0===window.Persistence){var _persistenceKey="github.com/SimonLammer/anki-persistence/",_defaultKey="_default";if(window.Persistence_sessionStorage=function(){var e=!1;try{"object"==typeof window.sessionStorage&&(e=!0,this.clear=function(){for(var e=0;e<sessionStorage.length;e++){var t=sessionStorage.key(e);0==t.indexOf(_persistenceKey)&&(sessionStorage.removeItem(t),e--)}},this.setItem=function(e,t){null==t&&(t=e,e=_defaultKey),sessionStorage.setItem(_persistenceKey+e,JSON.stringify(t))},this.getItem=function(e){return null==e&&(e=_defaultKey),JSON.parse(sessionStorage.getItem(_persistenceKey+e))},this.removeItem=function(e){null==e&&(e=_defaultKey),sessionStorage.removeItem(_persistenceKey+e)})}catch(e){}this.isAvailable=function(){return e}},window.Persistence_windowKey=function(e){var t=window[e],n=!1;"object"==typeof t&&(n=!0,this.clear=function(){t[_persistenceKey]={}},this.setItem=function(e,n){null==n&&(n=e,e=_defaultKey),t[_persistenceKey][e]=n},this.getItem=function(e){return null==e&&(e=_defaultKey),null==t[_persistenceKey][e]?null:t[_persistenceKey][e]},this.removeItem=function(e){null==e&&(e=_defaultKey),delete t[_persistenceKey][e]},null==t[_persistenceKey]&&this.clear()),this.isAvailable=function(){return n}},window.Persistence=new Persistence_sessionStorage,Persistence.isAvailable()||(window.Persistence=new Persistence_windowKey("py")),!Persistence.isAvailable()){var titleStartIndex=window.location.toString().indexOf("title"),titleContentIndex=window.location.toString().indexOf("main",titleStartIndex);titleStartIndex>0&&titleContentIndex>0&&titleContentIndex-titleStartIndex<10&&(window.Persistence=new Persistence_windowKey("qt"))}}
</script>
Go back to Front Template, and add the following where you want the value to be shown. If you don't know, just put it anywhere, check at the end where it renders well, and change it then, so you have visual feedback. Also avoid having other tags with id=values.
<div id="values">{{Values}}</div>
If you renamed the field Values, change the one between double braces too.
6. Add at the bottom of the template the following. This will be responsible for picking a value at random.
<script>
var valuesNode = document.getElementById("values");
var values = valuesNode.innerText.split(',');
var defaultValue = values[0];
var value = defaultValue;
if (Persistence.isAvailable()) {
value = Persistence.getItem();
if (value == null) {
value = values[Math.floor(Math.random() * values.length)];
Persistence.setItem(value);
}
}
valuesNode.innerText = value;
</script>
Go to the Back Template, and add the following where you want the value to be shown (just like in the front template):
<div id="values">{{Values}}</div>
At the bottom of the template, add the following. This will be responsible for showing the randomly picked value when showing the answer.
<script>
var valuesNode = document.getElementById("values");
var values = valuesNode.innerText.split(',');
var defaultValue = values[0];
var value = defaultValue;
if (Persistence.isAvailable()) {
value = Persistence.getItem();
Persistence.clear();
}
valuesNode.innerText = value;
</script>
Here I'm going to explain why there is a default value. This is due to the fact that several Anki clients handle JavaScript differently. anki persistance should work when you are reviewing, but it may not work when you are previewing a card. In these cases, it could still pick a random value, but when you would reveal the answer it could not "remember" which value it picked, so it would pick an other one at random. To prevent that, if it knows it will not remember, it will just pick the default one, so it's consistent when you reveal the answer.

auto formatting python code to put parameters on same line

I really hate having spread out code, I am looking at a bunch of long code with parameters and arguments that are taking up way to much space.
def __init__(self,
network,
value_coef,
entropy_coef,
lr=None,
eps=None,
max_grad_norm=None,
conv=False):
Seems the guy who wrote it forced a 50 character line limit, I whole heartedly disagree. I would much rather it looked like this.
def __init__(self, network, value_coef, entropy_coef, lr=None, eps=None, max_grad_norm=None, conv=False):
There is also more nonsense like this which I would like to get rid of.
if self.conv:
grid_obs = rollouts.grid_obs[:-1]\
.view(-1, *rollouts.grid_obs.size()[2:])
dest_obs = rollouts.dest_obs[:-1]\
.view(-1, *rollouts.dest_obs.size()[2:])
obs = (grid_obs, dest_obs)
I am using VS code for the python and am an ex Intellij user and am missing all the built in code formatting code tools. Any one got any tips? I have been looking at autopep8 but it seems they are missing that functionality.
First, that's not 50 chars limit but 79 (as per pep8 conventions) and the way you would like to have it wouldn't be pep8 compliant as it's over 100 columns.
So, for the first snippet you can have it the way you don't like it (which is the correct way) or let your formatter know that you want the line-length to be over 79 columns.
For the second snippet you can remove the escape character \ and let the formatter do its job. I don't think it's 'nonsense' as you call it, but feel free to format it differently.
Autopep8 or Black both work very well and they are not missing any functionality.
Provided you installed one or the other, you have to add the proper key/value pair to your settings.json:
"python.formatting.provider": "autopep8" // (or "black")
If you use autopep8, for example, you can specify the line length you want (150 in your case) by adding this to your settings.json file:
"python.formatting.autopep8Args": [
"--line-length=150"
]
The same goes for black. In that case the value would be:
"python.formatting.blackArgs": [
"--line-length=150"
]
Formatting with that parameter will wrap your code to that amount.
You can format code with alt+shift+f (on a Mac) or right click on the editor and "Format Document".

Dynamo Revit set formula for a parameter in a family

I am trying to add a formula to a parameter within a Revit Family.
Currently I have multiple families in a project. I run Dynamo from within that project then I extract the families that I want to modify using Dynamo standard nodes.
Then I use a python script node that goes through every selected family and find the parameter I am interested in, and assign a formula for it.
That seemed fine until I noticed that it is not assigning the formula, but it is entering it as a string — as in it is in quotes. And sure enough, the code i am using will only work with Text type parameters.
Can someone shed the light on how to assign a formula to a parameter using dynamo?
see line 32 in code below
Thanks
for family in families:
TransactionManager.Instance.ForceCloseTransaction()
famdoc = doc.EditFamily(family)
FamilyMan = famdoc.FamilyManager
found.append(family.Name)
TransactionManager.Instance.EnsureInTransaction(famdoc)
check = 0
# Loop thru the list of parameters to assign formula values to them... these are given as imput
for r in range(len(param_name_lst)):
# Loop thru the list of parameters in the current family per the families outter loop above.
for param in FamilyMan.Parameters:
#for param in FamilyMan.get_Parameter(param_name_lst[r]):
# for each of the parameters get their name and store in paramName.
paramName = param.Definition.Name
# Check if we have a match in parameter name.
if param_name_lst[r] in paramName:
if param.CanAssignFormula:
canassignformula.append(param_name_lst[r])
else:
cannotassignformula.append(param_name_lst[r])
try:
# Make sure that the parameter is not locked.
if FamilyMan.IsParameterLocked(param):
FamilyMan.SetParameterLocked(param,False)
locked.append(paraName)
# Enter formula value to parameter.
FamilyMan.SetFormula(param, param_value_lst[r])
check += 1
except:
failed.append(paramName)
else:
continue
Actually, you can access the family from the main project, and you can assign a formula automatically.... That's what i currently do, i load all the families i want in one project and run the script.
After a lot of work, i was able to figure out what i was doing wrong, and in it is not in my code... my code was fine.
The main problem is that i need to have all of my formula's dependencies lined up.... just like in manual mode.
so if my formula is:
size_lookup(MY_ID_tbl, "MY_VAR", "MY_DefaultValue", ND1,ND2)
then i need to have the following:
MY_ID_tbl should exist and be assigned a valid value, in this case it should have a csv filename. Moreover, that file should be also loaded. This is important for the next steps.
MY_VAR should be defined in that csv file, so Does ND1, ND2
The default value (My_Default_Value) should match what that csv file says about that variable...in this case, it is a text.
Needless to say, i did not have all of the above lined up as it should be, once i fixed that, my setFormula code did its job. And i had to change my process altogether, cause i have to first create the MY_ID_tbl and load the csv file which i also do using dynamo, then i go and enter the formulas using dynamo.
Revit parameters can only be assigned to a formula inside the family editor only, that is the first point, so you should run your dynamo script inside the family editor for each family which will be a waste of time and you just edit the parameter's formula manually inside each family.
and the second point, I don't even think that it is possible to set a certain parameter's formula automatically, it must be done manually ( I haven't seen anything for it in the Revit API docs).

Snippets vs. Abbreviations in Vim

What advantages and/or disadvantages are there to using a "snippets" plugin, e.g. snipmate, ultisnips, for VIM as opposed to simply using the builtin "abbreviations" functionality?
Are there specific use-cases where declaring iabbr, cabbr, etc. lack some major features that the snippets plugins provide? I've been unsuccessful in finding a thorough comparison between these two "features" and their respective implementations.
As #peter-rincker pointed out in a comment:
It should be noted that abbreviations can execute code as well. Often via <c-r>= or via an expression abbreviation (<expr>). Example which expands ## to the current file's path: :iabbrev ## <c-r>=expand('%:p')<cr>
As an example for python, let's compare a snipmate snippet and an abbrev in Vim for inserting lines for class declaration.
Snipmate
# New Class
snippet cl
class ${1:ClassName}(${2:object}):
"""${3:docstring for $1}"""
def __init__(self, ${4:arg}):
${5:super($1, self).__init__()}
self.$4 = $4
${6}
Vimscript
au FileType python :iabbr cl class ClassName(object):<CR><Tab>"""docstring for ClassName"""<CR>def __init__(self, arg):<CR><Tab>super(ClassName, self).__init__()<CR>self.arg = arg
Am I missing some fundamental functionality of "snippets" or am I correct in assuming they are overkill for the most part, when Vim's abbr and :help template templates are able to do all most of the stuff snippets do?
I assume it's easier to implement snippets, and they provide additional aesthetic/visual features. For instance, if I use abbr in Vim and other plugins for running/testing python code inside vim--e.g. syntastic, pytest, ropevim, pep8, etc--am I missing out on some key features that snippets provide?
Everything that can be done with snippets can be done with abbreviations and vice-versa. You can have (mirrored or not) placeholders with abbreviations, you can have context-sensitive snippets.
There are two important differences:
Abbreviations are triggered when the abbreviation text has been typed, and a non word character (or esc) is hit. Snippets are triggered on demand, and shortcuts are possible (no need to type while + tab. w + tab may be enough).
It's much more easier to define new snippets (or to maintain old ones) than to define abbreviations. With abbreviations, a lot of boiler plate code is required when we want to do neat things.
There are a few other differences. For instance, abbreviations are always triggered everywhere. And seeing for expanded into for(placeholder) {\n} within a comment or a string context is certainly not what the end-user expects. With snippets, this is not a problem any more: we can expect the end-user to know what's he's doing when he asks to expand a snippet. Still, we can propose context-aware snippets that expand throw into #throw {domain::exception} {explanation} within a comment, or into throw domain::exception({message}); elsewhere.
Snippets
Rough superset of Vim's native abbreviations. Here are the highlights:
Only trigger on key press
Uses placeholders which a user can jump between
Exist only for insert mode
Dynamic expansions
Abbreviations
Great for common typos and small snippets.
Native to Vim so no need for plugins
Typically expand on whitespace or <c-]>
Some special rules on trigger text (See :h abbreviations)
Can be used in command mode via :cabbrev (often used to create command aliases)
No placeholders
Dynamic expansions
Conclusion
For the most part snippets are more powerful and provide many features that other editors enjoy, but you can use both and many people do. Abbreviations enjoy the benefit of being native which can be useful for remote environments. Abbreviations also enjoy another clear advantage which is can be used in command mode.
Snippets are more powerful.
Depending on the implementation, snippets can let you change (or accept defaults for) multiple placeholders and can even execute code when the snippet is expanded.
For example with ultisnips, you can have it execute shell commands, vimscript but also Python code.
An (ultisnips) example:
snippet hdr "General file header" b
# file: `!v expand('%:t')`
# vim:fileencoding=utf-8:ft=`!v &filetype`
# ${1}
#
# Author: ${2:J. Doe} ${3:<jdoe#gmail.com>}
# Created: `!v strftime("%F %T %z")`
# Last modified: `!v strftime("%F %T %z")`
endsnippet
This presents you with three placeholders to fill in (it gives default values for two of them), and sets the filename, filetype and current date and time.
After the word "snippet", the start line contains three items;
the trigger string,
a description and
options for the snippet.
Personally I mostly use the b option where the snippet is expanded at the beginning of a line and the w option that expands the snippet if the trigger string starts at the beginning of a word.
Note that you have to type the trigger string and then input a key or key combination that actually triggers the expansion. So a snippet is not expanded unless you want it to.
Additionally, snippets can be specialized by filetype. Suppose you want to define four levels of headings, h1 .. h4. You can have the same name expand differently between e.g. an HTML, markdown, LaTeX or restructuredtext file.
snippets are like the built-in :abbreviate on steroids, usually with:
parameter insertions: You can insert (type or select) text fragments in various places inside the snippet. An abbreviation just expands once.
mirroring: Parameters may be repeated (maybe even in transformed fashion) elsewhere in the snippet, usually updated as you type.
multiple stops inside: You can jump from one point to another within the snippet, sometimes even recursively expand snippets within one.
There are three things to evaluate in a snippet plugin: First, the features of the snippet engine itself, second, the quality and breadth of snippets provided by the author or others; third, how easy it is to add new snippets.

PLY: Token shifting problem in C parser

I'm writing a C parser using PLY, and recently ran into a problem.
This code:
typedef int my_type;
my_type x;
Is correct C code, because my_type is defined as a type previously to
being used as such. I handle it by filling a type symbol table in the
parser that gets used by the lexer to differentiate between types and
simple identifiers.
However, while the type declaration rule ends with SEMI (the ';' token), PLY shifts the token my_type from the second line before deciding it's done with the first one. Because of this, I have no chance to pass the update in the type symbol table to the lexer and it
sees my_type as an identifier and not a type.
Any ideas for a fix ?
The full code is at: http://code.google.com/p/pycparser/source/browse/trunk/src/c_parser.py
Not sure how I can create a smaller example out of this.
Edit:
Problem solved. See my solution below.
Not sure why you're doing that level of analysis in your lexer.
Lexical analysis should probably be used to separate the input stream into lexical tokens (number, line-change, keyword and so on). It's the parsing phase that should be doing that level of analysis, including table lookups for typedefs and such.
That's the way I've always separated the duties between lexx and yacc, my tools of choice.
With some help from Dave Beazley (PLY's creator), my problem was solved.
The idea is to use special sub-rules and do the actions in them. In my case, I split the declaration rule to:
def p_decl_body(self, p):
""" decl_body : declaration_specifiers init_declarator_list_opt
"""
# <<Handle the declaration here>>
def p_declaration(self, p):
""" declaration : decl_body SEMI
"""
p[0] = p[1]
decl_body is always reduced before the token after SEMI is shifted in, so my action gets executed at the correct time.
I think you need to move the check for whether an ID is a TYPEID from c_lexer.py to c_parser.py.
As you said, since the parser is looking ahead 1 token, you can't make that decision in the lexer.
Instead, alter your parser to check ID's to see if they are TYPEID's in declarations, and, if they aren't, generate an error.
As Pax Diablo said in his excellent answer, the lexer/tokenizer's job isn't to make those kinds of decisions about tokens. That's the parser's job.

Categories